Merge branch 'sockets-develop'

This commit is contained in:
Mark Thom
2020-05-09 14:26:29 -06:00
25 changed files with 3291 additions and 446 deletions

19
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",
@@ -637,6 +655,7 @@ dependencies = [
"ref_thread_local",
"rug",
"rustyline",
"unicode_reader",
]
[[package]]

View File

@@ -16,11 +16,13 @@ default = ["rug", "prolog_parser/rug"]
num = ["num-rug-adapter", "prolog_parser/num"]
[dependencies]
cpu-time = "1.0.0"
crossterm = "0.16.0"
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"
@@ -31,4 +33,4 @@ prolog_parser = { version = "0.8.56", default-features = false }
ref_thread_local = "0.0.0"
rug = { version = "1.4.0", optional = true }
rustyline = "6.0.0"
cpu-time = "1.0.0"
unicode_reader = "1.0.0"

View File

@@ -55,7 +55,10 @@ Extend Scryer Prolog to include the following, among other features:
- [x] A _redone_ representation of strings as difference lists of
characters, using a packed internal representation.
- [x] clp(B) and clp() as builtin libraries.
- [ ] Streams and predicates for stream control (_in progress_).
- [x] Streams and predicates for stream control.
- [x] A simple sockets library representing TCP connections as streams.
- [ ] Incremental compilation and loading process, newly written,
primarily in Prolog. (_in progress_)
- [ ] A compacting garbage collector satisfying the five
properties of "Precise Garbage Collection in Prolog."
- [ ] Mode declarations.
@@ -372,6 +375,8 @@ The modules that ship with Scryer Prolog are also called
Provides *delimited continuations* via `reset/3` and `shift/1`.
* [`random`](src/prolog/lib/random.pl)
Probabilistic predicates and random number generators.
* [`sockets`](src/prolog/lib/sockets.pl)
Predicates for opening and accepting TCP connections as streams.
To read contents of external files, use `phrase_from_file/2` from
[`library(pio)`](src/prolog/lib/pio.pl) to apply a DCG to

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

@@ -165,8 +165,10 @@ pub enum SystemClauseType {
CodesToNumber,
CopyTermWithoutAttrVars,
CheckCutPoint,
Close,
CopyToLiftedHeap,
CreatePartialString,
CurrentHostname,
CurrentInput,
CurrentOutput,
DeleteAttribute,
@@ -179,7 +181,11 @@ pub enum SystemClauseType {
FetchGlobalVar,
FetchGlobalVarWithOffset,
FileToChars,
FirstStream,
FlushOutput,
GetByte,
GetChar,
GetCode,
GetSingleChar,
ResetAttrVarState,
TruncateIfNoLiftedHeapGrowthDiff,
@@ -215,8 +221,16 @@ pub enum SystemClauseType {
NumberToChars,
NumberToCodes,
OpDeclaration,
Open,
NextStream,
PartialStringTail,
PeekByte,
PeekChar,
PeekCode,
PointsToContinuationResetMarker,
PutByte,
PutChar,
PutCode,
REPL(REPLCodePtr),
ReadQueryTerm,
ReadTerm,
@@ -233,6 +247,8 @@ pub enum SystemClauseType {
SetOutput,
StoreGlobalVar,
StoreGlobalVarWithOffset,
StreamProperty,
SetStreamPosition,
InferenceLevel,
CleanUpBlock,
EraseBall,
@@ -254,6 +270,10 @@ pub enum SystemClauseType {
SetSeed,
SkipMaxList,
Sleep,
SocketClientOpen,
SocketServerOpen,
SocketServerAccept,
SocketServerClose,
Succeed,
TermAttributedVariables,
TermVariables,
@@ -291,6 +311,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"),
@@ -303,6 +324,7 @@ impl SystemClauseType {
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => {
clause_name!("$use_qualified_module_from_file")
}
&SystemClauseType::Close => clause_name!("$close"),
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
@@ -316,7 +338,11 @@ impl SystemClauseType {
clause_name!("$fetch_global_var_with_offset")
}
&SystemClauseType::FileToChars => clause_name!("$file_to_chars"),
&SystemClauseType::FirstStream => clause_name!("$first_stream"),
&SystemClauseType::FlushOutput => clause_name!("$flush_output"),
&SystemClauseType::GetByte => clause_name!("$get_byte"),
&SystemClauseType::GetChar => clause_name!("$get_char"),
&SystemClauseType::GetCode => clause_name!("$get_code"),
&SystemClauseType::GetSingleChar => clause_name!("$get_single_char"),
&SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
&SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
@@ -346,13 +372,17 @@ impl SystemClauseType {
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
&SystemClauseType::Halt => clause_name!("$halt"),
&SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"),
&SystemClauseType::OpDeclaration => clause_name!("$op$"),
&SystemClauseType::Open => clause_name!("$open"),
&SystemClauseType::OpDeclaration => clause_name!("$op"),
&SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
&SystemClauseType::InstallInferenceCounter => {
clause_name!("$install_inference_counter")
}
&SystemClauseType::IsPartialString => clause_name!("$is_partial_string"),
&SystemClauseType::PartialStringTail => clause_name!("$partial_string_tail"),
&SystemClauseType::PeekByte => clause_name!("$peek_byte"),
&SystemClauseType::PeekChar => clause_name!("$peek_char"),
&SystemClauseType::PeekCode => clause_name!("$peek_code"),
&SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
&SystemClauseType::Maybe => clause_name!("maybe"),
&SystemClauseType::CpuNow => clause_name!("$cpu_now"),
@@ -365,12 +395,22 @@ impl SystemClauseType {
&SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
&SystemClauseType::ModuleExists => clause_name!("$module_exists"),
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
&SystemClauseType::NextStream => clause_name!("$next_stream"),
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
&SystemClauseType::PointsToContinuationResetMarker => {
clause_name!("$points_to_cont_reset_marker")
}
&SystemClauseType::PutByte => {
clause_name!("$put_byte")
}
&SystemClauseType::PutChar => {
clause_name!("$put_char")
}
&SystemClauseType::PutCode => {
clause_name!("$put_code")
}
&SystemClauseType::QuotedToken => {
clause_name!("$quoted_token")
}
@@ -382,6 +422,8 @@ impl SystemClauseType {
&SystemClauseType::SetInput => clause_name!("$set_input"),
&SystemClauseType::SetOutput => clause_name!("$set_output"),
&SystemClauseType::SetSeed => clause_name!("$set_seed"),
&SystemClauseType::StreamProperty => clause_name!("$stream_property"),
&SystemClauseType::SetStreamPosition => clause_name!("$set_stream_position"),
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
&SystemClauseType::StoreGlobalVarWithOffset => {
clause_name!("$store_global_var_with_offset")
@@ -410,6 +452,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,8 +496,13 @@ impl SystemClauseType {
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
("$close", 2) => Some(SystemClauseType::Close),
("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
("$current_input", 1) => Some(SystemClauseType::CurrentInput),
("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
("$first_stream", 1) => Some(SystemClauseType::FirstStream),
("$next_stream", 2) => Some(SystemClauseType::NextStream),
("$flush_output", 1) => Some(SystemClauseType::FlushOutput),
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef),
@@ -462,17 +513,31 @@ impl SystemClauseType {
("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal),
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
("$partial_string_tail", 2) => Some(SystemClauseType::PartialStringTail),
("$peek_byte", 2) => Some(SystemClauseType::PeekByte),
("$peek_char", 2) => Some(SystemClauseType::PeekChar),
("$peek_code", 2) => Some(SystemClauseType::PeekCode),
("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
("$file_to_chars", 2) => Some(SystemClauseType::FileToChars),
("$get_char", 1) => Some(SystemClauseType::GetChar),
("$get_byte", 2) => Some(SystemClauseType::GetByte),
("$get_char", 2) => Some(SystemClauseType::GetChar),
("$get_code", 2) => Some(SystemClauseType::GetCode),
("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar),
("$points_to_cont_reset_marker", 1) => {
Some(SystemClauseType::PointsToContinuationResetMarker)
}
("$put_byte", 2) => {
Some(SystemClauseType::PutByte)
}
("$put_char", 2) => {
Some(SystemClauseType::PutChar)
}
("$put_code", 2) => {
Some(SystemClauseType::PutCode)
}
("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState),
("$truncate_if_no_lh_growth", 1) => {
Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
@@ -503,6 +568,7 @@ impl SystemClauseType {
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
("$op", 3) => Some(SystemClauseType::OpDeclaration),
("$open", 7) => Some(SystemClauseType::Open),
("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding),
("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
@@ -510,6 +576,8 @@ impl SystemClauseType {
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
("$set_input", 1) => Some(SystemClauseType::SetInput),
("$set_output", 1) => Some(SystemClauseType::SetOutput),
("$stream_property", 3) => Some(SystemClauseType::StreamProperty),
("$set_stream_position", 2) => Some(SystemClauseType::SetStreamPosition),
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
@@ -523,8 +591,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 +606,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),
@@ -555,7 +627,7 @@ impl SystemClauseType {
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
("$variant", 2) => Some(SystemClauseType::Variant),
("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
("$write_term", 6) => Some(SystemClauseType::WriteTerm),
("$write_term", 7) => Some(SystemClauseType::WriteTerm),
("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars),
("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion),
_ => None,

View File

@@ -0,0 +1,31 @@
:- module(echo_server, [echo_server/0,
echo_server/1]).
:- use_module(library(format)).
:- use_module(library(sockets)).
echo_server :-
echo_server('127.0.0.1').
echo_server(Addr) :-
socket_server_open(Addr:Port, ServerSocket),
format("echo_server: connection opened at ~w:~d~n", [Addr, Port]),
socket_server_accept(ServerSocket, Client, Stream, [eof_action(eof_code)]),
format("echo_server: connection accepted from ~a~n", [Client]),
!,
echo_loop(Stream),
socket_server_close(ServerSocket).
echo_loop(Stream) :-
read_term(Stream, Term, []),
( Term == end_of_file ->
true
;
format("received: ~w~n", [Term]),
!,
echo_loop(Stream)
).

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

@@ -41,20 +41,30 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
:- module(builtins, [(=)/2, (\=)/2, (\+)/1, (',')/2, (->)/2, (;)/2,
(=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6,
(:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
abolish/1, asserta/1, assertz/1, atom_chars/2,
atom_codes/2, atom_concat/3, atom_length/2,
bagof/3, catch/3, char_code/2, clause/2,
current_input/1, current_output/1, current_op/3,
abolish/1, asserta/1, assertz/1,
at_end_of_stream/0, at_end_of_stream/1,
atom_chars/2, atom_codes/2, atom_concat/3,
atom_length/2, bagof/3, catch/3, char_code/2,
clause/2, close/1, close/2, current_input/1,
current_output/1, current_op/3,
current_predicate/1, current_prolog_flag/2,
expand_goal/2, expand_term/2, fail/0, false/0,
findall/3, findall/4, get_char/1, halt/0,
max_arity/1, number_chars/2, number_codes/2,
once/1, op/3, read_term/2, read_term/3, repeat/0,
retract/1, set_prolog_flag/2, set_input/1,
set_output/1, setof/3, sub_atom/5,
findall/3, findall/4, flush_output/0,
flush_output/1, get_byte/1, get_byte/2,
get_char/1, get_char/2, get_code/1, get_code/2,
halt/0, max_arity/1, number_chars/2,
number_codes/2, once/1, op/3, open/3, open/4,
peek_byte/1, peek_byte/2, peek_char/1,
peek_char/2, peek_code/1, peek_code/2,
put_byte/1, put_byte/2, put_code/1, put_code/2,
put_char/1, put_char/2, read_term/2, read_term/3,
repeat/0, retract/1, set_prolog_flag/2,
set_input/1, set_stream_position/2, set_output/1,
setof/3, stream_property/2, sub_atom/5,
subsumes_term/2, term_variables/2, throw/1,
true/0, unify_with_occurs_check/2, write/1,
write_canonical/1, write_term/2, writeq/1]).
write_canonical/1, write_term/2, write_term/3,
writeq/1]).
% the maximum arity flag. needs to be replaced with
@@ -312,36 +322,39 @@ get_args([Arg|Args], Func, I0, N) :-
'$call_with_default_policy'(I1 is I0 + 1),
'$call_with_default_policy'(get_args(Args, Func, I1, N)).
% write, write_canonical, writeq, write_term.
is_write_option(Functor) :-
Functor =.. [Name, Arg],
( Arg == true -> true
; Arg == false -> true
; Name == variable_names -> must_be_var_names_list(Arg)
; Name == max_depth -> integer(Arg), Arg >= 0
; var(Arg) -> throw(error(instantiation_error, write_term/2))
; throw(error(domain_error(write_option, Functor), write_term/2))
), % 8.14.2.3 e)
( Name == ignore_ops -> true
; Name == quoted -> true
; Name == numbervars -> true
; Name == variable_names -> true
; Name == max_depth -> true
; throw(error(domain_error(write_option, Functor), write_term/2))
). % 8.14.2.3 e)
parse_write_options(Options, OptionValues, Stub) :-
DefaultOptions = [ignore_ops-false, max_depth-0, numbervars-false,
quoted-false, variable_names-[]],
parse_options_list(Options, parse_write_options_, DefaultOptions, OptionValues, Stub).
inst_member_or([X|Xs], Y, Z) :-
( var(X) -> throw(error(instantiation_error, write_term/2))
; is_write_option(X) -> ( Y = X, ! ; inst_member_or(Xs, Y, Z) )
; throw(error(domain_error(write_option, X), write_term/2))
parse_write_options_(ignore_ops(IgnoreOps), ignore_ops-IgnoreOps) :-
( nonvar(IgnoreOps), lists:member(IgnoreOps, [true, false])
;
throw(error(domain_error(write_option, ignore_ops(IgnoreOps)), _))
).
parse_write_options_(quoted(Quoted), quoted-Quoted) :-
( nonvar(Quoted), lists:member(Quoted, [true, false])
;
throw(error(domain_error(write_option, quoted(Quoted)), _))
).
parse_write_options_(numbervars(NumberVars), numbervars-NumberVars) :-
( nonvar(NumberVars), lists:member(NumberVars, [true, false])
;
throw(error(domain_error(write_option, numbervars(NumberVars)), _))
).
parse_write_options_(variable_names(VNNames), variable_names-VNNames) :-
must_be_var_names_list(VNNames).
parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :-
( integer(MaxDepth), MaxDepth >= 0
;
throw(error(domain_error(write_option, max_depth(MaxDepth)), _))
).
inst_member_or([], Y, Y).
must_be_var_names_list(VarNames) :-
'$skip_max_list'(_, -1, VarNames, Tail),
( Tail == [] -> must_be_var_names_list_(VarNames, VarNames)
; var(Tail) -> throw(error(instantiation_error, write_term/2))
; throw(error(domain_error(write_options, variable_names(VarNames)), write_term/2))
; throw(error(domain_error(write_option, variable_names(VarNames)), write_term/2))
).
must_be_var_names_list_([], List).
@@ -350,36 +363,34 @@ must_be_var_names_list_([VarName | VarNames], List) :-
( VarName = (Atom = _) ->
( atom(Atom) -> must_be_var_names_list_(VarNames, List)
; var(Atom) -> throw(error(instantiation_error, write_term/2))
; throw(error(domain_error(write_options, variable_names(List)), write_term/2))
; throw(error(domain_error(write_option, variable_names(List)), write_term/2))
)
; throw(error(domain_error(write_options, variable_names(List)), write_term/2))
; throw(error(domain_error(write_option, variable_names(List)), write_term/2))
)
; throw(error(instantiation_error, write_term/2)) % throw(error(domain_error(write_options, variable_names(List)), write_term/2))
; throw(error(instantiation_error, write_term/2))
).
write_term(_, Options) :-
var(Options), throw(error(instantiation_error, write_term/2)).
write_term(Term, Options) :-
'$skip_max_list'(_, -1, Options, Options0),
( var(Options0) -> throw(error(instantiation_error, write_term/2))
; Options0 == [] -> true
; throw(error(type_error(list, Options), write_term/2))
), % 8.14.2.3 c)
inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)),
inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
inst_member_or(Options, quoted(Quoted), quoted(false)),
inst_member_or(Options, variable_names(VarNames), variable_names([])),
inst_member_or(Options, max_depth(MaxDepth), max_depth(0)),
'$write_term'(Term, IgnoreOps, NumberVars, Quoted, VarNames, MaxDepth).
current_output(Stream),
write_term(Stream, Term, Options).
write_term(Stream, Term, Options) :-
parse_write_options(Options, [IgnoreOps, MaxDepth, NumberVars, Quoted, VNNames], write_term/3),
'$write_term'(Stream, Term, IgnoreOps, NumberVars, Quoted, VNNames, MaxDepth).
write(Term) :-
'$write_term'(Term, false, true, false, [], 0).
current_output(Stream),
'$write_term'(Stream, Term, false, true, false, [], 0).
write_canonical(Term) :-
'$write_term'(Term, true, false, true, [], 0).
current_output(Stream),
'$write_term'(Stream, Term, true, false, true, [], 0).
writeq(Term) :-
'$write_term'(Term, false, true, true, [], 0).
current_output(Stream),
'$write_term'(Stream, Term, false, true, true, [], 0).
@@ -420,25 +431,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) :-
@@ -1004,11 +1006,11 @@ char_code(Char, Code) :-
).
get_char(C) :-
( var(C) -> '$get_char'(C)
; C == end_of_file -> '$get_char'(C)
; atom_length(C, 1) -> '$get_char'(C)
; throw(error(type_error(in_character, C), get_char/1))
).
current_input(S),
'$get_char'(S, C).
get_char(S, C) :-
'$get_char'(S, C).
can_be_number(N, PI) :-
( var(N) -> true
@@ -1148,3 +1150,182 @@ parse_stream_options_(eof_action(Action), eof_action-Action) :-
).
parse_stream_options_(E, _) :-
throw(error(domain_error(stream_option, E), _)). % 8.11.5.3i)
open(SourceSink, Mode, Stream) :-
open(SourceSink, Mode, Stream, []).
open(SourceSink, Mode, Stream, StreamOptions) :-
( var(SourceSink) ->
throw(error(instantiation_error, open/4)) % 8.11.5.3a)
; var(Mode) ->
throw(error(instantiation_error, open/4)) % 8.11.5.3b)
; \+ atom(Mode) ->
throw(error(type_error(atom, Mode), open/4)) % 8.11.5.3d)
; nonvar(Stream) ->
throw(error(type_error(variable, Stream), open/4)) % 8.11.5.3f)
;
parse_stream_options(StreamOptions, [Alias, EOFAction, Reposition, Type], open/4),
'$open'(SourceSink, Mode, Stream, Alias, EOFAction, Reposition, Type)
).
parse_close_options(Options, OptionValues, Stub) :-
DefaultOptions = [force-false],
parse_options_list(Options, parse_close_options_, DefaultOptions, OptionValues, Stub).
parse_close_options_(force(Force), force-Force) :-
( nonvar(Force), lists:member(Force, [true, false]), !
;
throw(error(domain_error(close_option, force(Force)), _))
).
parse_close_options_(E, _) :-
throw(error(domain_error(close_option, E), _)).
close(Stream, CloseOptions) :-
parse_close_options(CloseOptions, [Force], close/2),
'$close'(Stream, CloseOptions).
close(Stream) :-
'$close'(Stream, []).
flush_output(S) :-
'$flush_output'(S).
flush_output :-
current_output(S),
'$flush_output'(S).
get_byte(S, B) :-
'$get_byte'(S, B).
get_byte(B) :-
current_input(S),
'$get_byte'(S, B).
put_char(C) :-
current_output(S),
'$put_char'(S, C).
put_char(S, C) :-
'$put_char'(S, C).
put_byte(C) :-
current_output(S),
'$put_byte'(S, C).
put_byte(S, C) :-
'$put_byte'(S, C).
put_code(C) :-
current_output(S),
'$put_code'(S, C).
put_code(S, C) :-
'$put_code'(S, C).
get_code(C) :-
current_input(S),
'$get_code'(S, C).
get_code(S, C) :-
'$get_code'(S, C).
peek_byte(S, B) :-
'$peek_byte'(S, B).
peek_byte(B) :-
current_input(S),
'$peek_byte'(S, B).
peek_code(C) :-
current_input(S),
'$peek_code'(S, C).
peek_code(S, C) :-
'$peek_code'(S, C).
peek_char(C) :-
current_input(S),
'$peek_char'(S, C).
peek_char(S, C) :-
'$peek_char'(S, C).
check_stream_property(file_name(F), file_name, F) :-
( var(F) -> true ; atom(F) ).
check_stream_property(mode(M), mode, M) :-
( var(M) -> true ; lists:member(M, [read, write, append]) ).
check_stream_property(D, direction, D) :-
( var(D) -> true ; lists:member(D, [input, output, input_output]), ! ).
check_stream_property(alias(A), alias, A) :-
( var(A) -> true ; atom(A) ).
check_stream_property(position(P), position, P) :-
( var(P) -> true ; integer(P), P >= 0 ).
check_stream_property(end_of_stream(E), end_of_stream, E) :-
( var(E) -> true ; lists:member(E, [not, at, past]) ).
check_stream_property(eof_action(A), eof_action, A) :-
( var(A) -> true ; lists:member(A, [error, eof_code, reset]) ).
check_stream_property(reposition(B), reposition, B) :-
( var(B) -> true ; lists:member(B, [true, false]) ).
check_stream_property(type(T), type, T) :-
( var(T) -> true ; lists:member(T, [text, binary]) ).
stream_iter_(S, S).
stream_iter_(S, S1) :-
'$next_stream'(S, S0),
stream_iter_(S0, S1).
stream_iter(S) :-
( nonvar(S) ->
true
; '$first_stream'(S0),
stream_iter_(S0, S)
).
stream_property(S, P) :-
( nonvar(P), \+ check_stream_property(P, _, _) ->
throw(error(domain_error(stream_property, P), stream_property/2))
; stream_iter(S),
check_stream_property(P, PropertyName, PropertyValue),
'$stream_property'(S, PropertyName, PropertyValue)
).
at_end_of_stream(S_or_a) :-
( atom(S_or_a) ->
stream_property(S, alias(A))
; S = S_or_a
),
stream_property(S, end_of_stream(E)),
!,
( E = at ; E = past ).
at_end_of_stream :-
current_input(S),
stream_property(S, end_of_stream(E)),
!,
( E = at ; E = past ).
set_stream_position(S_or_a, Position) :-
( var(Position) ->
throw(error(instantiation_error, set_stream_position/2))
; integer(Position), Position >= 0 ->
true
; throw(error(domain_error(stream_position, Position)))
),
'$set_stream_position'(S_or_a, Position).

View File

@@ -124,21 +124,14 @@ read_term_from_chars(Chars, Term) :-
write_term_to_chars(_, Options, _) :-
var(Options), instantiation_error(write_term_to_chars/3).
write_term_to_chars(Term, Options, Chars) :-
'$skip_max_list'(_, -1, Options, Options0),
( var(Options0) ->
instantiation_error(write_term_to_chars/3)
; nonvar(Chars) ->
builtins:parse_write_options(Options,
[IgnoreOps, MaxDepth, NumberVars, Quoted, VNNames],
write_term_to_chars/3),
( nonvar(Chars) ->
throw(error(uninstantiation_error(Chars), write_term_to_chars/3))
; Options0 == [] ->
true
;
type_error(list, Options, write_term_to_chars/3)
true
),
builtins:inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)),
builtins:inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
builtins:inst_member_or(Options, quoted(Quoted), quoted(false)),
builtins:inst_member_or(Options, variable_names(VarNames), variable_names([])),
builtins:inst_member_or(Options, max_depth(MaxDepth), max_depth(0)),
term_variables(Term, Vars),
extend_var_list(Vars, VarNames, NewVarNames, numbervars),
'$write_term_to_chars'(Term, IgnoreOps, NumberVars, Quoted, NewVarNames, MaxDepth, Chars).
'$write_term_to_chars'(Chars, Term, IgnoreOps, NumberVars, Quoted, NewVarNames, MaxDepth).

58
src/prolog/lib/sockets.pl Normal file
View File

@@ -0,0 +1,58 @@
:- module(sockets, [socket_client_open/3,
socket_server_open/2,
socket_server_accept/4,
socket_server_close/1,
current_hostname/1]).
:- use_module(library(error)).
socket_client_open(Addr, Stream, Options) :-
( var(Addr) ->
throw(error(instantiation_error, socket_client_open/3))
;
true
),
must_be(var, Stream),
must_be(list, Options),
( Addr = Address:Port,
atom(Address),
( atom(Port) ; integer(Port) ) ->
true
;
throw(error(type_error(socket_address, Addr), socket_client_open/3))
),
builtins:parse_stream_options(Options,
[Alias, EOFAction, Reposition, Type],
socket_client_open/3),
'$socket_client_open'(Address, Port, Stream, Alias, EOFAction, Reposition, Type).
socket_server_open(Addr, ServerSocket) :-
must_be(var, ServerSocket),
( ( integer(Addr) ; var(Addr) ) ->
'$socket_server_open'([], Addr, ServerSocket)
;
Addr = Address:Port,
must_be(atom, Address),
can_be(integer, Port),
'$socket_server_open'(Address, Port, ServerSocket)
).
socket_server_accept(ServerSocket, Client, Stream, Options) :-
must_be(var, Client),
must_be(var, Stream),
builtins:parse_stream_options(Options,
[Alias, EOFAction, Reposition, Type],
socket_server_accept/4),
'$socket_server_accept'(ServerSocket, Client, Stream, Alias, EOFAction, Reposition, Type).
socket_server_close(ServerSocket) :-
'$socket_server_close'(ServerSocket).
current_hostname(HostName) :-
'$current_hostname'(HostName).

View File

@@ -119,7 +119,7 @@ fn load_module_from_file(
let mut path_buf = fix_filename(wam.indices.atom_tbl.clone(), path_buf)?;
let filename = clause_name!(path_buf.to_string_lossy().to_string(), wam.indices.atom_tbl);
let file_handle = Stream::from(File::open(&path_buf).or_else(|_| {
let file_handle = Stream::from_file_as_input(filename.clone(), File::open(&path_buf).or_else(|_| {
Err(SessionError::InvalidFileName(filename.clone()))
})?);
@@ -614,7 +614,7 @@ fn load_library(
)
}
None => {
let err = ExistenceError::SourceSink(ModuleSource::Library(
let err = ExistenceError::ModuleSource(ModuleSource::Library(
name.clone()
));
@@ -705,7 +705,7 @@ impl ListingCompiler {
Ok(wam_indices.insert_module(submodule))
} else {
let err = ExistenceError::SourceSink(ModuleSource::File(
let err = ExistenceError::ModuleSource(ModuleSource::File(
module_name,
));
@@ -743,7 +743,7 @@ impl ListingCompiler {
Ok(wam_indices.insert_module(submodule))
} else {
let err = ExistenceError::SourceSink(ModuleSource::File(
let err = ExistenceError::ModuleSource(ModuleSource::File(
module_name
));
@@ -1077,7 +1077,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,
));
@@ -1436,7 +1436,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

@@ -1,6 +1,5 @@
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::stack::*;
use crate::prolog::machine::streams::*;
use std::mem;
use std::ops::IndexMut;
@@ -215,24 +214,6 @@ impl<T: CopierTarget> CopyTermState<T> {
}
}
fn copy_stream(&mut self, addr: usize) {
let threshold = self.target.threshold();
let trail_item = mem::replace(
&mut self.target[addr],
HeapCellValue::Addr(Addr::Stream(threshold)),
);
self.trail.push((
Ref::HeapCell(addr),
trail_item,
));
self.target.push(HeapCellValue::Stream(Stream::null_stream()));
self.scan += 1;
}
fn copy_structure(&mut self, addr: usize) {
match self.target[addr].context_free_clone() {
HeapCellValue::NamedStr(arity, name, fixity) => {
@@ -285,12 +266,13 @@ impl<T: CopierTarget> CopyTermState<T> {
*self.value_at_scan() = HeapCellValue::Addr(addr);
}
}
Addr::Lis(h) if h >= self.old_h => {
self.scan += 1;
}
Addr::Lis(h) => {
if h >= self.old_h {
self.scan += 1;
} else {
self.copy_list(h);
}
}
addr @ Addr::AttrVar(_) |
addr @ Addr::HeapCell(_) |
addr @ Addr::StackCell(..) => {
@@ -303,7 +285,7 @@ impl<T: CopierTarget> CopyTermState<T> {
self.copy_partial_string(addr, n);
}
Addr::Stream(h) => {
self.copy_stream(h);
*self.value_at_scan() = self.target[h].context_free_clone();
}
_ => {
self.scan += 1;

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))
}
}
}
@@ -285,18 +288,15 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
HeapCellValue::Addr(addr) => {
addr
}
val @ HeapCellValue::Atom(..)
| val @ HeapCellValue::Integer(_)
| val @ HeapCellValue::DBRef(_)
| val @ HeapCellValue::Rational(_) => {
val @ HeapCellValue::Atom(..) |
val @ HeapCellValue::Integer(_) |
val @ HeapCellValue::DBRef(_) |
val @ HeapCellValue::Rational(_) => {
Addr::Con(self.push(val))
}
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,13 +17,13 @@ enum ErrorProvenance {
}
#[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 TypeError {
fn type_error(self, h: usize, valid_type: ValidType) -> MachineError;
}
@@ -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::Received,
}
}
ExistenceError::Stream(culprit) => {
let stub = functor!(
"existence_error",
@@ -454,17 +466,22 @@ pub enum Permission {
Create,
InputStream,
Modify,
Open,
OutputStream,
Reposition,
}
impl Permission {
#[inline]
pub fn as_str(self) -> &'static str {
match self {
Permission::Access => "access",
Permission::Create => "create",
Permission::InputStream => "input",
Permission::Modify => "modify",
Permission::Open => "open",
Permission::OutputStream => "output",
Permission::Reposition => "reposition",
}
}
}
@@ -475,20 +492,21 @@ pub enum ValidType {
Atom,
Atomic,
// Boolean,
// Byte,
Byte,
Callable,
Character,
Compound,
Evaluable,
Float,
// InByte,
// InCharacter,
InByte,
InCharacter,
Integer,
List,
// Number,
Pair,
// PredicateIndicator,
// Variable
TcpListener,
}
impl ValidType {
@@ -497,26 +515,28 @@ impl ValidType {
ValidType::Atom => "atom",
ValidType::Atomic => "atomic",
// ValidType::Boolean => "boolean",
// ValidType::Byte => "byte",
ValidType::Byte => "byte",
ValidType::Callable => "callable",
ValidType::Character => "character",
ValidType::Compound => "compound",
ValidType::Evaluable => "evaluable",
ValidType::Float => "float",
// ValidType::InByte => "in_byte",
// ValidType::InCharacter => "in_character",
ValidType::InByte => "in_byte",
ValidType::InCharacter => "in_character",
ValidType::Integer => "integer",
ValidType::List => "list",
// ValidType::Number => "number",
ValidType::Pair => "pair",
// ValidType::PredicateIndicator => "predicate_indicator",
// ValidType::Variable => "variable"
ValidType::TcpListener => "tcp_listener",
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum DomainErrorType {
IOMode,
NotLessThanZero,
Order,
Stream,
@@ -526,6 +546,7 @@ pub enum DomainErrorType {
impl DomainErrorType {
pub fn as_str(self) -> &'static str {
match self {
DomainErrorType::IOMode => "io_mode",
DomainErrorType::NotLessThanZero => "not_less_than_zero",
DomainErrorType::Order => "order",
DomainErrorType::Stream => "stream",
@@ -537,9 +558,9 @@ impl DomainErrorType {
// from 7.12.2 f) of 13211-1:1995
#[derive(Debug, Clone, Copy)]
pub enum RepFlag {
Character,
// Character,
CharacterCode,
// InCharacterCode,
InCharacterCode,
MaxArity,
// MaxInteger,
// MinInteger
@@ -548,9 +569,9 @@ pub enum RepFlag {
impl RepFlag {
pub fn as_str(self) -> &'static str {
match self {
RepFlag::Character => "character",
// RepFlag::Character => "character",
RepFlag::CharacterCode => "character_code",
// RepFlag::InCharacterCode => "in_character_code",
RepFlag::InCharacterCode => "in_character_code",
RepFlag::MaxArity => "max_arity",
// RepFlag::MaxInteger => "max_integer",
// RepFlag::MinInteger => "min_integer"
@@ -681,6 +702,41 @@ impl MachineState {
self.check_for_list_pairs(sorted)
}
#[inline]
pub(crate)
fn type_error<T: TypeError>(
&self,
valid_type: ValidType,
culprit: T,
caller: ClauseName,
arity: usize,
) -> MachineStub {
let stub = MachineError::functor_stub(caller, arity);
let err = MachineError::type_error(
self.heap.h(),
valid_type,
culprit,
);
return self.error_form(err, stub);
}
#[inline]
pub(crate)
fn representation_error(
&self,
rep_flag: RepFlag,
caller: ClauseName,
arity: usize,
) -> MachineStub {
let stub = MachineError::functor_stub(caller, arity);
let err = MachineError::representation_error(
rep_flag,
);
return self.error_form(err, stub);
}
pub(super)
fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub {
let location = err.location;
@@ -726,8 +782,9 @@ impl MachineState {
#[derive(Debug)]
pub enum ExistenceError {
Module(ClauseName),
ModuleSource(ModuleSource),
Procedure(ClauseName, usize),
SourceSink(ModuleSource),
SourceSink(Addr),
Stream(Addr),
}

View File

@@ -19,10 +19,11 @@ use indexmap::IndexMap;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::collections::{BTreeMap, VecDeque};
use std::collections::{BTreeMap, BTreeSet, 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)
}
}
}
@@ -437,8 +443,11 @@ impl HeapCellValue {
&HeapCellValue::PartialString(ref pstr, has_tail) => {
HeapCellValue::PartialString(pstr.clone(), has_tail)
}
&HeapCellValue::Stream(_) => {
HeapCellValue::Stream(Stream::null_stream())
&HeapCellValue::Stream(ref stream) => {
HeapCellValue::Stream(stream.clone())
}
&HeapCellValue::TcpListener(_) => {
HeapCellValue::Atom(clause_name!("$tcp_listener"), None)
}
}
}
@@ -815,6 +824,7 @@ impl ModuleStub {
pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
pub(crate) type StreamDir = BTreeSet<Stream>;
#[derive(Debug)]
pub struct IndexStore {
@@ -827,6 +837,7 @@ pub struct IndexStore {
pub(super) module_dir: ModuleDir,
pub(super) modules: ModuleDir,
pub(super) op_dir: OpDir,
pub(super) streams: StreamDir,
pub(super) stream_aliases: StreamAliasDir,
}
@@ -915,6 +926,7 @@ impl IndexStore {
op_dir: default_op_dir(),
modules: ModuleDir::new(),
stream_aliases: StreamAliasDir::new(),
streams: StreamDir::new(),
}
}

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,49 +613,40 @@ 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,
mut stream: Stream,
indices: &mut IndexStore,
) -> CallResult {
let mut stream = self.open_parsing_stream(
current_input_stream.clone(),
"read_term",
2,
self.check_stream_properties(
&mut stream,
StreamType::Text,
Some(self[temp_v!(2)]),
clause_name!("read_term"),
3,
)?;
if stream.past_end_of_stream() {
if EOFAction::Reset != stream.options.eof_action {
return return_from_clause!(self.last_call, self);
} else if self.fail {
return Ok(());
}
}
let mut orig_stream = stream.clone();
let mut stream = self.open_parsing_stream(stream, "read_term", 3)?;
loop {
match self.read(
&mut stream,
indices.atom_tbl.clone(),
&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,25 +667,77 @@ 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))
return Ok(self.unify(var_names_offset, var_names_addr));
}
Err(err) => {
if let ParserError::UnexpectedEOF = err {
std::process::exit(0);
self.eof_action(
self[temp_v!(2)],
&mut orig_stream,
clause_name!("read_term"),
3
)?;
if orig_stream.options.eof_action == EOFAction::Reset {
if self.fail == false {
continue;
} else {
return Ok(());
}
}
}
// reset the input stream after an input failure.
*current_input_stream = readline::input_stream();
let h = self.heap.h();
let syntax_error = MachineError::syntax_error(h, err);
let stub = MachineError::functor_stub(clause_name!("read_term"), 2);
Err(self.error_form(syntax_error, stub))
return Ok(());
}
}
}
}
@@ -706,10 +748,10 @@ impl MachineState {
op_dir: &'a OpDir,
) -> Result<Option<HCPrinter<'a, PrinterOutputter>>, MachineStub>
{
let ignore_ops = self.store(self.deref(self[temp_v!(2)]));
let numbervars = self.store(self.deref(self[temp_v!(3)]));
let quoted = self.store(self.deref(self[temp_v!(4)]));
let max_depth = self.store(self.deref(self[temp_v!(6)]));
let ignore_ops = self.store(self.deref(self[temp_v!(3)]));
let numbervars = self.store(self.deref(self[temp_v!(4)]));
let quoted = self.store(self.deref(self[temp_v!(5)]));
let max_depth = self.store(self.deref(self[temp_v!(7)]));
let mut printer = HCPrinter::new(&self, op_dir, PrinterOutputter::new());
@@ -759,7 +801,7 @@ impl MachineState {
let stub = MachineError::functor_stub(clause_name!("write_term"), 2);
match self.try_from_list(temp_v!(5), stub) {
match self.try_from_list(temp_v!(6), stub) {
Ok(addrs) => {
let mut var_names: IndexMap<Addr, String> = IndexMap::new();
@@ -792,9 +834,11 @@ impl MachineState {
var_names.insert(var, atom);
}
_ => unreachable!(),
_ => {
}
},
_ => unreachable!(),
_ => {
}
}
}

View File

@@ -1400,8 +1400,10 @@ impl MachineState {
let addr = self.store(self.deref(addr));
let offset = match addr {
Addr::HeapCell(_) | Addr::StackCell(..) |
Addr::AttrVar(..) | Addr::Stream(_) => {
Addr::Stream(_) | Addr::TcpListener(_) => {
0
}
Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => {
v
}
Addr::PStrLocation(..) => {

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"),
));
@@ -315,7 +315,10 @@ impl Machine {
if path.is_file() {
let file_src = match File::open(&path) {
Ok(file_handle) => Stream::from(file_handle),
Ok(file_handle) => Stream::from_file_as_input(
clause_name!(".scryerrc"),
file_handle,
),
Err(_) => return,
};
@@ -409,6 +412,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,
@@ -451,6 +463,28 @@ impl Machine {
wam.compile_scryerrc();
wam.current_input_stream.options.alias = Some(clause_name!("user_input"));
wam.indices.stream_aliases.insert(
clause_name!("user_input"),
wam.current_input_stream.clone(),
);
wam.indices.streams.insert(
wam.current_input_stream.clone()
);
wam.current_output_stream.options.alias = Some(clause_name!("user_output"));
wam.indices.stream_aliases.insert(
clause_name!("user_output"),
wam.current_output_stream.clone(),
);
wam.indices.streams.insert(
wam.current_output_stream.clone()
);
wam
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -358,6 +358,7 @@ macro_rules! index_store {
op_dir: $op_dir,
modules: $modules,
stream_aliases: StreamAliasDir::new(),
streams: StreamDir::new(),
}
};
}
@@ -405,3 +406,26 @@ macro_rules! ar_reg {
ArithmeticTerm::Reg($r)
};
}
macro_rules! atom_from {
($self:expr, $indices:expr, $e:expr) => {
match $e {
Addr::Con(h) if $self.heap.atom_at(h) => {
match &$self.heap[h] {
HeapCellValue::Atom(ref atom, _) => {
atom.clone()
}
_ => {
unreachable!()
}
}
}
Addr::Char(c) => {
clause_name!(c.to_string(), $indices.atom_tbl.clone())
}
_ => {
unreachable!()
}
}
}
}

View File

@@ -18,7 +18,7 @@ pub mod readline {
use crate::prolog::machine::streams::Stream;
use crate::prolog::rustyline::error::ReadlineError;
use crate::prolog::rustyline::{Cmd, Editor, KeyPress};
use std::io::{Cursor, Read};
use std::io::{Cursor, Error, ErrorKind, Read};
static mut PROMPT: bool = false;
@@ -42,6 +42,11 @@ pub mod readline {
}
impl ReadlineStream {
pub fn new(pending_input: String) -> Self {
let rl = Editor::<()>::new();
ReadlineStream { rl, pending_input: Cursor::new(pending_input) }
}
pub fn input_stream(pending_input: String) -> Stream {
let mut rl = Editor::<()>::new();
rl.bind_sequence(KeyPress::Tab, Cmd::Insert(1, "\t".to_string()));
@@ -68,7 +73,61 @@ pub mod readline {
Ok(0)
}
Err(e) => {
Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, e))
Err(Error::new(ErrorKind::InvalidInput, e))
}
}
}
pub fn peek_byte(&mut self) -> std::io::Result<u8> {
set_prompt(false);
loop {
match self.pending_input.get_ref().bytes().next() {
Some(b) => {
return Ok(b);
}
None => {
match self.call_readline(&mut []) {
Err(e) => {
return Err(e);
}
Ok(0) => {
return Err(Error::new(
ErrorKind::UnexpectedEof,
"end of file",
));
}
_ => {
}
}
}
}
}
}
pub fn peek_char(&mut self) -> std::io::Result<char> {
set_prompt(false);
loop {
match self.pending_input.get_ref().chars().next() {
Some(c) => {
return Ok(c);
}
None => {
match self.call_readline(&mut []) {
Err(e) => {
return Err(e);
}
Ok(0) => {
return Err(Error::new(
ErrorKind::UnexpectedEof,
"end of file",
));
}
_ => {
}
}
}
}
}
}

View File

@@ -105,7 +105,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.
@@ -235,8 +235,8 @@ write_eqs_and_read_input(B, VarList) :-
append([Vars0, AttrVars, AttrGoalVars], Vars),
charsio:extend_var_list(Vars, VarList, NewVarList, fabricated),
'$get_b_value'(B0),
gather_query_vars(VarList, QueryVars),
gather_equations(NewVarList, QueryVars, Goals, AttrGoals),
gather_query_vars(VarList, OrigVars),
gather_equations(NewVarList, OrigVars, Goals, AttrGoals),
( bb_get('$first_answer', true) ->
write(' '),
bb_put('$first_answer', false)
@@ -287,8 +287,8 @@ help_message :-
gather_query_vars([_ = Var | Vars], QueryVars) :-
( var(Var) ->
QueryVars = [Var | QueryVars1],
gather_query_vars(Vars, QueryVars1)
QueryVars = [Var | QueryVars0],
gather_query_vars(Vars, QueryVars0)
; gather_query_vars(Vars, QueryVars)
).
gather_query_vars([], []).
@@ -321,9 +321,9 @@ gather_equations([Var = Value | Pairs], OrigVarList, Goals, Goals1) :-
/*
gather_equations([], MasterList, Goals, Goals).
gather_equations([Var = Value | Pairs], MasterList, Goals, Goals1) :-
select((Var = _), MasterList, MasterPairs),
( ( nonvar(Value)
; is_a_different_variable(MasterPairs, Value)
; select((Var = _), MasterList, MasterPairs),
is_a_different_variable(MasterPairs, Value)
) ->
Goals = [Var = Value | Goals0],
gather_equations(Pairs, MasterList, Goals0, Goals1)

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)