merge with master
This commit is contained in:
18
Cargo.lock
generated
18
Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -48,6 +48,9 @@ impl<'a> HCPreOrderIterator<'a> {
|
||||
HeapCellValue::Stream(_) => {
|
||||
Addr::Stream(h)
|
||||
}
|
||||
&HeapCellValue::TcpListener(_) => {
|
||||
Addr::TcpListener(h)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(",") {
|
||||
|
||||
@@ -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) :-
|
||||
|
||||
@@ -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
|
||||
));
|
||||
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)];
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user