merge with master

This commit is contained in:
Mark Thom
2020-05-03 18:49:15 -06:00
parent b8400e0c92
commit b5368207d6
18 changed files with 852 additions and 166 deletions

18
Cargo.lock generated
View 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",

View 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"

View 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;

View 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),

View File

@@ -48,6 +48,9 @@ impl<'a> HCPreOrderIterator<'a> {
HeapCellValue::Stream(_) => {
Addr::Stream(h)
}
&HeapCellValue::TcpListener(_) => {
Addr::TcpListener(h)
}
}
}

View 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(",") {

View 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) :-

View 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
));

View 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 => {

View 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),
}

View 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)
}
}
}
}

View 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);

View 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() {

View 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,

View 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,

View 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)];

View 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.

View 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)