]> Repositorios git - scryer-prolog.git/commitdiff
merge with master
authorMark Thom <[email protected]>
Mon, 4 May 2020 00:49:15 +0000 (18:49 -0600)
committerMark Thom <[email protected]>
Mon, 4 May 2020 00:49:15 +0000 (18:49 -0600)
18 files changed:
Cargo.lock
Cargo.toml
src/main.rs
src/prolog/clause_types.rs
src/prolog/heap_iter.rs
src/prolog/heap_print.rs
src/prolog/lib/builtins.pl
src/prolog/machine/compile.rs
src/prolog/machine/heap.rs
src/prolog/machine/machine_errors.rs
src/prolog/machine/machine_indices.rs
src/prolog/machine/machine_state.rs
src/prolog/machine/machine_state_impl.rs
src/prolog/machine/mod.rs
src/prolog/machine/streams.rs
src/prolog/machine/system_calls.rs
src/prolog/toplevel.pl
src/prolog/write.rs

index a766ca2f240b79ed0d25eb7c19792f4e4c2818c4..a4357f1276b512f16b24a90d3d7c59bb868689ee 100644 (file)
@@ -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",
index 37b4ef3a24ec527e3f250e8fea072887e4ae4640..a70173af69f96a823fbbd41d882abc7c0949413a 100644 (file)
@@ -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"
index fc38f3f03a15942b5f0942f41449739fc6ed3570..8319600424854596dbbafcb0774d277dc1e27ca7 100644 (file)
@@ -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;
index d05c8559e8abcecf0bfecb86b7859a26f53b6f8d..b5bfae0e9d42396d6f8d20b67d1fdd2463f72c16 100644 (file)
@@ -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),
index de398ccbcc04478dcd22a2c1f153f2d92a74bfe6..28cdaf85ae31c7524c1fd7c304ca5f5b723f4cce 100644 (file)
@@ -48,6 +48,9 @@ impl<'a> HCPreOrderIterator<'a> {
             HeapCellValue::Stream(_) => {
                 Addr::Stream(h)
             }
+            &HeapCellValue::TcpListener(_) => {
+                Addr::TcpListener(h)
+            }
         }
     }
 
index 5ddbcdd45362f3116fe2dff70ddb8962abaab1b0..b68a580a1b670f5cc5e35abcc336352e7717ae80 100644 (file)
@@ -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<DirectedOp>),
     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<DirectedOp>) {
         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(",") {
index 0cebab9b44a71e9c16345b0cd35a28ce5bf7f963..1d5080e576dfcb52b0b6e82fdf666b89a0b1a0d2 100644 (file)
@@ -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) :-
index 10bc4d229816fece72a3d3521926633e923eaa2a..4777e0543aeee15cb37f01b68cc70c13808fad23 100644 (file)
@@ -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
         ));
 
index 9d8cbfe746cdfc02e691834accddee5d69a5c530..3e813fe8faaeadec608083a320f33ffe6339bb62 100644 (file)
@@ -171,15 +171,18 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
             &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<T: RawBlockTraits> HeapTemplate<T> {
             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<T: RawBlockTraits> HeapTemplate<T> {
 
                 Addr::Con(h)
             }
+            val @ HeapCellValue::Stream(..) => {
+                Addr::Stream(self.push(val))
+            }
+            val @ HeapCellValue::TcpListener(..) => {
+                Addr::TcpListener(self.push(val))
+            }
         }
     }
 
@@ -517,7 +523,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
     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 => {
index fd1e93978e91bf10ddbbebfdae033d9c69547fad..a46345e27b28b246726a9c4a5276ff6ba050800d 100644 (file)
@@ -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),
 }
 
index f35e76f6e21378508c039ae258ccdecd755745b7..cb43359c56cfffd2729eda6c7a9dc7bde8120e10 100644 (file)
@@ -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<Rational>),
     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)
+            }
         }
     }
 }
index 5f3557fbb80e8ed1b5df38aecbe8e4883bc2c98b..46fc5ed93e658f17e5d4e61275530a1f0b2abd4d 100644 (file)
@@ -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<PrologStream, MachineStub> {
-        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<Ref, bool> = 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);
index 42e45b4d0b8b38a3caa5d45fa70e7c841a2ce352..aa7cb9113ab1fac28befa65f069896ee168e83d9 100644 (file)
@@ -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() {
index da14cc8009a45a0d59ee5863852c46983058d8c3..48100377575acdd1a33f62d85aae10c9e210dc43 100644 (file)
@@ -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,
index d9a8393469b1d25800455fe38b61048f1e0c2283..4e4af96e1498f17dcc88c3efc3b34e1395b8fe9a 100644 (file)
@@ -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<TcpStream> for Stream {
+    fn from(tcp_stream: TcpStream) -> Self {
+        Stream {
+            options: StreamOptions::default(),
+            stream_inst: WrappedStreamInstance::new(
+                StreamInstance::TcpStream(tcp_stream)
+            )
+        }
+    }
+}
+
 impl From<String> for Stream {
     fn from(string: String) -> Self {
         Stream {
@@ -187,7 +202,7 @@ impl From<File> for Stream {
 impl Stream {
     #[inline]
     pub(crate)
-    fn as_ptr(&self) -> *const RefCell<StreamInstance> {
+    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<Stream, MachineStub>
+    {
+        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<PrologStream, MachineStub> {
+        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<T: PermissionError>(
+        &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<usize> {
         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,
index 881789eac78ee801340371941cb22c34f4c7f7ea..1806d63931d3886ed795205b77ae6922f2ed1040 100644 (file)
@@ -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<Stream, MachineStub>
-    {
-        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)];
 
index 461e71959bb57da95c3c14018480468e34279334..7d50c07f9e227599cd93b44e684c99edcdf7441e 100644 (file)
@@ -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.
index 9c2267ae0d6d5400caed5d4f5ab148cdbeb22ea6..4c94d9556f5cf9d21658eb3ce3a13d0de97f2992 100644 (file)
@@ -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)