Merge branch 'sockets-develop'
This commit is contained in:
19
Cargo.lock
generated
19
Cargo.lock
generated
@@ -228,6 +228,17 @@ dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hostname"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"match_cfg",
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.3.2"
|
||||
@@ -310,6 +321,12 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "match_cfg"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
|
||||
|
||||
[[package]]
|
||||
name = "maybe-uninit"
|
||||
version = "2.0.0"
|
||||
@@ -627,6 +644,7 @@ dependencies = [
|
||||
"divrem",
|
||||
"downcast",
|
||||
"git-version",
|
||||
"hostname",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
@@ -637,6 +655,7 @@ dependencies = [
|
||||
"ref_thread_local",
|
||||
"rug",
|
||||
"rustyline",
|
||||
"unicode_reader",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
31
src/prolog/examples/echo_server.pl
Normal file
31
src/prolog/examples/echo_server.pl
Normal 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)
|
||||
).
|
||||
|
||||
@@ -48,6 +48,9 @@ impl<'a> HCPreOrderIterator<'a> {
|
||||
HeapCellValue::Stream(_) => {
|
||||
Addr::Stream(h)
|
||||
}
|
||||
&HeapCellValue::TcpListener(_) => {
|
||||
Addr::TcpListener(h)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::prolog::heap_iter::*;
|
||||
use crate::prolog::machine::heap::*;
|
||||
use crate::prolog::machine::machine_indices::*;
|
||||
use crate::prolog::machine::machine_state::*;
|
||||
use crate::prolog::machine::streams::*;
|
||||
use crate::prolog::ordered_float::OrderedFloat;
|
||||
use crate::prolog::rug::{Integer, Rational};
|
||||
|
||||
@@ -14,6 +15,7 @@ use indexmap::{IndexMap, IndexSet};
|
||||
use std::cell::Cell;
|
||||
use std::convert::TryFrom;
|
||||
use std::iter::{FromIterator, once};
|
||||
use std::net::{IpAddr, TcpListener};
|
||||
use std::ops::{Range, RangeFrom};
|
||||
use std::rc::Rc;
|
||||
|
||||
@@ -170,10 +172,12 @@ enum TokenOrRedirect {
|
||||
NumberedVar(String),
|
||||
CompositeRedirect(usize, DirectedOp),
|
||||
FunctorRedirect(usize),
|
||||
IpAddr(IpAddr),
|
||||
Number(Number, Option<DirectedOp>),
|
||||
Open,
|
||||
Close,
|
||||
Comma,
|
||||
RawPtr(*const u8),
|
||||
Space,
|
||||
LeftCurly,
|
||||
RightCurly,
|
||||
@@ -643,8 +647,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
}
|
||||
|
||||
self.state_stack.pop();
|
||||
self.state_stack.push(TokenOrRedirect::Open);
|
||||
|
||||
self.state_stack.push(TokenOrRedirect::Open);
|
||||
self.state_stack.push(TokenOrRedirect::Atom(name));
|
||||
|
||||
true
|
||||
@@ -964,6 +968,18 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn print_ip_addr(&mut self, ip: IpAddr) {
|
||||
self.push_char('\'');
|
||||
self.append_str(&format!("{}", ip));
|
||||
self.push_char('\'');
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn print_raw_ptr(&mut self, ptr: *const u8) {
|
||||
self.append_str(&format!("0x{:x}", ptr as usize));
|
||||
}
|
||||
|
||||
fn print_number(&mut self, n: Number, op: &Option<DirectedOp>) {
|
||||
let add_brackets = if let Some(op) = op {
|
||||
op.is_negative_sign() && n.is_positive()
|
||||
@@ -1330,6 +1346,66 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
}
|
||||
}
|
||||
|
||||
fn print_tcp_listener(
|
||||
&mut self,
|
||||
iter: &mut HCPreOrderIterator,
|
||||
tcp_listener: &TcpListener,
|
||||
max_depth: usize,
|
||||
) {
|
||||
let (ip, port) =
|
||||
if let Some(addr) = tcp_listener.local_addr().ok() {
|
||||
(addr.ip(), Number::from(addr.port() as isize))
|
||||
} else {
|
||||
let disconnected_atom = clause_name!("$disconnected_tcp_listener");
|
||||
self.state_stack.push(TokenOrRedirect::Atom(disconnected_atom));
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
if self.format_struct(iter, max_depth, 1, clause_name!("$tcp_listener")) {
|
||||
let atom = self.state_stack.pop().unwrap();
|
||||
|
||||
self.state_stack.pop();
|
||||
self.state_stack.pop();
|
||||
|
||||
self.state_stack.push(TokenOrRedirect::Number(port, None));
|
||||
self.state_stack.push(TokenOrRedirect::Comma);
|
||||
self.state_stack.push(TokenOrRedirect::IpAddr(ip));
|
||||
|
||||
self.state_stack.push(TokenOrRedirect::Open);
|
||||
self.state_stack.push(atom);
|
||||
}
|
||||
}
|
||||
|
||||
fn print_stream(
|
||||
&mut self,
|
||||
iter: &mut HCPreOrderIterator,
|
||||
stream: &Stream,
|
||||
max_depth: usize,
|
||||
) {
|
||||
if let Some(alias) = &stream.options.alias {
|
||||
self.print_atom(alias);
|
||||
} else {
|
||||
if self.format_struct(iter, max_depth, 1, clause_name!("$stream")) {
|
||||
let atom =
|
||||
if stream.is_stdout() || stream.is_stdin() {
|
||||
TokenOrRedirect::Atom(clause_name!("user"))
|
||||
} else {
|
||||
TokenOrRedirect::RawPtr(stream.as_ptr())
|
||||
};
|
||||
|
||||
let stream_root = self.state_stack.pop().unwrap();
|
||||
|
||||
self.state_stack.pop();
|
||||
self.state_stack.pop();
|
||||
|
||||
self.state_stack.push(atom);
|
||||
self.state_stack.push(TokenOrRedirect::Open);
|
||||
self.state_stack.push(stream_root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_heap_term(
|
||||
&mut self,
|
||||
iter: &mut HCPreOrderIterator,
|
||||
@@ -1440,15 +1516,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
self.print_number(Number::Rational(n.clone()), &op);
|
||||
}
|
||||
&HeapCellValue::Stream(ref stream) => {
|
||||
if let Some(alias) = &stream.options.alias {
|
||||
self.print_atom(alias);
|
||||
} else {
|
||||
if stream.is_stdout() || stream.is_stdin() {
|
||||
self.print_atom(&clause_name!("user"));
|
||||
} else {
|
||||
self.format_struct(iter, max_depth, 1, clause_name!("$stream"));
|
||||
}
|
||||
}
|
||||
self.print_stream(iter, stream, max_depth);
|
||||
}
|
||||
&HeapCellValue::TcpListener(ref tcp_listener) => {
|
||||
self.print_tcp_listener(iter, tcp_listener, max_depth);
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
@@ -1486,6 +1557,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
||||
self.handle_heap_term(&mut iter, None, true, max_depth)
|
||||
}
|
||||
TokenOrRedirect::Close => self.push_char(')'),
|
||||
TokenOrRedirect::IpAddr(ip) => self.print_ip_addr(ip),
|
||||
TokenOrRedirect::RawPtr(ptr) => self.print_raw_ptr(ptr),
|
||||
TokenOrRedirect::Open => self.push_char('('),
|
||||
TokenOrRedirect::OpenList(delimit) => {
|
||||
if !self.at_cdr(",") {
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
58
src/prolog/lib/sockets.pl
Normal 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).
|
||||
@@ -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
|
||||
));
|
||||
|
||||
|
||||
@@ -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,11 +266,12 @@ 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) => {
|
||||
self.copy_list(h);
|
||||
if h >= self.old_h {
|
||||
self.scan += 1;
|
||||
} else {
|
||||
self.copy_list(h);
|
||||
}
|
||||
}
|
||||
addr @ Addr::AttrVar(_) |
|
||||
addr @ Addr::HeapCell(_) |
|
||||
@@ -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;
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,88 +613,131 @@ 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,
|
||||
)?;
|
||||
|
||||
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);
|
||||
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 term = self[temp_v!(2)];
|
||||
self.unify(Addr::HeapCell(term_write_result.heap_loc), term);
|
||||
|
||||
if self.fail {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut list_of_var_eqs = vec![];
|
||||
|
||||
for (var, binding) in term_write_result.var_dict.into_iter() {
|
||||
let var_atom = clause_name!(var.to_string(), indices.atom_tbl);
|
||||
|
||||
let h = self.heap.h();
|
||||
let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
|
||||
|
||||
self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec));
|
||||
self.heap.push(HeapCellValue::Atom(var_atom, None));
|
||||
self.heap.push(HeapCellValue::Addr(binding));
|
||||
|
||||
list_of_var_eqs.push(Addr::Str(h));
|
||||
}
|
||||
|
||||
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()));
|
||||
|
||||
return Ok(self.unify(var_names_offset, var_names_addr));
|
||||
}
|
||||
Err(err) => {
|
||||
if let ParserError::UnexpectedEOF = err {
|
||||
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(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.fail {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut list_of_var_eqs = vec![];
|
||||
|
||||
for (var, binding) in term_write_result.var_dict.into_iter() {
|
||||
let var_atom = clause_name!(var.to_string(), indices.atom_tbl);
|
||||
|
||||
let h = self.heap.h();
|
||||
let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
|
||||
|
||||
self.heap.push(HeapCellValue::NamedStr(2, clause_name!("="), spec));
|
||||
self.heap.push(HeapCellValue::Atom(var_atom, None));
|
||||
self.heap.push(HeapCellValue::Addr(binding));
|
||||
|
||||
list_of_var_eqs.push(Addr::Str(h));
|
||||
}
|
||||
|
||||
let a2 = self[temp_v!(2)];
|
||||
let list_offset =
|
||||
Addr::HeapCell(self.heap.to_list(list_of_var_eqs.into_iter()));
|
||||
|
||||
Ok(self.unify(list_offset, a2))
|
||||
}
|
||||
Err(err) => {
|
||||
if let ParserError::UnexpectedEOF = err {
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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!(),
|
||||
_ => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1400,9 +1400,11 @@ impl MachineState {
|
||||
let addr = self.store(self.deref(addr));
|
||||
|
||||
let offset = match addr {
|
||||
Addr::HeapCell(_) | Addr::StackCell(..) |
|
||||
Addr::AttrVar(..) | Addr::Stream(_) => {
|
||||
v
|
||||
Addr::Stream(_) | Addr::TcpListener(_) => {
|
||||
0
|
||||
}
|
||||
Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => {
|
||||
v
|
||||
}
|
||||
Addr::PStrLocation(..) => {
|
||||
if !self.flags.double_quotes.is_atom() {
|
||||
|
||||
@@ -297,7 +297,7 @@ impl Machine {
|
||||
|
||||
Ok(self.indices.insert_module(module))
|
||||
} else {
|
||||
let err = ExistenceError::SourceSink(ModuleSource::File(
|
||||
let err = ExistenceError::ModuleSource(ModuleSource::File(
|
||||
clause_name!("$toplevel"),
|
||||
));
|
||||
|
||||
@@ -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
@@ -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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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([], []).
|
||||
@@ -298,7 +298,7 @@ is_a_different_variable([_ = Binding | Pairs], Value) :-
|
||||
; is_a_different_variable(Pairs, Value)
|
||||
).
|
||||
|
||||
eq_member(X, [Y|_]) :- X == Y, !.
|
||||
eq_member(X, [Y|_]) :- X == Y, !.
|
||||
eq_member(X, [_|Ys]) :- eq_member(X, Ys).
|
||||
|
||||
gather_equations([], _, Goals, Goals).
|
||||
@@ -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)
|
||||
|
||||
@@ -181,6 +181,9 @@ impl fmt::Display for HeapCellValue {
|
||||
&HeapCellValue::Stream(ref stream) => {
|
||||
write!(f, "$stream({})", stream.as_ptr() as usize)
|
||||
}
|
||||
&HeapCellValue::TcpListener(ref tcp_listener) => {
|
||||
write!(f, "$tcp_listener({})", tcp_listener.local_addr().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,6 +216,7 @@ impl fmt::Display for Addr {
|
||||
&Addr::Str(s) => write!(f, "Addr::Str({})", s),
|
||||
&Addr::PStrLocation(h, n) => write!(f, "Addr::PStrLocation({}, {})", h, n),
|
||||
&Addr::Stream(stream) => write!(f, "Addr::Stream({})", stream),
|
||||
&Addr::TcpListener(tcp_listener) => write!(f, "Addr::TcpListener({})", tcp_listener),
|
||||
&Addr::Usize(cp) => write!(f, "Addr::Usize({})", cp),
|
||||
}
|
||||
}
|
||||
@@ -332,11 +336,14 @@ impl fmt::Display for ExistenceError {
|
||||
&ExistenceError::Module(ref module_name) => {
|
||||
write!(f, "the module {} does not exist", module_name)
|
||||
}
|
||||
&ExistenceError::ModuleSource(ref module_source) => {
|
||||
write!(f, "the source/sink {} does not exist", module_source)
|
||||
}
|
||||
&ExistenceError::Procedure(ref name, arity) => {
|
||||
write!(f, "the procedure {}/{} does not exist", name, arity)
|
||||
}
|
||||
&ExistenceError::SourceSink(ref module_source) => {
|
||||
write!(f, "the source/sink {} does not exist", module_source)
|
||||
&ExistenceError::SourceSink(ref addr) => {
|
||||
write!(f, "the source/sink {} does not exist", addr)
|
||||
}
|
||||
&ExistenceError::Stream(ref addr) => {
|
||||
write!(f, "the stream at {} does not exist", addr)
|
||||
|
||||
Reference in New Issue
Block a user