scryer_prolog/machine/
machine_errors.rs

1use crate::arena::*;
2use crate::atom_table::*;
3use crate::parser::ast::*;
4
5#[cfg(feature = "ffi")]
6use crate::ffi::FFIError;
7use crate::forms::*;
8use crate::machine::heap::*;
9use crate::machine::loader::CompilationTarget;
10use crate::machine::machine_state::*;
11use crate::machine::streams::*;
12use crate::machine::system_calls::BrentAlgState;
13use crate::types::*;
14
15pub type MachineStub = Vec<HeapCellValue>;
16pub type MachineStubGen = Box<dyn Fn(&mut MachineState) -> MachineStub>;
17
18#[derive(Debug, Clone, Copy)]
19enum ErrorProvenance {
20    Constructed, // if constructed, offset the addresses.
21    Received,    // otherwise, preserve the addresses.
22}
23
24#[derive(Debug)]
25pub(crate) struct MachineError {
26    stub: MachineStub,
27    location: Option<(usize, usize)>, // line_num, col_num
28    from: ErrorProvenance,
29}
30
31// from 7.12.2 b) of 13211-1:1995
32#[derive(Debug, Clone, Copy)]
33pub(crate) enum ValidType {
34    Atom,
35    Atomic,
36    //    Boolean,
37    Byte,
38    Callable,
39    Character,
40    Compound,
41    Evaluable,
42    Float,
43    InByte,
44    InCharacter,
45    Integer,
46    List,
47    #[allow(unused)]
48    Number,
49    Pair,
50    //    PredicateIndicator,
51    //    Variable
52    TcpListener,
53}
54
55impl ValidType {
56    pub(crate) fn as_atom(self) -> Atom {
57        match self {
58            ValidType::Atom => atom!("atom"),
59            ValidType::Atomic => atom!("atomic"),
60            //            ValidType::Boolean => atom!("boolean"),
61            ValidType::Byte => atom!("byte"),
62            ValidType::Callable => atom!("callable"),
63            ValidType::Character => atom!("character"),
64            ValidType::Compound => atom!("compound"),
65            ValidType::Evaluable => atom!("evaluable"),
66            ValidType::Float => atom!("float"),
67            ValidType::InByte => atom!("in_byte"),
68            ValidType::InCharacter => atom!("in_character"),
69            ValidType::Integer => atom!("integer"),
70            ValidType::List => atom!("list"),
71            ValidType::Number => atom!("number"),
72            ValidType::Pair => atom!("pair"),
73            //            ValidType::PredicateIndicator => atom!("predicate_indicator"),
74            //            ValidType::Variable => atom!("variable")
75            ValidType::TcpListener => atom!("tcp_listener"),
76        }
77    }
78}
79
80#[derive(Debug, Clone, Copy)]
81pub(crate) enum ResourceError {
82    FiniteMemory(HeapCellValue),
83    OutOfFiles,
84}
85
86pub(crate) trait TypeError {
87    fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError;
88}
89
90impl TypeError for HeapCellValue {
91    fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
92        let stub = functor!(
93            atom!("type_error"),
94            [atom(valid_type.as_atom()), cell(self)]
95        );
96
97        MachineError {
98            stub,
99            location: None,
100            from: ErrorProvenance::Received,
101        }
102    }
103}
104
105impl TypeError for MachineStub {
106    fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
107        let stub = functor!(
108            atom!("type_error"),
109            [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)],
110            [self]
111        );
112
113        MachineError {
114            stub,
115            location: None,
116            from: ErrorProvenance::Constructed,
117        }
118    }
119}
120
121impl TypeError for FunctorStub {
122    fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
123        let stub = functor!(
124            atom!("type_error"),
125            [atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)],
126            [self]
127        );
128
129        MachineError {
130            stub,
131            location: None,
132            from: ErrorProvenance::Constructed,
133        }
134    }
135}
136
137impl TypeError for Number {
138    fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
139        let stub = functor!(
140            atom!("type_error"),
141            [
142                atom(valid_type.as_atom()),
143                number(&mut machine_st.arena, self)
144            ]
145        );
146
147        MachineError {
148            stub,
149            location: None,
150            from: ErrorProvenance::Received,
151        }
152    }
153}
154
155pub(crate) trait PermissionError {
156    fn permission_error(
157        self,
158        machine_st: &mut MachineState,
159        index_atom: Atom,
160        perm: Permission,
161    ) -> MachineError;
162}
163
164impl PermissionError for Atom {
165    fn permission_error(
166        self,
167        _machine_st: &mut MachineState,
168        index_atom: Atom,
169        perm: Permission,
170    ) -> MachineError {
171        let stub = functor!(
172            atom!("permission_error"),
173            [
174                atom(perm.as_atom()),
175                atom(index_atom),
176                cell(atom_as_cell!(self))
177            ]
178        );
179
180        MachineError {
181            stub,
182            location: None,
183            from: ErrorProvenance::Received,
184        }
185    }
186}
187
188impl PermissionError for HeapCellValue {
189    fn permission_error(
190        self,
191        _machine_st: &mut MachineState,
192        index_atom: Atom,
193        perm: Permission,
194    ) -> MachineError {
195        let cell = read_heap_cell!(self,
196            (HeapCellValueTag::Cons, ptr) => {
197                match_untyped_arena_ptr!(ptr,
198                    (ArenaHeaderTag::Stream, stream) => {
199                        if let Some(alias) = stream.options().get_alias() {
200                            atom_as_cell!(alias)
201                        } else {
202                            self
203                        }
204                    }
205                    _ => {
206                        self
207                    }
208                )
209            }
210            _ => {
211                self
212            }
213        );
214
215        let stub = functor!(
216            atom!("permission_error"),
217            [atom(perm.as_atom()), atom(index_atom), cell(cell)]
218        );
219
220        MachineError {
221            stub,
222            location: None,
223            from: ErrorProvenance::Received,
224        }
225    }
226}
227
228impl PermissionError for MachineStub {
229    fn permission_error(
230        self,
231        machine_st: &mut MachineState,
232        index_atom: Atom,
233        perm: Permission,
234    ) -> MachineError {
235        let stub = functor!(
236            atom!("permission_error"),
237            [
238                atom(perm.as_atom()),
239                atom(index_atom),
240                str(machine_st.heap.len(), 0)
241            ],
242            [self]
243        );
244
245        MachineError {
246            stub,
247            location: None,
248            from: ErrorProvenance::Constructed,
249        }
250    }
251}
252
253pub(super) trait DomainError {
254    fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError;
255}
256
257impl DomainError for HeapCellValue {
258    fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
259        let stub = functor!(atom!("domain_error"), [atom(error.as_atom()), cell(self)]);
260
261        MachineError {
262            stub,
263            location: None,
264            from: ErrorProvenance::Received,
265        }
266    }
267}
268
269impl DomainError for Number {
270    fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
271        let stub = functor!(
272            atom!("domain_error"),
273            [atom(error.as_atom()), number(&mut machine_st.arena, self)]
274        );
275
276        MachineError {
277            stub,
278            location: None,
279            from: ErrorProvenance::Received,
280        }
281    }
282}
283
284pub(super) type FunctorStub = [HeapCellValue; 3];
285
286#[inline(always)]
287pub(super) fn functor_stub(name: Atom, arity: usize) -> FunctorStub {
288    [
289        atom_as_cell!(atom!("/"), 2),
290        atom_as_cell!(name),
291        fixnum_as_cell!(Fixnum::build_with(arity as i64)),
292    ]
293}
294
295impl MachineState {
296    #[inline]
297    pub(super) fn interrupt_error(&mut self) -> MachineError {
298        let stub = functor!(atom!("$interrupt_thrown"));
299
300        MachineError {
301            stub,
302            location: None,
303            from: ErrorProvenance::Received,
304        }
305    }
306
307    pub(super) fn evaluation_error(&mut self, eval_error: EvalError) -> MachineError {
308        let stub = functor!(atom!("evaluation_error"), [atom(eval_error.as_atom())]);
309
310        MachineError {
311            stub,
312            location: None,
313            from: ErrorProvenance::Received,
314        }
315    }
316
317    pub(super) fn resource_error(&mut self, err: ResourceError) -> MachineError {
318        let stub = match err {
319            ResourceError::FiniteMemory(size_requested) => {
320                functor!(
321                    atom!("resource_error"),
322                    [atom(atom!("finite_memory")), cell(size_requested)]
323                )
324            }
325            ResourceError::OutOfFiles => {
326                functor!(atom!("resource_error"), [atom(atom!("file_descriptors"))])
327            }
328        };
329
330        MachineError {
331            stub,
332            location: None,
333            from: ErrorProvenance::Received,
334        }
335    }
336
337    pub(super) fn type_error<T: TypeError>(
338        &mut self,
339        valid_type: ValidType,
340        culprit: T,
341    ) -> MachineError {
342        culprit.type_error(self, valid_type)
343    }
344
345    pub(super) fn existence_error(&mut self, err: ExistenceError) -> MachineError {
346        match err {
347            ExistenceError::Module(name) => {
348                let stub = functor!(
349                    atom!("existence_error"),
350                    [atom(atom!("source_sink")), atom(name)]
351                );
352
353                MachineError {
354                    stub,
355                    location: None,
356                    from: ErrorProvenance::Received,
357                }
358            }
359            ExistenceError::QualifiedProcedure {
360                module_name,
361                name,
362                arity,
363            } => {
364                let h = self.heap.len();
365
366                let ind_stub = functor!(atom!("/"), [atom(name), fixnum(arity)]);
367                let res_stub = functor!(atom!(":"), [atom(module_name), str(h + 3, 0)], [ind_stub]);
368
369                let stub = functor!(
370                    atom!("existence_error"),
371                    [atom(atom!("procedure")), str(h, 0)],
372                    [res_stub]
373                );
374
375                MachineError {
376                    stub,
377                    location: None,
378                    from: ErrorProvenance::Constructed,
379                }
380            }
381            ExistenceError::Procedure(name, arity) => {
382                let culprit = functor!(atom!("/"), [atom(name), fixnum(arity)]);
383
384                let stub = functor!(
385                    atom!("existence_error"),
386                    [atom(atom!("procedure")), str(self.heap.len(), 0)],
387                    [culprit]
388                );
389
390                MachineError {
391                    stub,
392                    location: None,
393                    from: ErrorProvenance::Constructed,
394                }
395            }
396            ExistenceError::ModuleSource(source) => {
397                let source_stub = source.as_functor_stub();
398
399                let stub = functor!(
400                    atom!("existence_error"),
401                    [atom(atom!("source_sink")), str(self.heap.len(), 0)],
402                    [source_stub]
403                );
404
405                MachineError {
406                    stub,
407                    location: None,
408                    from: ErrorProvenance::Constructed,
409                }
410            }
411            ExistenceError::SourceSink(culprit) => {
412                let stub = functor!(
413                    atom!("existence_error"),
414                    [atom(atom!("source_sink")), cell(culprit)]
415                );
416
417                MachineError {
418                    stub,
419                    location: None,
420                    from: ErrorProvenance::Received,
421                }
422            }
423            ExistenceError::Stream(culprit) => {
424                let stub = functor!(
425                    atom!("existence_error"),
426                    [atom(atom!("stream")), cell(culprit)]
427                );
428
429                MachineError {
430                    stub,
431                    location: None,
432                    from: ErrorProvenance::Received,
433                }
434            }
435        }
436    }
437
438    pub(super) fn permission_error<T: PermissionError>(
439        &mut self,
440        err: Permission,
441        index_atom: Atom,
442        culprit: T,
443    ) -> MachineError {
444        culprit.permission_error(self, index_atom, err)
445    }
446
447    pub(super) fn evaluable_error(&mut self, name: Atom, arity: usize) -> MachineError {
448        let evaluable_stub = functor_stub(name, arity);
449        evaluable_stub.type_error(self, ValidType::Evaluable)
450    }
451
452    fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError {
453        match err {
454            ArithmeticError::UninstantiatedVar => self.instantiation_error(),
455            ArithmeticError::NonEvaluableFunctor(literal, arity) => {
456                let culprit = functor!(atom!("/"), [literal(literal), fixnum(arity)]);
457
458                self.type_error(ValidType::Evaluable, culprit)
459            }
460        }
461    }
462
463    #[inline]
464    pub(super) fn domain_error<T: DomainError>(
465        &mut self,
466        error: DomainErrorType,
467        culprit: T,
468    ) -> MachineError {
469        culprit.domain_error(self, error)
470    }
471
472    pub(super) fn instantiation_error(&mut self) -> MachineError {
473        let stub = functor!(atom!("instantiation_error"));
474
475        MachineError {
476            stub,
477            location: None,
478            from: ErrorProvenance::Received,
479        }
480    }
481
482    pub(super) fn session_error(&mut self, err: SessionError) -> MachineError {
483        match err {
484            SessionError::CannotOverwriteBuiltIn(key) => self.permission_error(
485                Permission::Modify,
486                atom!("static_procedure"),
487                functor_stub(key.0, key.1)
488                    .into_iter()
489                    .collect::<MachineStub>(),
490            ),
491            SessionError::CannotOverwriteStaticProcedure(key) => self.permission_error(
492                Permission::Modify,
493                atom!("static_procedure"),
494                functor_stub(key.0, key.1)
495                    .into_iter()
496                    .collect::<MachineStub>(),
497            ),
498            SessionError::CannotOverwriteBuiltInModule(module) => {
499                self.permission_error(Permission::Modify, atom!("static_module"), module)
500            }
501            SessionError::ExistenceError(err) => self.existence_error(err),
502            SessionError::ModuleDoesNotContainExport(module_name, key) => {
503                let functor_stub = functor_stub(key.0, key.1);
504
505                let stub = functor!(
506                    atom!("module_does_not_contain_claimed_export"),
507                    [atom(module_name), str(self.heap.len() + 4, 0)],
508                    [functor_stub]
509                );
510
511                self.permission_error(Permission::Access, atom!("private_procedure"), stub)
512            }
513            SessionError::ModuleCannotImportSelf(module_name) => {
514                let error_atom = atom!("module_cannot_import_self");
515
516                self.permission_error(
517                    Permission::Modify,
518                    atom!("module"),
519                    functor!(error_atom, [atom(module_name)]),
520                )
521            }
522            SessionError::NamelessEntry => {
523                let error_atom = atom!("nameless_procedure");
524                self.permission_error(
525                    Permission::Create,
526                    atom!("static_procedure"),
527                    functor!(error_atom),
528                )
529            }
530            SessionError::OpIsInfixAndPostFix(op) => {
531                self.permission_error(Permission::Create, atom!("operator"), functor!(op))
532            }
533            SessionError::CompilationError(CompilationError::ExceededMaxArity) => {
534                self.representation_error(RepFlag::MaxArity)
535            }
536            SessionError::CompilationError(err) => self.syntax_error(err),
537            SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
538                let functor_stub = functor_stub(key.0, key.1);
539
540                let stub = functor!(
541                    atom!(":"),
542                    [
543                        atom(compilation_target.module_name()),
544                        str(self.heap.len() + 4, 0)
545                    ],
546                    [functor_stub]
547                );
548
549                self.permission_error(
550                    Permission::Modify,
551                    atom!("not_declared_multifile_or_discontiguous"),
552                    stub,
553                )
554            }
555            SessionError::QueryCannotBeDefinedAsFact => {
556                let error_atom = atom!("query_cannot_be_defined_as_fact");
557
558                self.permission_error(
559                    Permission::Create,
560                    atom!("static_procedure"),
561                    functor!(error_atom),
562                )
563            }
564        }
565    }
566
567    pub(super) fn syntax_error<E: Into<CompilationError>>(&mut self, err: E) -> MachineError {
568        let err = err.into();
569
570        if let CompilationError::Arithmetic(err) = err {
571            return self.arithmetic_error(err);
572        }
573
574        let location = err.line_and_col_num();
575        let stub = err.as_functor();
576
577        let stub = functor!(atom!("syntax_error"), [str(self.heap.len(), 0)], [stub]);
578
579        MachineError {
580            stub,
581            location,
582            from: ErrorProvenance::Constructed,
583        }
584    }
585
586    pub(super) fn representation_error(&mut self, flag: RepFlag) -> MachineError {
587        let stub = functor!(atom!("representation_error"), [atom(flag.as_atom())]);
588
589        MachineError {
590            stub,
591            location: None,
592            from: ErrorProvenance::Received,
593        }
594    }
595
596    #[cfg(feature = "ffi")]
597    pub(super) fn ffi_error(&mut self, err: FFIError) -> MachineError {
598        let error_atom = match err {
599            FFIError::ValueCast => atom!("value_cast"),
600            FFIError::ValueDontFit => atom!("value_dont_fit"),
601            FFIError::InvalidFFIType => atom!("invalid_ffi_type"),
602            FFIError::InvalidStructName => atom!("invalid_struct_name"),
603            FFIError::FunctionNotFound => atom!("function_not_found"),
604            FFIError::StructNotFound => atom!("struct_not_found"),
605        };
606        let stub = functor!(atom!("ffi_error"), [atom(error_atom)]);
607
608        MachineError {
609            stub,
610            location: None,
611            from: ErrorProvenance::Constructed,
612        }
613    }
614
615    pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub {
616        let h = self.heap.len();
617        let location = err.location;
618        let stub_addition_len = if err.len() == 1 {
619            0 // if err contains 1 cell, it can be inlined at stub[1].
620        } else {
621            err.len()
622        };
623
624        let mut stub = vec![
625            atom_as_cell!(atom!("error"), 2),
626            str_loc_as_cell!(h + 3),
627            str_loc_as_cell!(h + 3 + stub_addition_len),
628        ];
629
630        if stub_addition_len > 0 {
631            stub.extend(err.into_iter(3));
632        } else {
633            stub[1] = err.stub[0];
634        }
635
636        if let Some((line_num, _)) = location {
637            stub.push(atom_as_cell!(atom!(":"), 2));
638            stub.push(str_loc_as_cell!(h + 6 + stub_addition_len));
639            stub.push(integer_as_cell!(Number::arena_from(
640                line_num,
641                &mut self.arena
642            )));
643        }
644
645        stub.extend(src.iter());
646        stub
647    }
648
649    pub(super) fn throw_exception(&mut self, err: MachineStub) {
650        let h = self.heap.len();
651        let err_len = err.len();
652
653        self.ball.boundary = 0;
654        self.ball.stub.truncate(0);
655
656        self.heap.extend(err);
657
658        self.registers[1] = if err_len == 1 {
659            heap_loc_as_cell!(h)
660        } else {
661            str_loc_as_cell!(h)
662        };
663
664        self.set_ball();
665        self.unwind_stack();
666    }
667}
668
669impl MachineError {
670    fn into_iter(self, offset: usize) -> Box<dyn Iterator<Item = HeapCellValue>> {
671        match self.from {
672            ErrorProvenance::Constructed => {
673                Box::new(self.stub.into_iter().map(move |hcv| hcv + offset))
674            }
675            ErrorProvenance::Received => Box::new(self.stub.into_iter()),
676        }
677    }
678
679    fn len(&self) -> usize {
680        self.stub.len()
681    }
682}
683
684#[derive(Debug)]
685pub enum CompilationError {
686    Arithmetic(ArithmeticError),
687    ParserError(ParserError),
688    CannotParseCyclicTerm,
689    ExceededMaxArity,
690    ExpectedRel,
691    InadmissibleFact,
692    InadmissibleQueryTerm,
693    InconsistentEntry,
694    InvalidMetaPredicateDecl,
695    InvalidModuleDecl,
696    InvalidModuleExport,
697    InvalidRuleHead,
698    InvalidUseModuleDecl,
699    InvalidModuleResolution(Atom),
700    UnreadableTerm,
701}
702
703impl From<ArithmeticError> for CompilationError {
704    #[inline]
705    fn from(err: ArithmeticError) -> CompilationError {
706        CompilationError::Arithmetic(err)
707    }
708}
709
710impl From<ParserError> for CompilationError {
711    #[inline]
712    fn from(err: ParserError) -> CompilationError {
713        CompilationError::ParserError(err)
714    }
715}
716
717impl CompilationError {
718    pub(crate) fn line_and_col_num(&self) -> Option<(usize, usize)> {
719        match self {
720            CompilationError::ParserError(err) => err.line_and_col_num(),
721            _ => None,
722        }
723    }
724
725    pub(crate) fn as_functor(&self) -> MachineStub {
726        match self {
727            CompilationError::Arithmetic(..) => {
728                functor!(atom!("arithmetic_error"))
729            }
730            CompilationError::CannotParseCyclicTerm => {
731                functor!(atom!("cannot_parse_cyclic_term"))
732            }
733            CompilationError::ExceededMaxArity => {
734                functor!(atom!("exceeded_max_arity"))
735            }
736            CompilationError::ExpectedRel => {
737                functor!(atom!("expected_relation"))
738            }
739            CompilationError::InadmissibleFact => {
740                // TODO: type_error(callable, _).
741                functor!(atom!("inadmissible_fact"))
742            }
743            CompilationError::InadmissibleQueryTerm => {
744                // TODO: type_error(callable, _).
745                functor!(atom!("inadmissible_query_term"))
746            }
747            CompilationError::InconsistentEntry => {
748                functor!(atom!("inconsistent_entry"))
749            }
750            CompilationError::InvalidMetaPredicateDecl => {
751                functor!(atom!("invalid_meta_predicate_decl"))
752            }
753            CompilationError::InvalidModuleDecl => {
754                functor!(atom!("invalid_module_declaration"))
755            }
756            CompilationError::InvalidModuleExport => {
757                functor!(atom!("invalid_module_export"))
758            }
759            CompilationError::InvalidModuleResolution(ref module_name) => {
760                functor!(atom!("no_such_module"), [atom(module_name)])
761            }
762            CompilationError::InvalidRuleHead => {
763                functor!(atom!("invalid_head_of_rule")) // TODO: type_error(callable, _).
764            }
765            CompilationError::InvalidUseModuleDecl => {
766                functor!(atom!("invalid_use_module_declaration"))
767            }
768            CompilationError::ParserError(ref err) => {
769                functor!(err.as_atom())
770            }
771            CompilationError::UnreadableTerm => {
772                functor!(atom!("unreadable_term"))
773            }
774        }
775    }
776}
777
778#[derive(Debug, Clone, Copy)]
779pub(crate) enum Permission {
780    Access,
781    Create,
782    InputStream,
783    Modify,
784    Open,
785    OutputStream,
786    Reposition,
787}
788
789impl Permission {
790    #[inline]
791    pub(crate) fn as_atom(self) -> Atom {
792        match self {
793            Permission::Access => atom!("access"),
794            Permission::Create => atom!("create"),
795            Permission::InputStream => atom!("input"),
796            Permission::Modify => atom!("modify"),
797            Permission::Open => atom!("open"),
798            Permission::OutputStream => atom!("output"),
799            Permission::Reposition => atom!("reposition"),
800        }
801    }
802}
803
804#[derive(Debug, Clone, Copy)]
805pub(crate) enum DomainErrorType {
806    IOMode,
807    NotLessThanZero,
808    Order,
809    SourceSink,
810    Stream,
811    StreamOrAlias,
812}
813
814impl DomainErrorType {
815    pub(crate) fn as_atom(self) -> Atom {
816        match self {
817            DomainErrorType::IOMode => atom!("io_mode"),
818            DomainErrorType::NotLessThanZero => atom!("not_less_than_zero"),
819            DomainErrorType::Order => atom!("order"),
820            DomainErrorType::SourceSink => atom!("source_sink"),
821            DomainErrorType::Stream => atom!("stream"),
822            DomainErrorType::StreamOrAlias => atom!("stream_or_alias"),
823        }
824    }
825}
826
827// from 7.12.2 f) of 13211-1:1995
828#[derive(Debug, Clone, Copy)]
829pub(crate) enum RepFlag {
830    Character,
831    CharacterCode,
832    InCharacterCode,
833    MaxArity,
834    //    MaxInteger,
835    //    MinInteger,
836    Term,
837}
838
839impl RepFlag {
840    pub(crate) fn as_atom(self) -> Atom {
841        match self {
842            RepFlag::Character => atom!("character"),
843            RepFlag::CharacterCode => atom!("character_code"),
844            RepFlag::InCharacterCode => atom!("in_character_code"),
845            RepFlag::MaxArity => atom!("max_arity"),
846            RepFlag::Term => atom!("term"),
847            //            RepFlag::MaxInteger => atom!("max_integer"),
848            //            RepFlag::MinInteger => atom!("min_integer")
849        }
850    }
851}
852
853// from 7.12.2 g) of 13211-1:1995
854#[derive(Debug, Clone, Copy)]
855pub enum EvalError {
856    FloatOverflow,
857    Undefined,
858    //    Underflow,
859    ZeroDivisor,
860}
861
862impl EvalError {
863    pub(crate) fn as_atom(self) -> Atom {
864        match self {
865            EvalError::FloatOverflow => atom!("float_overflow"),
866            EvalError::Undefined => atom!("undefined"),
867            //            EvalError::FloatUnderflow => atom!("underflow"),
868            EvalError::ZeroDivisor => atom!("zero_divisor"),
869        }
870    }
871}
872
873// used by '$skip_max_list'.
874#[derive(Debug, Clone, Copy, PartialEq, Eq)]
875pub enum CycleSearchResult {
876    Cyclic(usize),
877    EmptyList,
878    NotList(usize, HeapCellValue), // the list length until the second argument in the heap
879    PartialList(usize, Ref),       // the list length (up to max), and an offset into the heap.
880    ProperList(usize),             // the list length.
881    PStrLocation(usize, usize, usize), // list length (up to max), the heap address of the PStr, the offset
882    UntouchedList(usize, usize), // list length (up to max), the address of an uniterated Addr::Lis(address).
883    UntouchedCStr(Atom, usize),
884}
885
886impl MachineState {
887    // see 8.4.3 of Draft Technical Corrigendum 2.
888    pub(super) fn check_sort_errors(&mut self) -> CallResult {
889        let stub_gen = || functor_stub(atom!("sort"), 2);
890
891        let list = self.store(self.deref(self.registers[1]));
892        let sorted = self.store(self.deref(self.registers[2]));
893
894        match BrentAlgState::detect_cycles(&self.heap, list) {
895            CycleSearchResult::PartialList(..) => {
896                let err = self.instantiation_error();
897                return Err(self.error_form(err, stub_gen()));
898            }
899            CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
900                let err = self.type_error(ValidType::List, list);
901                return Err(self.error_form(err, stub_gen()));
902            }
903            _ => {}
904        };
905
906        match BrentAlgState::detect_cycles(&self.heap, sorted) {
907            CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) if !sorted.is_var() => {
908                let err = self.type_error(ValidType::List, sorted);
909                Err(self.error_form(err, stub_gen()))
910            }
911            _ => Ok(()),
912        }
913    }
914
915    fn check_for_list_pairs(&mut self, mut list: HeapCellValue) -> CallResult {
916        let stub_gen = || functor_stub(atom!("keysort"), 2);
917
918        match BrentAlgState::detect_cycles(&self.heap, list) {
919            CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) if !list.is_var() => {
920                let err = self.type_error(ValidType::List, list);
921                Err(self.error_form(err, stub_gen()))
922            }
923            _ => {
924                loop {
925                    read_heap_cell!(self.store(self.deref(list)),
926                        (HeapCellValueTag::Lis, l) => {
927                            let mut new_l = l;
928
929                            loop {
930                                read_heap_cell!(self.heap[new_l],
931                                    (HeapCellValueTag::Str, s) => {
932                                        new_l = s;
933                                    }
934                                    (HeapCellValueTag::Atom, (name, arity)) => {
935                                        if name == atom!("-") && arity == 2 {
936                                            break;
937                                        } else {
938                                            let err = self.type_error(
939                                                ValidType::Pair,
940                                                list_loc_as_cell!(l),
941                                            );
942
943                                            return Err(self.error_form(err, stub_gen()));
944                                        }
945                                    }
946                                    (HeapCellValueTag::Var | HeapCellValueTag::AttrVar) => {
947                                        break;
948                                    }
949                                    _ => {
950                                        let err = self.type_error(
951                                            ValidType::Pair,
952                                            list_loc_as_cell!(l),
953                                        );
954
955                                        return Err(self.error_form(err, stub_gen()));
956                                    }
957                                );
958                            }
959
960                            list = heap_loc_as_cell!(l+1);
961                        }
962                        _ => {
963                            break;
964                        }
965                    );
966                }
967
968                Ok(())
969            }
970        }
971    }
972
973    // see 8.4.4 of Draft Technical Corrigendum 2.
974    pub(super) fn check_keysort_errors(&mut self) -> CallResult {
975        let stub_gen = || functor_stub(atom!("keysort"), 2);
976
977        let pairs = self.store(self.deref(self[temp_v!(1)]));
978        let sorted = self.store(self.deref(self[temp_v!(2)]));
979
980        match BrentAlgState::detect_cycles(&self.heap, pairs) {
981            CycleSearchResult::PartialList(..) => {
982                let err = self.instantiation_error();
983                Err(self.error_form(err, stub_gen()))
984            }
985            CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
986                let err = self.type_error(ValidType::List, pairs);
987                Err(self.error_form(err, stub_gen()))
988            }
989            _ => Ok(()),
990        }?;
991
992        self.check_for_list_pairs(sorted)
993    }
994}
995
996#[derive(Debug)]
997pub enum ExistenceError {
998    Module(Atom),
999    ModuleSource(ModuleSource),
1000    Procedure(Atom, usize),
1001    QualifiedProcedure {
1002        module_name: Atom,
1003        name: Atom,
1004        arity: usize,
1005    },
1006    SourceSink(HeapCellValue),
1007    Stream(HeapCellValue),
1008}
1009
1010#[derive(Debug)]
1011pub enum SessionError {
1012    CompilationError(CompilationError),
1013    CannotOverwriteBuiltIn(PredicateKey),
1014    CannotOverwriteBuiltInModule(Atom),
1015    CannotOverwriteStaticProcedure(PredicateKey),
1016    ExistenceError(ExistenceError),
1017    ModuleDoesNotContainExport(Atom, PredicateKey),
1018    ModuleCannotImportSelf(Atom),
1019    NamelessEntry,
1020    OpIsInfixAndPostFix(Atom),
1021    PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey),
1022    QueryCannotBeDefinedAsFact,
1023}
1024
1025impl From<std::io::Error> for SessionError {
1026    #[inline]
1027    fn from(err: std::io::Error) -> SessionError {
1028        SessionError::from(ParserError::from(err))
1029    }
1030}
1031
1032impl From<ParserError> for SessionError {
1033    #[inline]
1034    fn from(err: ParserError) -> Self {
1035        SessionError::CompilationError(CompilationError::from(err))
1036    }
1037}
1038
1039impl From<CompilationError> for SessionError {
1040    #[inline]
1041    fn from(err: CompilationError) -> Self {
1042        SessionError::CompilationError(err)
1043    }
1044}