1208 lines
38 KiB
Rust
1208 lines
38 KiB
Rust
use crate::arena::*;
|
|
use crate::atom_table::*;
|
|
use crate::parser::ast::*;
|
|
|
|
#[cfg(feature = "ffi")]
|
|
use crate::ffi::{self, FfiError};
|
|
use crate::forms::*;
|
|
use crate::functor_macro::*;
|
|
use crate::machine::heap::AllocError;
|
|
use crate::machine::heap::*;
|
|
use crate::machine::loader::CompilationTarget;
|
|
use crate::machine::machine_state::*;
|
|
use crate::machine::streams::*;
|
|
use crate::machine::system_calls::BrentAlgState;
|
|
use crate::types::*;
|
|
|
|
pub type MachineStub = Vec<FunctorElement>;
|
|
pub type MachineStubGen = Box<dyn Fn(&mut MachineState) -> MachineStub>;
|
|
|
|
#[derive(Debug)]
|
|
pub(crate) struct MachineError {
|
|
stub: MachineStub,
|
|
location: Option<(usize, usize)>, // line_num, col_num
|
|
}
|
|
|
|
// from 7.12.2 b) of 13211-1:1995
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub(crate) enum ValidType {
|
|
Atom,
|
|
Atomic,
|
|
// Boolean,
|
|
Byte,
|
|
Callable,
|
|
Character,
|
|
Compound,
|
|
Evaluable,
|
|
Float,
|
|
InByte,
|
|
InCharacter,
|
|
Integer,
|
|
List,
|
|
#[allow(unused)]
|
|
Number,
|
|
Pair,
|
|
// PredicateIndicator,
|
|
// Variable
|
|
TcpListener,
|
|
Process,
|
|
}
|
|
|
|
impl ValidType {
|
|
pub(crate) fn as_atom(self) -> Atom {
|
|
match self {
|
|
ValidType::Atom => atom!("atom"),
|
|
ValidType::Atomic => atom!("atomic"),
|
|
// ValidType::Boolean => atom!("boolean"),
|
|
ValidType::Byte => atom!("byte"),
|
|
ValidType::Callable => atom!("callable"),
|
|
ValidType::Character => atom!("character"),
|
|
ValidType::Compound => atom!("compound"),
|
|
ValidType::Evaluable => atom!("evaluable"),
|
|
ValidType::Float => atom!("float"),
|
|
ValidType::InByte => atom!("in_byte"),
|
|
ValidType::InCharacter => atom!("in_character"),
|
|
ValidType::Integer => atom!("integer"),
|
|
ValidType::List => atom!("list"),
|
|
ValidType::Number => atom!("number"),
|
|
ValidType::Pair => atom!("pair"),
|
|
// ValidType::PredicateIndicator => atom!("predicate_indicator"),
|
|
// ValidType::Variable => atom!("variable")
|
|
ValidType::TcpListener => atom!("tcp_listener"),
|
|
ValidType::Process => atom!("process"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub(crate) enum ResourceError {
|
|
FiniteMemory(HeapCellValue),
|
|
OutOfFiles,
|
|
}
|
|
|
|
pub(crate) trait TypeError {
|
|
fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError;
|
|
}
|
|
|
|
impl TypeError for HeapCellValue {
|
|
fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
|
|
let stub = functor!(
|
|
atom!("type_error"),
|
|
[atom_as_cell((valid_type.as_atom())), cell(self)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TypeError for MachineStub {
|
|
fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
|
|
let stub = functor!(
|
|
atom!("type_error"),
|
|
[atom_as_cell((valid_type.as_atom())), functor(self)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TypeError for Number {
|
|
fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
|
|
let stub = functor!(
|
|
atom!("type_error"),
|
|
[
|
|
atom_as_cell((valid_type.as_atom())),
|
|
number(self, (&mut machine_st.arena))
|
|
]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) trait PermissionError {
|
|
fn permission_error(
|
|
self,
|
|
machine_st: &mut MachineState,
|
|
index_atom: Atom,
|
|
perm: Permission,
|
|
) -> MachineError;
|
|
}
|
|
|
|
impl PermissionError for Atom {
|
|
fn permission_error(
|
|
self,
|
|
_machine_st: &mut MachineState,
|
|
index_atom: Atom,
|
|
perm: Permission,
|
|
) -> MachineError {
|
|
let stub = functor!(
|
|
atom!("permission_error"),
|
|
[
|
|
atom_as_cell((perm.as_atom())),
|
|
atom_as_cell(index_atom),
|
|
atom_as_cell(self)
|
|
]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PermissionError for HeapCellValue {
|
|
fn permission_error(
|
|
self,
|
|
_machine_st: &mut MachineState,
|
|
index_atom: Atom,
|
|
perm: Permission,
|
|
) -> MachineError {
|
|
let cell = read_heap_cell!(self,
|
|
(HeapCellValueTag::Cons, ptr) => {
|
|
match_untyped_arena_ptr!(ptr,
|
|
(ArenaHeaderTag::Stream, stream) => {
|
|
if let Some(alias) = stream.options().get_alias() {
|
|
atom_as_cell!(alias)
|
|
} else {
|
|
self
|
|
}
|
|
}
|
|
_ => {
|
|
self
|
|
}
|
|
)
|
|
}
|
|
_ => {
|
|
self
|
|
}
|
|
);
|
|
|
|
let stub = functor!(
|
|
atom!("permission_error"),
|
|
[
|
|
atom_as_cell((perm.as_atom())),
|
|
atom_as_cell(index_atom),
|
|
cell(cell)
|
|
]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PermissionError for MachineStub {
|
|
fn permission_error(
|
|
self,
|
|
_machine_st: &mut MachineState,
|
|
index_atom: Atom,
|
|
perm: Permission,
|
|
) -> MachineError {
|
|
let stub = functor!(
|
|
atom!("permission_error"),
|
|
[
|
|
atom_as_cell((perm.as_atom())),
|
|
atom_as_cell(index_atom),
|
|
functor(self)
|
|
]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) trait DomainError {
|
|
fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError;
|
|
}
|
|
|
|
impl DomainError for HeapCellValue {
|
|
fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
|
|
let stub = functor!(
|
|
atom!("domain_error"),
|
|
[atom_as_cell((error.as_atom())), cell(self)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DomainError for Number {
|
|
fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
|
|
let stub = functor!(
|
|
atom!("domain_error"),
|
|
[
|
|
atom_as_cell((error.as_atom())),
|
|
number(self, (&mut machine_st.arena))
|
|
]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DomainError for MachineStub {
|
|
fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
|
|
let stub = functor!(
|
|
atom!("domain_error"),
|
|
[atom_as_cell((error.as_atom())), functor(self)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "ffi")]
|
|
impl DomainError for ffi::Value {
|
|
fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
|
|
use ffi::Value;
|
|
|
|
match self {
|
|
Value::Number(number) => number.domain_error(machine_st, error),
|
|
Value::CString(cstring) => {
|
|
let str = cstring.to_string_lossy().into_owned();
|
|
let stub = functor!(
|
|
atom!("domain_error"),
|
|
[atom_as_cell((error.as_atom())), string(str)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
Value::Struct(atom, _values) => atom_as_cell!(atom).domain_error(machine_st, error),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[inline(always)]
|
|
pub(super) fn functor_stub(name: Atom, arity: usize) -> MachineStub {
|
|
functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)])
|
|
}
|
|
|
|
impl MachineState {
|
|
#[inline]
|
|
pub(super) fn interrupt_error(&mut self) -> MachineError {
|
|
let stub = functor!(atom!("$interrupt_thrown"));
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
|
|
pub(super) fn evaluation_error(&mut self, eval_error: EvalError) -> MachineError {
|
|
let stub = functor!(
|
|
atom!("evaluation_error"),
|
|
[atom_as_cell((eval_error.as_atom()))]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
|
|
pub(super) fn resource_error(err: ResourceError) -> MachineError {
|
|
let stub = match err {
|
|
ResourceError::FiniteMemory(size_requested) => {
|
|
functor!(
|
|
atom!("resource_error"),
|
|
[atom_as_cell((atom!("finite_memory"))), cell(size_requested)]
|
|
)
|
|
}
|
|
ResourceError::OutOfFiles => {
|
|
functor!(
|
|
atom!("resource_error"),
|
|
[atom_as_cell((atom!("file_descriptors")))]
|
|
)
|
|
}
|
|
};
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
|
|
pub(super) fn type_error<T: TypeError>(
|
|
&mut self,
|
|
valid_type: ValidType,
|
|
culprit: T,
|
|
) -> MachineError {
|
|
culprit.type_error(self, valid_type)
|
|
}
|
|
|
|
pub(super) fn existence_error(&mut self, err: ExistenceError) -> MachineError {
|
|
match err {
|
|
ExistenceError::Module(name) => {
|
|
let stub = functor!(
|
|
atom!("existence_error"),
|
|
[atom_as_cell((atom!("source_sink"))), atom_as_cell(name)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
ExistenceError::QualifiedProcedure {
|
|
module_name,
|
|
name,
|
|
arity,
|
|
} => {
|
|
let ind_stub = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]);
|
|
let res_stub = functor!(atom!(":"), [atom_as_cell(module_name), functor(ind_stub)]);
|
|
|
|
let stub = functor!(
|
|
atom!("existence_error"),
|
|
[atom_as_cell((atom!("procedure"))), functor(res_stub)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
ExistenceError::Procedure(name, arity) => {
|
|
let culprit = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]);
|
|
|
|
let stub = functor!(
|
|
atom!("existence_error"),
|
|
[atom_as_cell((atom!("procedure"))), functor(culprit)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
ExistenceError::ModuleSource(source) => {
|
|
let source_stub = source.as_functor_stub();
|
|
|
|
let stub = functor!(
|
|
atom!("existence_error"),
|
|
[atom_as_cell((atom!("source_sink"))), functor(source_stub)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
ExistenceError::SourceSink(culprit) => {
|
|
let stub = functor!(
|
|
atom!("existence_error"),
|
|
[atom_as_cell((atom!("source_sink"))), cell(culprit)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
ExistenceError::Stream(culprit) => {
|
|
let stub = functor!(
|
|
atom!("existence_error"),
|
|
[atom_as_cell((atom!("stream"))), cell(culprit)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
ExistenceError::Process(culprit) => {
|
|
let stub = functor!(
|
|
atom!("existence_error"),
|
|
[atom_as_cell((atom!("process"))), cell(culprit)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
ExistenceError::FfiFunction(name, arity) => {
|
|
let culprit = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]);
|
|
let stub = functor!(
|
|
atom!("existence_error"),
|
|
[atom_as_cell((atom!("ffi_function"))), functor(culprit)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
ExistenceError::FfiStructConstructor(name, arity) => {
|
|
let culprit = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]);
|
|
let stub = functor!(
|
|
atom!("existence_error"),
|
|
[
|
|
atom_as_cell((atom!("ffi_struct_constructor"))),
|
|
functor(culprit)
|
|
]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
ExistenceError::FfiStructType(atom) => {
|
|
let stub = functor!(
|
|
atom!("existence_error"),
|
|
[atom_as_cell((atom!("ffi_struct_type"))), atom_as_cell(atom)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) fn directive_error(&mut self, err: DirectiveError) -> MachineError {
|
|
match err {
|
|
DirectiveError::ExpectedDirective(_term) => self.domain_error(
|
|
DomainErrorType::Directive,
|
|
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
|
|
),
|
|
DirectiveError::InvalidDirective(name, arity) => {
|
|
self.domain_error(DomainErrorType::Directive, functor_stub(name, arity))
|
|
}
|
|
DirectiveError::InvalidOpDeclNameType(_term) => self.type_error(
|
|
ValidType::List,
|
|
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
|
|
),
|
|
DirectiveError::InvalidOpDeclSpecDomain(_term) => self.domain_error(
|
|
DomainErrorType::OperatorSpecifier,
|
|
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
|
|
),
|
|
DirectiveError::InvalidOpDeclSpecValue(atom) => {
|
|
self.domain_error(DomainErrorType::OperatorSpecifier, atom_as_cell!(atom))
|
|
}
|
|
DirectiveError::InvalidOpDeclPrecType(_term) => self.type_error(
|
|
ValidType::Integer,
|
|
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
|
|
),
|
|
DirectiveError::InvalidOpDeclPrecDomain(num) => {
|
|
self.domain_error(DomainErrorType::OperatorPriority, fixnum_as_cell!(num))
|
|
}
|
|
DirectiveError::ShallNotCreate(atom) => {
|
|
self.permission_error(Permission::Create, atom!("operator"), atom)
|
|
}
|
|
DirectiveError::ShallNotModify(atom) => {
|
|
self.permission_error(Permission::Modify, atom!("operator"), atom)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) fn permission_error<T: PermissionError>(
|
|
&mut self,
|
|
err: Permission,
|
|
index_atom: Atom,
|
|
culprit: T,
|
|
) -> MachineError {
|
|
culprit.permission_error(self, index_atom, err)
|
|
}
|
|
|
|
pub(super) fn evaluable_error(&mut self, name: Atom, arity: usize) -> MachineError {
|
|
let evaluable_stub = functor_stub(name, arity);
|
|
evaluable_stub.type_error(self, ValidType::Evaluable)
|
|
}
|
|
|
|
fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError {
|
|
match err {
|
|
ArithmeticError::NonEvaluableFunctor(cell, arity) => {
|
|
let culprit = functor!(atom!("/"), [literal(cell), fixnum(arity)]);
|
|
self.type_error(ValidType::Evaluable, culprit)
|
|
}
|
|
ArithmeticError::UninstantiatedVar => self.instantiation_error(),
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
pub(super) fn domain_error<T: DomainError>(
|
|
&mut self,
|
|
error: DomainErrorType,
|
|
culprit: T,
|
|
) -> MachineError {
|
|
culprit.domain_error(self, error)
|
|
}
|
|
|
|
pub(super) fn instantiation_error(&mut self) -> MachineError {
|
|
let stub = functor!(atom!("instantiation_error"));
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
|
|
pub(super) fn session_error(&mut self, err: SessionError) -> MachineError {
|
|
match err {
|
|
SessionError::CannotOverwriteBuiltIn(key) => self.permission_error(
|
|
Permission::Modify,
|
|
atom!("static_procedure"),
|
|
functor_stub(key.0, key.1),
|
|
),
|
|
SessionError::CannotOverwriteStaticProcedure(key) => self.permission_error(
|
|
Permission::Modify,
|
|
atom!("static_procedure"),
|
|
functor_stub(key.0, key.1),
|
|
),
|
|
SessionError::CannotOverwriteBuiltInModule(module) => {
|
|
self.permission_error(Permission::Modify, atom!("static_module"), module)
|
|
}
|
|
SessionError::ExistenceError(err) => self.existence_error(err),
|
|
SessionError::ModuleDoesNotContainExport(module_name, key) => {
|
|
let functor_stub = functor_stub(key.0, key.1);
|
|
|
|
let stub = functor!(
|
|
atom!("module_does_not_contain_claimed_export"),
|
|
[atom_as_cell(module_name), functor(functor_stub)]
|
|
);
|
|
|
|
self.permission_error(Permission::Access, atom!("private_procedure"), stub)
|
|
}
|
|
SessionError::ModuleCannotImportSelf(module_name) => {
|
|
let error_atom = atom!("module_cannot_import_self");
|
|
|
|
self.permission_error(
|
|
Permission::Modify,
|
|
atom!("module"),
|
|
functor!(error_atom, [atom_as_cell(module_name)]),
|
|
)
|
|
}
|
|
SessionError::NamelessEntry => {
|
|
let error_atom = atom!("nameless_procedure");
|
|
self.permission_error(
|
|
Permission::Create,
|
|
atom!("static_procedure"),
|
|
functor!(error_atom),
|
|
)
|
|
}
|
|
SessionError::OpIsInfixAndPostFix(op) => {
|
|
self.permission_error(Permission::Create, atom!("operator"), functor!(op))
|
|
}
|
|
SessionError::CompilationError(CompilationError::ExceededMaxArity) => {
|
|
self.representation_error(RepFlag::MaxArity)
|
|
}
|
|
SessionError::CompilationError(err) => self.syntax_error(err),
|
|
SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
|
|
let stub = functor!(
|
|
atom!(":"),
|
|
[
|
|
atom_as_cell((compilation_target.module_name())),
|
|
functor((key.0), [fixnum((key.1))])
|
|
]
|
|
);
|
|
|
|
self.permission_error(
|
|
Permission::Modify,
|
|
atom!("not_declared_multifile_or_discontiguous"),
|
|
stub,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) fn syntax_error<E: Into<CompilationError>>(&mut self, err: E) -> MachineError {
|
|
let err = err.into();
|
|
|
|
if let CompilationError::Arithmetic(err) = err {
|
|
return self.arithmetic_error(err);
|
|
}
|
|
|
|
if let CompilationError::InvalidDirective(err) = err {
|
|
return self.directive_error(err);
|
|
}
|
|
|
|
let location = err.line_and_col_num();
|
|
let stub = err.as_functor();
|
|
|
|
let stub = functor!(atom!("syntax_error"), [functor(stub)]);
|
|
|
|
MachineError { stub, location }
|
|
}
|
|
|
|
pub(super) fn representation_error(&self, flag: RepFlag) -> MachineError {
|
|
let stub = functor!(
|
|
atom!("representation_error"),
|
|
[atom_as_cell((flag.as_atom()))]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code)] // not used when all features are enabled
|
|
pub(super) fn missing_feature_error(&self, feature: Atom) -> MachineError {
|
|
let stub = functor!(
|
|
atom!("representation_error"),
|
|
[functor(
|
|
(functor!(atom!("feature"), [atom_as_cell((feature))]))
|
|
)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
|
|
pub(super) fn unreachable_error(&self) -> MachineError {
|
|
let stub = functor!(atom!("system_error"));
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "ffi")]
|
|
pub(super) fn ffi_error(&mut self, err: FfiError) -> MachineError {
|
|
match err {
|
|
FfiError::ValueCast(expected, actual) => {
|
|
let stub = functor!(
|
|
atom!("domain_error"),
|
|
[atom_as_cell(expected), atom_as_cell(actual)]
|
|
);
|
|
|
|
MachineError {
|
|
stub,
|
|
location: None,
|
|
}
|
|
}
|
|
FfiError::ValueOutOfRange(domain, culprit) => self.domain_error(domain, culprit),
|
|
FfiError::FunctionNotFound(name, arity) => {
|
|
self.existence_error(ExistenceError::FfiFunction(name, arity))
|
|
}
|
|
FfiError::StructNotFound(name) => {
|
|
self.existence_error(ExistenceError::FfiStructType(name))
|
|
}
|
|
FfiError::ArgCountMismatch {
|
|
name,
|
|
kind,
|
|
expected: _,
|
|
got,
|
|
} => match kind {
|
|
ffi::ArgCountMismatchKind::Function => {
|
|
self.existence_error(ExistenceError::FfiFunction(name, got))
|
|
}
|
|
ffi::ArgCountMismatchKind::Struct => {
|
|
self.existence_error(ExistenceError::FfiStructConstructor(name, got))
|
|
}
|
|
},
|
|
FfiError::AllocationFailed => MachineError {
|
|
stub: functor!(atom!("resource_error"), [atom_as_cell((atom!("heap")))]),
|
|
location: None,
|
|
},
|
|
FfiError::LayoutError => self.representation_error(RepFlag::FfiLayout),
|
|
FfiError::UnsupportedTypedef => self.representation_error(RepFlag::FfiLayout),
|
|
FfiError::UnsupportedAbi => self.representation_error(RepFlag::FfiAbi),
|
|
FfiError::VoidArgumentType => self.domain_error(
|
|
DomainErrorType::FfiArgumentType,
|
|
atom_as_cell!(atom!("void")),
|
|
),
|
|
FfiError::CStrFieldType => self.domain_error(
|
|
DomainErrorType::NonCStrFfiArgumentType,
|
|
atom_as_cell!(atom!("cstr")),
|
|
),
|
|
FfiError::NullPtr => self.domain_error(
|
|
DomainErrorType::NonNullPtr,
|
|
fixnum_as_cell!(Fixnum::build_with(0)),
|
|
),
|
|
}
|
|
}
|
|
|
|
pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub {
|
|
if let Some((line_num, _col_num)) = err.location {
|
|
functor!(
|
|
atom!("error"),
|
|
[
|
|
functor((err.stub)),
|
|
functor(
|
|
(atom!(":")),
|
|
[functor(src), number(line_num, (&mut self.arena))]
|
|
)
|
|
]
|
|
)
|
|
} else {
|
|
functor!(atom!("error"), [functor((err.stub)), functor(src)])
|
|
}
|
|
}
|
|
|
|
// throw an error pre-allocated in the heap
|
|
pub(super) fn throw_resource_error(&mut self, err: AllocError) {
|
|
self.registers[1] = str_loc_as_cell!(err.resource_error_offset(&mut self.heap));
|
|
self.set_ball();
|
|
self.unwind_stack();
|
|
}
|
|
|
|
pub(super) fn throw_exception(&mut self, err: MachineStub) {
|
|
self.ball.boundary = 0;
|
|
self.ball.stub.truncate(0);
|
|
|
|
let mut writer = Heap::functor_writer(err);
|
|
|
|
self.registers[1] = match writer(&mut self.heap) {
|
|
Ok(loc) => loc,
|
|
Err(err) => {
|
|
self.throw_resource_error(err);
|
|
return;
|
|
}
|
|
};
|
|
|
|
self.set_ball();
|
|
self.unwind_stack();
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum CompilationError {
|
|
Arithmetic(ArithmeticError),
|
|
ParserError(ParserError),
|
|
ExceededMaxArity,
|
|
InadmissibleFact,
|
|
InadmissibleQueryTerm,
|
|
InvalidDirective(DirectiveError),
|
|
InvalidMetaPredicateDecl,
|
|
InvalidModuleDecl,
|
|
InvalidModuleExport,
|
|
InvalidRuleHead,
|
|
InvalidUseModuleDecl,
|
|
InvalidModuleResolution(Atom),
|
|
FiniteMemoryInHeap(usize),
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum DirectiveError {
|
|
ExpectedDirective(Term),
|
|
InvalidDirective(Atom, usize /* arity */),
|
|
InvalidOpDeclNameType(Term),
|
|
InvalidOpDeclSpecDomain(Term),
|
|
InvalidOpDeclSpecValue(Atom),
|
|
InvalidOpDeclPrecType(Term),
|
|
InvalidOpDeclPrecDomain(Fixnum),
|
|
ShallNotCreate(Atom),
|
|
ShallNotModify(Atom),
|
|
}
|
|
|
|
impl From<ArithmeticError> for CompilationError {
|
|
#[inline]
|
|
fn from(err: ArithmeticError) -> CompilationError {
|
|
CompilationError::Arithmetic(err)
|
|
}
|
|
}
|
|
|
|
impl From<ParserError> for CompilationError {
|
|
#[inline]
|
|
fn from(err: ParserError) -> CompilationError {
|
|
CompilationError::ParserError(err)
|
|
}
|
|
}
|
|
|
|
impl CompilationError {
|
|
pub(crate) fn line_and_col_num(&self) -> Option<(usize, usize)> {
|
|
match self {
|
|
CompilationError::ParserError(err) => err.line_and_col_num(),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn as_functor(&self) -> MachineStub {
|
|
match self {
|
|
CompilationError::Arithmetic(..) => {
|
|
functor!(atom!("arithmetic_error"))
|
|
}
|
|
CompilationError::ExceededMaxArity => {
|
|
functor!(atom!("exceeded_max_arity"))
|
|
}
|
|
CompilationError::InadmissibleFact => {
|
|
functor!(atom!("inadmissible_fact"))
|
|
}
|
|
CompilationError::InadmissibleQueryTerm => {
|
|
functor!(atom!("inadmissible_query_term"))
|
|
}
|
|
CompilationError::InvalidDirective(_) => {
|
|
functor!(atom!("directive_error"))
|
|
}
|
|
CompilationError::InvalidMetaPredicateDecl => {
|
|
functor!(atom!("invalid_meta_predicate_decl"))
|
|
}
|
|
CompilationError::InvalidModuleDecl => {
|
|
functor!(atom!("invalid_module_declaration"))
|
|
}
|
|
CompilationError::InvalidModuleExport => {
|
|
functor!(atom!("invalid_module_export"))
|
|
}
|
|
&CompilationError::InvalidModuleResolution(module_name) => {
|
|
functor!(atom!("no_such_module"), [atom_as_cell(module_name)])
|
|
}
|
|
CompilationError::InvalidRuleHead => {
|
|
functor!(atom!("invalid_head_of_rule")) // TODO: type_error(callable, _).
|
|
}
|
|
CompilationError::InvalidUseModuleDecl => {
|
|
functor!(atom!("invalid_use_module_declaration"))
|
|
}
|
|
CompilationError::ParserError(ref err) => {
|
|
functor!(err.as_atom())
|
|
}
|
|
CompilationError::FiniteMemoryInHeap(h) => {
|
|
vec![FunctorElement::AbsoluteCell(str_loc_as_cell!(*h))]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub(crate) enum Permission {
|
|
Access,
|
|
Create,
|
|
InputStream,
|
|
Modify,
|
|
Open,
|
|
OutputStream,
|
|
Reposition,
|
|
}
|
|
|
|
impl Permission {
|
|
#[inline]
|
|
pub(crate) fn as_atom(self) -> Atom {
|
|
match self {
|
|
Permission::Access => atom!("access"),
|
|
Permission::Create => atom!("create"),
|
|
Permission::InputStream => atom!("input"),
|
|
Permission::Modify => atom!("modify"),
|
|
Permission::Open => atom!("open"),
|
|
Permission::OutputStream => atom!("output"),
|
|
Permission::Reposition => atom!("reposition"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub(crate) enum DomainErrorType {
|
|
IOMode,
|
|
NotLessThanZero,
|
|
Order,
|
|
SourceSink,
|
|
Stream,
|
|
StreamOrAlias,
|
|
OperatorSpecifier,
|
|
OperatorPriority,
|
|
Directive,
|
|
Allocator,
|
|
FfiStruct,
|
|
ZeroOrOne,
|
|
NonNullPtr,
|
|
PtrLike,
|
|
F64,
|
|
FfiArgument,
|
|
FfiArgumentType,
|
|
FixedSizedInt,
|
|
NonCStrFfiArgumentType,
|
|
}
|
|
|
|
impl DomainErrorType {
|
|
pub(crate) fn as_atom(self) -> Atom {
|
|
match self {
|
|
DomainErrorType::IOMode => atom!("io_mode"),
|
|
DomainErrorType::NotLessThanZero => atom!("not_less_than_zero"),
|
|
DomainErrorType::Order => atom!("order"),
|
|
DomainErrorType::SourceSink => atom!("source_sink"),
|
|
DomainErrorType::Stream => atom!("stream"),
|
|
DomainErrorType::StreamOrAlias => atom!("stream_or_alias"),
|
|
DomainErrorType::OperatorSpecifier => atom!("operator_specifier"),
|
|
DomainErrorType::OperatorPriority => atom!("operator_priority"),
|
|
DomainErrorType::Directive => atom!("directive"),
|
|
DomainErrorType::Allocator => atom!("allocator"),
|
|
DomainErrorType::ZeroOrOne => atom!("zero_or_one"),
|
|
DomainErrorType::FfiStruct => atom!("ffi_struct"),
|
|
DomainErrorType::NonNullPtr => atom!("non_null_pointer"),
|
|
DomainErrorType::PtrLike => atom!("pointer_like"),
|
|
DomainErrorType::F64 => atom!("f64"),
|
|
DomainErrorType::FfiArgument => atom!("ffi_argument"),
|
|
DomainErrorType::FfiArgumentType => atom!("ffi_argument_type"),
|
|
DomainErrorType::FixedSizedInt => atom!("fixed_sized_int"),
|
|
DomainErrorType::NonCStrFfiArgumentType => atom!("non_cstr_ffi_argument_type"),
|
|
}
|
|
}
|
|
}
|
|
|
|
// from 7.12.2 f) of 13211-1:1995
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub(crate) enum RepFlag {
|
|
Character,
|
|
CharacterCode,
|
|
InCharacterCode,
|
|
MaxArity,
|
|
// MaxInteger,
|
|
// MinInteger,
|
|
Term,
|
|
FfiLayout,
|
|
FfiAbi,
|
|
}
|
|
|
|
impl RepFlag {
|
|
pub(crate) fn as_atom(self) -> Atom {
|
|
match self {
|
|
RepFlag::Character => atom!("character"),
|
|
RepFlag::CharacterCode => atom!("character_code"),
|
|
RepFlag::InCharacterCode => atom!("in_character_code"),
|
|
RepFlag::MaxArity => atom!("max_arity"),
|
|
RepFlag::Term => atom!("term"),
|
|
// RepFlag::MaxInteger => atom!("max_integer"),
|
|
// RepFlag::MinInteger => atom!("min_integer"),
|
|
RepFlag::FfiLayout => atom!("ffi_layout"),
|
|
RepFlag::FfiAbi => atom!("ffi_abi"),
|
|
}
|
|
}
|
|
}
|
|
|
|
// from 7.12.2 g) of 13211-1:1995
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub enum EvalError {
|
|
FloatOverflow,
|
|
Undefined,
|
|
// Underflow,
|
|
ZeroDivisor,
|
|
}
|
|
|
|
impl EvalError {
|
|
pub(crate) fn as_atom(self) -> Atom {
|
|
match self {
|
|
EvalError::FloatOverflow => atom!("float_overflow"),
|
|
EvalError::Undefined => atom!("undefined"),
|
|
// EvalError::FloatUnderflow => atom!("underflow"),
|
|
EvalError::ZeroDivisor => atom!("zero_divisor"),
|
|
}
|
|
}
|
|
}
|
|
|
|
// used by '$skip_max_list'.
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum CycleSearchResult {
|
|
Cyclic {
|
|
lambda: usize,
|
|
}, // number of steps
|
|
EmptyList,
|
|
NotList {
|
|
num_steps: usize,
|
|
heap_loc: HeapCellValue,
|
|
},
|
|
PartialList {
|
|
num_steps: usize,
|
|
heap_loc: HeapCellValue,
|
|
},
|
|
ProperList {
|
|
num_steps: usize,
|
|
},
|
|
PStrLocation {
|
|
num_steps: usize,
|
|
pstr_loc: HeapCellValue,
|
|
},
|
|
UntouchedList {
|
|
num_steps: usize,
|
|
list_loc: usize,
|
|
},
|
|
}
|
|
|
|
impl MachineState {
|
|
// see 8.4.3 of Draft Technical Corrigendum 2.
|
|
pub(super) fn check_sort_errors(&mut self) -> CallResult {
|
|
let stub_gen = || functor_stub(atom!("sort"), 2);
|
|
|
|
let list = self.store(self.deref(self.registers[1]));
|
|
let sorted = self.store(self.deref(self.registers[2]));
|
|
|
|
match BrentAlgState::detect_cycles(&self.heap, list) {
|
|
CycleSearchResult::PartialList { .. } => {
|
|
let err = self.instantiation_error();
|
|
return Err(self.error_form(err, stub_gen()));
|
|
}
|
|
CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } => {
|
|
let err = self.type_error(ValidType::List, list);
|
|
return Err(self.error_form(err, stub_gen()));
|
|
}
|
|
_ => {}
|
|
};
|
|
|
|
match BrentAlgState::detect_cycles(&self.heap, sorted) {
|
|
CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. }
|
|
if !sorted.is_var() =>
|
|
{
|
|
let err = self.type_error(ValidType::List, sorted);
|
|
Err(self.error_form(err, stub_gen()))
|
|
}
|
|
_ => Ok(()),
|
|
}
|
|
}
|
|
|
|
fn check_for_list_pairs(&mut self, mut list: HeapCellValue) -> CallResult {
|
|
let stub_gen = || functor_stub(atom!("keysort"), 2);
|
|
|
|
match BrentAlgState::detect_cycles(&self.heap, list) {
|
|
CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. }
|
|
if !list.is_var() =>
|
|
{
|
|
let err = self.type_error(ValidType::List, list);
|
|
Err(self.error_form(err, stub_gen()))
|
|
}
|
|
_ => {
|
|
loop {
|
|
read_heap_cell!(self.store(self.deref(list)),
|
|
(HeapCellValueTag::Lis, l) => {
|
|
let mut new_l = l;
|
|
|
|
loop {
|
|
read_heap_cell!(self.heap[new_l],
|
|
(HeapCellValueTag::Str, s) => {
|
|
new_l = s;
|
|
}
|
|
(HeapCellValueTag::Atom, (name, arity)) => {
|
|
if name == atom!("-") && arity == 2 {
|
|
break;
|
|
} else {
|
|
let err = self.type_error(
|
|
ValidType::Pair,
|
|
list_loc_as_cell!(l),
|
|
);
|
|
|
|
return Err(self.error_form(err, stub_gen()));
|
|
}
|
|
}
|
|
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar) => {
|
|
break;
|
|
}
|
|
_ => {
|
|
let err = self.type_error(
|
|
ValidType::Pair,
|
|
list_loc_as_cell!(l),
|
|
);
|
|
|
|
return Err(self.error_form(err, stub_gen()));
|
|
}
|
|
);
|
|
}
|
|
|
|
list = heap_loc_as_cell!(l+1);
|
|
}
|
|
_ => {
|
|
break;
|
|
}
|
|
);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
|
|
// see 8.4.4 of Draft Technical Corrigendum 2.
|
|
pub(super) fn check_keysort_errors(&mut self) -> CallResult {
|
|
let stub_gen = || functor_stub(atom!("keysort"), 2);
|
|
|
|
let pairs = self.store(self.deref(self[temp_v!(1)]));
|
|
let sorted = self.store(self.deref(self[temp_v!(2)]));
|
|
|
|
match BrentAlgState::detect_cycles(&self.heap, pairs) {
|
|
CycleSearchResult::PartialList { .. } => {
|
|
let err = self.instantiation_error();
|
|
Err(self.error_form(err, stub_gen()))
|
|
}
|
|
CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } => {
|
|
let err = self.type_error(ValidType::List, pairs);
|
|
Err(self.error_form(err, stub_gen()))
|
|
}
|
|
_ => Ok(()),
|
|
}?;
|
|
|
|
self.check_for_list_pairs(sorted)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum ExistenceError {
|
|
Module(Atom),
|
|
ModuleSource(ModuleSource),
|
|
Procedure(Atom, usize),
|
|
QualifiedProcedure {
|
|
module_name: Atom,
|
|
name: Atom,
|
|
arity: usize,
|
|
},
|
|
SourceSink(HeapCellValue),
|
|
Stream(HeapCellValue),
|
|
Process(HeapCellValue),
|
|
FfiFunction(Atom, usize),
|
|
FfiStructConstructor(Atom, usize),
|
|
FfiStructType(Atom),
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum SessionError {
|
|
CompilationError(CompilationError),
|
|
CannotOverwriteBuiltIn(PredicateKey),
|
|
CannotOverwriteBuiltInModule(Atom),
|
|
CannotOverwriteStaticProcedure(PredicateKey),
|
|
ExistenceError(ExistenceError),
|
|
ModuleDoesNotContainExport(Atom, PredicateKey),
|
|
ModuleCannotImportSelf(Atom),
|
|
NamelessEntry,
|
|
OpIsInfixAndPostFix(Atom),
|
|
PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey),
|
|
}
|
|
|
|
impl From<std::io::Error> for SessionError {
|
|
#[inline]
|
|
fn from(err: std::io::Error) -> SessionError {
|
|
SessionError::from(ParserError::from(err))
|
|
}
|
|
}
|
|
|
|
impl From<ParserError> for SessionError {
|
|
#[inline]
|
|
fn from(err: ParserError) -> Self {
|
|
SessionError::CompilationError(CompilationError::from(err))
|
|
}
|
|
}
|
|
|
|
impl From<CompilationError> for SessionError {
|
|
#[inline]
|
|
fn from(err: CompilationError) -> Self {
|
|
SessionError::CompilationError(err)
|
|
}
|
|
}
|