add user_error stream (#917)
This commit is contained in:
@@ -6,7 +6,11 @@ fn main() {
|
|||||||
let handler = signal::SigHandler::Handler(handle_sigint);
|
let handler = signal::SigHandler::Handler(handle_sigint);
|
||||||
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
|
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
|
||||||
|
|
||||||
let mut wam = machine::Machine::new(readline::input_stream(), machine::Stream::stdout());
|
let mut wam = machine::Machine::new(
|
||||||
|
readline::input_stream(),
|
||||||
|
machine::Stream::stdout(),
|
||||||
|
machine::Stream::stderr(),
|
||||||
|
);
|
||||||
wam.run_top_level();
|
wam.run_top_level();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1331,7 +1331,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
self.print_atom(alias);
|
self.print_atom(alias);
|
||||||
} else {
|
} else {
|
||||||
if self.format_struct(iter, max_depth, 1, clause_name!("$stream")) {
|
if self.format_struct(iter, max_depth, 1, clause_name!("$stream")) {
|
||||||
let atom = if stream.is_stdout() || stream.is_stdin() {
|
let atom = if stream.is_stdout() || stream.is_stdin() || stream.is_stderr() {
|
||||||
TokenOrRedirect::Atom(clause_name!("user"))
|
TokenOrRedirect::Atom(clause_name!("user"))
|
||||||
} else {
|
} else {
|
||||||
TokenOrRedirect::RawPtr(stream.as_ptr())
|
TokenOrRedirect::RawPtr(stream.as_ptr())
|
||||||
|
|||||||
@@ -14,13 +14,15 @@ fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
|
|||||||
stack.push(index + offset);
|
stack.push(index + offset);
|
||||||
}
|
}
|
||||||
&Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(offset)))
|
&Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(offset)))
|
||||||
if offset > 0 => {
|
if offset > 0 =>
|
||||||
stack.push(index + offset);
|
{
|
||||||
}
|
stack.push(index + offset);
|
||||||
|
}
|
||||||
&Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(offset)))
|
&Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(offset)))
|
||||||
if offset > 0 => {
|
if offset > 0 =>
|
||||||
stack.push(index + offset);
|
{
|
||||||
}
|
stack.push(index + offset);
|
||||||
|
}
|
||||||
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
|
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
|
||||||
stack.push(index + offset);
|
stack.push(index + offset);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -310,49 +310,55 @@ pub(crate) struct MachineState {
|
|||||||
impl fmt::Debug for MachineState {
|
impl fmt::Debug for MachineState {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_struct("MachineState")
|
f.debug_struct("MachineState")
|
||||||
.field("atom_tbl", &self.atom_tbl)
|
.field("atom_tbl", &self.atom_tbl)
|
||||||
.field("s", &self.s)
|
.field("s", &self.s)
|
||||||
.field("p", &self.p)
|
.field("p", &self.p)
|
||||||
.field("b", &self.b)
|
.field("b", &self.b)
|
||||||
.field("b0", &self.b0)
|
.field("b0", &self.b0)
|
||||||
.field("e", &self.e)
|
.field("e", &self.e)
|
||||||
.field("num_of_args", &self.num_of_args)
|
.field("num_of_args", &self.num_of_args)
|
||||||
.field("cp", &self.cp)
|
.field("cp", &self.cp)
|
||||||
.field("attr_var_init", &self.attr_var_init)
|
.field("attr_var_init", &self.attr_var_init)
|
||||||
.field("fail", &self.fail)
|
.field("fail", &self.fail)
|
||||||
.field("heap", &self.heap)
|
.field("heap", &self.heap)
|
||||||
.field("mode", &self.mode)
|
.field("mode", &self.mode)
|
||||||
.field("stack", &self.stack)
|
.field("stack", &self.stack)
|
||||||
.field("registers", &self.registers)
|
.field("registers", &self.registers)
|
||||||
.field("trail", &self.trail)
|
.field("trail", &self.trail)
|
||||||
.field("tr", &self.tr)
|
.field("tr", &self.tr)
|
||||||
.field("hb", &self.hb)
|
.field("hb", &self.hb)
|
||||||
.field("block", &self.block)
|
.field("block", &self.block)
|
||||||
.field("ball", &self.ball)
|
.field("ball", &self.ball)
|
||||||
.field("lifted_heap", &self.lifted_heap)
|
.field("lifted_heap", &self.lifted_heap)
|
||||||
.field("interms", &self.interms)
|
.field("interms", &self.interms)
|
||||||
.field("last_call", &self.last_call)
|
.field("last_call", &self.last_call)
|
||||||
.field("flags", &self.flags)
|
.field("flags", &self.flags)
|
||||||
.field("cc", &self.cc)
|
.field("cc", &self.cc)
|
||||||
.field("global_clock", &self.global_clock)
|
.field("global_clock", &self.global_clock)
|
||||||
.field("dynamic_mode", &self.dynamic_mode)
|
.field("dynamic_mode", &self.dynamic_mode)
|
||||||
.field("unify_fn",
|
.field(
|
||||||
|
"unify_fn",
|
||||||
if self.unify_fn as usize == MachineState::unify as usize {
|
if self.unify_fn as usize == MachineState::unify as usize {
|
||||||
&"MachineState::unify"
|
&"MachineState::unify"
|
||||||
} else if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
|
} else if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
|
||||||
&"MachineState::unify_with_occurs_check"
|
&"MachineState::unify_with_occurs_check"
|
||||||
} else {
|
} else {
|
||||||
&"MachineState::unify_with_occurs_check_with_error"
|
&"MachineState::unify_with_occurs_check_with_error"
|
||||||
})
|
},
|
||||||
.field("bind_fn",
|
)
|
||||||
|
.field(
|
||||||
|
"bind_fn",
|
||||||
if self.bind_fn as usize == MachineState::bind as usize {
|
if self.bind_fn as usize == MachineState::bind as usize {
|
||||||
&"MachineState::bind"
|
&"MachineState::bind"
|
||||||
} else if self.bind_fn as usize == MachineState::bind_with_occurs_check_wrapper as usize {
|
} else if self.bind_fn as usize
|
||||||
|
== MachineState::bind_with_occurs_check_wrapper as usize
|
||||||
|
{
|
||||||
&"MachineState::bind_with_occurs_check"
|
&"MachineState::bind_with_occurs_check"
|
||||||
} else {
|
} else {
|
||||||
&"MachineState::bind_with_occurs_check_with_error_wrapper"
|
&"MachineState::bind_with_occurs_check_with_error_wrapper"
|
||||||
})
|
},
|
||||||
.finish()
|
)
|
||||||
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ impl MachineState {
|
|||||||
&mut self,
|
&mut self,
|
||||||
a1: Addr,
|
a1: Addr,
|
||||||
a2: Addr,
|
a2: Addr,
|
||||||
mut occurs_trigger: impl FnMut()
|
mut occurs_trigger: impl FnMut(),
|
||||||
) {
|
) {
|
||||||
let mut pdl = vec![a1, a2];
|
let mut pdl = vec![a1, a2];
|
||||||
let mut tabu_list: IndexSet<(Addr, Addr)> = IndexSet::new();
|
let mut tabu_list: IndexSet<(Addr, Addr)> = IndexSet::new();
|
||||||
@@ -1241,7 +1241,8 @@ impl MachineState {
|
|||||||
let h = self.heap.h();
|
let h = self.heap.h();
|
||||||
|
|
||||||
self.heap.push(HeapCellValue::Addr(Addr::Str(h + 1)));
|
self.heap.push(HeapCellValue::Addr(Addr::Str(h + 1)));
|
||||||
self.heap.push(HeapCellValue::NamedStr(arity, ct.name(), ct.spec()));
|
self.heap
|
||||||
|
.push(HeapCellValue::NamedStr(arity, ct.name(), ct.spec()));
|
||||||
|
|
||||||
self.bind(addr.as_var().unwrap(), Addr::HeapCell(h));
|
self.bind(addr.as_var().unwrap(), Addr::HeapCell(h));
|
||||||
|
|
||||||
@@ -1380,7 +1381,7 @@ impl MachineState {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
match &code[p-1] {
|
match &code[p - 1] {
|
||||||
&Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, _)) => {
|
&Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, _)) => {
|
||||||
if birth < machine_st.cc && Death::Finite(machine_st.cc) <= death {
|
if birth < machine_st.cc && Death::Finite(machine_st.cc) <= death {
|
||||||
return true;
|
return true;
|
||||||
@@ -1411,9 +1412,7 @@ impl MachineState {
|
|||||||
Addr::LoadStatePayload(_) | Addr::Stream(_) | Addr::TcpListener(_) => {
|
Addr::LoadStatePayload(_) | Addr::Stream(_) | Addr::TcpListener(_) => {
|
||||||
IndexingCodePtr::Fail
|
IndexingCodePtr::Fail
|
||||||
}
|
}
|
||||||
Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => {
|
Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => v,
|
||||||
v
|
|
||||||
}
|
|
||||||
Addr::PStrLocation(..) => l,
|
Addr::PStrLocation(..) => l,
|
||||||
Addr::Char(_)
|
Addr::Char(_)
|
||||||
| Addr::Con(_)
|
| Addr::Con(_)
|
||||||
@@ -3203,15 +3202,11 @@ impl MachineState {
|
|||||||
|
|
||||||
match code_repo.find_living_dynamic(p, self.cc) {
|
match code_repo.find_living_dynamic(p, self.cc) {
|
||||||
Some((offset, oi, ii, is_next_clause)) => {
|
Some((offset, oi, ii, is_next_clause)) => {
|
||||||
self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(
|
self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p.abs_loc(), oi, ii));
|
||||||
p.abs_loc(), oi, ii,
|
|
||||||
));
|
|
||||||
|
|
||||||
match self.dynamic_mode {
|
match self.dynamic_mode {
|
||||||
FirstOrNext::First if !is_next_clause => {
|
FirstOrNext::First if !is_next_clause => {
|
||||||
self.p = CodePtr::Local(LocalCodePtr::DirEntry(
|
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset));
|
||||||
p.abs_loc() + offset,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
FirstOrNext::First => {
|
FirstOrNext::First => {
|
||||||
// there's a leading DynamicElse that sets self.cc.
|
// there's a leading DynamicElse that sets self.cc.
|
||||||
@@ -3234,9 +3229,8 @@ impl MachineState {
|
|||||||
self.num_of_args -= 1;
|
self.num_of_args -= 1;
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.p = CodePtr::Local(LocalCodePtr::DirEntry(
|
self.p =
|
||||||
p.abs_loc() + offset,
|
CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3261,33 +3255,18 @@ impl MachineState {
|
|||||||
Some(_) => {
|
Some(_) => {
|
||||||
try_or_fail!(
|
try_or_fail!(
|
||||||
self,
|
self,
|
||||||
call_policy.retry(
|
call_policy.retry(self, offset, global_variables,)
|
||||||
self,
|
|
||||||
offset,
|
|
||||||
global_variables,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
try_or_fail!(
|
try_or_fail!(
|
||||||
self,
|
self,
|
||||||
call_policy.trust(
|
call_policy.trust(self, offset, global_variables,)
|
||||||
self,
|
|
||||||
offset,
|
|
||||||
global_variables,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try_or_fail!(
|
try_or_fail!(self, call_policy.trust(self, offset, global_variables,))
|
||||||
self,
|
|
||||||
call_policy.trust(
|
|
||||||
self,
|
|
||||||
offset,
|
|
||||||
global_variables,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3297,7 +3276,7 @@ impl MachineState {
|
|||||||
None => {
|
None => {
|
||||||
self.fail = true;
|
self.fail = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn execute_indexed_choice_instr(
|
pub(super) fn execute_indexed_choice_instr(
|
||||||
@@ -3415,20 +3394,14 @@ impl MachineState {
|
|||||||
None => {
|
None => {
|
||||||
try_or_fail!(
|
try_or_fail!(
|
||||||
self,
|
self,
|
||||||
call_policy.trust_me(
|
call_policy.trust_me(self, global_variables,)
|
||||||
self,
|
|
||||||
global_variables,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try_or_fail!(
|
try_or_fail!(
|
||||||
self,
|
self,
|
||||||
call_policy.trust_me(
|
call_policy.trust_me(self, global_variables,)
|
||||||
self,
|
|
||||||
global_variables,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3500,20 +3473,14 @@ impl MachineState {
|
|||||||
None => {
|
None => {
|
||||||
try_or_fail!(
|
try_or_fail!(
|
||||||
self,
|
self,
|
||||||
call_policy.trust_me(
|
call_policy.trust_me(self, global_variables,)
|
||||||
self,
|
|
||||||
global_variables,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try_or_fail!(
|
try_or_fail!(
|
||||||
self,
|
self,
|
||||||
call_policy.trust_me(
|
call_policy.trust_me(self, global_variables,)
|
||||||
self,
|
|
||||||
global_variables,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ pub struct Machine {
|
|||||||
pub(super) code_repo: CodeRepo,
|
pub(super) code_repo: CodeRepo,
|
||||||
pub(super) user_input: Stream,
|
pub(super) user_input: Stream,
|
||||||
pub(super) user_output: Stream,
|
pub(super) user_output: Stream,
|
||||||
|
pub(super) user_error: Stream,
|
||||||
pub(super) load_contexts: Vec<LoadContext>,
|
pub(super) load_contexts: Vec<LoadContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,7 +275,7 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(user_input: Stream, user_output: Stream) -> Self {
|
pub fn new(user_input: Stream, user_output: Stream, user_error: Stream) -> Self {
|
||||||
use ref_thread_local::RefThreadLocal;
|
use ref_thread_local::RefThreadLocal;
|
||||||
|
|
||||||
let mut wam = Machine {
|
let mut wam = Machine {
|
||||||
@@ -285,6 +286,7 @@ impl Machine {
|
|||||||
code_repo: CodeRepo::new(),
|
code_repo: CodeRepo::new(),
|
||||||
user_input,
|
user_input,
|
||||||
user_output,
|
user_output,
|
||||||
|
user_error,
|
||||||
load_contexts: vec![],
|
load_contexts: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -367,6 +369,12 @@ impl Machine {
|
|||||||
.stream_aliases
|
.stream_aliases
|
||||||
.insert(clause_name!("user_output"), self.user_output.clone());
|
.insert(clause_name!("user_output"), self.user_output.clone());
|
||||||
|
|
||||||
|
self.user_error.options_mut().alias = Some(clause_name!("user_error"));
|
||||||
|
|
||||||
|
self.indices
|
||||||
|
.stream_aliases
|
||||||
|
.insert(clause_name!("user_error"), self.user_error.clone());
|
||||||
|
|
||||||
self.indices.streams.insert(self.user_output.clone());
|
self.indices.streams.insert(self.user_output.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,14 +536,12 @@ impl MachineState {
|
|||||||
) {
|
) {
|
||||||
match instr {
|
match instr {
|
||||||
&Line::Arithmetic(ref arith_instr) => self.execute_arith_instr(arith_instr),
|
&Line::Arithmetic(ref arith_instr) => self.execute_arith_instr(arith_instr),
|
||||||
&Line::Choice(ref choice_instr) => {
|
&Line::Choice(ref choice_instr) => self.execute_choice_instr(
|
||||||
self.execute_choice_instr(
|
choice_instr,
|
||||||
choice_instr,
|
code_repo,
|
||||||
code_repo,
|
&mut policies.call_policy,
|
||||||
&mut policies.call_policy,
|
&mut indices.global_variables,
|
||||||
&mut indices.global_variables,
|
),
|
||||||
)
|
|
||||||
}
|
|
||||||
&Line::Cut(ref cut_instr) => {
|
&Line::Cut(ref cut_instr) => {
|
||||||
self.execute_cut_instr(cut_instr, &mut policies.cut_policy)
|
self.execute_cut_instr(cut_instr, &mut policies.cut_policy)
|
||||||
}
|
}
|
||||||
@@ -553,25 +559,18 @@ impl MachineState {
|
|||||||
self.p += 1;
|
self.p += 1;
|
||||||
}
|
}
|
||||||
&Line::IndexingCode(ref indexing_lines) => {
|
&Line::IndexingCode(ref indexing_lines) => {
|
||||||
self.execute_indexing_instr(
|
self.execute_indexing_instr(indexing_lines, code_repo)
|
||||||
indexing_lines,
|
|
||||||
code_repo,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
&Line::IndexedChoice(ref choice_instr) => {
|
|
||||||
self.execute_indexed_choice_instr(
|
|
||||||
choice_instr,
|
|
||||||
&mut policies.call_policy,
|
|
||||||
&mut indices.global_variables,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
&Line::DynamicIndexedChoice(_) => {
|
|
||||||
self.execute_dynamic_indexed_choice_instr(
|
|
||||||
code_repo,
|
|
||||||
&mut policies.call_policy,
|
|
||||||
&mut indices.global_variables,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
&Line::IndexedChoice(ref choice_instr) => self.execute_indexed_choice_instr(
|
||||||
|
choice_instr,
|
||||||
|
&mut policies.call_policy,
|
||||||
|
&mut indices.global_variables,
|
||||||
|
),
|
||||||
|
&Line::DynamicIndexedChoice(_) => self.execute_dynamic_indexed_choice_instr(
|
||||||
|
code_repo,
|
||||||
|
&mut policies.call_policy,
|
||||||
|
&mut indices.global_variables,
|
||||||
|
),
|
||||||
&Line::Query(ref query_instr) => {
|
&Line::Query(ref query_instr) => {
|
||||||
self.execute_query_instr(&query_instr);
|
self.execute_query_instr(&query_instr);
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
|
|||||||
@@ -409,13 +409,11 @@ pub(super) fn compare_pstr_prefixes<'a>(
|
|||||||
|
|
||||||
let machine_st = i1.machine_st;
|
let machine_st = i1.machine_st;
|
||||||
|
|
||||||
let check_focuses = || {
|
let check_focuses = || match (i1.focus(), i2.focus()) {
|
||||||
match (i1.focus(), i2.focus()) {
|
(Addr::EmptyList, Addr::EmptyList) => Some(Ordering::Equal),
|
||||||
(Addr::EmptyList, Addr::EmptyList) => Some(Ordering::Equal),
|
(Addr::EmptyList, _) => Some(Ordering::Less),
|
||||||
(Addr::EmptyList, _) => Some(Ordering::Less),
|
(_, Addr::EmptyList) => Some(Ordering::Greater),
|
||||||
(_, Addr::EmptyList) => Some(Ordering::Greater),
|
_ => None,
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return match r1 {
|
return match r1 {
|
||||||
@@ -430,12 +428,8 @@ pub(super) fn compare_pstr_prefixes<'a>(
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(PStrIteratee::Char(_)) => {
|
Some(PStrIteratee::Char(_)) => Some(ordering),
|
||||||
Some(ordering)
|
None => check_focuses(),
|
||||||
}
|
|
||||||
None => {
|
|
||||||
check_focuses()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,13 @@ pub(crate) struct RawBlock<T: RawBlockTraits> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RawBlockTraits> RawBlock<T> {
|
impl<T: RawBlockTraits> RawBlock<T> {
|
||||||
pub(crate)
|
pub(crate) fn new() -> Self {
|
||||||
fn new() -> Self {
|
let mut block = RawBlock {
|
||||||
let mut block = RawBlock { size: 0,
|
size: 0,
|
||||||
base: ptr::null(),
|
base: ptr::null(),
|
||||||
top: ptr::null(),
|
top: ptr::null(),
|
||||||
_marker: PhantomData };
|
_marker: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
block.grow();
|
block.grow();
|
||||||
@@ -46,45 +47,47 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
|||||||
self.top = T::base_offset(self.base);
|
self.top = T::base_offset(self.base);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super)
|
pub(super) unsafe fn grow(&mut self) {
|
||||||
unsafe fn grow(&mut self) {
|
|
||||||
if self.size == 0 {
|
if self.size == 0 {
|
||||||
self.init_at_size(T::init_size());
|
self.init_at_size(T::init_size());
|
||||||
} else {
|
} else {
|
||||||
let layout = alloc::Layout::from_size_align_unchecked(T::init_size(), T::align());
|
let layout = alloc::Layout::from_size_align_unchecked(T::init_size(), T::align());
|
||||||
let top_dist = self.top as usize - self.base as usize;
|
let top_dist = self.top as usize - self.base as usize;
|
||||||
|
|
||||||
self.base = alloc::realloc(self.base as *mut _, layout, self.size*2) as *const _;
|
self.base = alloc::realloc(self.base as *mut _, layout, self.size * 2) as *const _;
|
||||||
self.top = (self.base as usize + top_dist) as *const _;
|
self.top = (self.base as usize + top_dist) as *const _;
|
||||||
self.size *= 2;
|
self.size *= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty_block() -> Self {
|
fn empty_block() -> Self {
|
||||||
RawBlock { size: 0,
|
RawBlock {
|
||||||
base: ptr::null(),
|
size: 0,
|
||||||
top: ptr::null(),
|
base: ptr::null(),
|
||||||
_marker: PhantomData }
|
top: ptr::null(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate)
|
pub(crate) fn take(&mut self) -> Self {
|
||||||
fn take(&mut self) -> Self {
|
|
||||||
mem::replace(self, Self::empty_block())
|
mem::replace(self, Self::empty_block())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn free_space(&self) -> usize {
|
fn free_space(&self) -> usize {
|
||||||
debug_assert!(self.top >= self.base,
|
debug_assert!(
|
||||||
"self.top = {:?} < {:?} = self.base",
|
self.top >= self.base,
|
||||||
self.top, self.base);
|
"self.top = {:?} < {:?} = self.base",
|
||||||
|
self.top,
|
||||||
|
self.base
|
||||||
|
);
|
||||||
|
|
||||||
self.size - (self.top as usize - self.base as usize)
|
self.size - (self.top as usize - self.base as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate)
|
pub(crate) unsafe fn new_block(&mut self, size: usize) -> *const u8 {
|
||||||
unsafe fn new_block(&mut self, size: usize) -> *const u8 {
|
|
||||||
loop {
|
loop {
|
||||||
if self.free_space() >= size {
|
if self.free_space() >= size {
|
||||||
return (self.top as usize + size) as *const _;
|
return (self.top as usize + size) as *const _;
|
||||||
@@ -94,14 +97,13 @@ impl<T: RawBlockTraits> RawBlock<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate)
|
pub(crate) fn deallocate(&mut self) {
|
||||||
fn deallocate(&mut self) {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let layout = alloc::Layout::from_size_align_unchecked(self.size, T::align());
|
let layout = alloc::Layout::from_size_align_unchecked(self.size, T::align());
|
||||||
|
|
||||||
alloc::dealloc(self.base as *mut u8, layout);
|
alloc::dealloc(self.base as *mut u8, layout);
|
||||||
|
|
||||||
self.top = ptr::null();
|
self.top = ptr::null();
|
||||||
self.base = ptr::null();
|
self.base = ptr::null();
|
||||||
self.size = 0;
|
self.size = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use std::fmt;
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
|
use std::io::{stderr, stdout, Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::net::{Shutdown, TcpStream};
|
use std::net::{Shutdown, TcpStream};
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
@@ -114,6 +114,7 @@ enum StreamInstance {
|
|||||||
PausedPrologStream(Vec<u8>, Box<StreamInstance>),
|
PausedPrologStream(Vec<u8>, Box<StreamInstance>),
|
||||||
ReadlineStream(ReadlineStream),
|
ReadlineStream(ReadlineStream),
|
||||||
StaticStr(Cursor<&'static str>),
|
StaticStr(Cursor<&'static str>),
|
||||||
|
Stderr,
|
||||||
Stdout,
|
Stdout,
|
||||||
TcpStream(ClauseName, TcpStream),
|
TcpStream(ClauseName, TcpStream),
|
||||||
TlsStream(ClauseName, TlsStream<TcpStream>),
|
TlsStream(ClauseName, TlsStream<TcpStream>),
|
||||||
@@ -148,12 +149,13 @@ impl StreamInstance {
|
|||||||
StreamInstance::ReadlineStream(ref mut rl_stream) => rl_stream.read(buf),
|
StreamInstance::ReadlineStream(ref mut rl_stream) => rl_stream.read(buf),
|
||||||
StreamInstance::StaticStr(ref mut src) => src.read(buf),
|
StreamInstance::StaticStr(ref mut src) => src.read(buf),
|
||||||
StreamInstance::Bytes(ref mut cursor) => cursor.read(buf),
|
StreamInstance::Bytes(ref mut cursor) => cursor.read(buf),
|
||||||
StreamInstance::OutputFile(..) | StreamInstance::Stdout | StreamInstance::Null => {
|
StreamInstance::OutputFile(..)
|
||||||
Err(std::io::Error::new(
|
| StreamInstance::Stderr
|
||||||
ErrorKind::PermissionDenied,
|
| StreamInstance::Stdout
|
||||||
StreamError::ReadFromOutputStream,
|
| StreamInstance::Null => Err(std::io::Error::new(
|
||||||
))
|
ErrorKind::PermissionDenied,
|
||||||
}
|
StreamError::ReadFromOutputStream,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,6 +188,7 @@ impl fmt::Debug for StreamInstance {
|
|||||||
&StreamInstance::ReadlineStream(ref readline_stream) => {
|
&StreamInstance::ReadlineStream(ref readline_stream) => {
|
||||||
write!(fmt, "ReadlineStream({:?})", readline_stream)
|
write!(fmt, "ReadlineStream({:?})", readline_stream)
|
||||||
}
|
}
|
||||||
|
&StreamInstance::Stderr => write!(fmt, "Stderr"),
|
||||||
&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)
|
||||||
@@ -521,7 +524,9 @@ impl Stream {
|
|||||||
| StreamInstance::InputFile(..) => "read",
|
| StreamInstance::InputFile(..) => "read",
|
||||||
StreamInstance::TcpStream(..) | StreamInstance::TlsStream(..) => "read_append",
|
StreamInstance::TcpStream(..) | StreamInstance::TlsStream(..) => "read_append",
|
||||||
StreamInstance::OutputFile(_, _, true) => "append",
|
StreamInstance::OutputFile(_, _, true) => "append",
|
||||||
StreamInstance::Stdout | StreamInstance::OutputFile(_, _, false) => "write",
|
StreamInstance::Stderr
|
||||||
|
| StreamInstance::Stdout
|
||||||
|
| StreamInstance::OutputFile(_, _, false) => "write",
|
||||||
StreamInstance::Null => "",
|
StreamInstance::Null => "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -538,6 +543,11 @@ impl Stream {
|
|||||||
Stream::from_inst(StreamInstance::Stdout)
|
Stream::from_inst(StreamInstance::Stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn stderr() -> Self {
|
||||||
|
Stream::from_inst(StreamInstance::Stderr)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn from_tcp_stream(address: ClauseName, tcp_stream: TcpStream) -> Self {
|
pub(crate) fn from_tcp_stream(address: ClauseName, tcp_stream: TcpStream) -> Self {
|
||||||
tcp_stream.set_read_timeout(None).unwrap();
|
tcp_stream.set_read_timeout(None).unwrap();
|
||||||
@@ -561,6 +571,14 @@ impl Stream {
|
|||||||
Stream::from_inst(StreamInstance::InputFile(name, file))
|
Stream::from_inst(StreamInstance::InputFile(name, file))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn is_stderr(&self) -> bool {
|
||||||
|
match self.stream_inst.0.borrow().stream_inst {
|
||||||
|
StreamInstance::Stderr => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn is_stdout(&self) -> bool {
|
pub(crate) fn is_stdout(&self) -> bool {
|
||||||
match self.stream_inst.0.borrow().stream_inst {
|
match self.stream_inst.0.borrow().stream_inst {
|
||||||
@@ -608,7 +626,8 @@ impl Stream {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn is_output_stream(&self) -> bool {
|
pub(crate) fn is_output_stream(&self) -> bool {
|
||||||
match self.stream_inst.0.borrow().stream_inst {
|
match self.stream_inst.0.borrow().stream_inst {
|
||||||
StreamInstance::Stdout
|
StreamInstance::Stderr
|
||||||
|
| StreamInstance::Stdout
|
||||||
| StreamInstance::TcpStream(..)
|
| StreamInstance::TcpStream(..)
|
||||||
| StreamInstance::TlsStream(..)
|
| StreamInstance::TlsStream(..)
|
||||||
| StreamInstance::Bytes(_)
|
| StreamInstance::Bytes(_)
|
||||||
@@ -1110,6 +1129,7 @@ impl Write for Stream {
|
|||||||
StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.write(buf),
|
StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.write(buf),
|
||||||
StreamInstance::Bytes(ref mut cursor) => cursor.write(buf),
|
StreamInstance::Bytes(ref mut cursor) => cursor.write(buf),
|
||||||
StreamInstance::Stdout => stdout().write(buf),
|
StreamInstance::Stdout => stdout().write(buf),
|
||||||
|
StreamInstance::Stderr => stderr().write(buf),
|
||||||
StreamInstance::PausedPrologStream(..)
|
StreamInstance::PausedPrologStream(..)
|
||||||
| StreamInstance::StaticStr(_)
|
| StreamInstance::StaticStr(_)
|
||||||
| StreamInstance::ReadlineStream(_)
|
| StreamInstance::ReadlineStream(_)
|
||||||
@@ -1127,6 +1147,7 @@ impl Write for Stream {
|
|||||||
StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.flush(),
|
StreamInstance::TcpStream(_, ref mut tcp_stream) => tcp_stream.flush(),
|
||||||
StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.flush(),
|
StreamInstance::TlsStream(_, ref mut tls_stream) => tls_stream.flush(),
|
||||||
StreamInstance::Bytes(ref mut cursor) => cursor.flush(),
|
StreamInstance::Bytes(ref mut cursor) => cursor.flush(),
|
||||||
|
StreamInstance::Stderr => stderr().flush(),
|
||||||
StreamInstance::Stdout => stdout().flush(),
|
StreamInstance::Stdout => stdout().flush(),
|
||||||
StreamInstance::PausedPrologStream(..)
|
StreamInstance::PausedPrologStream(..)
|
||||||
| StreamInstance::StaticStr(_)
|
| StreamInstance::StaticStr(_)
|
||||||
|
|||||||
@@ -1852,26 +1852,24 @@ impl MachineState {
|
|||||||
let addr = self[temp_v!(2)];
|
let addr = self[temp_v!(2)];
|
||||||
|
|
||||||
match indices.global_variables.get_mut(&key) {
|
match indices.global_variables.get_mut(&key) {
|
||||||
Some((ref ball, ref mut loc)) => {
|
Some((ref ball, ref mut loc)) => match loc {
|
||||||
match loc {
|
Some(ref value_addr) => {
|
||||||
Some(ref value_addr) => {
|
(self.unify_fn)(self, addr, *value_addr);
|
||||||
(self.unify_fn)(self, addr, *value_addr);
|
|
||||||
}
|
|
||||||
loc @ None if !ball.stub.is_empty() => {
|
|
||||||
let h = self.heap.h();
|
|
||||||
let stub = ball.copy_and_align(h);
|
|
||||||
|
|
||||||
self.heap.extend(stub.into_iter());
|
|
||||||
(self.unify_fn)(self, addr, Addr::HeapCell(h));
|
|
||||||
|
|
||||||
if !self.fail {
|
|
||||||
*loc = Some(Addr::HeapCell(h));
|
|
||||||
self.trail(TrailRef::BlackboardEntry(key_h));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => self.fail = true,
|
|
||||||
}
|
}
|
||||||
}
|
loc @ None if !ball.stub.is_empty() => {
|
||||||
|
let h = self.heap.h();
|
||||||
|
let stub = ball.copy_and_align(h);
|
||||||
|
|
||||||
|
self.heap.extend(stub.into_iter());
|
||||||
|
(self.unify_fn)(self, addr, Addr::HeapCell(h));
|
||||||
|
|
||||||
|
if !self.fail {
|
||||||
|
*loc = Some(Addr::HeapCell(h));
|
||||||
|
self.trail(TrailRef::BlackboardEntry(key_h));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => self.fail = true,
|
||||||
|
},
|
||||||
None => self.fail = true,
|
None => self.fail = true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -2617,7 +2615,7 @@ impl MachineState {
|
|||||||
indices.streams.insert(current_output_stream.clone());
|
indices.streams.insert(current_output_stream.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if !stream.is_stdin() && !stream.is_stdout() {
|
if !stream.is_stdin() && !stream.is_stdout() && !stream.is_stderr() {
|
||||||
stream.close();
|
stream.close();
|
||||||
|
|
||||||
if let Some(ref alias) = stream.options().alias {
|
if let Some(ref alias) = stream.options().alias {
|
||||||
@@ -3472,17 +3470,22 @@ impl MachineState {
|
|||||||
self.fail = match self.store(self.deref(self[temp_v!(2)])) {
|
self.fail = match self.store(self.deref(self[temp_v!(2)])) {
|
||||||
Addr::Str(s) => match &self.heap[s] {
|
Addr::Str(s) => match &self.heap[s] {
|
||||||
&HeapCellValue::NamedStr(arity, ref name, ref spec) => {
|
&HeapCellValue::NamedStr(arity, ref name, ref spec) => {
|
||||||
if CLAUSE_TYPE_FORMS.borrow().get(&(name.as_str(), arity)).is_some() {
|
if CLAUSE_TYPE_FORMS
|
||||||
|
.borrow()
|
||||||
|
.get(&(name.as_str(), arity))
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
let index = indices.get_predicate_code_index(
|
let index = indices
|
||||||
name.clone(),
|
.get_predicate_code_index(
|
||||||
arity,
|
name.clone(),
|
||||||
module_name,
|
arity,
|
||||||
spec.clone(),
|
module_name,
|
||||||
)
|
spec.clone(),
|
||||||
.map(|index| index.get())
|
)
|
||||||
.unwrap_or(IndexPtr::DynamicUndefined);
|
.map(|index| index.get())
|
||||||
|
.unwrap_or(IndexPtr::DynamicUndefined);
|
||||||
|
|
||||||
match index {
|
match index {
|
||||||
IndexPtr::DynamicUndefined => false,
|
IndexPtr::DynamicUndefined => false,
|
||||||
@@ -3499,17 +3502,22 @@ impl MachineState {
|
|||||||
let spec =
|
let spec =
|
||||||
fetch_atom_op_spec(name.clone(), spec.clone(), &indices.op_dir);
|
fetch_atom_op_spec(name.clone(), spec.clone(), &indices.op_dir);
|
||||||
|
|
||||||
if CLAUSE_TYPE_FORMS.borrow().get(&(name.as_str(), 0)).is_some() {
|
if CLAUSE_TYPE_FORMS
|
||||||
|
.borrow()
|
||||||
|
.get(&(name.as_str(), 0))
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
let index = indices.get_predicate_code_index(
|
let index = indices
|
||||||
name.clone(),
|
.get_predicate_code_index(
|
||||||
0,
|
name.clone(),
|
||||||
module_name,
|
0,
|
||||||
spec.clone(),
|
module_name,
|
||||||
)
|
spec.clone(),
|
||||||
.map(|index| index.get())
|
)
|
||||||
.unwrap_or(IndexPtr::DynamicUndefined);
|
.map(|index| index.get())
|
||||||
|
.unwrap_or(IndexPtr::DynamicUndefined);
|
||||||
|
|
||||||
match index {
|
match index {
|
||||||
IndexPtr::DynamicUndefined => false,
|
IndexPtr::DynamicUndefined => false,
|
||||||
@@ -4482,22 +4490,22 @@ impl MachineState {
|
|||||||
let new_value = self.store(self.deref(self[temp_v!(2)]));
|
let new_value = self.store(self.deref(self[temp_v!(2)]));
|
||||||
|
|
||||||
match indices.global_variables.get_mut(&key) {
|
match indices.global_variables.get_mut(&key) {
|
||||||
Some((_, ref mut loc)) => {
|
Some((_, ref mut loc)) => match loc {
|
||||||
match loc {
|
Some(ref mut value) => {
|
||||||
Some(ref mut value) => {
|
let old_value_loc = self.heap.push(HeapCellValue::Addr(*value));
|
||||||
let old_value_loc = self.heap.push(HeapCellValue::Addr(*value));
|
self.trail(TrailRef::BlackboardOffset(key_h, old_value_loc));
|
||||||
self.trail(TrailRef::BlackboardOffset(key_h, old_value_loc));
|
*value = new_value;
|
||||||
*value = new_value;
|
|
||||||
}
|
|
||||||
loc @ None => {
|
|
||||||
self.trail(TrailRef::BlackboardEntry(key_h));
|
|
||||||
*loc = Some(new_value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
loc @ None => {
|
||||||
|
self.trail(TrailRef::BlackboardEntry(key_h));
|
||||||
|
*loc = Some(new_value);
|
||||||
|
}
|
||||||
|
},
|
||||||
None => {
|
None => {
|
||||||
self.trail(TrailRef::BlackboardEntry(key_h));
|
self.trail(TrailRef::BlackboardEntry(key_h));
|
||||||
indices.global_variables.insert(key, (Ball::new(), Some(new_value)));
|
indices
|
||||||
|
.global_variables
|
||||||
|
.insert(key, (Ball::new(), Some(new_value)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5361,21 +5369,23 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
&SystemClauseType::IsSTOEnabled => {
|
&SystemClauseType::IsSTOEnabled => {
|
||||||
if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
|
if self.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
|
||||||
let value = self.heap.to_unifiable(
|
let value = self
|
||||||
HeapCellValue::Atom(clause_name!("true"), None),
|
.heap
|
||||||
);
|
.to_unifiable(HeapCellValue::Atom(clause_name!("true"), None));
|
||||||
|
|
||||||
(self.unify_fn)(self, self[temp_v!(1)], value);
|
(self.unify_fn)(self, self[temp_v!(1)], value);
|
||||||
} else if self.unify_fn as usize == MachineState::unify_with_occurs_check_with_error as usize {
|
} else if self.unify_fn as usize
|
||||||
let value = self.heap.to_unifiable(
|
== MachineState::unify_with_occurs_check_with_error as usize
|
||||||
HeapCellValue::Atom(clause_name!("error"), None),
|
{
|
||||||
);
|
let value = self
|
||||||
|
.heap
|
||||||
|
.to_unifiable(HeapCellValue::Atom(clause_name!("error"), None));
|
||||||
|
|
||||||
(self.unify_fn)(self, self[temp_v!(1)], value);
|
(self.unify_fn)(self, self[temp_v!(1)], value);
|
||||||
} else {
|
} else {
|
||||||
let value = self.heap.to_unifiable(
|
let value = self
|
||||||
HeapCellValue::Atom(clause_name!("false"), None),
|
.heap
|
||||||
);
|
.to_unifiable(HeapCellValue::Atom(clause_name!("false"), None));
|
||||||
|
|
||||||
(self.unify_fn)(self, self[temp_v!(1)], value);
|
(self.unify_fn)(self, self[temp_v!(1)], value);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user