From 4c88e97330583efff246524b70f4ede3932f5ba4 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 11 Mar 2020 00:38:01 -0600 Subject: [PATCH] add current_output, printing of stream terms --- Cargo.lock | 6 +- Cargo.toml | 2 +- src/main.rs | 3 +- src/prolog/clause_types.rs | 3 + src/prolog/heap_print.rs | 14 ++++ src/prolog/lib/builtins.pl | 14 ++-- src/prolog/machine/machine_indices.rs | 5 +- src/prolog/machine/machine_state.rs | 43 +++++++--- src/prolog/machine/machine_state_impl.rs | 14 +++- src/prolog/machine/mod.rs | 32 +++++-- src/prolog/machine/streams.rs | 101 ++++++++++++++++++++++- src/prolog/machine/system_calls.rs | 27 ++++++ src/prolog/machine/term_expansion.rs | 1 + src/prolog/macros.rs | 3 +- 14 files changed, 236 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0aafa8b7..61c28d82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -444,7 +444,7 @@ dependencies = [ [[package]] name = "prolog_parser" -version = "0.8.44" +version = "0.8.47" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -580,7 +580,7 @@ dependencies = [ "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "prolog_parser 0.8.44 (registry+https://github.com/rust-lang/crates.io-index)", + "prolog_parser 0.8.47 (registry+https://github.com/rust-lang/crates.io-index)", "ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustyline 6.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -791,7 +791,7 @@ dependencies = [ "checksum parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" "checksum parking_lot_core 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum prolog_parser 0.8.44 (registry+https://github.com/rust-lang/crates.io-index)" = "c113cce59b3e97ff141e933d09eb1618e44b11cad9fa2ce6eb53ef832c38dc5c" +"checksum prolog_parser 0.8.47 (registry+https://github.com/rust-lang/crates.io-index)" = "2cf575fc8b91b2d9a9487f13655cffb6f697a5294b74de9b24b6a5fbe987e229" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" diff --git a/Cargo.toml b/Cargo.toml index cc978a29..278c8948 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ libc = "0.2.62" nix = "0.15.0" num-rug-adapter = { optional = true, version = "0.1.1" } ordered-float = "0.5.0" -prolog_parser = { version = "0.8.44", default-features = false } +prolog_parser = { version = "0.8.47", default-features = false } ref_thread_local = "0.0.0" rug = { version = "1.4.0", optional = true } rustyline = "6.0.0" diff --git a/src/main.rs b/src/main.rs index 86cdd844..b7cd3152 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ use nix::sys::signal; mod prolog; use crate::prolog::machine::*; +use crate::prolog::machine::streams::*; use crate::prolog::read::*; use std::sync::atomic::Ordering; @@ -31,6 +32,6 @@ fn main() { let handler = signal::SigHandler::Handler(handle_sigint); unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap(); - let mut wam = Machine::new(readline::input_stream()); + let mut wam = Machine::new(readline::input_stream(), Stream::stdout()); wam.run_top_level(); } diff --git a/src/prolog/clause_types.rs b/src/prolog/clause_types.rs index e0cfbe90..4ccddfdb 100644 --- a/src/prolog/clause_types.rs +++ b/src/prolog/clause_types.rs @@ -171,6 +171,7 @@ pub enum SystemClauseType { CopyToLiftedHeap, CreatePartialString, CurrentInput, + CurrentOutput, DeleteAttribute, DeleteHeadAttribute, DynamicModuleResolution(usize), @@ -285,6 +286,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::CurrentOutput => clause_name!("$current_output"), &SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"), &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"), &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => { @@ -436,6 +438,7 @@ impl SystemClauseType { ("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)), ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), ("$current_input", 1) => Some(SystemClauseType::CurrentInput), + ("$current_output", 1) => Some(SystemClauseType::CurrentOutput), ("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute), ("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute), ("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef), diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index b7c25ded..0c2e846b 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -958,6 +958,20 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { self.push_list(); } } + HeapCellValue::Addr(Addr::Stream(stream)) => { + if let Some(alias) = &stream.options.alias { + self.print_atom(alias); + } else { + if stream.is_stdout() || stream.is_stdin() { + self.append_str("user"); + } else { + self.append_str(&format!( + "'$stream'(0x{:x})", + stream.as_ptr() as usize, + )); + } + } + } HeapCellValue::Addr(addr) => { if let Some(offset_str) = self.offset_as_string(iter, addr) { push_space_if_amb!(self, &offset_str, { diff --git a/src/prolog/lib/builtins.pl b/src/prolog/lib/builtins.pl index c8d85b9a..92807ac6 100644 --- a/src/prolog/lib/builtins.pl +++ b/src/prolog/lib/builtins.pl @@ -44,12 +44,12 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :- 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_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, repeat/0, retract/1, + 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, repeat/0, retract/1, set_prolog_flag/2, setof/3, sub_atom/5, subsumes_term/2, term_variables/2, throw/1, true/0, unify_with_occurs_check/2, write/1, @@ -1014,3 +1014,5 @@ subsumes_term(General, Specific) :- unify_with_occurs_check(X, Y) :- '$unify_with_occurs_check'(X, Y). current_input(S) :- '$current_input'(S). + +current_output(S) :- '$current_output'(S). diff --git a/src/prolog/machine/machine_indices.rs b/src/prolog/machine/machine_indices.rs index be54937e..53f5e159 100644 --- a/src/prolog/machine/machine_indices.rs +++ b/src/prolog/machine/machine_indices.rs @@ -615,17 +615,19 @@ impl ModuleStub { } pub(crate) type ModuleStubDir = IndexMap; +pub(crate) type StreamAliasDir = IndexMap; pub struct IndexStore { pub(super) atom_tbl: TabledData, pub(super) code_dir: CodeDir, - pub(super) module_dir: ModuleDir, pub(super) dynamic_code_dir: DynamicCodeDir, pub(super) global_variables: GlobalVarDir, pub(super) in_situ_code_dir: InSituCodeDir, pub(super) in_situ_module_dir: ModuleStubDir, + pub(super) module_dir: ModuleDir, pub(super) modules: ModuleDir, pub(super) op_dir: OpDir, + pub(super) stream_aliases: StreamAliasDir, } impl IndexStore { @@ -712,6 +714,7 @@ impl IndexStore { in_situ_module_dir: ModuleStubDir::new(), op_dir: default_op_dir(), modules: ModuleDir::new(), + stream_aliases: StreamAliasDir::new(), } } diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index f3cc271a..58e7f127 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -15,7 +15,7 @@ use crate::prolog::rug::Integer; use downcast::Any; use std::cmp::Ordering; -use std::io::{stdout, Write}; +use std::io::Write; use std::mem; use std::ops::{Index, IndexMut}; use std::rc::Rc; @@ -722,6 +722,7 @@ pub(crate) trait CallPolicy: Any { ct: &BuiltInClauseType, indices: &mut IndexStore, current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ) -> CallResult { match ct { &BuiltInClauseType::AcyclicTerm => { @@ -760,11 +761,10 @@ pub(crate) trait CallPolicy: Any { machine_st.compare_term(qt); return_from_clause!(machine_st.last_call, machine_st) } - &BuiltInClauseType::Nl => { - let mut stdout = stdout(); - - write!(stdout, "\n").unwrap(); - stdout.flush().unwrap(); + &BuiltInClauseType::Nl => { + write!(current_output_stream, "\n").unwrap(); + current_output_stream.flush().unwrap(); + return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::Read => { @@ -896,12 +896,19 @@ pub(crate) trait CallPolicy: Any { arity: usize, indices: &mut IndexStore, current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ) -> CallResult { if let Some((name, arity)) = machine_st.setup_call_n(arity) { match ClauseType::from(name.clone(), arity, None) { ClauseType::BuiltIn(built_in) => { machine_st.setup_built_in_call(built_in.clone()); - self.call_builtin(machine_st, &built_in, indices, current_input_stream)?; + self.call_builtin( + machine_st, + &built_in, + indices, + current_input_stream, + current_output_stream, + )?; } ClauseType::CallN => { machine_st.handle_internal_call_n(arity); @@ -982,9 +989,16 @@ impl CallPolicy for CWILCallPolicy { ct: &BuiltInClauseType, indices: &mut IndexStore, current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ) -> CallResult { - self.prev_policy - .call_builtin(machine_st, ct, indices, current_input_stream)?; + self.prev_policy.call_builtin( + machine_st, + ct, + indices, + current_input_stream, + current_output_stream + )?; + self.increment(machine_st) } @@ -994,9 +1008,16 @@ impl CallPolicy for CWILCallPolicy { arity: usize, indices: &mut IndexStore, current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ) -> CallResult { - self.prev_policy - .call_n(machine_st, arity, indices, current_input_stream)?; + self.prev_policy.call_n( + machine_st, + arity, + indices, + current_input_stream, + current_output_stream, + )?; + self.increment(machine_st) } } diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 3e35f0cc..00b2eb97 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -3219,6 +3219,7 @@ impl MachineState { call_policy: &mut Box, cut_policy: &mut Box, current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ct: &ClauseType, arity: usize, lco: bool, @@ -3245,11 +3246,17 @@ impl MachineState { match ct { &ClauseType::BuiltIn(ref ct) => try_or_fail!( self, - call_policy.call_builtin(self, ct, indices, current_input_stream) + call_policy.call_builtin( + self, + ct, + indices, + current_input_stream, + current_output_stream, + ) ), &ClauseType::CallN => try_or_fail!( self, - call_policy.call_n(self, arity, indices, current_input_stream) + call_policy.call_n(self, arity, indices, current_input_stream, current_output_stream) ), &ClauseType::Hook(ref hook) => try_or_fail!(self, call_policy.compile_hook(self, hook)), &ClauseType::Inlined(ref ct) => { @@ -3274,6 +3281,7 @@ impl MachineState { call_policy, cut_policy, current_input_stream, + current_output_stream, ) ), }; @@ -3288,6 +3296,7 @@ impl MachineState { call_policy: &mut Box, cut_policy: &mut Box, current_input_stream: &mut Stream, + current_output_stream: &mut Stream, instr: &ControlInstruction, ) { match instr { @@ -3301,6 +3310,7 @@ impl MachineState { call_policy, cut_policy, current_input_stream, + current_output_stream, ct, arity, lco, diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index 67afac2e..64bc4dd9 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -22,7 +22,7 @@ pub mod modules; mod partial_string; mod raw_block; mod stack; -pub(super) mod streams; +pub(crate) mod streams; pub(super) mod term_expansion; pub mod toplevel; @@ -77,6 +77,7 @@ pub struct Machine { pub(super) code_repo: CodeRepo, pub(super) toplevel_idx: usize, pub(super) current_input_stream: Stream, + pub(super) current_output_stream: Stream, } impl Index for CodeRepo { @@ -344,7 +345,7 @@ impl Machine { self.run_query(); } - pub fn new(current_input_stream: Stream) -> Self + pub fn new(current_input_stream: Stream, current_output_stream: Stream) -> Self { let mut wam = Machine { machine_st: MachineState::new(), @@ -354,6 +355,7 @@ impl Machine { code_repo: CodeRepo::new(), toplevel_idx: 0, current_input_stream, + current_output_stream, }; let atom_tbl = wam.indices.atom_tbl.clone(); @@ -775,6 +777,7 @@ impl Machine { &mut self.policies, &mut self.code_repo, &mut self.current_input_stream, + &mut self.current_output_stream, ); match self.machine_st.p { @@ -811,6 +814,7 @@ impl MachineState { policies: &mut MachinePolicies, code_repo: &CodeRepo, current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ) { match instr { &Line::Arithmetic(ref arith_instr) => self.execute_arith_instr(arith_instr), @@ -826,6 +830,7 @@ impl MachineState { &mut policies.call_policy, &mut policies.cut_policy, current_input_stream, + current_output_stream, control_instr, ), &Line::Fact(ref fact_instr) => { @@ -849,6 +854,7 @@ impl MachineState { policies: &mut MachinePolicies, code_repo: &CodeRepo, current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ) { let instr = match code_repo.lookup_instr(self.last_call, &self.p) { Some(instr) => instr, @@ -861,6 +867,7 @@ impl MachineState { policies, code_repo, current_input_stream, + current_output_stream, ); } @@ -913,6 +920,7 @@ impl MachineState { policies: &mut MachinePolicies, code_repo: &mut CodeRepo, current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ) -> bool { loop { let instr = match code_repo.lookup_instr(self.last_call, &self.p) { @@ -933,7 +941,8 @@ impl MachineState { indices, policies, code_repo, - current_input_stream + current_input_stream, + current_output_stream, ); if self.fail { @@ -959,9 +968,16 @@ impl MachineState { policies: &mut MachinePolicies, code_repo: &mut CodeRepo, current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ) { loop { - self.execute_instr(indices, policies, code_repo, current_input_stream); + self.execute_instr( + indices, + policies, + code_repo, + current_input_stream, + current_output_stream, + ); if self.fail { self.backtrack(); @@ -977,7 +993,13 @@ impl MachineState { if !instigating_instr.as_ref().is_head_instr() { let cp = self.p.local(); self.run_verify_attr_interrupt(cp); - } else if !self.verify_attr_stepper(indices, policies, code_repo, current_input_stream) { + } else if !self.verify_attr_stepper( + indices, + policies, + code_repo, + current_input_stream, + current_output_stream, + ) { if self.fail { break; } diff --git a/src/prolog/machine/streams.rs b/src/prolog/machine/streams.rs index 57d4835a..b8cd4247 100644 --- a/src/prolog/machine/streams.rs +++ b/src/prolog/machine/streams.rs @@ -6,7 +6,7 @@ use std::cell::RefCell; use std::error::Error; use std::fmt; use std::fs::File; -use std::io::{Cursor, ErrorKind, Read, Write}; +use std::io::{stdin, stdout, Cursor, ErrorKind, Read, Write}; use std::hash::{Hash, Hasher}; use std::net::TcpStream; use std::rc::Rc; @@ -31,6 +31,8 @@ pub enum StreamInstance { DynReadSource(Box), File(File), ReadlineStream(ReadlineStream), + Stdin, + Stdout, TcpStream(TcpStream), } @@ -176,6 +178,88 @@ impl Stream { ptr } + + #[inline] + pub(crate) + fn stdout() -> Self { + Stream { + options: StreamOptions::default(), + stream_inst: WrappedStreamInstance::new( + StreamInstance::Stdout + ), + } + } + + #[inline] + pub(crate) + fn stdin() -> Self { + Stream { + options: StreamOptions::default(), + stream_inst: WrappedStreamInstance::new( + StreamInstance::Stdin + ), + } + } + + #[inline] + pub(crate) + fn is_stdout(&self) -> bool { + match *self.stream_inst.0.borrow() { + StreamInstance::Stdout => { + true + } + _ => { + false + } + } + } + + #[inline] + pub(crate) + fn is_stdin(&self) -> bool { + match *self.stream_inst.0.borrow() { + StreamInstance::Stdin | StreamInstance::ReadlineStream(_) => { + true + } + _ => { + false + } + } + } + + #[inline] + pub(crate) + fn is_input_stream(&self) -> bool { + match *self.stream_inst.0.borrow() { + StreamInstance::Stdin + | StreamInstance::TcpStream(_) + | StreamInstance::Bytes(_) + | StreamInstance::ReadlineStream(_) + | StreamInstance::DynReadSource(_) + | StreamInstance::File(_) => { + true + } + _ => { + false + } + } + } + + #[inline] + pub(crate) + fn is_output_stream(&self) -> bool { + match *self.stream_inst.0.borrow() { + StreamInstance::Stdout + | StreamInstance::TcpStream(_) + | StreamInstance::Bytes(_) + | StreamInstance::File(_) => { + true + } + _ => { + false + } + } + } } impl Read for Stream { @@ -196,6 +280,15 @@ impl Read for Stream { StreamInstance::Bytes(ref mut cursor) => { cursor.read(buf) } + StreamInstance::Stdin => { + stdin().read(buf) + } + StreamInstance::Stdout => { + Err(std::io::Error::new( + ErrorKind::PermissionDenied, + StreamError::ReadFromOutputStream, + )) + } } } } @@ -212,6 +305,9 @@ impl Write for Stream { StreamInstance::Bytes(ref mut cursor) => { cursor.write(buf) } + StreamInstance::Stdout => { + stdout().write(buf) + } _ => { Err(std::io::Error::new( ErrorKind::PermissionDenied, @@ -232,6 +328,9 @@ impl Write for Stream { StreamInstance::Bytes(ref mut cursor) => { cursor.flush() } + StreamInstance::Stdout => { + stdout().flush() + } _ => { Err(std::io::Error::new( ErrorKind::PermissionDenied, diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index 6aa0432d..137c5ce0 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -673,6 +673,7 @@ impl MachineState { call_policy: &mut Box, cut_policy: &mut Box, current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ) -> CallResult { match ct { &SystemClauseType::AbolishClause => { @@ -748,6 +749,32 @@ impl MachineState { } } } + &SystemClauseType::CurrentOutput => { + let addr = self.store(self.deref(self[temp_v!(1)].clone())); + let stream = current_output_stream.clone(); + + match addr { + addr if addr.is_ref() => { + self.unify(Addr::Stream(stream), addr); + } + Addr::Stream(other_stream) => { + self.fail = stream != other_stream; + } + addr => { + let stub = MachineError::functor_stub( + clause_name!("current_input"), + 1, + ); + + let err = MachineError::domain_error( + DomainError::Stream, + addr, + ); + + return Err(self.error_form(err, stub)); + } + } + } &SystemClauseType::AtEndOfExpansion => { if self.cp == LocalCodePtr::TopLevel(0, 0) { self.at_end_of_expansion = true; diff --git a/src/prolog/machine/term_expansion.rs b/src/prolog/machine/term_expansion.rs index 8a7f7e94..20ea91d6 100644 --- a/src/prolog/machine/term_expansion.rs +++ b/src/prolog/machine/term_expansion.rs @@ -364,6 +364,7 @@ impl MachineState { &mut wam.policies, &mut wam.code_repo, &mut readline::input_stream(), + &mut Stream::stdout(), ); if self.fail || self.at_end_of_expansion { diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 89f971e7..7968aa34 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -237,7 +237,8 @@ macro_rules! index_store { in_situ_code_dir: InSituCodeDir::new(), in_situ_module_dir: ModuleStubDir::new(), op_dir: $op_dir, - modules: $modules, + modules: $modules, + stream_aliases: StreamAliasDir::new(), } }; } -- 2.54.0