add stream_property/2
This commit is contained in:
@@ -181,6 +181,7 @@ pub enum SystemClauseType {
|
|||||||
FetchGlobalVar,
|
FetchGlobalVar,
|
||||||
FetchGlobalVarWithOffset,
|
FetchGlobalVarWithOffset,
|
||||||
FileToChars,
|
FileToChars,
|
||||||
|
FirstStream,
|
||||||
FlushOutput,
|
FlushOutput,
|
||||||
GetByte,
|
GetByte,
|
||||||
GetChar,
|
GetChar,
|
||||||
@@ -221,6 +222,7 @@ pub enum SystemClauseType {
|
|||||||
NumberToCodes,
|
NumberToCodes,
|
||||||
OpDeclaration,
|
OpDeclaration,
|
||||||
Open,
|
Open,
|
||||||
|
NextStream,
|
||||||
PartialStringTail,
|
PartialStringTail,
|
||||||
PeekByte,
|
PeekByte,
|
||||||
PeekChar,
|
PeekChar,
|
||||||
@@ -245,6 +247,7 @@ pub enum SystemClauseType {
|
|||||||
SetOutput,
|
SetOutput,
|
||||||
StoreGlobalVar,
|
StoreGlobalVar,
|
||||||
StoreGlobalVarWithOffset,
|
StoreGlobalVarWithOffset,
|
||||||
|
StreamProperty,
|
||||||
InferenceLevel,
|
InferenceLevel,
|
||||||
CleanUpBlock,
|
CleanUpBlock,
|
||||||
EraseBall,
|
EraseBall,
|
||||||
@@ -334,6 +337,7 @@ impl SystemClauseType {
|
|||||||
clause_name!("$fetch_global_var_with_offset")
|
clause_name!("$fetch_global_var_with_offset")
|
||||||
}
|
}
|
||||||
&SystemClauseType::FileToChars => clause_name!("$file_to_chars"),
|
&SystemClauseType::FileToChars => clause_name!("$file_to_chars"),
|
||||||
|
&SystemClauseType::FirstStream => clause_name!("$first_stream"),
|
||||||
&SystemClauseType::FlushOutput => clause_name!("$flush_output"),
|
&SystemClauseType::FlushOutput => clause_name!("$flush_output"),
|
||||||
&SystemClauseType::GetByte => clause_name!("$get_byte"),
|
&SystemClauseType::GetByte => clause_name!("$get_byte"),
|
||||||
&SystemClauseType::GetChar => clause_name!("$get_char"),
|
&SystemClauseType::GetChar => clause_name!("$get_char"),
|
||||||
@@ -390,6 +394,7 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
|
&SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
|
||||||
&SystemClauseType::ModuleExists => clause_name!("$module_exists"),
|
&SystemClauseType::ModuleExists => clause_name!("$module_exists"),
|
||||||
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
|
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
|
||||||
|
&SystemClauseType::NextStream => clause_name!("$next_stream"),
|
||||||
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
||||||
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
||||||
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
|
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
|
||||||
@@ -416,6 +421,7 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::SetInput => clause_name!("$set_input"),
|
&SystemClauseType::SetInput => clause_name!("$set_input"),
|
||||||
&SystemClauseType::SetOutput => clause_name!("$set_output"),
|
&SystemClauseType::SetOutput => clause_name!("$set_output"),
|
||||||
&SystemClauseType::SetSeed => clause_name!("$set_seed"),
|
&SystemClauseType::SetSeed => clause_name!("$set_seed"),
|
||||||
|
&SystemClauseType::StreamProperty => clause_name!("$stream_property"),
|
||||||
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
|
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
|
||||||
&SystemClauseType::StoreGlobalVarWithOffset => {
|
&SystemClauseType::StoreGlobalVarWithOffset => {
|
||||||
clause_name!("$store_global_var_with_offset")
|
clause_name!("$store_global_var_with_offset")
|
||||||
@@ -492,6 +498,8 @@ impl SystemClauseType {
|
|||||||
("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
|
("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
|
||||||
("$current_input", 1) => Some(SystemClauseType::CurrentInput),
|
("$current_input", 1) => Some(SystemClauseType::CurrentInput),
|
||||||
("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
|
("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
|
||||||
|
("$first_stream", 1) => Some(SystemClauseType::FirstStream),
|
||||||
|
("$next_stream", 2) => Some(SystemClauseType::NextStream),
|
||||||
("$flush_output", 1) => Some(SystemClauseType::FlushOutput),
|
("$flush_output", 1) => Some(SystemClauseType::FlushOutput),
|
||||||
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
|
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
|
||||||
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
|
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
|
||||||
@@ -566,6 +574,7 @@ impl SystemClauseType {
|
|||||||
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
|
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
|
||||||
("$set_input", 1) => Some(SystemClauseType::SetInput),
|
("$set_input", 1) => Some(SystemClauseType::SetInput),
|
||||||
("$set_output", 1) => Some(SystemClauseType::SetOutput),
|
("$set_output", 1) => Some(SystemClauseType::SetOutput),
|
||||||
|
("$stream_property", 3) => Some(SystemClauseType::StreamProperty),
|
||||||
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
|
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
|
||||||
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
|
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
|
||||||
("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
|
("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
|
||||||
|
|||||||
@@ -58,9 +58,9 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
|
|||||||
put_code/2, put_char/1, put_char/2, read_term/2,
|
put_code/2, put_char/1, put_char/2, read_term/2,
|
||||||
read_term/3, repeat/0, retract/1,
|
read_term/3, repeat/0, retract/1,
|
||||||
set_prolog_flag/2, set_input/1, set_output/1,
|
set_prolog_flag/2, set_input/1, set_output/1,
|
||||||
setof/3, sub_atom/5, subsumes_term/2,
|
setof/3, stream_property/2, sub_atom/5,
|
||||||
term_variables/2, throw/1, true/0,
|
subsumes_term/2, term_variables/2, throw/1,
|
||||||
unify_with_occurs_check/2, write/1,
|
true/0, unify_with_occurs_check/2, write/1,
|
||||||
write_canonical/1, write_term/2, write_term/3,
|
write_canonical/1, write_term/2, write_term/3,
|
||||||
writeq/1]).
|
writeq/1]).
|
||||||
|
|
||||||
@@ -1259,3 +1259,45 @@ peek_char(C) :-
|
|||||||
|
|
||||||
peek_char(S, C) :-
|
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)
|
||||||
|
).
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ fn load_module_from_file(
|
|||||||
let mut path_buf = fix_filename(wam.indices.atom_tbl.clone(), path_buf)?;
|
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 filename = clause_name!(path_buf.to_string_lossy().to_string(), wam.indices.atom_tbl);
|
||||||
|
|
||||||
let file_handle = Stream::from_file_as_input(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()))
|
Err(SessionError::InvalidFileName(filename.clone()))
|
||||||
})?);
|
})?);
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ use indexmap::IndexMap;
|
|||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::{BTreeMap, VecDeque};
|
use std::collections::{BTreeMap, BTreeSet, VecDeque};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
@@ -824,6 +824,7 @@ impl ModuleStub {
|
|||||||
|
|
||||||
pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
|
pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
|
||||||
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
|
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
|
||||||
|
pub(crate) type StreamDir = BTreeSet<Stream>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IndexStore {
|
pub struct IndexStore {
|
||||||
@@ -836,6 +837,7 @@ pub struct IndexStore {
|
|||||||
pub(super) module_dir: ModuleDir,
|
pub(super) module_dir: ModuleDir,
|
||||||
pub(super) modules: ModuleDir,
|
pub(super) modules: ModuleDir,
|
||||||
pub(super) op_dir: OpDir,
|
pub(super) op_dir: OpDir,
|
||||||
|
pub(super) streams: StreamDir,
|
||||||
pub(super) stream_aliases: StreamAliasDir,
|
pub(super) stream_aliases: StreamAliasDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -924,6 +926,7 @@ impl IndexStore {
|
|||||||
op_dir: default_op_dir(),
|
op_dir: default_op_dir(),
|
||||||
modules: ModuleDir::new(),
|
modules: ModuleDir::new(),
|
||||||
stream_aliases: StreamAliasDir::new(),
|
stream_aliases: StreamAliasDir::new(),
|
||||||
|
streams: StreamDir::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -315,7 +315,10 @@ impl Machine {
|
|||||||
|
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
let file_src = match File::open(&path) {
|
let file_src = match File::open(&path) {
|
||||||
Ok(file_handle) => Stream::from_file_as_input(file_handle),
|
Ok(file_handle) => Stream::from_file_as_input(
|
||||||
|
clause_name!(".scryerrc"),
|
||||||
|
file_handle,
|
||||||
|
),
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -460,6 +463,28 @@ impl Machine {
|
|||||||
|
|
||||||
wam.compile_scryerrc();
|
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
|
wam
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use crate::prolog::machine::machine_errors::*;
|
|||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::prolog::machine::machine_indices::*;
|
||||||
use crate::prolog::machine::machine_state::*;
|
use crate::prolog::machine::machine_state::*;
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -26,8 +27,8 @@ impl StreamType {
|
|||||||
pub(crate)
|
pub(crate)
|
||||||
fn as_str(&self) -> &'static str {
|
fn as_str(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
StreamType::Binary => "binary_stream",
|
StreamType::Binary => "binary",
|
||||||
StreamType::Text => "text_stream",
|
StreamType::Text => "text",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,23 +49,53 @@ pub enum EOFAction {
|
|||||||
Reset,
|
Reset,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum AtEndOfStream {
|
||||||
|
Not,
|
||||||
|
End,
|
||||||
|
Past
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AtEndOfStream {
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
AtEndOfStream::Not => "not",
|
||||||
|
AtEndOfStream::Past => "past",
|
||||||
|
AtEndOfStream::End => "end",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EOFAction {
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn as_str(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
EOFAction::EOFCode => "eof_code",
|
||||||
|
EOFAction::Error => "error",
|
||||||
|
EOFAction::Reset => "reset",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* all these streams are closed automatically when the instance is
|
/* all these streams are closed automatically when the instance is
|
||||||
* dropped. */
|
* dropped. */
|
||||||
pub enum StreamInstance {
|
pub enum StreamInstance {
|
||||||
Bytes(Cursor<Vec<u8>>),
|
Bytes(Cursor<Vec<u8>>),
|
||||||
DynReadSource(Box<dyn Read>),
|
DynReadSource(Box<dyn Read>),
|
||||||
InputFile(File),
|
InputFile(ClauseName, File),
|
||||||
OutputFile(File),
|
OutputFile(ClauseName, File, bool), // File, append.
|
||||||
Null,
|
Null,
|
||||||
ReadlineStream(ReadlineStream),
|
ReadlineStream(ReadlineStream),
|
||||||
Stdout,
|
Stdout,
|
||||||
TcpStream(TcpStream),
|
TcpStream(ClauseName, TcpStream),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for StreamInstance {
|
impl Drop for StreamInstance {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
match self {
|
match self {
|
||||||
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
|
||||||
tcp_stream.shutdown(Shutdown::Both).unwrap();
|
tcp_stream.shutdown(Shutdown::Both).unwrap();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -80,14 +111,14 @@ impl fmt::Debug for StreamInstance {
|
|||||||
write!(fmt, "Bytes({:?})", bytes),
|
write!(fmt, "Bytes({:?})", bytes),
|
||||||
&StreamInstance::DynReadSource(_) =>
|
&StreamInstance::DynReadSource(_) =>
|
||||||
write!(fmt, "DynReadSource(_)"), // Hacky solution.
|
write!(fmt, "DynReadSource(_)"), // Hacky solution.
|
||||||
&StreamInstance::InputFile(ref file) => write!(fmt, "InputFile({:?})", file),
|
&StreamInstance::InputFile(_, ref file) => write!(fmt, "InputFile({:?})", file),
|
||||||
&StreamInstance::OutputFile(ref file) => write!(fmt, "OutputFile({:?})", file),
|
&StreamInstance::OutputFile(_, ref file, _) => write!(fmt, "OutputFile({:?})", file),
|
||||||
&StreamInstance::Null => write!(fmt, "Null"),
|
&StreamInstance::Null => write!(fmt, "Null"),
|
||||||
&StreamInstance::ReadlineStream(ref readline_stream) =>
|
&StreamInstance::ReadlineStream(ref readline_stream) =>
|
||||||
write!(fmt, "ReadlineStream({:?})", readline_stream),
|
write!(fmt, "ReadlineStream({:?})", readline_stream),
|
||||||
// &StreamInstance::Stdin => write!(fmt, "Stdin"),
|
// &StreamInstance::Stdin => write!(fmt, "Stdin"),
|
||||||
&StreamInstance::Stdout => write!(fmt, "Stdout"),
|
&StreamInstance::Stdout => write!(fmt, "Stdout"),
|
||||||
&StreamInstance::TcpStream(ref tcp_stream) =>
|
&StreamInstance::TcpStream(_, ref tcp_stream) =>
|
||||||
write!(fmt, "TcpStream({:?})", tcp_stream),
|
write!(fmt, "TcpStream({:?})", tcp_stream),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,6 +225,20 @@ pub struct Stream {
|
|||||||
stream_inst: WrappedStreamInstance,
|
stream_inst: WrappedStreamInstance,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for Stream {
|
||||||
|
#[inline]
|
||||||
|
fn partial_cmp(&self, other: &Stream) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for Stream {
|
||||||
|
#[inline]
|
||||||
|
fn cmp(&self, other: &Stream) -> Ordering {
|
||||||
|
self.as_ptr().cmp(&other.as_ptr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for Stream {
|
impl PartialEq for Stream {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
@@ -203,15 +248,6 @@ impl PartialEq for Stream {
|
|||||||
|
|
||||||
impl Eq for Stream {}
|
impl Eq for Stream {}
|
||||||
|
|
||||||
impl From<TcpStream> for Stream {
|
|
||||||
fn from(tcp_stream: TcpStream) -> Self {
|
|
||||||
tcp_stream.set_read_timeout(None).unwrap();
|
|
||||||
tcp_stream.set_write_timeout(None).unwrap();
|
|
||||||
|
|
||||||
Stream::from_inst(StreamInstance::TcpStream(tcp_stream))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<String> for Stream {
|
impl From<String> for Stream {
|
||||||
fn from(string: String) -> Self {
|
fn from(string: String) -> Self {
|
||||||
Stream::from_inst(StreamInstance::Bytes(Cursor::new(string.into_bytes())))
|
Stream::from_inst(StreamInstance::Bytes(Cursor::new(string.into_bytes())))
|
||||||
@@ -245,6 +281,105 @@ impl Stream {
|
|||||||
ptr as *const u8
|
ptr as *const u8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn position(&mut self) -> Option<u64> {
|
||||||
|
match *self.stream_inst.0.borrow_mut() {
|
||||||
|
StreamInstance::InputFile(_, ref mut file) => {
|
||||||
|
file.seek(SeekFrom::Current(0)).ok()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn position_relative_to_end(&mut self) -> AtEndOfStream {
|
||||||
|
if self.past_end_of_stream {
|
||||||
|
return AtEndOfStream::Past;
|
||||||
|
}
|
||||||
|
|
||||||
|
match *self.stream_inst.0.borrow_mut() {
|
||||||
|
StreamInstance::InputFile(_, ref mut file) => {
|
||||||
|
match file.metadata() {
|
||||||
|
Ok(metadata) => {
|
||||||
|
if let Ok(position) = file.seek(SeekFrom::Current(0)) {
|
||||||
|
return match position.cmp(&metadata.len()) {
|
||||||
|
Ordering::Equal => {
|
||||||
|
AtEndOfStream::End
|
||||||
|
}
|
||||||
|
Ordering::Less => {
|
||||||
|
AtEndOfStream::Not
|
||||||
|
}
|
||||||
|
Ordering::Greater => {
|
||||||
|
self.past_end_of_stream = true;
|
||||||
|
AtEndOfStream::Past
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
self.past_end_of_stream = true;
|
||||||
|
AtEndOfStream::Past
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.past_end_of_stream = true;
|
||||||
|
AtEndOfStream::Past
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
AtEndOfStream::Not
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn file_name(&self) -> Option<ClauseName> {
|
||||||
|
match *self.stream_inst.0.borrow() {
|
||||||
|
StreamInstance::InputFile(ref name, _) => {
|
||||||
|
Some(name.clone())
|
||||||
|
}
|
||||||
|
StreamInstance::OutputFile(ref name, ..) => {
|
||||||
|
Some(name.clone())
|
||||||
|
}
|
||||||
|
StreamInstance::TcpStream(ref name, _) => {
|
||||||
|
Some(name.clone())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn mode(&self) -> &'static str {
|
||||||
|
match *self.stream_inst.0.borrow() {
|
||||||
|
StreamInstance::Bytes(_) |
|
||||||
|
StreamInstance::ReadlineStream(_) |
|
||||||
|
StreamInstance::DynReadSource(_) |
|
||||||
|
StreamInstance::InputFile(..) => {
|
||||||
|
"read"
|
||||||
|
}
|
||||||
|
StreamInstance::TcpStream(..) => {
|
||||||
|
"read_append"
|
||||||
|
}
|
||||||
|
StreamInstance::OutputFile(_, _, true) => {
|
||||||
|
"append"
|
||||||
|
}
|
||||||
|
StreamInstance::Stdout |
|
||||||
|
StreamInstance::OutputFile(_, _, false) => {
|
||||||
|
"write"
|
||||||
|
}
|
||||||
|
StreamInstance::Null => {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_inst(stream_inst: StreamInstance) -> Self {
|
fn from_inst(stream_inst: StreamInstance) -> Self {
|
||||||
Stream {
|
Stream {
|
||||||
@@ -262,14 +397,23 @@ impl Stream {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate)
|
pub(crate)
|
||||||
fn from_file_as_output(file: File) -> Self {
|
fn from_tcp_stream(address: ClauseName, tcp_stream: TcpStream) -> Self {
|
||||||
Stream::from_inst(StreamInstance::OutputFile(file))
|
tcp_stream.set_read_timeout(None).unwrap();
|
||||||
|
tcp_stream.set_write_timeout(None).unwrap();
|
||||||
|
|
||||||
|
Stream::from_inst(StreamInstance::TcpStream(address, tcp_stream))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate)
|
pub(crate)
|
||||||
fn from_file_as_input(file: File) -> Self {
|
fn from_file_as_output(name: ClauseName, file: File, in_append_mode: bool) -> Self {
|
||||||
Stream::from_inst(StreamInstance::InputFile(file))
|
Stream::from_inst(StreamInstance::OutputFile(name, file, in_append_mode))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn from_file_as_input(name: ClauseName, file: File) -> Self {
|
||||||
|
Stream::from_inst(StreamInstance::InputFile(name, file))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -321,11 +465,11 @@ impl Stream {
|
|||||||
fn is_input_stream(&self) -> bool {
|
fn is_input_stream(&self) -> bool {
|
||||||
match *self.stream_inst.0.borrow() {
|
match *self.stream_inst.0.borrow() {
|
||||||
// StreamInstance::Stdin |
|
// StreamInstance::Stdin |
|
||||||
StreamInstance::TcpStream(_) |
|
StreamInstance::TcpStream(..) |
|
||||||
StreamInstance::Bytes(_) |
|
StreamInstance::Bytes(_) |
|
||||||
StreamInstance::ReadlineStream(_) |
|
StreamInstance::ReadlineStream(_) |
|
||||||
StreamInstance::DynReadSource(_) |
|
StreamInstance::DynReadSource(_) |
|
||||||
StreamInstance::InputFile(_) => {
|
StreamInstance::InputFile(..) => {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -339,9 +483,9 @@ impl Stream {
|
|||||||
fn is_output_stream(&self) -> bool {
|
fn is_output_stream(&self) -> bool {
|
||||||
match *self.stream_inst.0.borrow() {
|
match *self.stream_inst.0.borrow() {
|
||||||
StreamInstance::Stdout
|
StreamInstance::Stdout
|
||||||
| StreamInstance::TcpStream(_)
|
| StreamInstance::TcpStream(..)
|
||||||
| StreamInstance::Bytes(_)
|
| StreamInstance::Bytes(_)
|
||||||
| StreamInstance::OutputFile(_) => {
|
| StreamInstance::OutputFile(..) => {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -358,7 +502,7 @@ impl Stream {
|
|||||||
cursor.set_position(0);
|
cursor.set_position(0);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
StreamInstance::InputFile(ref mut file) => {
|
StreamInstance::InputFile(_, ref mut file) => {
|
||||||
file.seek(SeekFrom::Start(0)).unwrap();
|
file.seek(SeekFrom::Start(0)).unwrap();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@@ -393,7 +537,7 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StreamInstance::InputFile(ref mut file) => {
|
StreamInstance::InputFile(_, ref mut file) => {
|
||||||
let mut b = [0u8; 1];
|
let mut b = [0u8; 1];
|
||||||
|
|
||||||
match file.read(&mut b)? {
|
match file.read(&mut b)? {
|
||||||
@@ -412,7 +556,7 @@ impl Stream {
|
|||||||
StreamInstance::ReadlineStream(ref mut stream) => {
|
StreamInstance::ReadlineStream(ref mut stream) => {
|
||||||
stream.peek_byte()
|
stream.peek_byte()
|
||||||
}
|
}
|
||||||
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
|
||||||
let mut b = [0u8; 1];
|
let mut b = [0u8; 1];
|
||||||
tcp_stream.peek(&mut b)?;
|
tcp_stream.peek(&mut b)?;
|
||||||
Ok(b[0])
|
Ok(b[0])
|
||||||
@@ -432,7 +576,7 @@ impl Stream {
|
|||||||
use unicode_reader::CodePoints;
|
use unicode_reader::CodePoints;
|
||||||
|
|
||||||
match *self.stream_inst.0.borrow_mut() {
|
match *self.stream_inst.0.borrow_mut() {
|
||||||
StreamInstance::InputFile(ref mut file) => {
|
StreamInstance::InputFile(_, ref mut file) => {
|
||||||
let c = {
|
let c = {
|
||||||
let mut iter = CodePoints::from(&*file);
|
let mut iter = CodePoints::from(&*file);
|
||||||
|
|
||||||
@@ -453,7 +597,7 @@ impl Stream {
|
|||||||
StreamInstance::ReadlineStream(ref mut stream) => {
|
StreamInstance::ReadlineStream(ref mut stream) => {
|
||||||
stream.peek_char()
|
stream.peek_char()
|
||||||
}
|
}
|
||||||
StreamInstance::TcpStream(ref tcp_stream) => {
|
StreamInstance::TcpStream(_, ref tcp_stream) => {
|
||||||
let c = {
|
let c = {
|
||||||
let mut buf = [0u8; 8];
|
let mut buf = [0u8; 8];
|
||||||
tcp_stream.peek(&mut buf)?;
|
tcp_stream.peek(&mut buf)?;
|
||||||
@@ -832,10 +976,10 @@ impl MachineState {
|
|||||||
impl Read for Stream {
|
impl Read for Stream {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
match *self.stream_inst.0.borrow_mut() {
|
match *self.stream_inst.0.borrow_mut() {
|
||||||
StreamInstance::InputFile(ref mut file) => {
|
StreamInstance::InputFile(_, ref mut file) => {
|
||||||
file.read(buf)
|
file.read(buf)
|
||||||
}
|
}
|
||||||
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
|
||||||
tcp_stream.read(buf)
|
tcp_stream.read(buf)
|
||||||
}
|
}
|
||||||
StreamInstance::ReadlineStream(ref mut rl_stream) => {
|
StreamInstance::ReadlineStream(ref mut rl_stream) => {
|
||||||
@@ -852,7 +996,7 @@ impl Read for Stream {
|
|||||||
stdin().read(buf)
|
stdin().read(buf)
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
StreamInstance::OutputFile(_) | StreamInstance::Stdout | StreamInstance::Null => {
|
StreamInstance::OutputFile(..) | StreamInstance::Stdout | StreamInstance::Null => {
|
||||||
Err(std::io::Error::new(
|
Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::ReadFromOutputStream,
|
StreamError::ReadFromOutputStream,
|
||||||
@@ -865,10 +1009,10 @@ impl Read for Stream {
|
|||||||
impl Write for Stream {
|
impl Write for Stream {
|
||||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||||
match *self.stream_inst.0.borrow_mut() {
|
match *self.stream_inst.0.borrow_mut() {
|
||||||
StreamInstance::OutputFile(ref mut file) => {
|
StreamInstance::OutputFile(_, ref mut file, _) => {
|
||||||
file.write(buf)
|
file.write(buf)
|
||||||
}
|
}
|
||||||
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
|
||||||
tcp_stream.write(buf)
|
tcp_stream.write(buf)
|
||||||
}
|
}
|
||||||
StreamInstance::Bytes(ref mut cursor) => {
|
StreamInstance::Bytes(ref mut cursor) => {
|
||||||
@@ -878,7 +1022,7 @@ impl Write for Stream {
|
|||||||
stdout().write(buf)
|
stdout().write(buf)
|
||||||
}
|
}
|
||||||
StreamInstance::DynReadSource(_) | StreamInstance::ReadlineStream(_) |
|
StreamInstance::DynReadSource(_) | StreamInstance::ReadlineStream(_) |
|
||||||
StreamInstance::InputFile(_) | StreamInstance::Null => {
|
StreamInstance::InputFile(..) | StreamInstance::Null => {
|
||||||
Err(std::io::Error::new(
|
Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::WriteToInputStream,
|
StreamError::WriteToInputStream,
|
||||||
@@ -889,10 +1033,10 @@ impl Write for Stream {
|
|||||||
|
|
||||||
fn flush(&mut self) -> std::io::Result<()> {
|
fn flush(&mut self) -> std::io::Result<()> {
|
||||||
match *self.stream_inst.0.borrow_mut() {
|
match *self.stream_inst.0.borrow_mut() {
|
||||||
StreamInstance::OutputFile(ref mut file) => {
|
StreamInstance::OutputFile(_, ref mut file, _) => {
|
||||||
file.flush()
|
file.flush()
|
||||||
}
|
}
|
||||||
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
StreamInstance::TcpStream(_, ref mut tcp_stream) => {
|
||||||
tcp_stream.flush()
|
tcp_stream.flush()
|
||||||
}
|
}
|
||||||
StreamInstance::Bytes(ref mut cursor) => {
|
StreamInstance::Bytes(ref mut cursor) => {
|
||||||
@@ -902,7 +1046,7 @@ impl Write for Stream {
|
|||||||
stdout().flush()
|
stdout().flush()
|
||||||
}
|
}
|
||||||
StreamInstance::DynReadSource(_) | StreamInstance::ReadlineStream(_) |
|
StreamInstance::DynReadSource(_) | StreamInstance::ReadlineStream(_) |
|
||||||
StreamInstance::InputFile(_) | StreamInstance::Null => {
|
StreamInstance::InputFile(..) | StreamInstance::Null => {
|
||||||
Err(std::io::Error::new(
|
Err(std::io::Error::new(
|
||||||
ErrorKind::PermissionDenied,
|
ErrorKind::PermissionDenied,
|
||||||
StreamError::FlushToInputStream,
|
StreamError::FlushToInputStream,
|
||||||
@@ -911,5 +1055,3 @@ impl Write for Stream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: write a Seek instance.
|
|
||||||
|
|||||||
@@ -21,11 +21,13 @@ use crate::prolog::rug::Integer;
|
|||||||
use crate::ref_thread_local::RefThreadLocal;
|
use crate::ref_thread_local::RefThreadLocal;
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::io::{ErrorKind, Read, Write};
|
use std::io::{ErrorKind, Read, Write};
|
||||||
use std::iter::{once, FromIterator};
|
use std::iter::{once, FromIterator};
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::net::{TcpListener, TcpStream};
|
use std::net::{TcpListener, TcpStream};
|
||||||
|
use std::ops::Sub;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@@ -2361,11 +2363,75 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::FirstStream => {
|
||||||
|
let mut first_stream = None;
|
||||||
|
let mut null_streams = BTreeSet::new();
|
||||||
|
|
||||||
|
for stream in indices.streams.iter().cloned() {
|
||||||
|
if !stream.is_null_stream() {
|
||||||
|
first_stream = Some(stream);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
null_streams.insert(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
indices.streams = indices.streams.sub(&null_streams);
|
||||||
|
|
||||||
|
if let Some(first_stream) = first_stream {
|
||||||
|
let stream = self.heap.to_unifiable(HeapCellValue::Stream(first_stream));
|
||||||
|
|
||||||
|
let var = self.store(self.deref(self[temp_v!(1)])).as_var().unwrap();
|
||||||
|
self.bind(var, stream);
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&SystemClauseType::NextStream => {
|
||||||
|
let prev_stream =
|
||||||
|
match self.store(self.deref(self[temp_v!(1)])) {
|
||||||
|
Addr::Stream(h) => {
|
||||||
|
if let HeapCellValue::Stream(ref stream) = &self.heap[h] {
|
||||||
|
stream.clone()
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut next_stream = None;
|
||||||
|
let mut null_streams = BTreeSet::new();
|
||||||
|
|
||||||
|
for stream in indices.streams.range(prev_stream.clone() ..).skip(1).cloned() {
|
||||||
|
if !stream.is_null_stream() {
|
||||||
|
next_stream = Some(stream);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
null_streams.insert(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
indices.streams = indices.streams.sub(&null_streams);
|
||||||
|
|
||||||
|
if let Some(next_stream) = next_stream {
|
||||||
|
let var = self.store(self.deref(self[temp_v!(2)])).as_var().unwrap();
|
||||||
|
let next_stream = self.heap.to_unifiable(HeapCellValue::Stream(next_stream));
|
||||||
|
|
||||||
|
self.bind(var, next_stream);
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
&SystemClauseType::FlushOutput => {
|
&SystemClauseType::FlushOutput => {
|
||||||
let mut stream =
|
let mut stream =
|
||||||
self.get_stream_or_alias(self[temp_v!(1)], indices, "flush_output", 1)?;
|
self.get_stream_or_alias(self[temp_v!(1)], indices, "flush_output", 1)?;
|
||||||
|
|
||||||
if stream.is_input_stream() {
|
if !stream.is_output_stream() {
|
||||||
let stub = MachineError::functor_stub(clause_name!("flush_output"), 1);
|
let stub = MachineError::functor_stub(clause_name!("flush_output"), 1);
|
||||||
|
|
||||||
let addr = vec![
|
let addr = vec![
|
||||||
@@ -2508,14 +2574,24 @@ impl MachineState {
|
|||||||
let mut stream =
|
let mut stream =
|
||||||
self.get_stream_or_alias(self[temp_v!(1)], indices, "close", 2)?;
|
self.get_stream_or_alias(self[temp_v!(1)], indices, "close", 2)?;
|
||||||
|
|
||||||
if stream.is_output_stream() {
|
if !stream.is_input_stream() {
|
||||||
stream.flush().unwrap(); // 8.11.6.1b)
|
stream.flush().unwrap(); // 8.11.6.1b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indices.streams.remove(&stream);
|
||||||
|
|
||||||
if stream == *current_input_stream {
|
if stream == *current_input_stream {
|
||||||
*current_input_stream = readline::input_stream();
|
*current_input_stream = indices.stream_aliases.get(
|
||||||
|
&clause_name!("user_input")
|
||||||
|
).cloned().unwrap();
|
||||||
|
|
||||||
|
indices.streams.insert(current_input_stream.clone());
|
||||||
} else if stream == *current_output_stream {
|
} else if stream == *current_output_stream {
|
||||||
*current_output_stream = Stream::stdout();
|
*current_output_stream = indices.stream_aliases.get(
|
||||||
|
&clause_name!("user_output")
|
||||||
|
).cloned().unwrap();
|
||||||
|
|
||||||
|
indices.streams.insert(current_output_stream.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.close();
|
stream.close();
|
||||||
@@ -3015,19 +3091,19 @@ impl MachineState {
|
|||||||
|
|
||||||
let mut open_options = OpenOptions::new();
|
let mut open_options = OpenOptions::new();
|
||||||
|
|
||||||
let is_input_file =
|
let (is_input_file, in_append_mode) =
|
||||||
match mode.as_str() {
|
match mode.as_str() {
|
||||||
"read" => {
|
"read" => {
|
||||||
open_options.read(true).write(false).create(false);
|
open_options.read(true).write(false).create(false);
|
||||||
true
|
(true, false)
|
||||||
}
|
}
|
||||||
"write" => {
|
"write" => {
|
||||||
open_options.read(false).write(true).truncate(true).create(true);
|
open_options.read(false).write(true).truncate(true).create(true);
|
||||||
false
|
(false, false)
|
||||||
}
|
}
|
||||||
"append" => {
|
"append" => {
|
||||||
open_options.read(false).write(true).create(true).append(true);
|
open_options.read(false).write(true).create(true).append(true);
|
||||||
false
|
(false, true)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let stub = MachineError::functor_stub(clause_name!("open"), 4);
|
let stub = MachineError::functor_stub(clause_name!("open"), 4);
|
||||||
@@ -3072,13 +3148,15 @@ impl MachineState {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut stream = if is_input_file {
|
let mut stream = if is_input_file {
|
||||||
Stream::from_file_as_input(file)
|
Stream::from_file_as_input(file_spec, file)
|
||||||
} else {
|
} else {
|
||||||
Stream::from_file_as_output(file)
|
Stream::from_file_as_output(file_spec, file, in_append_mode)
|
||||||
};
|
};
|
||||||
|
|
||||||
stream.options = options;
|
stream.options = options;
|
||||||
|
|
||||||
|
indices.streams.insert(stream.clone());
|
||||||
|
|
||||||
if let Some(ref alias) = &stream.options.alias {
|
if let Some(ref alias) = &stream.options.alias {
|
||||||
indices.stream_aliases.insert(alias.clone(), stream.clone());
|
indices.stream_aliases.insert(alias.clone(), stream.clone());
|
||||||
}
|
}
|
||||||
@@ -3721,7 +3799,7 @@ impl MachineState {
|
|||||||
let addr = self.store(self.deref(self[temp_v!(1)]));
|
let addr = self.store(self.deref(self[temp_v!(1)]));
|
||||||
let stream = self.get_stream_or_alias(addr, indices, "set_input", 1)?;
|
let stream = self.get_stream_or_alias(addr, indices, "set_input", 1)?;
|
||||||
|
|
||||||
if stream.is_output_stream() {
|
if !stream.is_input_stream() {
|
||||||
let stub = MachineError::functor_stub(
|
let stub = MachineError::functor_stub(
|
||||||
clause_name!("set_input"),
|
clause_name!("set_input"),
|
||||||
1,
|
1,
|
||||||
@@ -3747,7 +3825,7 @@ impl MachineState {
|
|||||||
let addr = self.store(self.deref(self[temp_v!(1)]));
|
let addr = self.store(self.deref(self[temp_v!(1)]));
|
||||||
let stream = self.get_stream_or_alias(addr, indices, "set_output", 1)?;
|
let stream = self.get_stream_or_alias(addr, indices, "set_output", 1)?;
|
||||||
|
|
||||||
if stream.is_input_stream() {
|
if !stream.is_output_stream() {
|
||||||
let stub = MachineError::functor_stub(
|
let stub = MachineError::functor_stub(
|
||||||
clause_name!("set_input"),
|
clause_name!("set_input"),
|
||||||
1,
|
1,
|
||||||
@@ -4246,15 +4324,19 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let stream =
|
let stream =
|
||||||
match TcpStream::connect(socket_addr).map_err(|e| e.kind()) {
|
match TcpStream::connect(&socket_addr).map_err(|e| e.kind()) {
|
||||||
Ok(tcp_stream) => {
|
Ok(tcp_stream) => {
|
||||||
let mut stream = Stream::from(tcp_stream);
|
let socket_addr = clause_name!(socket_addr, indices.atom_tbl.clone());
|
||||||
|
|
||||||
|
let mut stream = Stream::from_tcp_stream(socket_addr, tcp_stream);
|
||||||
stream.options = options;
|
stream.options = options;
|
||||||
|
|
||||||
if let Some(ref alias) = &stream.options.alias {
|
if let Some(ref alias) = &stream.options.alias {
|
||||||
indices.stream_aliases.insert(alias.clone(), stream.clone());
|
indices.stream_aliases.insert(alias.clone(), stream.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indices.streams.insert(stream.clone());
|
||||||
|
|
||||||
self.heap.to_unifiable(HeapCellValue::Stream(stream))
|
self.heap.to_unifiable(HeapCellValue::Stream(stream))
|
||||||
}
|
}
|
||||||
Err(ErrorKind::PermissionDenied) => {
|
Err(ErrorKind::PermissionDenied) => {
|
||||||
@@ -4383,20 +4465,42 @@ impl MachineState {
|
|||||||
return Err(self.reposition_error("socket_server_accept", 4));
|
return Err(self.reposition_error("socket_server_accept", 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref alias) = &options.alias {
|
||||||
|
if indices.stream_aliases.contains_key(alias) {
|
||||||
|
return Err(self.occupied_alias_permission_error(
|
||||||
|
alias.clone(),
|
||||||
|
"socket_server_accept",
|
||||||
|
4,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match self.store(self.deref(self[temp_v!(1)])) {
|
match self.store(self.deref(self[temp_v!(1)])) {
|
||||||
Addr::TcpListener(h) => {
|
Addr::TcpListener(h) => {
|
||||||
match &mut self.heap[h] {
|
match &mut self.heap[h] {
|
||||||
HeapCellValue::TcpListener(ref mut tcp_listener) => {
|
HeapCellValue::TcpListener(ref mut tcp_listener) => {
|
||||||
match tcp_listener.accept().ok() {
|
match tcp_listener.accept().ok() {
|
||||||
Some((tcp_stream, socket_addr)) => {
|
Some((tcp_stream, socket_addr)) => {
|
||||||
let mut tcp_stream = Stream::from(tcp_stream);
|
let client =
|
||||||
|
clause_name!(format!("{}", socket_addr), indices.atom_tbl);
|
||||||
|
|
||||||
|
let mut tcp_stream =
|
||||||
|
Stream::from_tcp_stream(client.clone(), tcp_stream);
|
||||||
|
|
||||||
tcp_stream.options = options;
|
tcp_stream.options = options;
|
||||||
|
|
||||||
|
if let Some(ref alias) = &tcp_stream.options.alias {
|
||||||
|
indices.stream_aliases.insert(
|
||||||
|
alias.clone(),
|
||||||
|
tcp_stream.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
indices.streams.insert(tcp_stream.clone());
|
||||||
|
|
||||||
let tcp_stream =
|
let tcp_stream =
|
||||||
self.heap.to_unifiable(HeapCellValue::Stream(tcp_stream));
|
self.heap.to_unifiable(HeapCellValue::Stream(tcp_stream));
|
||||||
|
|
||||||
let client =
|
|
||||||
clause_name!(format!("{}", socket_addr), indices.atom_tbl);
|
|
||||||
let client =
|
let client =
|
||||||
self.heap.to_unifiable(HeapCellValue::Atom(client, None));
|
self.heap.to_unifiable(HeapCellValue::Atom(client, None));
|
||||||
|
|
||||||
@@ -4450,6 +4554,120 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::StreamProperty => {
|
||||||
|
let mut stream = self.get_stream_or_alias(
|
||||||
|
self[temp_v!(1)],
|
||||||
|
indices,
|
||||||
|
"stream_property",
|
||||||
|
2,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let property =
|
||||||
|
match self.store(self.deref(self[temp_v!(2)])) {
|
||||||
|
Addr::Con(h) if self.heap.atom_at(h) => {
|
||||||
|
match &self.heap[h] {
|
||||||
|
HeapCellValue::Atom(ref name, _) => {
|
||||||
|
match name.as_str() {
|
||||||
|
"file_name" => {
|
||||||
|
if let Some(file_name) = stream.file_name() {
|
||||||
|
HeapCellValue::Atom(
|
||||||
|
file_name,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"mode" => {
|
||||||
|
HeapCellValue::Atom(
|
||||||
|
clause_name!(stream.mode()),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"direction" => {
|
||||||
|
HeapCellValue::Atom(
|
||||||
|
if stream.is_input_stream() && stream.is_output_stream() {
|
||||||
|
clause_name!("input_output")
|
||||||
|
} else if stream.is_input_stream() {
|
||||||
|
clause_name!("input")
|
||||||
|
} else {
|
||||||
|
clause_name!("output")
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"alias" => {
|
||||||
|
if let Some(alias) = &stream.options.alias {
|
||||||
|
HeapCellValue::Atom(
|
||||||
|
alias.clone(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"position" => {
|
||||||
|
if stream.options.reposition {
|
||||||
|
if let Some(position) = stream.position() {
|
||||||
|
HeapCellValue::Addr(Addr::Usize(position as usize))
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"end_of_stream" => {
|
||||||
|
let end_of_stream_pos = stream.position_relative_to_end();
|
||||||
|
|
||||||
|
HeapCellValue::Atom(
|
||||||
|
clause_name!(end_of_stream_pos.as_str()),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"eof_action" => {
|
||||||
|
HeapCellValue::Atom(
|
||||||
|
clause_name!(stream.options.eof_action.as_str()),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"reposition" => {
|
||||||
|
HeapCellValue::Atom(
|
||||||
|
clause_name!(if stream.options.reposition {
|
||||||
|
"true"
|
||||||
|
} else {
|
||||||
|
"false"
|
||||||
|
}),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"type" => {
|
||||||
|
HeapCellValue::Atom(
|
||||||
|
clause_name!(stream.options.stream_type.as_str()),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let property = self.heap.to_unifiable(property);
|
||||||
|
self.unify(self[temp_v!(3)], property);
|
||||||
|
}
|
||||||
&SystemClauseType::StoreGlobalVar => {
|
&SystemClauseType::StoreGlobalVar => {
|
||||||
let key = self[temp_v!(1)];
|
let key = self[temp_v!(1)];
|
||||||
|
|
||||||
|
|||||||
@@ -358,6 +358,7 @@ macro_rules! index_store {
|
|||||||
op_dir: $op_dir,
|
op_dir: $op_dir,
|
||||||
modules: $modules,
|
modules: $modules,
|
||||||
stream_aliases: StreamAliasDir::new(),
|
stream_aliases: StreamAliasDir::new(),
|
||||||
|
streams: StreamDir::new(),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user