From b5368207d676ad140f0fa344628b5382cd7b6e42 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 3 May 2020 18:49:15 -0600 Subject: [PATCH] merge with master --- Cargo.lock | 18 + Cargo.toml | 1 + src/main.rs | 1 + src/prolog/clause_types.rs | 19 +- src/prolog/heap_iter.rs | 3 + src/prolog/heap_print.rs | 93 ++++- src/prolog/lib/builtins.pl | 23 +- src/prolog/machine/compile.rs | 10 +- src/prolog/machine/heap.rs | 20 +- src/prolog/machine/machine_errors.rs | 25 +- src/prolog/machine/machine_indices.rs | 11 +- src/prolog/machine/machine_state.rs | 89 +++-- src/prolog/machine/machine_state_impl.rs | 8 +- src/prolog/machine/mod.rs | 11 +- src/prolog/machine/streams.rs | 259 +++++++++++++- src/prolog/machine/system_calls.rs | 414 +++++++++++++++++++---- src/prolog/toplevel.pl | 2 +- src/prolog/write.rs | 11 +- 18 files changed, 852 insertions(+), 166 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a766ca2f..a4357f12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -228,6 +228,17 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi 0.3.8", +] + [[package]] name = "indexmap" version = "1.3.2" @@ -310,6 +321,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "maybe-uninit" version = "2.0.0" @@ -627,6 +644,7 @@ dependencies = [ "divrem", "downcast", "git-version", + "hostname", "indexmap", "lazy_static", "libc", diff --git a/Cargo.toml b/Cargo.toml index 37b4ef3a..a70173af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ dirs = "2.0.2" divrem = "0.1.0" downcast = "0.10.0" git-version = "0.3.4" +hostname = "0.3.1" indexmap = "1.0.2" lazy_static = "1.4.0" libc = "0.2.62" diff --git a/src/main.rs b/src/main.rs index fc38f3f0..83196004 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ extern crate divrem; #[macro_use] extern crate downcast; extern crate git_version; +extern crate hostname; extern crate indexmap; #[macro_use] extern crate lazy_static; diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index d05c8559..b5bfae0e 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -167,6 +167,7 @@ pub enum SystemClauseType { CheckCutPoint, CopyToLiftedHeap, CreatePartialString, + CurrentHostname, CurrentInput, CurrentOutput, DeleteAttribute, @@ -254,6 +255,10 @@ pub enum SystemClauseType { SetSeed, SkipMaxList, Sleep, + SocketClientOpen, + SocketServerOpen, + SocketServerAccept, + SocketServerClose, Succeed, TermAttributedVariables, TermVariables, @@ -291,6 +296,7 @@ impl SystemClauseType { &SystemClauseType::CopyTermWithoutAttrVars => clause_name!("$copy_term_without_attr_vars"), &SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"), &SystemClauseType::CurrentInput => clause_name!("$current_input"), + &SystemClauseType::CurrentHostname => clause_name!("$current_hostname"), &SystemClauseType::CurrentOutput => clause_name!("$current_output"), &SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"), &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"), @@ -410,6 +416,10 @@ impl SystemClauseType { &SystemClauseType::SetDoubleQuotes => clause_name!("$set_double_quotes"), &SystemClauseType::SkipMaxList => clause_name!("$skip_max_list"), &SystemClauseType::Sleep => clause_name!("$sleep"), + &SystemClauseType::SocketClientOpen => clause_name!("$socket_client_open"), + &SystemClauseType::SocketServerOpen => clause_name!("$socket_server_open"), + &SystemClauseType::SocketServerAccept => clause_name!("$socket_server_accept"), + &SystemClauseType::SocketServerClose => clause_name!("$socket_server_close"), &SystemClauseType::Succeed => clause_name!("$succeed"), &SystemClauseType::TermAttributedVariables => clause_name!("$term_attributed_variables"), &SystemClauseType::TermVariables => clause_name!("$term_variables"), @@ -450,6 +460,7 @@ impl SystemClauseType { ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), ("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)), ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), + ("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname), ("$current_input", 1) => Some(SystemClauseType::CurrentInput), ("$current_output", 1) => Some(SystemClauseType::CurrentOutput), ("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute), @@ -523,8 +534,8 @@ impl SystemClauseType { ("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock), ("$quoted_token", 1) => Some(SystemClauseType::QuotedToken), ("$nextEP", 3) => Some(SystemClauseType::NextEP), - ("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm), - ("$read_term", 2) => Some(SystemClauseType::ReadTerm), + ("$read_query_term", 5) => Some(SystemClauseType::ReadQueryTerm), + ("$read_term", 5) => Some(SystemClauseType::ReadTerm), ("$read_term_from_chars", 2) => Some(SystemClauseType::ReadTermFromChars), ("$reset_block", 1) => Some(SystemClauseType::ResetBlock), ("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker), @@ -538,6 +549,10 @@ impl SystemClauseType { ("$set_seed", 1) => Some(SystemClauseType::SetSeed), ("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList), ("$sleep", 1) => Some(SystemClauseType::Sleep), + ("$socket_client_open", 7) => Some(SystemClauseType::SocketClientOpen), + ("$socket_server_open", 3) => Some(SystemClauseType::SocketServerOpen), + ("$socket_server_accept", 7) => Some(SystemClauseType::SocketServerAccept), + ("$socket_server_close", 1) => Some(SystemClauseType::SocketServerClose), ("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar), ("$store_global_var_with_offset", 2) => Some(SystemClauseType::StoreGlobalVarWithOffset), ("$term_attributed_variables", 2) => Some(SystemClauseType::TermAttributedVariables), diff --git a/src/prolog/heap_iter.rs b/src/prolog/heap_iter.rs index de398ccb..28cdaf85 100644 --- a/src/prolog/heap_iter.rs +++ b/src/prolog/heap_iter.rs @@ -48,6 +48,9 @@ impl<'a> HCPreOrderIterator<'a> { HeapCellValue::Stream(_) => { Addr::Stream(h) } + &HeapCellValue::TcpListener(_) => { + Addr::TcpListener(h) + } } } diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 5ddbcdd4..b68a580a 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -6,6 +6,7 @@ use crate::prolog::heap_iter::*; use crate::prolog::machine::heap::*; use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_state::*; +use crate::prolog::machine::streams::*; use crate::prolog::ordered_float::OrderedFloat; use crate::prolog::rug::{Integer, Rational}; @@ -14,6 +15,7 @@ use indexmap::{IndexMap, IndexSet}; use std::cell::Cell; use std::convert::TryFrom; use std::iter::{FromIterator, once}; +use std::net::{IpAddr, TcpListener}; use std::ops::{Range, RangeFrom}; use std::rc::Rc; @@ -170,10 +172,12 @@ enum TokenOrRedirect { NumberedVar(String), CompositeRedirect(usize, DirectedOp), FunctorRedirect(usize), + IpAddr(IpAddr), Number(Number, Option), Open, Close, Comma, + RawPtr(*const u8), Space, LeftCurly, RightCurly, @@ -643,8 +647,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } self.state_stack.pop(); - self.state_stack.push(TokenOrRedirect::Open); + self.state_stack.push(TokenOrRedirect::Open); self.state_stack.push(TokenOrRedirect::Atom(name)); true @@ -964,6 +968,18 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { }); } + #[inline] + fn print_ip_addr(&mut self, ip: IpAddr) { + self.push_char('\''); + self.append_str(&format!("{}", ip)); + self.push_char('\''); + } + + #[inline] + fn print_raw_ptr(&mut self, ptr: *const u8) { + self.append_str(&format!("0x{:x}", ptr as usize)); + } + fn print_number(&mut self, n: Number, op: &Option) { let add_brackets = if let Some(op) = op { op.is_negative_sign() && n.is_positive() @@ -1330,6 +1346,66 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { } } + fn print_tcp_listener( + &mut self, + iter: &mut HCPreOrderIterator, + tcp_listener: &TcpListener, + max_depth: usize, + ) { + let (ip, port) = + if let Some(addr) = tcp_listener.local_addr().ok() { + (addr.ip(), Number::from(addr.port() as isize)) + } else { + let disconnected_atom = clause_name!("$disconnected_tcp_listener"); + self.state_stack.push(TokenOrRedirect::Atom(disconnected_atom)); + + return; + }; + + if self.format_struct(iter, max_depth, 1, clause_name!("$tcp_listener")) { + let atom = self.state_stack.pop().unwrap(); + + self.state_stack.pop(); + self.state_stack.pop(); + + self.state_stack.push(TokenOrRedirect::Number(port, None)); + self.state_stack.push(TokenOrRedirect::Comma); + self.state_stack.push(TokenOrRedirect::IpAddr(ip)); + + self.state_stack.push(TokenOrRedirect::Open); + self.state_stack.push(atom); + } + } + + fn print_stream( + &mut self, + iter: &mut HCPreOrderIterator, + stream: &Stream, + max_depth: usize, + ) { + if let Some(alias) = &stream.options.alias { + self.print_atom(alias); + } else { + if self.format_struct(iter, max_depth, 1, clause_name!("$stream")) { + let atom = + if stream.is_stdout() || stream.is_stdin() { + TokenOrRedirect::Atom(clause_name!("user")) + } else { + TokenOrRedirect::RawPtr(stream.as_ptr()) + }; + + let stream_root = self.state_stack.pop().unwrap(); + + self.state_stack.pop(); + self.state_stack.pop(); + + self.state_stack.push(atom); + self.state_stack.push(TokenOrRedirect::Open); + self.state_stack.push(stream_root); + } + } + } + fn handle_heap_term( &mut self, iter: &mut HCPreOrderIterator, @@ -1440,15 +1516,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.print_number(Number::Rational(n.clone()), &op); } &HeapCellValue::Stream(ref stream) => { - if let Some(alias) = &stream.options.alias { - self.print_atom(alias); - } else { - if stream.is_stdout() || stream.is_stdin() { - self.print_atom(&clause_name!("user")); - } else { - self.format_struct(iter, max_depth, 1, clause_name!("$stream")); - } - } + self.print_stream(iter, stream, max_depth); + } + &HeapCellValue::TcpListener(ref tcp_listener) => { + self.print_tcp_listener(iter, tcp_listener, max_depth); } _ => { unreachable!() @@ -1486,6 +1557,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.handle_heap_term(&mut iter, None, true, max_depth) } TokenOrRedirect::Close => self.push_char(')'), + TokenOrRedirect::IpAddr(ip) => self.print_ip_addr(ip), + TokenOrRedirect::RawPtr(ptr) => self.print_raw_ptr(ptr), TokenOrRedirect::Open => self.push_char('('), TokenOrRedirect::OpenList(delimit) => { if !self.at_cdr(",") { diff --git a/src/prolog/lib/builtins.pl b/src/prolog/lib/builtins.pl index 0cebab9b..1d5080e5 100644 --- a/src/prolog/lib/builtins.pl +++ b/src/prolog/lib/builtins.pl @@ -420,25 +420,16 @@ parse_read_term_options(Options, OptionValues, Stub) :- parse_options_list(Options, parse_read_term_options_, DefaultOptions, OptionValues, Stub). -parse_read_term_options_(singletons(Vars), singletons-Vars) :- - ( '$skip_max_list'(Vars, _, -1, Tail), Tail == [], ! - ; - throw(error(domain_error(read_option, singletons(Vars)), _)) - ). -parse_read_term_options_(variables(Vars), variables-Vars) :- - ( '$skip_max_list'(Vars, _, -1, Tail), Tail == [], ! - ; - throw(error(domain_error(read_option, variables(Vars)), _)) - ). -parse_read_term_options_(variable_names(Vars), variable_names-Vars) :- - ( '$skip_max_list'(Vars, _, -1, Tail), Tail == [], ! - ; - throw(error(domain_error(read_option, variable_names(Vars)), _)) - ). +parse_read_term_options_(singletons(Vars), singletons-Vars). +parse_read_term_options_(variables(Vars), variables-Vars). +parse_read_term_options_(variable_names(Vars), variable_names-Vars). +parse_read_term_options_(E,_) :- + throw(error(domain_error(read_option, E), _)). + read_term(Stream, Term, Options) :- - parse_read_term_options(Options, [Singletons, Variables, VariableNames], read_term/3), + parse_read_term_options(Options, [Singletons, VariableNames, Variables], read_term/3), '$read_term'(Stream, Term, Singletons, Variables, VariableNames). read_term(Term, Options) :- diff --git a/src/prolog/machine/compile.rs b/src/prolog/machine/compile.rs index 10bc4d22..4777e054 100644 --- a/src/prolog/machine/compile.rs +++ b/src/prolog/machine/compile.rs @@ -617,7 +617,7 @@ fn load_library( ) } None => { - let err = ExistenceError::SourceSink(ModuleSource::Library( + let err = ExistenceError::ModuleSource(ModuleSource::Library( name.clone() )); @@ -708,7 +708,7 @@ impl ListingCompiler { Ok(wam_indices.insert_module(submodule)) } else { - let err = ExistenceError::SourceSink(ModuleSource::File( + let err = ExistenceError::ModuleSource(ModuleSource::File( module_name, )); @@ -746,7 +746,7 @@ impl ListingCompiler { Ok(wam_indices.insert_module(submodule)) } else { - let err = ExistenceError::SourceSink(ModuleSource::File( + let err = ExistenceError::ModuleSource(ModuleSource::File( module_name )); @@ -1080,7 +1080,7 @@ impl ListingCompiler { insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs); } None => { - let err = ExistenceError::SourceSink(ModuleSource::File( + let err = ExistenceError::ModuleSource(ModuleSource::File( module_name, )); @@ -1438,7 +1438,7 @@ pub(super) fn setup_indices( wam.indices.insert_module(module); result } else { - let err = ExistenceError::SourceSink(ModuleSource::Library( + let err = ExistenceError::ModuleSource(ModuleSource::Library( module )); diff --git a/src/prolog/machine/heap.rs b/src/prolog/machine/heap.rs index 9d8cbfe7..3e813fe8 100644 --- a/src/prolog/machine/heap.rs +++ b/src/prolog/machine/heap.rs @@ -171,15 +171,18 @@ impl HeapTemplate { &HeapCellValue::NamedStr(arity, ref name, ref op) => { HeapCellValue::NamedStr(arity, name.clone(), op.clone()) } - &HeapCellValue::Rational(ref r) => { - HeapCellValue::Rational(r.clone()) - } &HeapCellValue::PartialString(..) => { HeapCellValue::Addr(Addr::PStrLocation(h, 0)) } + &HeapCellValue::Rational(ref r) => { + HeapCellValue::Rational(r.clone()) + } &HeapCellValue::Stream(_) => { HeapCellValue::Addr(Addr::Stream(h)) } + &HeapCellValue::TcpListener(_) => { + HeapCellValue::Addr(Addr::TcpListener(h)) + } } } @@ -294,9 +297,6 @@ impl HeapTemplate { val @ HeapCellValue::NamedStr(..) => { Addr::Str(self.push(val)) } - val @ HeapCellValue::Stream(..) => { - Addr::Stream(self.push(val)) - } HeapCellValue::PartialString(pstr, has_tail) => { let h = self.push(HeapCellValue::PartialString(pstr, has_tail)); @@ -306,6 +306,12 @@ impl HeapTemplate { Addr::Con(h) } + val @ HeapCellValue::Stream(..) => { + Addr::Stream(self.push(val)) + } + val @ HeapCellValue::TcpListener(..) => { + Addr::TcpListener(self.push(val)) + } } } @@ -517,7 +523,7 @@ impl HeapTemplate { pub fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> { match addr { - &Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) => { + &Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) | &Addr::TcpListener(h) => { RefOrOwned::Borrowed(&self[h]) } addr => { diff --git a/src/prolog/machine/machine_errors.rs b/src/prolog/machine/machine_errors.rs index fd1e9397..a46345e2 100644 --- a/src/prolog/machine/machine_errors.rs +++ b/src/prolog/machine/machine_errors.rs @@ -17,7 +17,7 @@ enum ErrorProvenance { } #[derive(Debug)] -pub(super) struct MachineError { +pub(crate) struct MachineError { stub: MachineStub, location: Option<(usize, usize)>, // line_num, col_num from: ErrorProvenance, @@ -74,7 +74,7 @@ impl TypeError for Number { } } -pub(super) +pub(crate) trait PermissionError { fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError; } @@ -250,7 +250,7 @@ impl MachineError { from: ErrorProvenance::Constructed, } } - ExistenceError::SourceSink(source) => { + ExistenceError::ModuleSource(source) => { let source_stub = source.as_functor_stub(); let stub = functor!( @@ -265,6 +265,18 @@ impl MachineError { from: ErrorProvenance::Constructed, } } + ExistenceError::SourceSink(culprit) => { + let stub = functor!( + "existence_error", + [atom("source_sink"), addr(culprit)] + ); + + MachineError { + stub, + location: None, + from: ErrorProvenance::Constructed, + } + } ExistenceError::Stream(culprit) => { let stub = functor!( "existence_error", @@ -454,6 +466,7 @@ pub enum Permission { Create, InputStream, Modify, + Open, OutputStream, } @@ -464,6 +477,7 @@ impl Permission { Permission::Create => "create", Permission::InputStream => "input", Permission::Modify => "modify", + Permission::Open => "open", Permission::OutputStream => "output", } } @@ -489,6 +503,7 @@ pub enum ValidType { Pair, // PredicateIndicator, // Variable + TcpListener, } impl ValidType { @@ -511,6 +526,7 @@ impl ValidType { ValidType::Pair => "pair", // ValidType::PredicateIndicator => "predicate_indicator", // ValidType::Variable => "variable" + ValidType::TcpListener => "tcp_listener", } } } @@ -726,8 +742,9 @@ impl MachineState { #[derive(Debug)] pub enum ExistenceError { Module(ClauseName), + ModuleSource(ModuleSource), Procedure(ClauseName, usize), - SourceSink(ModuleSource), + SourceSink(Addr), Stream(Addr), } diff --git a/src/prolog/machine/machine_indices.rs b/src/prolog/machine/machine_indices.rs index f35e76f6..cb43359c 100644 --- a/src/prolog/machine/machine_indices.rs +++ b/src/prolog/machine/machine_indices.rs @@ -23,6 +23,7 @@ use std::collections::{BTreeMap, VecDeque}; use std::convert::TryFrom; use std::fmt; use std::mem; +use std::net::TcpListener; use std::ops::{Add, AddAssign, Sub, SubAssign}; use std::rc::Rc; @@ -69,6 +70,7 @@ pub enum Addr { StackCell(usize, usize), Str(usize), Stream(usize), + TcpListener(usize), Usize(usize), } @@ -230,7 +232,7 @@ impl Addr { Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => { Some(TermOrderCategory::Compound) } - Addr::CutPoint(_) | Addr::Stream(_) => { + Addr::CutPoint(_) | Addr::Stream(_) | Addr::TcpListener(_) => { None } } @@ -388,6 +390,7 @@ pub enum HeapCellValue { Rational(Rc), PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant. Stream(Stream), + TcpListener(TcpListener), } impl HeapCellValue { @@ -410,6 +413,9 @@ impl HeapCellValue { HeapCellValue::Stream(_) => { Addr::Stream(focus) } + HeapCellValue::TcpListener(_) => { + Addr::TcpListener(focus) + } } } @@ -440,6 +446,9 @@ impl HeapCellValue { &HeapCellValue::Stream(_) => { HeapCellValue::Stream(Stream::null_stream()) } + &HeapCellValue::TcpListener(_) => { + HeapCellValue::Atom(clause_name!("$socket_server"), None) + } } } } diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 5f3557fb..46fc5ed9 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -12,7 +12,6 @@ use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::modules::*; use crate::prolog::machine::stack::*; use crate::prolog::machine::streams::*; -use crate::prolog::read::{PrologStream, readline}; use crate::prolog::rug::Integer; use downcast::Any; @@ -614,40 +613,13 @@ pub struct MachineState { } impl MachineState { - pub(crate) - fn open_parsing_stream( - &self, - stream: Stream, - stub_name: &'static str, - stub_arity: usize, - ) -> Result { - match parsing_stream(stream) { - Ok(stream) => { - Ok(stream) - } - Err(e) => { - let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); - let err = MachineError::session_error( - self.heap.h(), - SessionError::from(e), - ); - - Err(self.error_form(err, stub)) - } - } - } - pub(crate) fn read_term( &mut self, - current_input_stream: &mut Stream, + stream: Stream, indices: &mut IndexStore, ) -> CallResult { - let mut stream = self.open_parsing_stream( - current_input_stream.clone(), - "read_term", - 2, - )?; + let mut stream = self.open_parsing_stream(stream, "read_term", 3)?; match self.read( &mut stream, @@ -655,8 +627,8 @@ impl MachineState { &indices.op_dir, ) { Ok(term_write_result) => { - let a1 = self[temp_v!(1)]; - self.unify(Addr::HeapCell(term_write_result.heap_loc), a1); + let term = self[temp_v!(2)]; + self.unify(Addr::HeapCell(term_write_result.heap_loc), term); if self.fail { return Ok(()); @@ -677,11 +649,56 @@ impl MachineState { list_of_var_eqs.push(Addr::Str(h)); } - let a2 = self[temp_v!(2)]; - let list_offset = + let mut var_set: IndexMap = IndexMap::new(); + + for addr in self.acyclic_pre_order_iter(term) { + if let Some(var) = addr.as_var() { + if !var_set.contains_key(&var) { + var_set.insert(var, true); + } else { + var_set.insert(var, false); + } + } + } + + let mut var_list = vec![]; + let mut singleton_var_list = vec![]; + + for addr in self.acyclic_pre_order_iter(term) { + if let Some(var) = addr.as_var() { + if var_set.get(&var) == Some(&true) { + singleton_var_list.push(var.as_addr()); + } + + var_list.push(var.as_addr()); + } + } + + let singleton_addr = self[temp_v!(3)]; + let singletons_offset = + Addr::HeapCell(self.heap.to_list(singleton_var_list.into_iter())); + + self.unify(singletons_offset, singleton_addr); + + if self.fail { + return Ok(()); + } + + let vars_addr = self[temp_v!(4)]; + let vars_offset = + Addr::HeapCell(self.heap.to_list(var_list.into_iter())); + + self.unify(vars_offset, vars_addr); + + if self.fail { + return Ok(()); + } + + let var_names_addr = self[temp_v!(5)]; + let var_names_offset = Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter())); - Ok(self.unify(list_offset, a2)) + Ok(self.unify(var_names_offset, var_names_addr)) } Err(err) => { if let ParserError::UnexpectedEOF = err { @@ -689,7 +706,7 @@ impl MachineState { } // reset the input stream after an input failure. - *current_input_stream = readline::input_stream(); + //*stream = readline::input_stream(); let h = self.heap.h(); let syntax_error = MachineError::syntax_error(h, err); diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 42e45b4d..aa7cb911 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -1400,9 +1400,11 @@ impl MachineState { let addr = self.store(self.deref(addr)); let offset = match addr { - Addr::HeapCell(_) | Addr::StackCell(..) | - Addr::AttrVar(..) | Addr::Stream(_) => { - v + Addr::Stream(_) | Addr::TcpListener(_) => { + 0 + } + Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => { + v } Addr::PStrLocation(..) => { if !self.flags.double_quotes.is_atom() { diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index da14cc80..48100377 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -297,7 +297,7 @@ impl Machine { Ok(self.indices.insert_module(module)) } else { - let err = ExistenceError::SourceSink(ModuleSource::File( + let err = ExistenceError::ModuleSource(ModuleSource::File( clause_name!("$toplevel"), )); @@ -409,6 +409,15 @@ impl Machine { ) ); + compile_user_module(&mut wam, + Stream::from(PAIRS), + true, + ListingSource::from_file_and_path( + clause_name!("pairs"), + lib_path.clone(), + ) + ); + compile_user_module(&mut wam, Stream::from(LISTS), true, diff --git a/src/prolog/machine/streams.rs b/src/prolog/machine/streams.rs index d9a83934..4e4af96e 100644 --- a/src/prolog/machine/streams.rs +++ b/src/prolog/machine/streams.rs @@ -1,12 +1,16 @@ use crate::prolog_parser::ast::*; use crate::prolog::read::readline::*; +use crate::prolog::machine::machine_errors::*; +use crate::prolog::machine::machine_indices::*; +use crate::prolog::machine::machine_state::*; +use crate::prolog::read::PrologStream; use std::cell::RefCell; use std::error::Error; use std::fmt; use std::fs::File; -use std::io::{stdin, stdout, Cursor, ErrorKind, Read, Write}; +use std::io::{stdout, Cursor, ErrorKind, Read, Write}; use std::hash::{Hash, Hasher}; use std::net::TcpStream; use std::rc::Rc; @@ -32,7 +36,7 @@ pub enum StreamInstance { File(File), Null, ReadlineStream(ReadlineStream), - Stdin, + // Stdin, Stdout, TcpStream(TcpStream), } @@ -48,7 +52,7 @@ impl fmt::Debug for StreamInstance { &StreamInstance::Null => write!(fmt, "Null"), &StreamInstance::ReadlineStream(ref readline_stream) => write!(fmt, "ReadlineStream({:?})", readline_stream), - &StreamInstance::Stdin => write!(fmt, "Stdin"), + // &StreamInstance::Stdin => write!(fmt, "Stdin"), &StreamInstance::Stdout => write!(fmt, "Stdout"), &StreamInstance::TcpStream(ref tcp_stream) => write!(fmt, "TcpStream({:?})", tcp_stream), @@ -140,6 +144,17 @@ pub struct Stream { stream_inst: WrappedStreamInstance, } +impl From for Stream { + fn from(tcp_stream: TcpStream) -> Self { + Stream { + options: StreamOptions::default(), + stream_inst: WrappedStreamInstance::new( + StreamInstance::TcpStream(tcp_stream) + ) + } + } +} + impl From for Stream { fn from(string: String) -> Self { Stream { @@ -187,7 +202,7 @@ impl From for Stream { impl Stream { #[inline] pub(crate) - fn as_ptr(&self) -> *const RefCell { + fn as_ptr(&self) -> *const u8 { let rc = self.stream_inst.0.clone(); let ptr = Rc::into_raw(rc); @@ -196,7 +211,7 @@ impl Stream { let _ = Rc::from_raw(ptr); } - ptr + ptr as *const u8 } #[inline] @@ -210,6 +225,7 @@ impl Stream { } } +/* #[inline] pub(crate) fn stdin() -> Self { @@ -220,6 +236,7 @@ impl Stream { ), } } +*/ #[inline] pub(crate) @@ -249,7 +266,8 @@ impl Stream { pub(crate) fn is_stdin(&self) -> bool { match *self.stream_inst.0.borrow() { - StreamInstance::Stdin | StreamInstance::ReadlineStream(_) => { + //StreamInstance::Stdin | + StreamInstance::ReadlineStream(_) => { true } _ => { @@ -262,12 +280,12 @@ impl Stream { pub(crate) fn is_input_stream(&self) -> bool { match *self.stream_inst.0.borrow() { - StreamInstance::Stdin - | StreamInstance::TcpStream(_) - | StreamInstance::Bytes(_) - | StreamInstance::ReadlineStream(_) - | StreamInstance::DynReadSource(_) - | StreamInstance::File(_) => { + // StreamInstance::Stdin | + StreamInstance::TcpStream(_) | + StreamInstance::Bytes(_) | + StreamInstance::ReadlineStream(_) | + StreamInstance::DynReadSource(_) | + StreamInstance::File(_) => { true } _ => { @@ -293,6 +311,221 @@ impl Stream { } } +impl MachineState { + pub(crate) + fn to_stream_options( + &self, + alias: Addr, + eof_action: Addr, + reposition: Addr, + stream_type: Addr, + ) -> StreamOptions { + let alias = + match self.store(self.deref(alias)) { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + Some(name.clone()) + } else { + unreachable!() + } + } + _ => { + None + } + }; + + let eof_action = + match self.store(self.deref(eof_action)) { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + match name.as_str() { + "eof_code" => EOFAction::EOFCode, + "error" => EOFAction::Error, + "reset" => EOFAction::Reset, + _ => unreachable!(), + } + } else { + unreachable!() + } + } + _ => { + unreachable!() + } + }; + + let reposition = + match self.store(self.deref(reposition)) { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + name.as_str() == "true" + } else { + unreachable!() + } + } + _ => { + unreachable!() + } + }; + + let stream_type = + match self.store(self.deref(stream_type)) { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + match name.as_str() { + "text" => StreamType::Text, + "binary" => StreamType::Binary, + _ => unreachable!() + } + } else { + unreachable!() + } + } + _ => { + unreachable!() + } + }; + + let mut options = StreamOptions::default(); + + options.stream_type = stream_type; + options.reposition = reposition; + options.alias = alias; + options.eof_action = eof_action; + + options + } + + pub(crate) + fn get_stream_or_alias( + &mut self, + addr: Addr, + indices: &IndexStore, + caller: &'static str, + arity: usize, + ) -> Result + { + Ok(match addr { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref atom, ref spec) = self.heap.clone(h) { + match indices.stream_aliases.get(atom) { + Some(stream) => { + stream.clone() + } + None => { + let stub = MachineError::functor_stub(clause_name!(caller), arity); + let h = self.heap.h(); + + let addr = self.heap.to_unifiable( + HeapCellValue::Atom(atom.clone(), spec.clone()) + ); + + return Err(self.error_form( + MachineError::existence_error(h + 1, ExistenceError::Stream(addr)), + stub, + )); + } + } + } else { + unreachable!() + } + } + Addr::Stream(h) => { + if let HeapCellValue::Stream(ref stream) = &self.heap[h] { + stream.clone() + } else { + unreachable!() + } + } + _ => { + let stub = MachineError::functor_stub(clause_name!(caller), arity); + + return Err(self.error_form( + MachineError::domain_error(DomainErrorType::StreamOrAlias, addr), + stub, + )); + } + }) + } + + pub(crate) + fn open_parsing_stream( + &self, + stream: Stream, + stub_name: &'static str, + stub_arity: usize, + ) -> Result { + match parsing_stream(stream) { + Ok(stream) => { + Ok(stream) + } + Err(e) => { + let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); + let err = MachineError::session_error( + self.heap.h(), + SessionError::from(e), + ); + + Err(self.error_form(err, stub)) + } + } + } + + pub(crate) + fn open_permission_error( + &self, + culprit: T, + stub_name: &'static str, + stub_arity: usize, + ) -> MachineStub { + let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); + let err = MachineError::permission_error( + self.heap.h(), + Permission::Open, + "source_sink", + culprit, + ); + + return self.error_form(err, stub); + } + + pub(crate) + fn occupied_alias_permission_error( + &self, + alias: ClauseName, + stub_name: &'static str, + stub_arity: usize, + ) -> MachineStub { + let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); + let err = MachineError::permission_error( + self.heap.h(), + Permission::Open, + "source_sink", + functor!("alias", [clause_name(alias)]), + ); + + return self.error_form(err, stub); + } + + pub(crate) + fn reposition_error( + &self, + stub_name: &'static str, + stub_arity: usize, + ) -> MachineStub { + let stub = MachineError::functor_stub(clause_name!(stub_name), stub_arity); + let rep_stub = functor!("reposition", [atom("true")]); + + let err = MachineError::permission_error( + self.heap.h(), + Permission::Open, + "source_sink", + rep_stub, + ); + + return self.error_form(err, stub); + } +} + impl Read for Stream { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { match *self.stream_inst.0.borrow_mut() { @@ -311,9 +544,11 @@ impl Read for Stream { StreamInstance::Bytes(ref mut cursor) => { cursor.read(buf) } +/* StreamInstance::Stdin => { stdin().read(buf) } +*/ StreamInstance::Stdout | StreamInstance::Null => { Err(std::io::Error::new( ErrorKind::PermissionDenied, diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 881789ea..1806d639 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -22,9 +22,10 @@ use crate::ref_thread_local::RefThreadLocal; use std::cmp; use std::convert::TryFrom; -use std::io::{stdout, Read, Write}; +use std::io::{stdout, ErrorKind, Read, Write}; use std::iter::{once, FromIterator}; use std::fs::File; +use std::net::{TcpListener, TcpStream}; use std::rc::Rc; use std::time::Duration; @@ -364,56 +365,6 @@ impl MachineState { Ok(()) } - fn get_stream_or_alias( - &mut self, - addr: Addr, - indices: &IndexStore, - caller: &'static str, - ) -> Result - { - Ok(match addr { - Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(ref atom, ref spec) = self.heap.clone(h) { - match indices.stream_aliases.get(atom) { - Some(stream) => { - stream.clone() - } - None => { - let stub = MachineError::functor_stub(clause_name!(caller), 1); - let h = self.heap.h(); - - let addr = self.heap.to_unifiable( - HeapCellValue::Atom(atom.clone(), spec.clone()) - ); - - return Err(self.error_form( - MachineError::existence_error(h + 1, ExistenceError::Stream(addr)), - stub, - )); - } - } - } else { - unreachable!() - } - } - Addr::Stream(h) => { - if let HeapCellValue::Stream(ref stream) = &self.heap[h] { - stream.clone() - } else { - unreachable!() - } - } - _ => { - let stub = MachineError::functor_stub(clause_name!(caller), 1); - - return Err(self.error_form( - MachineError::domain_error(DomainErrorType::StreamOrAlias, addr), - stub, - )); - } - }) - } - #[inline] fn install_new_block(&mut self, r: RegType) -> usize { self.block = self.b; @@ -779,6 +730,29 @@ impl MachineState { self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } + &SystemClauseType::CurrentHostname => { + match hostname::get().ok() { + Some(host) => { + match host.into_string().ok() { + Some(host) => { + let hostname = self.heap.to_unifiable( + HeapCellValue::Atom(clause_name!(host, indices.atom_tbl), None) + ); + + self.unify(self[temp_v!(1)], hostname); + return return_from_clause!(self.last_call, self); + } + None => { + } + } + } + None => { + } + } + + self.fail = true; + return Ok(()); + } &SystemClauseType::CurrentInput => { let addr = self.store(self.deref(self[temp_v!(1)])); @@ -1539,8 +1513,6 @@ impl MachineState { } &SystemClauseType::FileToChars => { // TODO: Replace this with stream. - use std::io; - let a1 = self.store(self.deref(self[temp_v!(1)])); let a2 = self.store(self.deref(self[temp_v!(2)])); @@ -1570,15 +1542,15 @@ impl MachineState { let h = self.heap.h(); let err = match e.kind() { - io::ErrorKind::NotFound => { + ErrorKind::NotFound => { MachineError::existence_error( h, - ExistenceError::SourceSink( + ExistenceError::ModuleSource( ModuleSource::File(file_name) ), ) } - io::ErrorKind::PermissionDenied => { + ErrorKind::PermissionDenied => { let source_sink = self.store(self.deref(a1)); MachineError::permission_error( @@ -2545,17 +2517,14 @@ impl MachineState { 3, ); - let type_error = self.error_form( + return Err(self.error_form( MachineError::type_error( self.heap.h(), ValidType::Integer, a2, ), stub, - ); - - self.throw_exception(type_error); - return Ok(()); + )); } }; @@ -2868,7 +2837,7 @@ impl MachineState { } &SystemClauseType::SetInput => { let addr = self.store(self.deref(self[temp_v!(1)])); - let stream = self.get_stream_or_alias(addr, indices, "set_input")?; + let stream = self.get_stream_or_alias(addr, indices, "set_input", 1)?; if stream.is_output_stream() { let stub = MachineError::functor_stub( @@ -2894,7 +2863,7 @@ impl MachineState { } &SystemClauseType::SetOutput => { let addr = self.store(self.deref(self[temp_v!(1)])); - let stream = self.get_stream_or_alias(addr, indices, "set_output")?; + let stream = self.get_stream_or_alias(addr, indices, "set_output", 1)?; if stream.is_input_stream() { let stub = MachineError::functor_stub( @@ -3182,14 +3151,29 @@ impl MachineState { } &SystemClauseType::ReadQueryTerm => { readline::set_prompt(true); - let result = self.read_term(current_input_stream, indices); + let result = self.read_term(current_input_stream.clone(), indices); readline::set_prompt(false); - let _ = result?; + match result { + Ok(()) => { + } + Err(e) => { + *current_input_stream = readline::input_stream(); + return Err(e); + } + } } &SystemClauseType::ReadTerm => { readline::set_prompt(false); - self.read_term(current_input_stream, indices)?; + + let stream = self.get_stream_or_alias( + self[temp_v!(1)], + indices, + "read_term", + 3, + )?; + + self.read_term(stream, indices)?; } &SystemClauseType::ReadTermFromChars => { let mut heap_pstr_iter = self.heap_pstr_iter(self[temp_v!(1)]); @@ -3302,6 +3286,304 @@ impl MachineState { let duration = duration.mul_f64(time); ::std::thread::sleep(duration); } + &SystemClauseType::SocketClientOpen => { + let addr = self.store(self.deref(self[temp_v!(1)])); + let port = self.store(self.deref(self[temp_v!(2)])); + + let socket_atom = + match addr { + Addr::Con(h) if self.heap.atom_at(h) => { + if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { + name.clone() + } else { + unreachable!() + } + } + _ => { + unreachable!() + } + }; + + let port = + match port { + Addr::Fixnum(n) => { + n.to_string() + } + Addr::Usize(n) => { + n.to_string() + } + Addr::Con(h) => { + match &self.heap[h] { + HeapCellValue::Atom(ref name, _) => { + name.as_str().to_string() + } + HeapCellValue::Integer(ref n) => { + n.to_string() + } + _ => { + unreachable!() + } + } + } + _ => { + unreachable!() + } + }; + + let socket_addr = + format!( + "{}:{}", + if socket_atom.as_str() == "" { + "127.0.0.1" + } else { + socket_atom.as_str() + }, + port, + ); + + 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); + + if options.reposition { + return Err(self.reposition_error("socket_client_open", 3)); + } + + if let Some(ref alias) = &options.alias { + if indices.stream_aliases.contains_key(alias) { + return Err(self.occupied_alias_permission_error( + alias.clone(), + "socket_client_open", + 3, + )); + } + } + + let stream = + match TcpStream::connect(socket_addr).map_err(|e| e.kind()) { + Ok(tcp_stream) => { + let mut stream = Stream::from(tcp_stream); + + if let Some(ref alias) = &options.alias { + indices.stream_aliases.insert(alias.clone(), stream.clone()); + } + + stream.options = options; + self.heap.to_unifiable(HeapCellValue::Stream(stream)) + } + Err(ErrorKind::PermissionDenied) => { + return Err(self.open_permission_error(addr, "socket_client_open", 3)); + } + Err(ErrorKind::NotFound) => { + let stub = MachineError::functor_stub( + clause_name!("socket_client_open"), + 3, + ); + + let err = MachineError::existence_error( + self.heap.h(), + ExistenceError::SourceSink(addr), + ); + + return Err(self.error_form(err, stub)); + } + Err(_) => { + // for now, just fail. expand to meaningful error messages later. + self.fail = true; + return Ok(()); + } + }; + + let stream_addr = self.store(self.deref(self[temp_v!(3)])); + self.bind(stream_addr.as_var().unwrap(), stream); + } + &SystemClauseType::SocketServerOpen => { + let addr = self.store(self.deref(self[temp_v!(1)])); + let socket_atom = + match addr { + Addr::EmptyList => { + "127.0.0.1".to_string() + } + Addr::Con(h) if self.heap.atom_at(h) => { + match &self.heap[h] { + HeapCellValue::Atom(ref name, _) => { + name.as_str().to_string() + } + _ => { + unreachable!() + } + } + } + _ => { + unreachable!() + } + }; + + let port = + match self.store(self.deref(self[temp_v!(2)])) { + Addr::Fixnum(n) => { + n.to_string() + } + Addr::Usize(n) => { + n.to_string() + } + Addr::Con(h) => { + match &self.heap[h] { + HeapCellValue::Integer(ref n) => { + n.to_string() + } + _ => { + unreachable!() + } + } + } + addr if addr.is_ref() => { + "0".to_string() + } + _ => { + unreachable!() + } + }; + + let had_zero_port = &port == "0"; + + let server_addr = if socket_atom.is_empty() { + port + } else { + format!("{}:{}", socket_atom, port) + }; + + let (tcp_listener, port) = + match TcpListener::bind(server_addr).map_err(|e| e.kind()) { + Ok(tcp_listener) => { + let port = tcp_listener.local_addr().map(|addr| addr.port()).ok(); + + if let Some(port) = port { + ( + self.heap.to_unifiable(HeapCellValue::TcpListener(tcp_listener)), + port as usize, + ) + } else { + self.fail = true; + return Ok(()); + } + } + Err(ErrorKind::PermissionDenied) => { + return Err(self.open_permission_error(addr, "socket_server_open", 2)); + } + _ => { + self.fail = true; + return Ok(()); + } + }; + + let addr = self.store(self.deref(self[temp_v!(3)])); + self.bind(addr.as_var().unwrap(), tcp_listener); + + if had_zero_port { + self.unify(self[temp_v!(2)], Addr::Usize(port)); + } + } + &SystemClauseType::SocketServerAccept => { + 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); + + if options.reposition { + return Err(self.reposition_error("socket_server_accept", 4)); + } + + match self.store(self.deref(self[temp_v!(1)])) { + Addr::TcpListener(h) => { + match &mut self.heap[h] { + HeapCellValue::TcpListener(ref mut tcp_listener) => { + match tcp_listener.accept().ok() { + Some((tcp_stream, socket_addr)) => { + let mut tcp_stream = Stream::from(tcp_stream); + tcp_stream.options = options; + + let tcp_stream = + self.heap.to_unifiable(HeapCellValue::Stream(tcp_stream)); + + let client = + clause_name!(format!("{}", socket_addr), indices.atom_tbl); + let client = + self.heap.to_unifiable(HeapCellValue::Atom(client, None)); + + let client_addr = self.store(self.deref(self[temp_v!(2)])); + let stream_addr = self.store(self.deref(self[temp_v!(3)])); + + self.bind(client_addr.as_var().unwrap(), client); + self.bind(stream_addr.as_var().unwrap(), tcp_stream); + } + None => { + self.fail = true; + return Ok(()); + } + } + } + culprit => { + let culprit = culprit.as_addr(h); + let stub = MachineError::functor_stub( + clause_name!("socket_server_close"), + 1, + ); + + let err = MachineError::type_error( + self.heap.h(), + ValidType::TcpListener, + culprit, + ); + + return Err(self.error_form(err, stub)); + } + } + } + culprit => { + let stub = MachineError::functor_stub( + clause_name!("socket_server_accept"), + 4, + ); + + let err = MachineError::type_error( + self.heap.h(), + ValidType::TcpListener, + culprit, + ); + + return Err(self.error_form(err, stub)); + } + } + } + &SystemClauseType::SocketServerClose => { + match self.store(self.deref(self[temp_v!(1)])) { + Addr::TcpListener(h) => { + self.heap[h] = HeapCellValue::Addr(Addr::EmptyList); + } + culprit => { + let stub = MachineError::functor_stub( + clause_name!("socket_server_close"), + 1, + ); + + let err = MachineError::type_error( + self.heap.h(), + ValidType::TcpListener, + culprit, + ); + + return Err(self.error_form(err, stub)); + } + } + } &SystemClauseType::StoreGlobalVar => { let key = self[temp_v!(1)]; diff --git a/src/prolog/toplevel.pl b/src/prolog/toplevel.pl index 461e7195..7d50c07f 100644 --- a/src/prolog/toplevel.pl +++ b/src/prolog/toplevel.pl @@ -106,7 +106,7 @@ repl :- repl. read_and_match :- - '$read_query_term'(Term, VarList), + '$read_query_term'(_, Term, _, _, VarList), instruction_match(Term, VarList). % make compile_batch, a system routine, callable. diff --git a/src/prolog/write.rs b/src/prolog/write.rs index 9c2267ae..4c94d955 100644 --- a/src/prolog/write.rs +++ b/src/prolog/write.rs @@ -181,6 +181,9 @@ impl fmt::Display for HeapCellValue { &HeapCellValue::Stream(ref stream) => { write!(f, "$stream({})", stream.as_ptr() as usize) } + &HeapCellValue::TcpListener(ref tcp_listener) => { + write!(f, "$tcp_listener({})", tcp_listener.local_addr().unwrap()) + } } } } @@ -213,6 +216,7 @@ impl fmt::Display for Addr { &Addr::Str(s) => write!(f, "Addr::Str({})", s), &Addr::PStrLocation(h, n) => write!(f, "Addr::PStrLocation({}, {})", h, n), &Addr::Stream(stream) => write!(f, "Addr::Stream({})", stream), + &Addr::TcpListener(tcp_listener) => write!(f, "Addr::TcpListener({})", tcp_listener), &Addr::Usize(cp) => write!(f, "Addr::Usize({})", cp), } } @@ -332,11 +336,14 @@ impl fmt::Display for ExistenceError { &ExistenceError::Module(ref module_name) => { write!(f, "the module {} does not exist", module_name) } + &ExistenceError::ModuleSource(ref module_source) => { + write!(f, "the source/sink {} does not exist", module_source) + } &ExistenceError::Procedure(ref name, arity) => { write!(f, "the procedure {}/{} does not exist", name, arity) } - &ExistenceError::SourceSink(ref module_source) => { - write!(f, "the source/sink {} does not exist", module_source) + &ExistenceError::SourceSink(ref addr) => { + write!(f, "the source/sink {} does not exist", addr) } &ExistenceError::Stream(ref addr) => { write!(f, "the stream at {} does not exist", addr) -- 2.54.0