"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"
"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"
"divrem",
"downcast",
"git-version",
+ "hostname",
"indexmap",
"lazy_static",
"libc",
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"
#[macro_use]
extern crate downcast;
extern crate git_version;
+extern crate hostname;
extern crate indexmap;
#[macro_use]
extern crate lazy_static;
CheckCutPoint,
CopyToLiftedHeap,
CreatePartialString,
+ CurrentHostname,
CurrentInput,
CurrentOutput,
DeleteAttribute,
SetSeed,
SkipMaxList,
Sleep,
+ SocketClientOpen,
+ SocketServerOpen,
+ SocketServerAccept,
+ SocketServerClose,
Succeed,
TermAttributedVariables,
TermVariables,
&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"),
&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"),
("$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),
("$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),
("$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),
HeapCellValue::Stream(_) => {
Addr::Stream(h)
}
+ &HeapCellValue::TcpListener(_) => {
+ Addr::TcpListener(h)
+ }
}
}
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};
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;
NumberedVar(String),
CompositeRedirect(usize, DirectedOp),
FunctorRedirect(usize),
+ IpAddr(IpAddr),
Number(Number, Option<DirectedOp>),
Open,
Close,
Comma,
+ RawPtr(*const u8),
Space,
LeftCurly,
RightCurly,
}
self.state_stack.pop();
- self.state_stack.push(TokenOrRedirect::Open);
+ self.state_stack.push(TokenOrRedirect::Open);
self.state_stack.push(TokenOrRedirect::Atom(name));
true
});
}
+ #[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()
}
}
+ 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,
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!()
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(",") {
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) :-
)
}
None => {
- let err = ExistenceError::SourceSink(ModuleSource::Library(
+ let err = ExistenceError::ModuleSource(ModuleSource::Library(
name.clone()
));
Ok(wam_indices.insert_module(submodule))
} else {
- let err = ExistenceError::SourceSink(ModuleSource::File(
+ let err = ExistenceError::ModuleSource(ModuleSource::File(
module_name,
));
Ok(wam_indices.insert_module(submodule))
} else {
- let err = ExistenceError::SourceSink(ModuleSource::File(
+ let err = ExistenceError::ModuleSource(ModuleSource::File(
module_name
));
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,
));
wam.indices.insert_module(module);
result
} else {
- let err = ExistenceError::SourceSink(ModuleSource::Library(
+ let err = ExistenceError::ModuleSource(ModuleSource::Library(
module
));
&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))
+ }
}
}
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));
Addr::Con(h)
}
+ val @ HeapCellValue::Stream(..) => {
+ Addr::Stream(self.push(val))
+ }
+ val @ HeapCellValue::TcpListener(..) => {
+ Addr::TcpListener(self.push(val))
+ }
}
}
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 => {
}
#[derive(Debug)]
-pub(super) struct MachineError {
+pub(crate) struct MachineError {
stub: MachineStub,
location: Option<(usize, usize)>, // line_num, col_num
from: ErrorProvenance,
}
}
-pub(super)
+pub(crate)
trait PermissionError {
fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError;
}
from: ErrorProvenance::Constructed,
}
}
- ExistenceError::SourceSink(source) => {
+ ExistenceError::ModuleSource(source) => {
let source_stub = source.as_functor_stub();
let stub = functor!(
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",
Create,
InputStream,
Modify,
+ Open,
OutputStream,
}
Permission::Create => "create",
Permission::InputStream => "input",
Permission::Modify => "modify",
+ Permission::Open => "open",
Permission::OutputStream => "output",
}
}
Pair,
// PredicateIndicator,
// Variable
+ TcpListener,
}
impl ValidType {
ValidType::Pair => "pair",
// ValidType::PredicateIndicator => "predicate_indicator",
// ValidType::Variable => "variable"
+ ValidType::TcpListener => "tcp_listener",
}
}
}
#[derive(Debug)]
pub enum ExistenceError {
Module(ClauseName),
+ ModuleSource(ModuleSource),
Procedure(ClauseName, usize),
- SourceSink(ModuleSource),
+ SourceSink(Addr),
Stream(Addr),
}
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;
StackCell(usize, usize),
Str(usize),
Stream(usize),
+ TcpListener(usize),
Usize(usize),
}
Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => {
Some(TermOrderCategory::Compound)
}
- Addr::CutPoint(_) | Addr::Stream(_) => {
+ Addr::CutPoint(_) | Addr::Stream(_) | Addr::TcpListener(_) => {
None
}
}
Rational(Rc<Rational>),
PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant.
Stream(Stream),
+ TcpListener(TcpListener),
}
impl HeapCellValue {
HeapCellValue::Stream(_) => {
Addr::Stream(focus)
}
+ HeapCellValue::TcpListener(_) => {
+ Addr::TcpListener(focus)
+ }
}
}
&HeapCellValue::Stream(_) => {
HeapCellValue::Stream(Stream::null_stream())
}
+ &HeapCellValue::TcpListener(_) => {
+ HeapCellValue::Atom(clause_name!("$socket_server"), None)
+ }
}
}
}
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;
}
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,
&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(());
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 {
}
// 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);
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() {
Ok(self.indices.insert_module(module))
} else {
- let err = ExistenceError::SourceSink(ModuleSource::File(
+ let err = ExistenceError::ModuleSource(ModuleSource::File(
clause_name!("$toplevel"),
));
)
);
+ 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,
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;
File(File),
Null,
ReadlineStream(ReadlineStream),
- Stdin,
+ // Stdin,
Stdout,
TcpStream(TcpStream),
}
&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),
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 {
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);
let _ = Rc::from_raw(ptr);
}
- ptr
+ ptr as *const u8
}
#[inline]
}
}
+/*
#[inline]
pub(crate)
fn stdin() -> Self {
),
}
}
+*/
#[inline]
pub(crate)
pub(crate)
fn is_stdin(&self) -> bool {
match *self.stream_inst.0.borrow() {
- StreamInstance::Stdin | StreamInstance::ReadlineStream(_) => {
+ //StreamInstance::Stdin |
+ StreamInstance::ReadlineStream(_) => {
true
}
_ => {
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
}
_ => {
}
}
+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() {
StreamInstance::Bytes(ref mut cursor) => {
cursor.read(buf)
}
+/*
StreamInstance::Stdin => {
stdin().read(buf)
}
+*/
StreamInstance::Stdout | StreamInstance::Null => {
Err(std::io::Error::new(
ErrorKind::PermissionDenied,
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;
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;
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)]));
}
&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)]));
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(
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(());
+ ));
}
};
}
&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(
}
&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(
}
&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)]);
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)];
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.
&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())
+ }
}
}
}
&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),
}
}
&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)