add open/3, write_term/3
This commit is contained in:
@@ -216,6 +216,7 @@ pub enum SystemClauseType {
|
|||||||
NumberToChars,
|
NumberToChars,
|
||||||
NumberToCodes,
|
NumberToCodes,
|
||||||
OpDeclaration,
|
OpDeclaration,
|
||||||
|
Open,
|
||||||
PartialStringTail,
|
PartialStringTail,
|
||||||
PointsToContinuationResetMarker,
|
PointsToContinuationResetMarker,
|
||||||
REPL(REPLCodePtr),
|
REPL(REPLCodePtr),
|
||||||
@@ -352,7 +353,8 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
|
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
|
||||||
&SystemClauseType::Halt => clause_name!("$halt"),
|
&SystemClauseType::Halt => clause_name!("$halt"),
|
||||||
&SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"),
|
&SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"),
|
||||||
&SystemClauseType::OpDeclaration => clause_name!("$op$"),
|
&SystemClauseType::Open => clause_name!("$open"),
|
||||||
|
&SystemClauseType::OpDeclaration => clause_name!("$op"),
|
||||||
&SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
|
&SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
|
||||||
&SystemClauseType::InstallInferenceCounter => {
|
&SystemClauseType::InstallInferenceCounter => {
|
||||||
clause_name!("$install_inference_counter")
|
clause_name!("$install_inference_counter")
|
||||||
@@ -514,6 +516,7 @@ impl SystemClauseType {
|
|||||||
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
|
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
|
||||||
("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
|
("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
|
||||||
("$op", 3) => Some(SystemClauseType::OpDeclaration),
|
("$op", 3) => Some(SystemClauseType::OpDeclaration),
|
||||||
|
("$open", 7) => Some(SystemClauseType::Open),
|
||||||
("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding),
|
("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding),
|
||||||
("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
|
("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
|
||||||
("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
|
("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
|
||||||
@@ -570,7 +573,7 @@ impl SystemClauseType {
|
|||||||
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
|
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
|
||||||
("$variant", 2) => Some(SystemClauseType::Variant),
|
("$variant", 2) => Some(SystemClauseType::Variant),
|
||||||
("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
|
("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
|
||||||
("$write_term", 6) => Some(SystemClauseType::WriteTerm),
|
("$write_term", 7) => Some(SystemClauseType::WriteTerm),
|
||||||
("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars),
|
("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars),
|
||||||
("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion),
|
("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|||||||
@@ -49,12 +49,14 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
|
|||||||
expand_goal/2, expand_term/2, fail/0, false/0,
|
expand_goal/2, expand_term/2, fail/0, false/0,
|
||||||
findall/3, findall/4, get_char/1, halt/0,
|
findall/3, findall/4, get_char/1, halt/0,
|
||||||
max_arity/1, number_chars/2, number_codes/2,
|
max_arity/1, number_chars/2, number_codes/2,
|
||||||
once/1, op/3, read_term/2, read_term/3, repeat/0,
|
once/1, op/3, open/3, open/4, read_term/2,
|
||||||
retract/1, set_prolog_flag/2, set_input/1,
|
read_term/3, repeat/0, retract/1,
|
||||||
set_output/1, setof/3, sub_atom/5,
|
set_prolog_flag/2, set_input/1, set_output/1,
|
||||||
subsumes_term/2, term_variables/2, throw/1,
|
setof/3, sub_atom/5, subsumes_term/2,
|
||||||
true/0, unify_with_occurs_check/2, write/1,
|
term_variables/2, throw/1, true/0,
|
||||||
write_canonical/1, write_term/2, writeq/1]).
|
unify_with_occurs_check/2, write/1,
|
||||||
|
write_canonical/1, write_term/2, write_term/3,
|
||||||
|
writeq/1]).
|
||||||
|
|
||||||
|
|
||||||
% the maximum arity flag. needs to be replaced with
|
% the maximum arity flag. needs to be replaced with
|
||||||
@@ -312,36 +314,39 @@ get_args([Arg|Args], Func, I0, N) :-
|
|||||||
'$call_with_default_policy'(I1 is I0 + 1),
|
'$call_with_default_policy'(I1 is I0 + 1),
|
||||||
'$call_with_default_policy'(get_args(Args, Func, I1, N)).
|
'$call_with_default_policy'(get_args(Args, Func, I1, N)).
|
||||||
|
|
||||||
% write, write_canonical, writeq, write_term.
|
parse_write_options(Options, OptionValues, Stub) :-
|
||||||
is_write_option(Functor) :-
|
DefaultOptions = [ignore_ops-false, max_depth-0, numbervars-false,
|
||||||
Functor =.. [Name, Arg],
|
quoted-false, variable_names-[]],
|
||||||
( Arg == true -> true
|
parse_options_list(Options, parse_write_options_, DefaultOptions, OptionValues, Stub).
|
||||||
; Arg == false -> true
|
|
||||||
; Name == variable_names -> must_be_var_names_list(Arg)
|
|
||||||
; Name == max_depth -> integer(Arg), Arg >= 0
|
|
||||||
; var(Arg) -> throw(error(instantiation_error, write_term/2))
|
|
||||||
; throw(error(domain_error(write_option, Functor), write_term/2))
|
|
||||||
), % 8.14.2.3 e)
|
|
||||||
( Name == ignore_ops -> true
|
|
||||||
; Name == quoted -> true
|
|
||||||
; Name == numbervars -> true
|
|
||||||
; Name == variable_names -> true
|
|
||||||
; Name == max_depth -> true
|
|
||||||
; throw(error(domain_error(write_option, Functor), write_term/2))
|
|
||||||
). % 8.14.2.3 e)
|
|
||||||
|
|
||||||
inst_member_or([X|Xs], Y, Z) :-
|
parse_write_options_(ignore_ops(IgnoreOps), ignore_ops-IgnoreOps) :-
|
||||||
( var(X) -> throw(error(instantiation_error, write_term/2))
|
( nonvar(IgnoreOps), lists:member(IgnoreOps, [true, false])
|
||||||
; is_write_option(X) -> ( Y = X, ! ; inst_member_or(Xs, Y, Z) )
|
;
|
||||||
; throw(error(domain_error(write_option, X), write_term/2))
|
throw(error(domain_error(write_option, ignore_ops(IgnoreOps)), _))
|
||||||
|
).
|
||||||
|
parse_write_options_(quoted(Quoted), quoted-Quoted) :-
|
||||||
|
( nonvar(Quoted), lists:member(Quoted, [true, false])
|
||||||
|
;
|
||||||
|
throw(error(domain_error(write_option, quoted(Quoted)), _))
|
||||||
|
).
|
||||||
|
parse_write_options_(numbervars(NumberVars), numbervars-NumberVars) :-
|
||||||
|
( nonvar(NumberVars), lists:member(NumberVars, [true, false])
|
||||||
|
;
|
||||||
|
throw(error(domain_error(write_option, numbervars(NumberVars)), _))
|
||||||
|
).
|
||||||
|
parse_write_options_(variable_names(VNNames), variable_names-VNNames) :-
|
||||||
|
must_be_var_names_list(VNNames).
|
||||||
|
parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :-
|
||||||
|
( integer(MaxDepth), MaxDepth >= 0
|
||||||
|
;
|
||||||
|
throw(error(domain_error(write_option, max_depth(MaxDepth)), _))
|
||||||
).
|
).
|
||||||
inst_member_or([], Y, Y).
|
|
||||||
|
|
||||||
must_be_var_names_list(VarNames) :-
|
must_be_var_names_list(VarNames) :-
|
||||||
'$skip_max_list'(_, -1, VarNames, Tail),
|
'$skip_max_list'(_, -1, VarNames, Tail),
|
||||||
( Tail == [] -> must_be_var_names_list_(VarNames, VarNames)
|
( Tail == [] -> must_be_var_names_list_(VarNames, VarNames)
|
||||||
; var(Tail) -> throw(error(instantiation_error, write_term/2))
|
; var(Tail) -> throw(error(instantiation_error, write_term/2))
|
||||||
; throw(error(domain_error(write_options, variable_names(VarNames)), write_term/2))
|
; throw(error(domain_error(write_option, variable_names(VarNames)), write_term/2))
|
||||||
).
|
).
|
||||||
|
|
||||||
must_be_var_names_list_([], List).
|
must_be_var_names_list_([], List).
|
||||||
@@ -350,36 +355,34 @@ must_be_var_names_list_([VarName | VarNames], List) :-
|
|||||||
( VarName = (Atom = _) ->
|
( VarName = (Atom = _) ->
|
||||||
( atom(Atom) -> must_be_var_names_list_(VarNames, List)
|
( atom(Atom) -> must_be_var_names_list_(VarNames, List)
|
||||||
; var(Atom) -> throw(error(instantiation_error, write_term/2))
|
; var(Atom) -> throw(error(instantiation_error, write_term/2))
|
||||||
; throw(error(domain_error(write_options, variable_names(List)), write_term/2))
|
; throw(error(domain_error(write_option, variable_names(List)), write_term/2))
|
||||||
)
|
)
|
||||||
; throw(error(domain_error(write_options, variable_names(List)), write_term/2))
|
; throw(error(domain_error(write_option, variable_names(List)), write_term/2))
|
||||||
)
|
)
|
||||||
; throw(error(instantiation_error, write_term/2)) % throw(error(domain_error(write_options, variable_names(List)), write_term/2))
|
; throw(error(instantiation_error, write_term/2))
|
||||||
).
|
).
|
||||||
|
|
||||||
write_term(_, Options) :-
|
|
||||||
var(Options), throw(error(instantiation_error, write_term/2)).
|
|
||||||
write_term(Term, Options) :-
|
write_term(Term, Options) :-
|
||||||
'$skip_max_list'(_, -1, Options, Options0),
|
current_output(Stream),
|
||||||
( var(Options0) -> throw(error(instantiation_error, write_term/2))
|
write_term(Stream, Term, Options).
|
||||||
; Options0 == [] -> true
|
|
||||||
; throw(error(type_error(list, Options), write_term/2))
|
write_term(Stream, Term, Options) :-
|
||||||
), % 8.14.2.3 c)
|
parse_write_options(Options, [IgnoreOps, MaxDepth, NumberVars, Quoted, VNNames], write_term/3),
|
||||||
inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)),
|
'$write_term'(Stream, Term, IgnoreOps, NumberVars, Quoted, VNNames, MaxDepth).
|
||||||
inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
|
|
||||||
inst_member_or(Options, quoted(Quoted), quoted(false)),
|
|
||||||
inst_member_or(Options, variable_names(VarNames), variable_names([])),
|
|
||||||
inst_member_or(Options, max_depth(MaxDepth), max_depth(0)),
|
|
||||||
'$write_term'(Term, IgnoreOps, NumberVars, Quoted, VarNames, MaxDepth).
|
|
||||||
|
|
||||||
write(Term) :-
|
write(Term) :-
|
||||||
'$write_term'(Term, false, true, false, [], 0).
|
current_output(Stream),
|
||||||
|
'$write_term'(Stream, Term, false, true, false, [], 0).
|
||||||
|
|
||||||
write_canonical(Term) :-
|
write_canonical(Term) :-
|
||||||
'$write_term'(Term, true, false, true, [], 0).
|
current_output(Stream),
|
||||||
|
'$write_term'(Stream, Term, true, false, true, [], 0).
|
||||||
|
|
||||||
writeq(Term) :-
|
writeq(Term) :-
|
||||||
'$write_term'(Term, false, true, true, [], 0).
|
current_output(Stream),
|
||||||
|
'$write_term'(Stream, Term, false, true, true, [], 0).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1139,3 +1142,22 @@ parse_stream_options_(eof_action(Action), eof_action-Action) :-
|
|||||||
).
|
).
|
||||||
parse_stream_options_(E, _) :-
|
parse_stream_options_(E, _) :-
|
||||||
throw(error(domain_error(stream_option, E), _)). % 8.11.5.3i)
|
throw(error(domain_error(stream_option, E), _)). % 8.11.5.3i)
|
||||||
|
|
||||||
|
|
||||||
|
open(SourceSink, Mode, Stream) :-
|
||||||
|
open(SourceSink, Mode, Stream, []).
|
||||||
|
|
||||||
|
open(SourceSink, Mode, Stream, StreamOptions) :-
|
||||||
|
( var(SourceSink) ->
|
||||||
|
throw(error(instantiation_error, open/4)) % 8.11.5.3a)
|
||||||
|
; var(Mode) ->
|
||||||
|
throw(error(instantiation_error, open/4)) % 8.11.5.3b)
|
||||||
|
; \+ atom(Mode) ->
|
||||||
|
throw(error(type_error(atom, Mode), open/4)) % 8.11.5.3d)
|
||||||
|
; nonvar(Stream) ->
|
||||||
|
throw(error(type_error(variable, Stream), open/4)) % 8.11.5.3f)
|
||||||
|
;
|
||||||
|
parse_stream_options(StreamOptions, [Alias, EOFAction, Reposition, Type], open/4),
|
||||||
|
'$open'(SourceSink, Mode, Stream, Alias, EOFAction, Reposition, Type)
|
||||||
|
).
|
||||||
|
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ fn load_module_from_file(
|
|||||||
let mut path_buf = fix_filename(wam.indices.atom_tbl.clone(), path_buf)?;
|
let mut path_buf = fix_filename(wam.indices.atom_tbl.clone(), path_buf)?;
|
||||||
let filename = clause_name!(path_buf.to_string_lossy().to_string(), wam.indices.atom_tbl);
|
let filename = clause_name!(path_buf.to_string_lossy().to_string(), wam.indices.atom_tbl);
|
||||||
|
|
||||||
let file_handle = Stream::from(File::open(&path_buf).or_else(|_| {
|
let file_handle = Stream::from_file_as_input(File::open(&path_buf).or_else(|_| {
|
||||||
Err(SessionError::InvalidFileName(filename.clone()))
|
Err(SessionError::InvalidFileName(filename.clone()))
|
||||||
})?);
|
})?);
|
||||||
|
|
||||||
|
|||||||
@@ -274,7 +274,7 @@ impl MachineError {
|
|||||||
MachineError {
|
MachineError {
|
||||||
stub,
|
stub,
|
||||||
location: None,
|
location: None,
|
||||||
from: ErrorProvenance::Constructed,
|
from: ErrorProvenance::Received,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExistenceError::Stream(culprit) => {
|
ExistenceError::Stream(culprit) => {
|
||||||
@@ -533,6 +533,7 @@ impl ValidType {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum DomainErrorType {
|
pub enum DomainErrorType {
|
||||||
|
IOMode,
|
||||||
NotLessThanZero,
|
NotLessThanZero,
|
||||||
Order,
|
Order,
|
||||||
Stream,
|
Stream,
|
||||||
@@ -542,6 +543,7 @@ pub enum DomainErrorType {
|
|||||||
impl DomainErrorType {
|
impl DomainErrorType {
|
||||||
pub fn as_str(self) -> &'static str {
|
pub fn as_str(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
|
DomainErrorType::IOMode => "io_mode",
|
||||||
DomainErrorType::NotLessThanZero => "not_less_than_zero",
|
DomainErrorType::NotLessThanZero => "not_less_than_zero",
|
||||||
DomainErrorType::Order => "order",
|
DomainErrorType::Order => "order",
|
||||||
DomainErrorType::Stream => "stream",
|
DomainErrorType::Stream => "stream",
|
||||||
|
|||||||
@@ -723,10 +723,10 @@ impl MachineState {
|
|||||||
op_dir: &'a OpDir,
|
op_dir: &'a OpDir,
|
||||||
) -> Result<Option<HCPrinter<'a, PrinterOutputter>>, MachineStub>
|
) -> Result<Option<HCPrinter<'a, PrinterOutputter>>, MachineStub>
|
||||||
{
|
{
|
||||||
let ignore_ops = self.store(self.deref(self[temp_v!(2)]));
|
let ignore_ops = self.store(self.deref(self[temp_v!(3)]));
|
||||||
let numbervars = self.store(self.deref(self[temp_v!(3)]));
|
let numbervars = self.store(self.deref(self[temp_v!(4)]));
|
||||||
let quoted = self.store(self.deref(self[temp_v!(4)]));
|
let quoted = self.store(self.deref(self[temp_v!(5)]));
|
||||||
let max_depth = self.store(self.deref(self[temp_v!(6)]));
|
let max_depth = self.store(self.deref(self[temp_v!(7)]));
|
||||||
|
|
||||||
let mut printer = HCPrinter::new(&self, op_dir, PrinterOutputter::new());
|
let mut printer = HCPrinter::new(&self, op_dir, PrinterOutputter::new());
|
||||||
|
|
||||||
@@ -776,7 +776,7 @@ impl MachineState {
|
|||||||
|
|
||||||
let stub = MachineError::functor_stub(clause_name!("write_term"), 2);
|
let stub = MachineError::functor_stub(clause_name!("write_term"), 2);
|
||||||
|
|
||||||
match self.try_from_list(temp_v!(5), stub) {
|
match self.try_from_list(temp_v!(6), stub) {
|
||||||
Ok(addrs) => {
|
Ok(addrs) => {
|
||||||
let mut var_names: IndexMap<Addr, String> = IndexMap::new();
|
let mut var_names: IndexMap<Addr, String> = IndexMap::new();
|
||||||
|
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ impl Machine {
|
|||||||
|
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
let file_src = match File::open(&path) {
|
let file_src = match File::open(&path) {
|
||||||
Ok(file_handle) => Stream::from(file_handle),
|
Ok(file_handle) => Stream::from_file_as_input(file_handle),
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ pub enum EOFAction {
|
|||||||
pub enum StreamInstance {
|
pub enum StreamInstance {
|
||||||
Bytes(Cursor<Vec<u8>>),
|
Bytes(Cursor<Vec<u8>>),
|
||||||
DynReadSource(Box<dyn Read>),
|
DynReadSource(Box<dyn Read>),
|
||||||
File(File),
|
InputFile(File),
|
||||||
|
OutputFile(File),
|
||||||
Null,
|
Null,
|
||||||
ReadlineStream(ReadlineStream),
|
ReadlineStream(ReadlineStream),
|
||||||
// Stdin,
|
// Stdin,
|
||||||
@@ -48,7 +49,8 @@ impl fmt::Debug for StreamInstance {
|
|||||||
write!(fmt, "Bytes({:?})", bytes),
|
write!(fmt, "Bytes({:?})", bytes),
|
||||||
&StreamInstance::DynReadSource(_) =>
|
&StreamInstance::DynReadSource(_) =>
|
||||||
write!(fmt, "DynReadSource(_)"), // Hacky solution.
|
write!(fmt, "DynReadSource(_)"), // Hacky solution.
|
||||||
&StreamInstance::File(ref file) => write!(fmt, "File({:?})", file),
|
&StreamInstance::InputFile(ref file) => write!(fmt, "InputFile({:?})", file),
|
||||||
|
&StreamInstance::OutputFile(ref file) => write!(fmt, "OutputFile({:?})", file),
|
||||||
&StreamInstance::Null => write!(fmt, "Null"),
|
&StreamInstance::Null => write!(fmt, "Null"),
|
||||||
&StreamInstance::ReadlineStream(ref readline_stream) =>
|
&StreamInstance::ReadlineStream(ref readline_stream) =>
|
||||||
write!(fmt, "ReadlineStream({:?})", readline_stream),
|
write!(fmt, "ReadlineStream({:?})", readline_stream),
|
||||||
@@ -188,17 +190,6 @@ impl From<&'static str> for Stream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<File> for Stream {
|
|
||||||
fn from(file: File) -> Stream {
|
|
||||||
Stream {
|
|
||||||
options: StreamOptions::default(),
|
|
||||||
stream_inst: WrappedStreamInstance::new(
|
|
||||||
StreamInstance::File(file)
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Stream {
|
impl Stream {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate)
|
pub(crate)
|
||||||
@@ -225,6 +216,28 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn from_file_as_output(file: File) -> Self {
|
||||||
|
Stream {
|
||||||
|
options: StreamOptions::default(),
|
||||||
|
stream_inst: WrappedStreamInstance::new(
|
||||||
|
StreamInstance::OutputFile(file)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn from_file_as_input(file: File) -> Self {
|
||||||
|
Stream {
|
||||||
|
options: StreamOptions::default(),
|
||||||
|
stream_inst: WrappedStreamInstance::new(
|
||||||
|
StreamInstance::InputFile(file)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate)
|
pub(crate)
|
||||||
@@ -285,9 +298,9 @@ impl Stream {
|
|||||||
StreamInstance::Bytes(_) |
|
StreamInstance::Bytes(_) |
|
||||||
StreamInstance::ReadlineStream(_) |
|
StreamInstance::ReadlineStream(_) |
|
||||||
StreamInstance::DynReadSource(_) |
|
StreamInstance::DynReadSource(_) |
|
||||||
StreamInstance::File(_) => {
|
StreamInstance::InputFile(_) => {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@@ -301,7 +314,7 @@ impl Stream {
|
|||||||
StreamInstance::Stdout
|
StreamInstance::Stdout
|
||||||
| StreamInstance::TcpStream(_)
|
| StreamInstance::TcpStream(_)
|
||||||
| StreamInstance::Bytes(_)
|
| StreamInstance::Bytes(_)
|
||||||
| StreamInstance::File(_) => {
|
| StreamInstance::OutputFile(_) => {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -404,9 +417,9 @@ impl MachineState {
|
|||||||
arity: usize,
|
arity: usize,
|
||||||
) -> Result<Stream, MachineStub>
|
) -> Result<Stream, MachineStub>
|
||||||
{
|
{
|
||||||
Ok(match addr {
|
Ok(match self.store(self.deref(addr)) {
|
||||||
Addr::Con(h) if self.heap.atom_at(h) => {
|
Addr::Con(h) if self.heap.atom_at(h) => {
|
||||||
if let HeapCellValue::Atom(ref atom, ref spec) = self.heap.clone(h) {
|
if let HeapCellValue::Atom(ref atom, ref spec) = self.heap.clone(h) {
|
||||||
match indices.stream_aliases.get(atom) {
|
match indices.stream_aliases.get(atom) {
|
||||||
Some(stream) => {
|
Some(stream) => {
|
||||||
stream.clone()
|
stream.clone()
|
||||||
@@ -436,13 +449,20 @@ impl MachineState {
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
addr => {
|
||||||
let stub = MachineError::functor_stub(clause_name!(caller), arity);
|
let stub = MachineError::functor_stub(clause_name!(caller), arity);
|
||||||
|
|
||||||
return Err(self.error_form(
|
if addr.is_ref() {
|
||||||
MachineError::domain_error(DomainErrorType::StreamOrAlias, addr),
|
return Err(self.error_form(
|
||||||
stub,
|
MachineError::instantiation_error(),
|
||||||
));
|
stub,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
return Err(self.error_form(
|
||||||
|
MachineError::domain_error(DomainErrorType::StreamOrAlias, addr),
|
||||||
|
stub,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -529,7 +549,7 @@ impl MachineState {
|
|||||||
impl Read for Stream {
|
impl Read for Stream {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
match *self.stream_inst.0.borrow_mut() {
|
match *self.stream_inst.0.borrow_mut() {
|
||||||
StreamInstance::File(ref mut file) => {
|
StreamInstance::InputFile(ref mut file) => {
|
||||||
file.read(buf)
|
file.read(buf)
|
||||||
}
|
}
|
||||||
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
||||||
@@ -549,7 +569,7 @@ impl Read for Stream {
|
|||||||
stdin().read(buf)
|
stdin().read(buf)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
StreamInstance::Stdout | StreamInstance::Null => {
|
StreamInstance::OutputFile(_) | StreamInstance::Stdout | StreamInstance::Null => {
|
||||||
Err(std::io::Error::new(
|
Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::ReadFromOutputStream,
|
StreamError::ReadFromOutputStream,
|
||||||
@@ -562,7 +582,7 @@ impl Read for Stream {
|
|||||||
impl Write for Stream {
|
impl Write for Stream {
|
||||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
match *self.stream_inst.0.borrow_mut() {
|
match *self.stream_inst.0.borrow_mut() {
|
||||||
StreamInstance::File(ref mut file) => {
|
StreamInstance::OutputFile(ref mut file) => {
|
||||||
file.write(buf)
|
file.write(buf)
|
||||||
}
|
}
|
||||||
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
||||||
@@ -574,7 +594,8 @@ impl Write for Stream {
|
|||||||
StreamInstance::Stdout => {
|
StreamInstance::Stdout => {
|
||||||
stdout().write(buf)
|
stdout().write(buf)
|
||||||
}
|
}
|
||||||
_ => {
|
StreamInstance::DynReadSource(_) | StreamInstance::ReadlineStream(_) |
|
||||||
|
StreamInstance::InputFile(_) | StreamInstance::Null => {
|
||||||
Err(std::io::Error::new(
|
Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::WriteToInputStream,
|
StreamError::WriteToInputStream,
|
||||||
@@ -585,7 +606,7 @@ impl Write for Stream {
|
|||||||
|
|
||||||
fn flush(&mut self) -> std::io::Result<()> {
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
match *self.stream_inst.0.borrow_mut() {
|
match *self.stream_inst.0.borrow_mut() {
|
||||||
StreamInstance::File(ref mut file) => {
|
StreamInstance::OutputFile(ref mut file) => {
|
||||||
file.flush()
|
file.flush()
|
||||||
}
|
}
|
||||||
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
||||||
@@ -597,7 +618,8 @@ impl Write for Stream {
|
|||||||
StreamInstance::Stdout => {
|
StreamInstance::Stdout => {
|
||||||
stdout().flush()
|
stdout().flush()
|
||||||
}
|
}
|
||||||
_ => {
|
StreamInstance::DynReadSource(_) | StreamInstance::ReadlineStream(_) |
|
||||||
|
StreamInstance::InputFile(_) | StreamInstance::Null => {
|
||||||
Err(std::io::Error::new(
|
Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::FlushToInputStream,
|
StreamError::FlushToInputStream,
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ use crate::ref_thread_local::RefThreadLocal;
|
|||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::io::{stdout, ErrorKind, Read, Write};
|
use std::io::{ErrorKind, Read, Write};
|
||||||
use std::iter::{once, FromIterator};
|
use std::iter::{once, FromIterator};
|
||||||
use std::fs::File;
|
use std::fs::{File, OpenOptions};
|
||||||
use std::net::{TcpListener, TcpStream};
|
use std::net::{TcpListener, TcpStream};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@@ -2206,6 +2206,103 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::Open => {
|
||||||
|
let alias = self[temp_v!(4)];
|
||||||
|
let eof_action = self[temp_v!(5)];
|
||||||
|
let reposition = self[temp_v!(6)];
|
||||||
|
let stream_type = self[temp_v!(7)];
|
||||||
|
|
||||||
|
let options =
|
||||||
|
self.to_stream_options(alias, eof_action, reposition, stream_type);
|
||||||
|
|
||||||
|
let file_spec =
|
||||||
|
atom_from!(self, indices, self.store(self.deref(self[temp_v!(1)])));
|
||||||
|
|
||||||
|
// 8.11.5.3l)
|
||||||
|
if let Some(ref alias) = &options.alias {
|
||||||
|
if indices.stream_aliases.contains_key(alias) {
|
||||||
|
return Err(self.occupied_alias_permission_error(
|
||||||
|
alias.clone(),
|
||||||
|
"open",
|
||||||
|
4,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mode =
|
||||||
|
atom_from!(self, indices, self.store(self.deref(self[temp_v!(2)])));
|
||||||
|
|
||||||
|
let mut open_options = OpenOptions::new();
|
||||||
|
|
||||||
|
let is_input_file =
|
||||||
|
match mode.as_str() {
|
||||||
|
"read" => {
|
||||||
|
open_options.read(true).write(false).create(false);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
"write" => {
|
||||||
|
open_options.read(false).write(true).create(true).append(false);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
"append" => {
|
||||||
|
open_options.read(false).write(true).create(true).append(true);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("open"), 4);
|
||||||
|
let err = MachineError::domain_error(
|
||||||
|
DomainErrorType::IOMode,
|
||||||
|
self[temp_v!(2)],
|
||||||
|
);
|
||||||
|
|
||||||
|
// 8.11.5.3h)
|
||||||
|
return Err(self.error_form(err, stub));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let file =
|
||||||
|
match open_options.open(file_spec.as_str()).map_err(|e| e.kind()) {
|
||||||
|
Ok(file) => {
|
||||||
|
file
|
||||||
|
}
|
||||||
|
Err(ErrorKind::NotFound) => {
|
||||||
|
// 8.11.5.3j)
|
||||||
|
let stub = MachineError::functor_stub(
|
||||||
|
clause_name!("open"),
|
||||||
|
4,
|
||||||
|
);
|
||||||
|
|
||||||
|
let err = MachineError::existence_error(
|
||||||
|
self.heap.h(),
|
||||||
|
ExistenceError::SourceSink(self[temp_v!(1)]),
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(self.error_form(err, stub));
|
||||||
|
}
|
||||||
|
Err(ErrorKind::PermissionDenied) => {
|
||||||
|
// 8.11.5.3k)
|
||||||
|
return Err(self.open_permission_error(self[temp_v!(1)], "open", 4));
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
// for now, just fail. expand to meaningful error messages later.
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut stream = if is_input_file {
|
||||||
|
Stream::from_file_as_input(file)
|
||||||
|
} else {
|
||||||
|
Stream::from_file_as_output(file)
|
||||||
|
};
|
||||||
|
|
||||||
|
stream.options = options;
|
||||||
|
|
||||||
|
let stream = self.heap.to_unifiable(HeapCellValue::Stream(stream));
|
||||||
|
let stream_var = self.store(self.deref(self[temp_v!(3)]));
|
||||||
|
|
||||||
|
self.bind(stream_var.as_var().unwrap(), stream);
|
||||||
|
}
|
||||||
&SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => {
|
&SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => {
|
||||||
self.truncate_if_no_lifted_heap_diff(|h| Addr::HeapCell(h))
|
self.truncate_if_no_lifted_heap_diff(|h| Addr::HeapCell(h))
|
||||||
}
|
}
|
||||||
@@ -3786,7 +3883,41 @@ impl MachineState {
|
|||||||
self.unify(listing, listing_var);
|
self.unify(listing, listing_var);
|
||||||
}
|
}
|
||||||
&SystemClauseType::WriteTerm => {
|
&SystemClauseType::WriteTerm => {
|
||||||
let addr = self[temp_v!(1)];
|
let mut stream = self.get_stream_or_alias(
|
||||||
|
self[temp_v!(1)],
|
||||||
|
indices,
|
||||||
|
"write_term",
|
||||||
|
3,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let opt_err =
|
||||||
|
if !stream.is_output_stream() {
|
||||||
|
Some("stream") // 8.14.2.3 g)
|
||||||
|
} else if stream.options.stream_type == StreamType::Binary {
|
||||||
|
Some("binary_stream") // 8.14.2.3 h)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(err_string) = opt_err {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("write_term"), 3);
|
||||||
|
let h = self.heap.h();
|
||||||
|
|
||||||
|
let addr = self.heap.to_unifiable(
|
||||||
|
HeapCellValue::Stream(stream)
|
||||||
|
);
|
||||||
|
|
||||||
|
let err = MachineError::permission_error(
|
||||||
|
h + 1,
|
||||||
|
Permission::OutputStream,
|
||||||
|
err_string,
|
||||||
|
addr,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(self.error_form(err, stub));
|
||||||
|
}
|
||||||
|
|
||||||
|
let addr = self[temp_v!(2)];
|
||||||
|
|
||||||
let printer =
|
let printer =
|
||||||
match self.write_term(&indices.op_dir)? {
|
match self.write_term(&indices.op_dir)? {
|
||||||
@@ -3801,8 +3932,21 @@ impl MachineState {
|
|||||||
|
|
||||||
let output = printer.print(addr);
|
let output = printer.print(addr);
|
||||||
|
|
||||||
print!("{}", output.result());
|
match write!(&mut stream, "{}", output.result()) {
|
||||||
stdout().flush().unwrap();
|
Ok(_) => {
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("open"), 4);
|
||||||
|
let err = MachineError::existence_error(
|
||||||
|
self.heap.h(),
|
||||||
|
ExistenceError::Stream(self[temp_v!(1)]),
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(self.error_form(err, stub));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.flush().unwrap();
|
||||||
}
|
}
|
||||||
&SystemClauseType::WriteTermToChars => {
|
&SystemClauseType::WriteTermToChars => {
|
||||||
let addr = self[temp_v!(1)];
|
let addr = self[temp_v!(1)];
|
||||||
|
|||||||
@@ -405,3 +405,26 @@ macro_rules! ar_reg {
|
|||||||
ArithmeticTerm::Reg($r)
|
ArithmeticTerm::Reg($r)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! atom_from {
|
||||||
|
($self:expr, $indices:expr, $e:expr) => {
|
||||||
|
match $e {
|
||||||
|
Addr::Con(h) if $self.heap.atom_at(h) => {
|
||||||
|
match &$self.heap[h] {
|
||||||
|
HeapCellValue::Atom(ref atom, _) => {
|
||||||
|
atom.clone()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Addr::Char(c) => {
|
||||||
|
clause_name!(c.to_string(), $indices.atom_tbl.clone())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user