add peek_char/{1,2}, peek_byte/{1,2}, peek_code/{1,2}
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -655,6 +655,7 @@ dependencies = [
|
|||||||
"ref_thread_local",
|
"ref_thread_local",
|
||||||
"rug",
|
"rug",
|
||||||
"rustyline",
|
"rustyline",
|
||||||
|
"unicode_reader",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ default = ["rug", "prolog_parser/rug"]
|
|||||||
num = ["num-rug-adapter", "prolog_parser/num"]
|
num = ["num-rug-adapter", "prolog_parser/num"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
cpu-time = "1.0.0"
|
||||||
crossterm = "0.16.0"
|
crossterm = "0.16.0"
|
||||||
dirs = "2.0.2"
|
dirs = "2.0.2"
|
||||||
divrem = "0.1.0"
|
divrem = "0.1.0"
|
||||||
@@ -32,4 +33,4 @@ prolog_parser = { version = "0.8.56", default-features = false }
|
|||||||
ref_thread_local = "0.0.0"
|
ref_thread_local = "0.0.0"
|
||||||
rug = { version = "1.4.0", optional = true }
|
rug = { version = "1.4.0", optional = true }
|
||||||
rustyline = "6.0.0"
|
rustyline = "6.0.0"
|
||||||
cpu-time = "1.0.0"
|
unicode_reader = "1.0.0"
|
||||||
|
|||||||
@@ -222,6 +222,9 @@ pub enum SystemClauseType {
|
|||||||
OpDeclaration,
|
OpDeclaration,
|
||||||
Open,
|
Open,
|
||||||
PartialStringTail,
|
PartialStringTail,
|
||||||
|
PeekByte,
|
||||||
|
PeekChar,
|
||||||
|
PeekCode,
|
||||||
PointsToContinuationResetMarker,
|
PointsToContinuationResetMarker,
|
||||||
PutByte,
|
PutByte,
|
||||||
PutChar,
|
PutChar,
|
||||||
@@ -372,6 +375,9 @@ impl SystemClauseType {
|
|||||||
}
|
}
|
||||||
&SystemClauseType::IsPartialString => clause_name!("$is_partial_string"),
|
&SystemClauseType::IsPartialString => clause_name!("$is_partial_string"),
|
||||||
&SystemClauseType::PartialStringTail => clause_name!("$partial_string_tail"),
|
&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::LiftedHeapLength => clause_name!("$lh_length"),
|
||||||
&SystemClauseType::Maybe => clause_name!("maybe"),
|
&SystemClauseType::Maybe => clause_name!("maybe"),
|
||||||
&SystemClauseType::CpuNow => clause_name!("$cpu_now"),
|
&SystemClauseType::CpuNow => clause_name!("$cpu_now"),
|
||||||
@@ -497,6 +503,9 @@ impl SystemClauseType {
|
|||||||
("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal),
|
("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal),
|
||||||
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
|
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
|
||||||
("$partial_string_tail", 2) => Some(SystemClauseType::PartialStringTail),
|
("$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),
|
("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
|
||||||
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
|
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
|
||||||
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
|
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
|
||||||
|
|||||||
@@ -52,9 +52,11 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :-
|
|||||||
get_byte/1, get_byte/2, get_char/1, get_char/2,
|
get_byte/1, get_byte/2, get_char/1, get_char/2,
|
||||||
get_code/1, get_code/2, halt/0, max_arity/1,
|
get_code/1, get_code/2, halt/0, max_arity/1,
|
||||||
number_chars/2, number_codes/2, once/1, op/3,
|
number_chars/2, number_codes/2, once/1, op/3,
|
||||||
open/3, open/4, put_byte/1, put_byte/2,
|
open/3, open/4, peek_byte/1, peek_byte/2,
|
||||||
put_code/1, put_code/2, put_char/1, put_char/2,
|
peek_char/1, peek_char/2, peek_code/1,
|
||||||
read_term/2, read_term/3, repeat/0, retract/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_output/1,
|
set_prolog_flag/2, set_input/1, set_output/1,
|
||||||
setof/3, sub_atom/5, subsumes_term/2,
|
setof/3, sub_atom/5, subsumes_term/2,
|
||||||
term_variables/2, throw/1, true/0,
|
term_variables/2, throw/1, true/0,
|
||||||
@@ -1233,3 +1235,27 @@ get_code(C) :-
|
|||||||
|
|
||||||
get_code(S, C) :-
|
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).
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
current_hostname/1]).
|
current_hostname/1]).
|
||||||
|
|
||||||
:- use_module(library(error)).
|
:- use_module(library(error)).
|
||||||
:- use_module(library(lists)).
|
|
||||||
:- use_module(library(pairs)).
|
|
||||||
|
|
||||||
|
|
||||||
socket_client_open(Addr, Stream, Options) :-
|
socket_client_open(Addr, Stream, Options) :-
|
||||||
|
|||||||
@@ -447,7 +447,7 @@ impl HeapCellValue {
|
|||||||
HeapCellValue::Stream(stream.clone())
|
HeapCellValue::Stream(stream.clone())
|
||||||
}
|
}
|
||||||
&HeapCellValue::TcpListener(_) => {
|
&HeapCellValue::TcpListener(_) => {
|
||||||
HeapCellValue::Atom(clause_name!("$socket_server"), None)
|
HeapCellValue::Atom(clause_name!("$tcp_listener"), None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,6 +128,10 @@ impl Hash for WrappedStreamInstance {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum StreamError {
|
enum StreamError {
|
||||||
|
PeekByteFailed,
|
||||||
|
PeekByteFromNonPeekableStream,
|
||||||
|
PeekCharFailed,
|
||||||
|
PeekCharFromNonPeekableStream,
|
||||||
ReadFromOutputStream,
|
ReadFromOutputStream,
|
||||||
WriteToInputStream,
|
WriteToInputStream,
|
||||||
FlushToInputStream,
|
FlushToInputStream,
|
||||||
@@ -136,6 +140,18 @@ enum StreamError {
|
|||||||
impl fmt::Display for StreamError {
|
impl fmt::Display for StreamError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
StreamError::PeekByteFailed => {
|
||||||
|
write!(f, "peek byte failed!")
|
||||||
|
}
|
||||||
|
StreamError::PeekByteFromNonPeekableStream => {
|
||||||
|
write!(f, "attempted to peek byte from a non-peekable input stream")
|
||||||
|
}
|
||||||
|
StreamError::PeekCharFailed => {
|
||||||
|
write!(f, "peek char failed!")
|
||||||
|
}
|
||||||
|
StreamError::PeekCharFromNonPeekableStream => {
|
||||||
|
write!(f, "attempted to peek char from a non-peekable input stream")
|
||||||
|
}
|
||||||
StreamError::ReadFromOutputStream => {
|
StreamError::ReadFromOutputStream => {
|
||||||
write!(f, "attempted to read from a write-only stream")
|
write!(f, "attempted to read from a write-only stream")
|
||||||
}
|
}
|
||||||
@@ -355,6 +371,115 @@ impl Stream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn peek_byte(&mut self) -> std::io::Result<u8> {
|
||||||
|
match *self.stream_inst.0.borrow_mut() {
|
||||||
|
StreamInstance::Bytes(ref mut cursor) => {
|
||||||
|
let mut b = [0u8; 1];
|
||||||
|
let pos = cursor.position();
|
||||||
|
|
||||||
|
match cursor.read(&mut b)? {
|
||||||
|
1 => {
|
||||||
|
cursor.set_position(pos);
|
||||||
|
Ok(b[0])
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(std::io::Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
"end of file",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StreamInstance::InputFile(ref mut file) => {
|
||||||
|
let mut b = [0u8; 1];
|
||||||
|
|
||||||
|
match file.read(&mut b)? {
|
||||||
|
1 => {
|
||||||
|
file.seek(SeekFrom::Current(-1))?;
|
||||||
|
Ok(b[0])
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(std::io::Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
StreamError::PeekByteFailed,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StreamInstance::ReadlineStream(ref mut stream) => {
|
||||||
|
stream.peek_byte()
|
||||||
|
}
|
||||||
|
StreamInstance::TcpStream(ref mut tcp_stream) => {
|
||||||
|
let mut b = [0u8; 1];
|
||||||
|
tcp_stream.peek(&mut b)?;
|
||||||
|
Ok(b[0])
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(std::io::Error::new(
|
||||||
|
ErrorKind::PermissionDenied,
|
||||||
|
StreamError::PeekByteFromNonPeekableStream,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate)
|
||||||
|
fn peek_char(&mut self) -> std::io::Result<char> {
|
||||||
|
use unicode_reader::CodePoints;
|
||||||
|
|
||||||
|
match *self.stream_inst.0.borrow_mut() {
|
||||||
|
StreamInstance::InputFile(ref mut file) => {
|
||||||
|
let c = {
|
||||||
|
let mut iter = CodePoints::from(&*file);
|
||||||
|
|
||||||
|
if let Some(Ok(c)) = iter.next() {
|
||||||
|
c
|
||||||
|
} else {
|
||||||
|
return Err(std::io::Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
StreamError::PeekCharFailed
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
file.seek(SeekFrom::Current(- (c.len_utf8() as i64)))?;
|
||||||
|
|
||||||
|
Ok(c)
|
||||||
|
}
|
||||||
|
StreamInstance::ReadlineStream(ref mut stream) => {
|
||||||
|
stream.peek_char()
|
||||||
|
}
|
||||||
|
StreamInstance::TcpStream(ref tcp_stream) => {
|
||||||
|
let c = {
|
||||||
|
let mut buf = [0u8; 8];
|
||||||
|
tcp_stream.peek(&mut buf)?;
|
||||||
|
|
||||||
|
let mut iter = CodePoints::from(buf.bytes());
|
||||||
|
|
||||||
|
if let Some(Ok(c)) = iter.next() {
|
||||||
|
c
|
||||||
|
} else {
|
||||||
|
return Err(std::io::Error::new(
|
||||||
|
ErrorKind::UnexpectedEof,
|
||||||
|
StreamError::PeekCharFailed
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(c)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
Err(std::io::Error::new(
|
||||||
|
ErrorKind::PermissionDenied,
|
||||||
|
StreamError::PeekCharFromNonPeekableStream,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
@@ -668,7 +793,7 @@ impl MachineState {
|
|||||||
let opt_err =
|
let opt_err =
|
||||||
if input.is_some() && !stream.is_input_stream() {
|
if input.is_some() && !stream.is_input_stream() {
|
||||||
Some("stream") // 8.14.2.3 g)
|
Some("stream") // 8.14.2.3 g)
|
||||||
} else if input.is_none() && stream.is_input_stream() {
|
} else if input.is_none() && !stream.is_output_stream() {
|
||||||
Some("stream") // 8.14.2.3 g)
|
Some("stream") // 8.14.2.3 g)
|
||||||
} else if stream.options.stream_type != expected_type {
|
} else if stream.options.stream_type != expected_type {
|
||||||
Some(expected_type.other().as_str()) // 8.14.2.3 h)
|
Some(expected_type.other().as_str()) // 8.14.2.3 h)
|
||||||
|
|||||||
@@ -1169,6 +1169,308 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::PeekByte => {
|
||||||
|
let mut stream =
|
||||||
|
self.get_stream_or_alias(self[temp_v!(1)], indices, "peek_byte", 2)?;
|
||||||
|
|
||||||
|
self.check_stream_properties(
|
||||||
|
&mut stream,
|
||||||
|
StreamType::Binary,
|
||||||
|
Some(self[temp_v!(2)]),
|
||||||
|
clause_name!("peek_byte"),
|
||||||
|
2,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
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 addr =
|
||||||
|
match self.store(self.deref(self[temp_v!(2)])) {
|
||||||
|
addr if addr.is_ref() => {
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
addr => {
|
||||||
|
match Number::try_from((addr, &self.heap)) {
|
||||||
|
Ok(Number::Integer(n)) => {
|
||||||
|
if let Some(nb) = n.to_u8() {
|
||||||
|
Addr::Usize(nb as usize)
|
||||||
|
} else {
|
||||||
|
return Err(self.type_error(
|
||||||
|
ValidType::InByte,
|
||||||
|
addr,
|
||||||
|
clause_name!("peek_byte"),
|
||||||
|
2,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Number::Fixnum(n)) => {
|
||||||
|
if let Ok(nb) = u8::try_from(n) {
|
||||||
|
Addr::Usize(nb as usize)
|
||||||
|
} else {
|
||||||
|
return Err(self.type_error(
|
||||||
|
ValidType::InByte,
|
||||||
|
addr,
|
||||||
|
clause_name!("peek_byte"),
|
||||||
|
2,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(self.type_error(
|
||||||
|
ValidType::InByte,
|
||||||
|
addr,
|
||||||
|
clause_name!("peek_byte"),
|
||||||
|
2,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match stream.peek_byte().map_err(|e| e.kind()) {
|
||||||
|
Ok(b) => {
|
||||||
|
if let Some(var) = addr.as_var() {
|
||||||
|
self.bind(var, Addr::Usize(b as usize));
|
||||||
|
break;
|
||||||
|
} else if addr == Addr::Usize(b as usize) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(ErrorKind::PermissionDenied) => {
|
||||||
|
self.fail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.eof_action(
|
||||||
|
self[temp_v!(2)],
|
||||||
|
&mut stream,
|
||||||
|
clause_name!("peek_byte"),
|
||||||
|
2,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if EOFAction::Reset != stream.options.eof_action {
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
} else if self.fail {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&SystemClauseType::PeekChar => {
|
||||||
|
let mut stream =
|
||||||
|
self.get_stream_or_alias(self[temp_v!(1)], indices, "peek_char", 2)?;
|
||||||
|
|
||||||
|
self.check_stream_properties(
|
||||||
|
&mut stream,
|
||||||
|
StreamType::Text,
|
||||||
|
Some(self[temp_v!(2)]),
|
||||||
|
clause_name!("peek_char"),
|
||||||
|
2,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
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 addr =
|
||||||
|
match self.store(self.deref(self[temp_v!(2)])) {
|
||||||
|
addr if addr.is_ref() => {
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
Addr::Con(h) if self.heap.atom_at(h) => {
|
||||||
|
match &self.heap[h] {
|
||||||
|
HeapCellValue::Atom(ref atom, _) if atom.is_char() => {
|
||||||
|
if let Some(c) = atom.as_str().chars().next() {
|
||||||
|
Addr::Char(c)
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
culprit => {
|
||||||
|
return Err(self.type_error(
|
||||||
|
ValidType::InCharacter,
|
||||||
|
culprit.as_addr(h),
|
||||||
|
clause_name!("peek_char"),
|
||||||
|
2,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Addr::Char(d) => {
|
||||||
|
Addr::Char(d)
|
||||||
|
}
|
||||||
|
culprit => {
|
||||||
|
return Err(self.type_error(
|
||||||
|
ValidType::InCharacter,
|
||||||
|
culprit,
|
||||||
|
clause_name!("peek_char"),
|
||||||
|
2,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match stream.peek_char().map_err(|e| e.kind()) {
|
||||||
|
Ok(d) => {
|
||||||
|
if let Some(var) = addr.as_var() {
|
||||||
|
self.bind(var, Addr::Char(d));
|
||||||
|
break;
|
||||||
|
} else if addr == Addr::Char(d) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(ErrorKind::PermissionDenied) => {
|
||||||
|
self.fail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.eof_action(
|
||||||
|
self[temp_v!(2)],
|
||||||
|
&mut stream,
|
||||||
|
clause_name!("peek_char"),
|
||||||
|
2,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if EOFAction::Reset != stream.options.eof_action {
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
} else if self.fail {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}/*
|
||||||
|
_ => {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("peek_char"), 2);
|
||||||
|
let err = MachineError::representation_error(RepFlag::Character);
|
||||||
|
let err = self.error_form(err, stub);
|
||||||
|
|
||||||
|
return Err(err);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&SystemClauseType::PeekCode => {
|
||||||
|
let mut stream =
|
||||||
|
self.get_stream_or_alias(self[temp_v!(1)], indices, "peek_code", 2)?;
|
||||||
|
|
||||||
|
self.check_stream_properties(
|
||||||
|
&mut stream,
|
||||||
|
StreamType::Text,
|
||||||
|
Some(self[temp_v!(2)]),
|
||||||
|
clause_name!("peek_code"),
|
||||||
|
2,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
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 addr =
|
||||||
|
match self.store(self.deref(self[temp_v!(2)])) {
|
||||||
|
addr if addr.is_ref() => {
|
||||||
|
addr
|
||||||
|
}
|
||||||
|
Addr::CharCode(d) => {
|
||||||
|
Addr::CharCode(d)
|
||||||
|
}
|
||||||
|
addr => {
|
||||||
|
match Number::try_from((addr, &self.heap)) {
|
||||||
|
Ok(Number::Integer(n)) => {
|
||||||
|
if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) {
|
||||||
|
Addr::CharCode(c as u32)
|
||||||
|
} else {
|
||||||
|
return Err(self.representation_error(
|
||||||
|
RepFlag::InCharacterCode,
|
||||||
|
clause_name!("peek_code"),
|
||||||
|
2,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Number::Fixnum(n)) => {
|
||||||
|
if let Some(c) = u32::try_from(n).ok().and_then(|c| char::try_from(c).ok()) {
|
||||||
|
Addr::CharCode(c as u32)
|
||||||
|
} else {
|
||||||
|
return Err(self.representation_error(
|
||||||
|
RepFlag::InCharacterCode,
|
||||||
|
clause_name!("peek_code"),
|
||||||
|
2,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(self.type_error(
|
||||||
|
ValidType::Integer,
|
||||||
|
self[temp_v!(2)],
|
||||||
|
clause_name!("peek_code"),
|
||||||
|
2,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let result = stream.peek_char();
|
||||||
|
|
||||||
|
match result.map_err(|e| e.kind()) {
|
||||||
|
Ok(c) => {
|
||||||
|
if let Some(var) = addr.as_var() {
|
||||||
|
self.bind(var, Addr::CharCode(c as u32));
|
||||||
|
break;
|
||||||
|
} else if addr == Addr::CharCode(c as u32) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(ErrorKind::PermissionDenied) => {
|
||||||
|
self.fail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.eof_action(
|
||||||
|
self[temp_v!(2)],
|
||||||
|
&mut stream,
|
||||||
|
clause_name!("peek_code"),
|
||||||
|
2,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if EOFAction::Reset != stream.options.eof_action {
|
||||||
|
return return_from_clause!(self.last_call, self);
|
||||||
|
} else if self.fail {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}/*
|
||||||
|
_ => {
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("get_char"), 2);
|
||||||
|
let err = MachineError::representation_error(RepFlag::Character);
|
||||||
|
let err = self.error_form(err, stub);
|
||||||
|
|
||||||
|
return Err(err);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
&SystemClauseType::NumberToChars => {
|
&SystemClauseType::NumberToChars => {
|
||||||
let n = self[temp_v!(1)];
|
let n = self[temp_v!(1)];
|
||||||
let chs = self[temp_v!(2)];
|
let chs = self[temp_v!(2)];
|
||||||
@@ -2039,7 +2341,7 @@ impl MachineState {
|
|||||||
self.eof_action(
|
self.eof_action(
|
||||||
self[temp_v!(2)],
|
self[temp_v!(2)],
|
||||||
&mut stream,
|
&mut stream,
|
||||||
clause_name!("get_coder"),
|
clause_name!("get_code"),
|
||||||
2,
|
2,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ pub mod readline {
|
|||||||
use crate::prolog::machine::streams::Stream;
|
use crate::prolog::machine::streams::Stream;
|
||||||
use crate::prolog::rustyline::error::ReadlineError;
|
use crate::prolog::rustyline::error::ReadlineError;
|
||||||
use crate::prolog::rustyline::{Cmd, Editor, KeyPress};
|
use crate::prolog::rustyline::{Cmd, Editor, KeyPress};
|
||||||
use std::io::{Cursor, Read};
|
use std::io::{Cursor, Error, ErrorKind, Read};
|
||||||
|
|
||||||
static mut PROMPT: bool = false;
|
static mut PROMPT: bool = false;
|
||||||
|
|
||||||
@@ -73,7 +73,61 @@ pub mod readline {
|
|||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
Err(e) => {
|
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",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user