add write_term_to_chars/3 to iso_ext.pl (#288)

This commit is contained in:
Mark Thom
2020-04-12 14:29:28 -06:00
parent 28099b9812
commit 0380d70a46
4 changed files with 195 additions and 119 deletions

View File

@@ -258,6 +258,7 @@ pub enum SystemClauseType {
Variant,
WAMInstructions,
WriteTerm,
WriteTermToChars,
}
impl SystemClauseType {
@@ -406,6 +407,7 @@ impl SystemClauseType {
&SystemClauseType::Variant => clause_name!("$variant"),
&SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"),
&SystemClauseType::WriteTerm => clause_name!("$write_term"),
&SystemClauseType::WriteTermToChars => clause_name!("$write_term_to_chars"),
}
}
@@ -532,8 +534,9 @@ impl SystemClauseType {
("$use_qualified_module_from_file", 2) =>
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)),
("$variant", 2) => Some(SystemClauseType::Variant),
("$write_term", 6) => Some(SystemClauseType::WriteTerm),
("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions),
("$write_term", 6) => Some(SystemClauseType::WriteTerm),
("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars),
_ => None,
}
}

View File

@@ -7,7 +7,8 @@
call_with_inference_limit/3, forall/2, maybe/0,
partial_string/1, partial_string/3,
partial_string_tail/2, set_random/1,
setup_call_cleanup/3, variant/2]).
setup_call_cleanup/3, variant/2,
write_term_to_chars/3]).
forall(Generate, Test) :-
\+ (Generate, \+ Test).
@@ -157,6 +158,7 @@ set_random(Seed) :-
; throw(error(instantiation_error, set_random/1))
).
partial_string(String, L, L0) :-
( String == [] ->
L = L0
@@ -174,3 +176,26 @@ partial_string_tail(String, Tail) :-
'$partial_string_tail'(String, Tail)
; throw(error(type_error(partial_string, String), partial_string_tail/2))
).
write_term_to_chars(_, Options, _) :-
var(Options), throw(error(instantiation_error, write_term_to_chars/3)).
write_term_to_chars(Term, Options, Chars) :-
'$skip_max_list'(_, -1, Options, Options0),
( var(Options0) ->
throw(error(instantiation_error, write_term_to_chars/3))
; var(Term) ->
throw(error(instantiation_error, write_term_to_chars/3))
; nonvar(Chars) ->
throw(error(uninstantiation_error(Chars), write_term_to_chars/3))
; Options0 == [] ->
true
;
throw(error(type_error(list, Options), write_term_to_chars/3))
),
builtins:inst_member_or(Options, ignore_ops(IgnoreOps), ignore_ops(false)),
builtins:inst_member_or(Options, numbervars(NumberVars), numbervars(false)),
builtins:inst_member_or(Options, quoted(Quoted), quoted(false)),
builtins:inst_member_or(Options, variable_names(VarNames), variable_names([])),
builtins:inst_member_or(Options, max_depth(MaxDepth), max_depth(0)),
'$write_term_to_chars'(Term, IgnoreOps, NumberVars, Quoted, VarNames, MaxDepth, Chars).

View File

@@ -2,6 +2,7 @@ use prolog_parser::ast::*;
use crate::prolog::clause_types::*;
use crate::prolog::forms::*;
use crate::prolog::heap_print::*;
use crate::prolog::machine::attributed_variables::*;
use crate::prolog::machine::copier::*;
use crate::prolog::machine::heap::*;
@@ -14,9 +15,10 @@ use crate::prolog::rug::Integer;
use downcast::Any;
use indexmap::IndexSet;
use indexmap::{IndexMap, IndexSet};
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::io::Write;
use std::mem;
use std::ops::{Index, IndexMut};
@@ -490,6 +492,114 @@ pub struct MachineState {
}
impl MachineState {
pub(crate)
fn write_term<'a>(
&'a self,
op_dir: &'a OpDir,
) -> Result<Option<HCPrinter<'a, PrinterOutputter>>, MachineStub>
{
let ignore_ops = self.store(self.deref(self[temp_v!(2)]));
let numbervars = self.store(self.deref(self[temp_v!(3)]));
let quoted = self.store(self.deref(self[temp_v!(4)]));
let max_depth = self.store(self.deref(self[temp_v!(6)]));
let mut printer = HCPrinter::new(&self, op_dir, PrinterOutputter::new());
if let &Addr::Con(h) = &ignore_ops {
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
printer.ignore_ops = name.as_str() == "true";
} else {
unreachable!()
}
}
if let &Addr::Con(h) = &numbervars {
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
printer.numbervars = name.as_str() == "true";
} else {
unreachable!()
}
}
if let &Addr::Con(h) = &quoted {
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
printer.quoted = name.as_str() == "true";
} else {
unreachable!()
}
}
match Number::try_from((max_depth, &self.heap)) {
Ok(Number::Fixnum(n)) => {
if let Ok(n) = usize::try_from(n) {
printer.max_depth = n;
} else {
return Ok(None);
}
}
Ok(Number::Integer(n)) => {
if let Some(n) = n.to_usize() {
printer.max_depth = n;
} else {
return Ok(None);
}
}
_ => {
unreachable!();
}
}
let stub = MachineError::functor_stub(clause_name!("write_term"), 2);
match self.try_from_list(temp_v!(5), stub) {
Ok(addrs) => {
let mut var_names: IndexMap<Addr, String> = IndexMap::new();
for addr in addrs {
match addr {
Addr::Str(s) => match &self.heap[s] {
&HeapCellValue::NamedStr(2, ref name, _)
if name.as_str() == "=" =>
{
let atom = self.heap[s + 1].as_addr(s + 1);
let var = self.heap[s + 2].as_addr(s + 2);
let atom = match self.store(self.deref(atom)) {
Addr::Con(h) => {
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
atom.to_string()
} else {
unreachable!()
}
}
Addr::Char(c) => c.to_string(),
_ => unreachable!(),
};
let var = self.store(self.deref(var));
if var_names.contains_key(&var) {
continue;
}
var_names.insert(var, atom);
}
_ => unreachable!(),
},
_ => unreachable!(),
}
}
printer.var_names = var_names;
}
Err(err) => {
return Err(err);
}
}
Ok(Some(printer))
}
#[inline]
pub(crate)
fn heap_pstr_iter<'a>(&'a self, focus: Addr) -> HeapPStrIter<'a> {

View File

@@ -4,11 +4,11 @@ use prolog_parser::tabled_rc::*;
use crate::prolog::clause_types::*;
use crate::prolog::forms::*;
use crate::prolog::heap_print::*;
use crate::prolog::instructions::*;
use crate::prolog::machine::code_repo::CodeRepo;
use crate::prolog::machine::copier::*;
use crate::prolog::machine::code_walker::*;
use crate::prolog::heap_print::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
@@ -20,7 +20,7 @@ use crate::prolog::rug::Integer;
use crate::ref_thread_local::RefThreadLocal;
use indexmap::{IndexMap, IndexSet};
use indexmap::IndexSet;
use std::cmp;
use std::convert::TryFrom;
@@ -3313,109 +3313,47 @@ impl MachineState {
&SystemClauseType::WriteTerm => {
let addr = self[temp_v!(1)];
let ignore_ops = self.store(self.deref(self[temp_v!(2)]));
let numbervars = self.store(self.deref(self[temp_v!(3)]));
let quoted = self.store(self.deref(self[temp_v!(4)]));
let max_depth = self.store(self.deref(self[temp_v!(6)]));
let mut printer = HCPrinter::new(&self, &indices.op_dir, PrinterOutputter::new());
if let &Addr::Con(h) = &ignore_ops {
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
printer.ignore_ops = name.as_str() == "true";
} else {
unreachable!()
}
}
if let &Addr::Con(h) = &numbervars {
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
printer.numbervars = name.as_str() == "true";
} else {
unreachable!()
}
}
if let &Addr::Con(h) = &quoted {
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
printer.quoted = name.as_str() == "true";
} else {
unreachable!()
}
}
match Number::try_from((max_depth, &self.heap)) {
Ok(Number::Fixnum(n)) => {
if let Ok(n) = usize::try_from(n) {
printer.max_depth = n;
} else {
let printer =
match self.write_term(&indices.op_dir)? {
None => {
self.fail = true;
return Ok(());
}
Some(printer) => {
printer
}
Ok(Number::Integer(n)) => {
if let Some(n) = n.to_usize() {
printer.max_depth = n;
} else {
self.fail = true;
return Ok(());
}
}
_ => {
unreachable!();
}
}
let stub = MachineError::functor_stub(clause_name!("write_term"), 2);
match self.try_from_list(temp_v!(5), stub) {
Ok(addrs) => {
let mut var_names: IndexMap<Addr, String> = IndexMap::new();
for addr in addrs {
match addr {
Addr::Str(s) => match &self.heap[s] {
&HeapCellValue::NamedStr(2, ref name, _)
if name.as_str() == "=" =>
{
let atom = self.heap[s + 1].as_addr(s + 1);
let var = self.heap[s + 2].as_addr(s + 2);
let atom = match self.store(self.deref(atom)) {
Addr::Con(h) => {
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
atom.to_string()
} else {
unreachable!()
}
}
Addr::Char(c) => c.to_string(),
_ => unreachable!(),
};
let var = self.store(self.deref(var));
if var_names.contains_key(&var) {
continue;
}
var_names.insert(var, atom);
}
_ => unreachable!(),
},
_ => unreachable!(),
}
}
printer.var_names = var_names;
}
Err(err) => return Err(err),
}
let output = printer.print(addr);
print!("{}", output.result());
stdout().flush().unwrap();
}
&SystemClauseType::WriteTermToChars => {
let addr = self[temp_v!(1)];
let printer =
match self.write_term(&indices.op_dir)? {
None => {
self.fail = true;
return Ok(());
}
Some(printer) => {
printer
}
};
let result = printer.print(addr).result();
let chars = self.heap.put_complete_string(&result);
let result_addr = self.store(self.deref(self[temp_v!(7)]));
if let Some(var) = result_addr.as_var() {
self.bind(var, chars);
} else {
unreachable!()
}
}
};
return_from_clause!(self.last_call, self)