Merge branch 'read_term_eof_changes'

This commit is contained in:
Mark
2023-07-17 13:22:51 -06:00
6 changed files with 216 additions and 113 deletions

View File

@@ -227,7 +227,32 @@ impl CodeIndex {
} }
} }
pub(crate) type HeapVarDict = IndexMap<VarPtr, HeapCellValue, FxBuildHasher>; #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum VarKey {
AnonVar(usize),
VarPtr(VarPtr),
}
impl VarKey {
#[inline]
pub(crate) fn to_string(&self) -> String {
match self {
VarKey::AnonVar(h) => format!("_{}", h),
VarKey::VarPtr(var) => var.borrow().to_string(),
}
}
#[inline(always)]
pub(crate) fn is_anon(&self) -> bool {
if let VarKey::AnonVar(_) = self {
true
} else {
false
}
}
}
pub(crate) type HeapVarDict = IndexMap<VarKey, HeapCellValue, FxBuildHasher>;
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>; pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;

View File

@@ -486,13 +486,13 @@ impl MachineState {
pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult { pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult {
fn push_var_eq_functors<'a>( fn push_var_eq_functors<'a>(
heap: &mut Heap, heap: &mut Heap,
iter: impl Iterator<Item = (&'a VarPtr, &'a HeapCellValue)>, iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
atom_tbl: &mut AtomTable, atom_tbl: &mut AtomTable,
) -> Vec<HeapCellValue> { ) -> Vec<HeapCellValue> {
let mut list_of_var_eqs = vec![]; let mut list_of_var_eqs = vec![];
for (var, binding) in iter { for (var, binding) in iter {
let var_atom = atom_tbl.build_with(&var.borrow().to_string()); let var_atom = atom_tbl.build_with(&var.to_string());
let h = heap.len(); let h = heap.len();
heap.push(atom_as_cell!(atom!("="), 2)); heap.push(atom_as_cell!(atom!("="), 2));
@@ -542,7 +542,11 @@ impl MachineState {
let singleton_var_list = push_var_eq_functors( let singleton_var_list = push_var_eq_functors(
&mut self.heap, &mut self.heap,
term_write_result.var_dict.iter().filter(|(_, binding)| { term_write_result.var_dict.iter().filter(|(var_name, binding)| {
if var_name.is_anon() {
return false;
}
if let Some(r) = binding.as_var() { if let Some(r) = binding.as_var() {
*singleton_var_set.get(&r).unwrap_or(&false) *singleton_var_set.get(&r).unwrap_or(&false)
} else { } else {
@@ -565,7 +569,7 @@ impl MachineState {
let list_of_var_eqs = push_var_eq_functors( let list_of_var_eqs = push_var_eq_functors(
&mut self.heap, &mut self.heap,
var_list.iter().map(|(var_name, var,_)| (var_name,var)), var_list.iter().filter_map(|(var_name, var,_)| if var_name.is_anon() { None } else { Some((var_name,var)) }),
&mut self.atom_tbl, &mut self.atom_tbl,
); );
@@ -616,7 +620,7 @@ impl MachineState {
unreachable!("Stream must be a Stream::Readline(_)") unreachable!("Stream must be a Stream::Readline(_)")
} }
pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult { pub fn read_term(&mut self, mut stream: Stream, indices: &mut IndexStore) -> CallResult {
self.check_stream_properties( self.check_stream_properties(
stream, stream,
StreamType::Text, StreamType::Text,
@@ -637,22 +641,27 @@ impl MachineState {
match self.read(stream, &indices.op_dir) { match self.read(stream, &indices.op_dir) {
Ok(term_write_result) => return self.read_term_body(term_write_result), Ok(term_write_result) => return self.read_term_body(term_write_result),
Err(err) => { Err(err) => {
match err { match &err {
CompilationError::ParserError(e) if e.is_unexpected_eof() => { CompilationError::ParserError(e) if e.is_unexpected_eof() => {
self.eof_action( if stream.at_end_of_stream() {
self.registers[2], unify!(self, self.registers[2], atom_as_cell!(atom!("end_of_file")));
stream, return Ok(());
atom!("read_term"), } else if stream.past_end_of_stream() {
3, self.eof_action(
)?; self.registers[2],
stream,
atom!("read_term"),
3,
)?;
if stream.options().eof_action() == EOFAction::Reset { if stream.options().eof_action() == EOFAction::Reset {
if self.fail == false { if self.fail == false {
continue; continue;
}
} }
}
return Ok(()); return Ok(());
}
} }
_ => {} _ => {}
} }

View File

@@ -71,7 +71,12 @@ impl MockWAM {
printer.var_names = term_write_result printer.var_names = term_write_result
.var_dict .var_dict
.into_iter() .into_iter()
.map(|(var, cell)| (cell, var)) .map(|(var, cell)| {
match var {
VarKey::VarPtr(var) => (cell, var.clone()),
VarKey::AnonVar(_) => (cell, VarPtr::from(var.to_string()))
}
})
.collect(); .collect();
Ok(printer.print().result()) Ok(printer.print().result())

View File

@@ -884,19 +884,38 @@ impl PartialEq for Stream {
impl Eq for Stream {} impl Eq for Stream {}
fn cursor_position<T>(past_end_of_stream: &mut bool, cursor: &Cursor<T>, cursor_len: u64) -> AtEndOfStream {
let position = cursor.position();
let at_end_of_stream = match position.cmp(&cursor_len) {
Ordering::Equal => AtEndOfStream::At,
Ordering::Greater => {
*past_end_of_stream = true;
AtEndOfStream::Past
}
Ordering::Less => AtEndOfStream::Not,
};
at_end_of_stream
}
impl Stream { impl Stream {
#[inline] #[inline]
pub(crate) fn position(&mut self) -> Option<(u64, usize)> { pub(crate) fn position(&mut self) -> Option<(u64, usize)> {
// returns lines_read, position. // returns lines_read, position.
let result = match self { let result = match self {
Stream::Byte(byte_stream_layout) => {
Some(byte_stream_layout.stream.get_ref().0.position())
}
Stream::StaticString(string_stream_layout) => {
Some(string_stream_layout.stream.stream.position())
}
Stream::InputFile(file_stream) => { Stream::InputFile(file_stream) => {
file_stream.position() file_stream.position()
} }
Stream::NamedTcp(..) Stream::NamedTcp(..) | Stream::NamedTls(..) | Stream::Readline(..) => {
| Stream::NamedTls(..) Some(0)
| Stream::Readline(..) }
| Stream::StaticString(..)
| Stream::Byte(..) => Some(0),
_ => None, _ => None,
}; };
@@ -971,38 +990,61 @@ impl Stream {
return AtEndOfStream::Past; return AtEndOfStream::Past;
} }
if let Stream::InputFile(stream_layout) = self { match self {
let position = stream_layout.position(); Stream::Byte(stream_layout) => {
let StreamLayout {
past_end_of_stream,
stream,
..
} = &mut **stream_layout;
let StreamLayout { let cursor_len = stream.get_ref().0.get_ref().len() as u64;
past_end_of_stream, cursor_position(past_end_of_stream, &stream.get_ref().0, cursor_len)
stream, }
.. Stream::StaticString(stream_layout) => {
} = &mut **stream_layout; let StreamLayout {
past_end_of_stream,
stream,
..
} = &mut **stream_layout;
match stream.get_ref().file.metadata() { let cursor_len = stream.stream.get_ref().len() as u64;
Ok(metadata) => { cursor_position(past_end_of_stream, &stream.stream, cursor_len)
if let Some(position) = position { }
return match position.cmp(&metadata.len()) { Stream::InputFile(stream_layout) => {
Ordering::Equal => AtEndOfStream::At, let position = stream_layout.position();
Ordering::Less => AtEndOfStream::Not,
Ordering::Greater => { let StreamLayout {
*past_end_of_stream = true; past_end_of_stream,
AtEndOfStream::Past stream,
..
} = &mut **stream_layout;
match stream.get_ref().file.metadata() {
Ok(metadata) => {
if let Some(position) = position {
match position.cmp(&metadata.len()) {
Ordering::Equal => AtEndOfStream::At,
Ordering::Less => AtEndOfStream::Not,
Ordering::Greater => {
*past_end_of_stream = true;
AtEndOfStream::Past
}
} }
}; } else {
} else { *past_end_of_stream = true;
AtEndOfStream::Past
}
}
_ => {
*past_end_of_stream = true; *past_end_of_stream = true;
AtEndOfStream::Past AtEndOfStream::Past
} }
} }
_ => {
*past_end_of_stream = true;
AtEndOfStream::Past
}
} }
} else { _ => {
AtEndOfStream::Not AtEndOfStream::Not
}
} }
} }
@@ -1306,7 +1348,7 @@ impl MachineState {
match eof_action { match eof_action {
EOFAction::Error => { EOFAction::Error => {
stream.set_past_end_of_stream(true); stream.set_past_end_of_stream(true);
return Err(self.open_past_eos_error(stream, caller, arity)); Err(self.open_past_eos_error(stream, caller, arity))
} }
EOFAction::EOFCode => { EOFAction::EOFCode => {
let end_of_stream = if stream.options().stream_type() == StreamType::Binary { let end_of_stream = if stream.options().stream_type() == StreamType::Binary {

View File

@@ -5796,72 +5796,71 @@ impl Machine {
self.machine_st.read_term(stream, &mut self.indices) self.machine_st.read_term(stream, &mut self.indices)
} }
#[inline(always)]
fn read_term_and_write_to_heap(
&mut self,
atom_or_string: AtomOrString,
) -> Result<Option<TermWriteResult>, MachineStub> {
let string = match atom_or_string {
AtomOrString::Atom(atom) if atom == atom!("[]") => "".to_owned(),
_ => atom_or_string.to_string(),
};
let chars = CharReader::new(ByteStream::from_string(string));
let mut parser = Parser::new(chars, &mut self.machine_st);
let op_dir = CompositeOpDir::new(&self.indices.op_dir, None);
let term_write_result = parser.read_term(&op_dir, Tokens::Default)
.map_err(|err| error_after_read_term(err, 0, &parser))
.and_then(|term| {
write_term_to_heap(
&term,
&mut self.machine_st.heap,
&mut self.machine_st.atom_tbl,
)
});
match term_write_result {
Ok(term_write_result) => Ok(Some(term_write_result)),
Err(CompilationError::ParserError(e)) if e.is_unexpected_eof() => {
let value = self.machine_st.registers[2];
self.machine_st.unify_atom(atom!("end_of_file"), value);
Ok(None)
}
Err(e) => {
let stub = functor_stub(atom!("read_term_from_chars"), 3);
let e = self.machine_st.session_error(SessionError::from(e));
Err(self.machine_st.error_form(e, stub))
}
}
}
#[inline(always)] #[inline(always)]
pub(crate) fn read_from_chars(&mut self) -> CallResult { pub(crate) fn read_from_chars(&mut self) -> CallResult {
if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
let chars = CharReader::new(ByteStream::from_string(atom_or_string.to_string())); if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? {
let mut parser = Parser::new(chars, &mut self.machine_st); let result = heap_loc_as_cell!(term_write_result.heap_loc);
let op_dir = CompositeOpDir::new(&self.indices.op_dir, None); let var = self.deref_register(2).as_var().unwrap();
let term_write_result = parser.read_term(&op_dir, Tokens::Default) self.machine_st.bind(var, result);
.map_err(CompilationError::from) }
.and_then(|term| {
write_term_to_heap(
&term,
&mut self.machine_st.heap,
&mut self.machine_st.atom_tbl,
)
});
let term_write_result = match term_write_result { Ok(())
Ok(term_write_result) => term_write_result,
Err(e) => {
let stub = functor_stub(atom!("read_from_chars"), 2);
let e = self.machine_st.session_error(SessionError::from(e));
return Err(self.machine_st.error_form(e, stub));
}
};
let result = heap_loc_as_cell!(term_write_result.heap_loc);
let var = self.deref_register(2).as_var().unwrap();
self.machine_st.bind(var, result);
} else { } else {
unreachable!() unreachable!()
} }
Ok(())
} }
#[inline(always)] #[inline(always)]
pub(crate) fn read_term_from_chars(&mut self) -> CallResult { pub(crate) fn read_term_from_chars(&mut self) -> CallResult {
if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) { if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
let chars = CharReader::new(ByteStream::from_string(atom_or_string.to_string())); if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? {
let mut parser = Parser::new(chars, &mut self.machine_st); self.machine_st.read_term_body(term_write_result)
let op_dir = CompositeOpDir::new(&self.indices.op_dir, None); } else {
Ok(())
let term_write_result = parser.read_term(&op_dir, Tokens::Default) }
.map_err(CompilationError::from)
.and_then(|term| {
write_term_to_heap(
&term,
&mut self.machine_st.heap,
&mut self.machine_st.atom_tbl,
)
});
let term_write_result = match term_write_result {
Ok(term_write_result) => term_write_result,
Err(e) => {
let stub = functor_stub(atom!("read_term_from_chars"), 3);
let e = self.machine_st.session_error(SessionError::from(e));
return Err(self.machine_st.error_form(e, stub));
}
};
self.machine_st.read_term_body(term_write_result)
} else { } else {
unreachable!() unreachable!()
} }

View File

@@ -36,6 +36,25 @@ pub(crate) fn devour_whitespace<'a, R: CharRead>(parser: &mut Parser<'a, R>) ->
} }
} }
pub(crate) fn error_after_read_term<R>(
err: ParserError,
prior_num_lines_read: usize,
parser: &Parser<R>,
) -> CompilationError {
if err.is_unexpected_eof() {
let line_num = parser.lexer.line_num;
let col_num = parser.lexer.col_num;
// rough overlap with errors 8.14.1.3 k) & l) of the ISO standard here
if !(line_num == prior_num_lines_read && col_num == 0) {
return CompilationError::from(ParserError::IncompleteReduction(line_num, col_num));
}
}
CompilationError::from(err)
}
impl MachineState { impl MachineState {
pub(crate) fn read( pub(crate) fn read(
&mut self, &mut self,
@@ -50,7 +69,7 @@ impl MachineState {
parser.add_lines_read(prior_num_lines_read); parser.add_lines_read(prior_num_lines_read);
let term = parser.read_term(&op_dir, Tokens::Default) let term = parser.read_term(&op_dir, Tokens::Default)
.map_err(CompilationError::from)?; .map_err(|err| error_after_read_term(err, prior_num_lines_read, &parser))?; // CompilationError::from
(term, parser.lines_read() - prior_num_lines_read) (term, parser.lines_read() - prior_num_lines_read)
}; };
@@ -240,9 +259,9 @@ impl CharRead for ReadlineStream {
} }
#[inline] #[inline]
pub(crate) fn write_term_to_heap( pub(crate) fn write_term_to_heap<'a, 'b>(
term: &Term, term: &'a Term,
heap: &mut Heap, heap: &'b mut Heap,
atom_tbl: &mut AtomTable, atom_tbl: &mut AtomTable,
) -> Result<TermWriteResult, CompilationError> { ) -> Result<TermWriteResult, CompilationError> {
let term_writer = TermWriter::new(heap, atom_tbl); let term_writer = TermWriter::new(heap, atom_tbl);
@@ -275,7 +294,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
} }
#[inline] #[inline]
fn modify_head_of_queue(&mut self, term: &TermRef<'a>, h: usize) { fn modify_head_of_queue(&mut self, term: &TermRef, h: usize) {
if let Some((arity, site_h)) = self.queue.pop_front() { if let Some((arity, site_h)) = self.queue.pop_front() {
self.heap[site_h] = self.term_as_addr(term, h); self.heap[site_h] = self.term_as_addr(term, h);
@@ -291,7 +310,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
self.heap.push(heap_loc_as_cell!(h)); self.heap.push(heap_loc_as_cell!(h));
} }
fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> HeapCellValue { fn term_as_addr(&mut self, term: &TermRef, h: usize) -> HeapCellValue {
match term { match term {
&TermRef::Cons(..) => list_loc_as_cell!(h), &TermRef::Cons(..) => list_loc_as_cell!(h),
&TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h), &TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
@@ -310,7 +329,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
} }
} }
fn write_term_to_heap(mut self, term: &'a Term) -> Result<TermWriteResult, CompilationError> { fn write_term_to_heap(mut self, term: &Term) -> Result<TermWriteResult, CompilationError> {
let heap_loc = self.heap.len(); let heap_loc = self.heap.len();
for term in breadth_first_iter(term, RootIterationPolicy::Iterated) { for term in breadth_first_iter(term, RootIterationPolicy::Iterated) {
@@ -364,17 +383,19 @@ impl<'a, 'b> TermWriter<'a, 'b> {
self.push_stub_addr(); self.push_stub_addr();
} }
} }
&TermRef::AnonVar(Level::Root) | &TermRef::Literal(Level::Root, ..) => { &TermRef::AnonVar(Level::Root) | TermRef::Literal(Level::Root, ..) => {
let addr = self.term_as_addr(&term, h); let addr = self.term_as_addr(&term, h);
self.heap.push(addr); self.heap.push(addr);
} }
&TermRef::Var(Level::Root, _, ref var_ptr) => { &TermRef::Var(Level::Root, _, ref var_ptr) => {
let addr = self.term_as_addr(&term, h); let addr = self.term_as_addr(&term, h);
self.var_dict.insert(var_ptr.clone(), heap_loc_as_cell!(h)); self.var_dict.insert(VarKey::VarPtr(var_ptr.clone()), addr);
self.heap.push(addr); self.heap.push(addr);
} }
&TermRef::AnonVar(_) => { &TermRef::AnonVar(_) => {
if let Some((arity, site_h)) = self.queue.pop_front() { if let Some((arity, site_h)) = self.queue.pop_front() {
self.var_dict.insert(VarKey::AnonVar(h), heap_loc_as_cell!(site_h));
if arity > 1 { if arity > 1 {
self.queue.push_front((arity - 1, site_h + 1)); self.queue.push_front((arity - 1, site_h + 1));
} }
@@ -403,10 +424,12 @@ impl<'a, 'b> TermWriter<'a, 'b> {
} }
&TermRef::Var(_, _, ref var) => { &TermRef::Var(_, _, ref var) => {
if let Some((arity, site_h)) = self.queue.pop_front() { if let Some((arity, site_h)) = self.queue.pop_front() {
if let Some(addr) = self.var_dict.get(var).cloned() { let var_key = VarKey::VarPtr(var.clone());
if let Some(addr) = self.var_dict.get(&var_key).cloned() {
self.heap[site_h] = addr; self.heap[site_h] = addr;
} else { } else {
self.var_dict.insert(var.clone(), heap_loc_as_cell!(site_h)); self.var_dict.insert(var_key, heap_loc_as_cell!(site_h));
} }
if arity > 1 { if arity > 1 {