From: Mark Thom Date: Mon, 4 May 2020 20:50:26 +0000 (-0600) Subject: add open/3, write_term/3 X-Git-Tag: v0.8.123~57^2~15 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=0d7a9f32d6207a661ceb283fcc68d91667a2aec2;p=scryer-prolog.git add open/3, write_term/3 --- diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index b5bfae0e..ce5d9e68 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -216,6 +216,7 @@ pub enum SystemClauseType { NumberToChars, NumberToCodes, OpDeclaration, + Open, PartialStringTail, PointsToContinuationResetMarker, REPL(REPLCodePtr), @@ -352,7 +353,8 @@ impl SystemClauseType { &SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"), &SystemClauseType::Halt => clause_name!("$halt"), &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::InstallInferenceCounter => { clause_name!("$install_inference_counter") @@ -514,6 +516,7 @@ impl SystemClauseType { ("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars), ("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes), ("$op", 3) => Some(SystemClauseType::OpDeclaration), + ("$open", 7) => Some(SystemClauseType::Open), ("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding), ("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck), ("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter), @@ -570,7 +573,7 @@ impl SystemClauseType { Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)), ("$variant", 2) => Some(SystemClauseType::Variant), ("$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), ("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion), _ => None, diff --git a/src/prolog/lib/builtins.pl b/src/prolog/lib/builtins.pl index 1d5080e5..2ec5680e 100644 --- a/src/prolog/lib/builtins.pl +++ b/src/prolog/lib/builtins.pl @@ -49,12 +49,14 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :- expand_goal/2, expand_term/2, fail/0, false/0, findall/3, findall/4, get_char/1, halt/0, max_arity/1, number_chars/2, number_codes/2, - once/1, op/3, read_term/2, read_term/3, repeat/0, - retract/1, set_prolog_flag/2, set_input/1, - set_output/1, setof/3, sub_atom/5, - subsumes_term/2, term_variables/2, throw/1, - true/0, unify_with_occurs_check/2, write/1, - write_canonical/1, write_term/2, writeq/1]). + once/1, op/3, open/3, open/4, read_term/2, + read_term/3, repeat/0, retract/1, + set_prolog_flag/2, set_input/1, set_output/1, + setof/3, sub_atom/5, subsumes_term/2, + term_variables/2, throw/1, true/0, + 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 @@ -312,36 +314,39 @@ get_args([Arg|Args], Func, I0, N) :- '$call_with_default_policy'(I1 is I0 + 1), '$call_with_default_policy'(get_args(Args, Func, I1, N)). -% write, write_canonical, writeq, write_term. -is_write_option(Functor) :- - Functor =.. [Name, Arg], - ( Arg == true -> true - ; 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) :- - ( var(X) -> throw(error(instantiation_error, write_term/2)) - ; is_write_option(X) -> ( Y = X, ! ; inst_member_or(Xs, Y, Z) ) - ; throw(error(domain_error(write_option, X), write_term/2)) - ). -inst_member_or([], Y, Y). +parse_write_options(Options, OptionValues, Stub) :- + DefaultOptions = [ignore_ops-false, max_depth-0, numbervars-false, + quoted-false, variable_names-[]], + parse_options_list(Options, parse_write_options_, DefaultOptions, OptionValues, Stub). + +parse_write_options_(ignore_ops(IgnoreOps), ignore_ops-IgnoreOps) :- + ( nonvar(IgnoreOps), lists:member(IgnoreOps, [true, false]) + ; + 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)), _)) + ). must_be_var_names_list(VarNames) :- '$skip_max_list'(_, -1, VarNames, Tail), ( Tail == [] -> must_be_var_names_list_(VarNames, VarNames) ; 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). @@ -350,36 +355,34 @@ must_be_var_names_list_([VarName | VarNames], List) :- ( VarName = (Atom = _) -> ( atom(Atom) -> must_be_var_names_list_(VarNames, List) ; 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) :- - '$skip_max_list'(_, -1, Options, Options0), - ( var(Options0) -> throw(error(instantiation_error, write_term/2)) - ; Options0 == [] -> true - ; throw(error(type_error(list, Options), write_term/2)) - ), % 8.14.2.3 c) - inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)), - 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). + current_output(Stream), + write_term(Stream, Term, Options). + +write_term(Stream, Term, Options) :- + parse_write_options(Options, [IgnoreOps, MaxDepth, NumberVars, Quoted, VNNames], write_term/3), + '$write_term'(Stream, Term, IgnoreOps, NumberVars, Quoted, VNNames, MaxDepth). + write(Term) :- - '$write_term'(Term, false, true, false, [], 0). + current_output(Stream), + '$write_term'(Stream, Term, false, true, false, [], 0). write_canonical(Term) :- - '$write_term'(Term, true, false, true, [], 0). + current_output(Stream), + '$write_term'(Stream, Term, true, false, true, [], 0). 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, _) :- 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) + ). + diff --git a/src/prolog/machine/compile.rs b/src/prolog/machine/compile.rs index 8882e2ff..a887cfb6 100644 --- a/src/prolog/machine/compile.rs +++ b/src/prolog/machine/compile.rs @@ -119,7 +119,7 @@ fn load_module_from_file( 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 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())) })?); diff --git a/src/prolog/machine/machine_errors.rs b/src/prolog/machine/machine_errors.rs index a46345e2..4a022316 100644 --- a/src/prolog/machine/machine_errors.rs +++ b/src/prolog/machine/machine_errors.rs @@ -274,7 +274,7 @@ impl MachineError { MachineError { stub, location: None, - from: ErrorProvenance::Constructed, + from: ErrorProvenance::Received, } } ExistenceError::Stream(culprit) => { @@ -533,6 +533,7 @@ impl ValidType { #[derive(Debug, Clone, Copy)] pub enum DomainErrorType { + IOMode, NotLessThanZero, Order, Stream, @@ -542,6 +543,7 @@ pub enum DomainErrorType { impl DomainErrorType { pub fn as_str(self) -> &'static str { match self { + DomainErrorType::IOMode => "io_mode", DomainErrorType::NotLessThanZero => "not_less_than_zero", DomainErrorType::Order => "order", DomainErrorType::Stream => "stream", diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 46fc5ed9..b86496b3 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -723,10 +723,10 @@ impl MachineState { op_dir: &'a OpDir, ) -> Result>, MachineStub> { - let ignore_ops = self.store(self.deref(self[temp_v!(2)])); - let numbervars = self.store(self.deref(self[temp_v!(3)])); - let quoted = self.store(self.deref(self[temp_v!(4)])); - let max_depth = self.store(self.deref(self[temp_v!(6)])); + let ignore_ops = 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!(5)])); + let max_depth = self.store(self.deref(self[temp_v!(7)])); 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); - match self.try_from_list(temp_v!(5), stub) { + match self.try_from_list(temp_v!(6), stub) { Ok(addrs) => { let mut var_names: IndexMap = IndexMap::new(); diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index f4412340..781fa8a3 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -315,7 +315,7 @@ impl Machine { if path.is_file() { 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, }; diff --git a/src/prolog/machine/streams.rs b/src/prolog/machine/streams.rs index 4e4af96e..8cd7cbf0 100644 --- a/src/prolog/machine/streams.rs +++ b/src/prolog/machine/streams.rs @@ -33,7 +33,8 @@ pub enum EOFAction { pub enum StreamInstance { Bytes(Cursor>), DynReadSource(Box), - File(File), + InputFile(File), + OutputFile(File), Null, ReadlineStream(ReadlineStream), // Stdin, @@ -48,7 +49,8 @@ impl fmt::Debug for StreamInstance { write!(fmt, "Bytes({:?})", bytes), &StreamInstance::DynReadSource(_) => 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::ReadlineStream(ref readline_stream) => write!(fmt, "ReadlineStream({:?})", readline_stream), @@ -188,17 +190,6 @@ impl From<&'static str> for Stream { } } -impl From for Stream { - fn from(file: File) -> Stream { - Stream { - options: StreamOptions::default(), - stream_inst: WrappedStreamInstance::new( - StreamInstance::File(file) - ), - } - } -} - impl Stream { #[inline] 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] pub(crate) @@ -285,9 +298,9 @@ impl Stream { StreamInstance::Bytes(_) | StreamInstance::ReadlineStream(_) | StreamInstance::DynReadSource(_) | - StreamInstance::File(_) => { + StreamInstance::InputFile(_) => { true - } + } _ => { false } @@ -301,7 +314,7 @@ impl Stream { StreamInstance::Stdout | StreamInstance::TcpStream(_) | StreamInstance::Bytes(_) - | StreamInstance::File(_) => { + | StreamInstance::OutputFile(_) => { true } _ => { @@ -404,9 +417,9 @@ impl MachineState { arity: usize, ) -> Result { - Ok(match addr { + Ok(match self.store(self.deref(addr)) { 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) { Some(stream) => { stream.clone() @@ -436,13 +449,20 @@ impl MachineState { unreachable!() } } - _ => { + addr => { let stub = MachineError::functor_stub(clause_name!(caller), arity); - return Err(self.error_form( - MachineError::domain_error(DomainErrorType::StreamOrAlias, addr), - stub, - )); + if addr.is_ref() { + return Err(self.error_form( + 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 { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { match *self.stream_inst.0.borrow_mut() { - StreamInstance::File(ref mut file) => { + StreamInstance::InputFile(ref mut file) => { file.read(buf) } StreamInstance::TcpStream(ref mut tcp_stream) => { @@ -549,7 +569,7 @@ impl Read for Stream { stdin().read(buf) } */ - StreamInstance::Stdout | StreamInstance::Null => { + StreamInstance::OutputFile(_) | StreamInstance::Stdout | StreamInstance::Null => { Err(std::io::Error::new( ErrorKind::PermissionDenied, StreamError::ReadFromOutputStream, @@ -562,7 +582,7 @@ impl Read for Stream { impl Write for Stream { fn write(&mut self, buf: &[u8]) -> std::io::Result { match *self.stream_inst.0.borrow_mut() { - StreamInstance::File(ref mut file) => { + StreamInstance::OutputFile(ref mut file) => { file.write(buf) } StreamInstance::TcpStream(ref mut tcp_stream) => { @@ -574,7 +594,8 @@ impl Write for Stream { StreamInstance::Stdout => { stdout().write(buf) } - _ => { + StreamInstance::DynReadSource(_) | StreamInstance::ReadlineStream(_) | + StreamInstance::InputFile(_) | StreamInstance::Null => { Err(std::io::Error::new( ErrorKind::PermissionDenied, StreamError::WriteToInputStream, @@ -585,7 +606,7 @@ impl Write for Stream { fn flush(&mut self) -> std::io::Result<()> { match *self.stream_inst.0.borrow_mut() { - StreamInstance::File(ref mut file) => { + StreamInstance::OutputFile(ref mut file) => { file.flush() } StreamInstance::TcpStream(ref mut tcp_stream) => { @@ -597,7 +618,8 @@ impl Write for Stream { StreamInstance::Stdout => { stdout().flush() } - _ => { + StreamInstance::DynReadSource(_) | StreamInstance::ReadlineStream(_) | + StreamInstance::InputFile(_) | StreamInstance::Null => { Err(std::io::Error::new( ErrorKind::PermissionDenied, StreamError::FlushToInputStream, diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 1806d639..a0e10b25 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -22,9 +22,9 @@ use crate::ref_thread_local::RefThreadLocal; use std::cmp; use std::convert::TryFrom; -use std::io::{stdout, ErrorKind, Read, Write}; +use std::io::{ErrorKind, Read, Write}; use std::iter::{once, FromIterator}; -use std::fs::File; +use std::fs::{File, OpenOptions}; use std::net::{TcpListener, TcpStream}; 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 => { self.truncate_if_no_lifted_heap_diff(|h| Addr::HeapCell(h)) } @@ -3786,7 +3883,41 @@ impl MachineState { self.unify(listing, listing_var); } &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 = match self.write_term(&indices.op_dir)? { @@ -3801,8 +3932,21 @@ impl MachineState { let output = printer.print(addr); - print!("{}", output.result()); - stdout().flush().unwrap(); + match write!(&mut stream, "{}", output.result()) { + 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 => { let addr = self[temp_v!(1)]; diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 834ad9f8..6a3e46c1 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -405,3 +405,26 @@ macro_rules! ar_reg { 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!() + } + } + } +}