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, Received, }
23
24#[derive(Debug)]
25pub(crate) struct MachineError {
26 stub: MachineStub,
27 location: Option<(usize, usize)>, from: ErrorProvenance,
29}
30
31#[derive(Debug, Clone, Copy)]
33pub(crate) enum ValidType {
34 Atom,
35 Atomic,
36 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 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::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::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 } 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 functor!(atom!("inadmissible_fact"))
742 }
743 CompilationError::InadmissibleQueryTerm => {
744 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")) }
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#[derive(Debug, Clone, Copy)]
829pub(crate) enum RepFlag {
830 Character,
831 CharacterCode,
832 InCharacterCode,
833 MaxArity,
834 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 }
850 }
851}
852
853#[derive(Debug, Clone, Copy)]
855pub enum EvalError {
856 FloatOverflow,
857 Undefined,
858 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::ZeroDivisor => atom!("zero_divisor"),
869 }
870 }
871}
872
873#[derive(Debug, Clone, Copy, PartialEq, Eq)]
875pub enum CycleSearchResult {
876 Cyclic(usize),
877 EmptyList,
878 NotList(usize, HeapCellValue), PartialList(usize, Ref), ProperList(usize), PStrLocation(usize, usize, usize), UntouchedList(usize, usize), UntouchedCStr(Atom, usize),
884}
885
886impl MachineState {
887 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 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}