1use rug::{Integer, Rational};
2use ordered_float::*;
3use tabled_rc::*;
4
5use put_back_n::*;
6
7use std::cell::Cell;
8use std::cmp::Ordering;
9use std::collections::HashMap;
10use std::fmt;
11use std::hash::{Hash, Hasher};
12use std::io::{Bytes, Error as IOError, Read};
13use std::rc::Rc;
14use std::vec::Vec;
15
16use unicode_reader::CodePoints;
17
18pub type Atom = String;
19
20pub type Var = String;
21
22pub type Specifier = u32;
23
24pub const MAX_ARITY: usize = 1023;
25
26pub const XFX: u32 = 0x0001;
27pub const XFY: u32 = 0x0002;
28pub const YFX: u32 = 0x0004;
29pub const XF: u32 = 0x0010;
30pub const YF: u32 = 0x0020;
31pub const FX: u32 = 0x0040;
32pub const FY: u32 = 0x0080;
33pub const DELIMITER: u32 = 0x0100;
34pub const TERM: u32 = 0x1000;
35pub const LTERM: u32 = 0x3000;
36
37pub const NEGATIVE_SIGN: u32 = 0x0200;
38
39#[macro_export]
40macro_rules! clause_name {
41 ($name: expr, $tbl: expr) => (
42 ClauseName::User(TabledRc::new($name, $tbl.clone()))
43 ) ;
44 ($name: expr) => (
45 ClauseName::BuiltIn($name)
46 )
47}
48
49#[macro_export]
50macro_rules! atom {
51 ($e:expr, $tbl:expr) => (
52 Constant::Atom(ClauseName::User(tabled_rc!($e, $tbl)), None)
53 );
54 ($e:expr) => (
55 Constant::Atom(clause_name!($e), None)
56 )
57}
58
59#[macro_export]
60macro_rules! rc_atom {
61 ($e:expr) => (
62 Rc::new(String::from($e))
63 )
64}
65macro_rules! is_term {
66 ($x:expr) => ( ($x & TERM) != 0 )
67}
68
69macro_rules! is_lterm {
70 ($x:expr) => ( ($x & LTERM) != 0 )
71}
72
73macro_rules! is_op {
74 ($x:expr) => ( $x & (XF | YF | FX | FY | XFX | XFY | YFX) != 0 )
75}
76
77macro_rules! is_negate {
78 ($x:expr) => ( ($x & NEGATIVE_SIGN) != 0 )
79}
80
81#[macro_export]
82macro_rules! is_prefix {
83 ($x:expr) => ( $x & (FX | FY) != 0 )
84}
85
86#[macro_export]
87macro_rules! is_postfix {
88 ($x:expr) => ( $x & (XF | YF) != 0 )
89}
90
91#[macro_export]
92macro_rules! is_infix {
93 ($x:expr) => ( ($x & (XFX | XFY | YFX)) != 0 )
94}
95
96#[macro_export]
97macro_rules! is_xfx {
98 ($x:expr) => ( ($x & XFX) != 0 )
99}
100
101#[macro_export]
102macro_rules! is_xfy {
103 ($x:expr) => ( ($x & XFY) != 0 )
104}
105
106#[macro_export]
107macro_rules! is_yfx {
108 ($x:expr) => ( ($x & YFX) != 0 )
109}
110
111#[macro_export]
112macro_rules! is_yf {
113 ($x:expr) => ( ($x & YF) != 0 )
114}
115
116#[macro_export]
117macro_rules! is_xf {
118 ($x:expr) => ( ($x & XF) != 0 )
119}
120
121#[macro_export]
122macro_rules! is_fx {
123 ($x:expr) => ( ($x & FX) != 0 )
124}
125
126#[macro_export]
127macro_rules! is_fy {
128 ($x:expr) => ( ($x & FY) != 0 )
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
132pub enum RegType {
133 Perm(usize),
134 Temp(usize)
135}
136
137impl Default for RegType {
138 fn default() -> Self {
139 RegType::Temp(0)
140 }
141}
142
143impl RegType {
144 pub fn reg_num(self) -> usize {
145 match self {
146 RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num
147 }
148 }
149
150 pub fn is_perm(self) -> bool {
151 match self {
152 RegType::Perm(_) => true,
153 _ => false
154 }
155 }
156}
157
158impl fmt::Display for RegType {
159 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
160 match self {
161 &RegType::Perm(val) => write!(f, "Y{}", val),
162 &RegType::Temp(val) => write!(f, "X{}", val)
163 }
164 }
165}
166
167#[derive(Debug, PartialEq, Eq, Clone, Copy)]
168pub enum VarReg {
169 ArgAndNorm(RegType, usize),
170 Norm(RegType)
171}
172
173impl VarReg {
174 pub fn norm(self) -> RegType {
175 match self {
176 VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg
177 }
178 }
179}
180
181impl fmt::Display for VarReg {
182 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
183 match self {
184 &VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
185 &VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
186 &VarReg::ArgAndNorm(RegType::Perm(reg), arg) =>
187 write!(f, "Y{} A{}", reg, arg),
188 &VarReg::ArgAndNorm(RegType::Temp(reg), arg) =>
189 write!(f, "X{} A{}", reg, arg)
190 }
191 }
192}
193
194impl Default for VarReg {
195 fn default() -> Self {
196 VarReg::Norm(RegType::default())
197 }
198}
199
200#[macro_export]
201macro_rules! temp_v {
202 ($x:expr) => (
203 RegType::Temp($x)
204 )
205}
206
207#[macro_export]
208macro_rules! perm_v {
209 ($x:expr) => (
210 RegType::Perm($x)
211 )
212}
213
214#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
215pub enum GenContext {
216 Head, Mid(usize), Last(usize) }
218
219impl GenContext {
220 pub fn chunk_num(self) -> usize {
221 match self {
222 GenContext::Head => 0,
223 GenContext::Mid(cn) | GenContext::Last(cn) => cn
224 }
225 }
226}
227
228pub type OpDirKey = (ClauseName, Fixity);
229
230#[derive(Debug, Clone)]
231pub struct OpDirValue(pub SharedOpDesc, pub ClauseName);
232
233impl OpDirValue {
234 pub fn new(spec: Specifier, priority: usize, module_name: ClauseName) -> Self {
235 OpDirValue(SharedOpDesc::new(priority, spec), module_name)
236 }
237
238 #[inline]
239 pub fn shared_op_desc(&self) -> SharedOpDesc {
240 self.0.clone()
241 }
242
243 #[inline]
244 pub fn owning_module(&self) -> ClauseName {
245 self.1.clone()
246 }
247}
248
249pub type OpDir = HashMap<OpDirKey, OpDirValue>;
251
252#[derive(Debug, Clone, Copy)]
253pub struct MachineFlags {
254 pub double_quotes: DoubleQuotes
255}
256
257impl Default for MachineFlags {
258 fn default() -> Self {
259 MachineFlags { double_quotes: DoubleQuotes::default() }
260 }
261}
262
263#[derive(Debug, Clone, Copy)]
264pub enum DoubleQuotes {
265 Atom, Chars, Codes
266}
267
268impl DoubleQuotes {
269 pub fn is_chars(self) -> bool {
270 if let DoubleQuotes::Chars = self {
271 true
272 } else {
273 false
274 }
275 }
276
277 pub fn is_atom(self) -> bool {
278 if let DoubleQuotes::Atom = self {
279 true
280 } else {
281 false
282 }
283 }
284
285 pub fn is_codes(self) -> bool {
286 if let DoubleQuotes::Codes = self {
287 true
288 } else {
289 false
290 }
291 }
292}
293
294impl Default for DoubleQuotes {
295 fn default() -> Self {
296 DoubleQuotes::Chars
297 }
298}
299
300pub fn default_op_dir() -> OpDir {
301 let module_name = clause_name!("builtins");
302 let mut op_dir = OpDir::new();
303
304 op_dir.insert((clause_name!(":-"), Fixity::In), OpDirValue::new(XFX, 1200, module_name.clone()));
305 op_dir.insert((clause_name!(":-"), Fixity::Pre), OpDirValue::new(FX, 1200, module_name.clone()));
306 op_dir.insert((clause_name!("?-"), Fixity::Pre), OpDirValue::new(FX, 1200, module_name.clone()));
307 op_dir.insert((clause_name!(","), Fixity::In), OpDirValue::new(XFY, 1000, module_name.clone()));
308
309 op_dir
310}
311
312#[derive(Debug, Clone)]
313pub enum ArithmeticError {
314 NonEvaluableFunctor(Constant, usize),
315 UninstantiatedVar
316}
317
318#[derive(Debug)]
319pub enum ParserError {
320 Arithmetic(ArithmeticError),
321 BackQuotedString(usize, usize),
322 BadPendingByte,
323 CannotParseCyclicTerm,
324 UnexpectedChar(char, usize, usize),
325 UnexpectedEOF,
326 IO(IOError),
327 ExpectedRel,
328 ExpectedTopLevelTerm,
329 InadmissibleFact,
330 InadmissibleQueryTerm,
331 IncompleteReduction(usize, usize),
332 InconsistentEntry,
333 InvalidDoubleQuotesDecl,
334 InvalidHook,
335 InvalidModuleDecl,
336 InvalidModuleExport,
337 InvalidRuleHead,
338 InvalidUseModuleDecl,
339 InvalidModuleResolution,
340 InvalidSingleQuotedCharacter(char),
341 MissingQuote(usize, usize),
342 NonPrologChar(usize, usize),
343 ParseBigInt(usize, usize),
344 ParseFloat(usize, usize),
345 Utf8Error(usize, usize)
346}
347
348impl ParserError {
349 pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
350 match self {
351 &ParserError::BackQuotedString(line_num, col_num)
352 | &ParserError::UnexpectedChar(_, line_num, col_num)
353 | &ParserError::IncompleteReduction(line_num, col_num)
354 | &ParserError::MissingQuote(line_num, col_num)
355 | &ParserError::NonPrologChar(line_num, col_num)
356 | &ParserError::ParseBigInt(line_num, col_num)
357 | &ParserError::ParseFloat(line_num, col_num)
358 | &ParserError::Utf8Error(line_num, col_num) =>
359 Some((line_num, col_num)),
360 _ =>
361 None
362 }
363 }
364
365 pub fn as_str(&self) -> &'static str {
366 match self {
367 &ParserError::Arithmetic(..) =>
368 "arithmetic_error",
369 &ParserError::BackQuotedString(..) =>
370 "back_quoted_string",
371 &ParserError::BadPendingByte =>
372 "bad_pending_byte",
373 &ParserError::UnexpectedChar(..) =>
374 "unexpected_char",
375 &ParserError::UnexpectedEOF =>
376 "unexpected_end_of_file",
377 &ParserError::ExpectedRel =>
378 "expected_relation",
379 &ParserError::ExpectedTopLevelTerm =>
380 "expected_atom_or_cons_or_clause",
381 &ParserError::InadmissibleFact =>
382 "inadmissible_fact",
383 &ParserError::InadmissibleQueryTerm =>
384 "inadmissible_query_term",
385 &ParserError::IncompleteReduction(..) =>
386 "incomplete_reduction",
387 &ParserError::InconsistentEntry =>
388 "inconsistent_entry",
389 &ParserError::InvalidDoubleQuotesDecl =>
390 "invalid_double_quotes_declaration",
391 &ParserError::InvalidHook =>
392 "invalid_hook",
393 &ParserError::InvalidModuleDecl =>
394 "invalid_module_declaration",
395 &ParserError::InvalidModuleExport =>
396 "invalid_module_export",
397 &ParserError::InvalidModuleResolution =>
398 "invalid_module_resolution",
399 &ParserError::InvalidRuleHead =>
400 "invalid_head_of_rule",
401 &ParserError::InvalidUseModuleDecl =>
402 "invalid_use_module_declaration",
403 &ParserError::InvalidSingleQuotedCharacter(..) =>
404 "invalid_single_quoted_character",
405 &ParserError::IO(_) =>
406 "input_output_error",
407 &ParserError::MissingQuote(..) =>
408 "missing_quote",
409 &ParserError::NonPrologChar(..) =>
410 "non_prolog_character",
411 &ParserError::ParseBigInt(..) =>
412 "cannot_parse_big_int",
413 &ParserError::ParseFloat(..) =>
414 "cannot_parse_float",
415 &ParserError::Utf8Error(..) =>
416 "utf8_conversion_error",
417 &ParserError::CannotParseCyclicTerm =>
418 "cannot_parse_cyclic_term"
419 }
420 }
421}
422
423impl From<ArithmeticError> for ParserError {
424 fn from(err: ArithmeticError) -> ParserError {
425 ParserError::Arithmetic(err)
426 }
427}
428
429impl From<IOError> for ParserError {
430 fn from(err: IOError) -> ParserError {
431 ParserError::IO(err)
432 }
433}
434
435impl From<&IOError> for ParserError {
436 fn from(error: &IOError) -> ParserError {
437 if error.get_ref().filter(|e| e.is::<BadUtf8Error>()).is_some() {
438 ParserError::Utf8Error(0, 0)
439 } else {
440 ParserError::IO(error.kind().into())
441 }
442 }
443}
444
445
446#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
447pub enum Fixity {
448 In, Post, Pre
449}
450
451#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
452pub struct SharedOpDesc(Rc<Cell<(usize, Specifier)>>);
453
454impl SharedOpDesc {
455 #[inline]
456 pub fn new(priority: usize, spec: Specifier) -> Self {
457 SharedOpDesc(Rc::new(Cell::new((priority, spec))))
458 }
459
460 #[inline]
461 pub fn ptr_eq(lop_desc: &SharedOpDesc, rop_desc: &SharedOpDesc) -> bool {
462 Rc::ptr_eq(&lop_desc.0, &rop_desc.0)
463 }
464
465 #[inline]
466 pub fn arity(&self) -> usize {
467 if self.get().1 & (XFX | XFY | YFX) == 0 {
468 1
469 } else {
470 2
471 }
472 }
473
474 #[inline]
475 pub fn get(&self) -> (usize, Specifier) {
476 self.0.get()
477 }
478
479 #[inline]
480 pub fn set(&self, prec: usize, spec: Specifier) {
481 self.0.set((prec, spec));
482 }
483
484 #[inline]
485 pub fn prec(&self) -> usize {
486 self.0.get().0
487 }
488
489 #[inline]
490 pub fn assoc(&self) -> Specifier {
491 self.0.get().1
492 }
493}
494
495impl Hash for SharedOpDesc {
500 fn hash<H: Hasher>(&self, state: &mut H) {
501 0.hash(state)
502 }
503}
504
505#[derive(Debug, Clone, Hash)]
506pub enum Constant {
507 Atom(ClauseName, Option<SharedOpDesc>),
508 Char(char),
509 EmptyList,
510 Fixnum(isize),
511 Integer(Rc<Integer>),
512 Rational(Rc<Rational>),
513 Float(OrderedFloat<f64>),
514 String(Rc<String>),
515 Usize(usize),
516}
517
518impl fmt::Display for Constant {
519 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
520 match self {
521 &Constant::Atom(ref atom, _) =>
522 if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) {
523 write!(f, "'{}'", atom.as_str())
524 } else {
525 write!(f, "{}", atom.as_str())
526 },
527 &Constant::Char(c) =>
528 write!(f, "'{}'", c as u32),
529 &Constant::EmptyList =>
530 write!(f, "[]"),
531 &Constant::Fixnum(n) =>
532 write!(f, "{}", n),
533 &Constant::Integer(ref n) =>
534 write!(f, "{}", n),
535 &Constant::Rational(ref n) =>
536 write!(f, "{}", n),
537 &Constant::Float(ref n) =>
538 write!(f, "{}", n),
539 &Constant::String(ref s) =>
540 write!(f, "\"{}\"", &s),
541 &Constant::Usize(integer) =>
542 write!(f, "u{}", integer),
543 }
544 }
545}
546
547impl PartialEq for Constant {
548 fn eq(&self, other: &Constant) -> bool {
549 match (self, other) {
550 (&Constant::Atom(ref atom, _), &Constant::Char(c))
551 | (&Constant::Char(c), &Constant::Atom(ref atom, _)) => {
552 atom.is_char() && Some(c) == atom.as_str().chars().next()
553 },
554 (&Constant::Atom(ref a1, _), &Constant::Atom(ref a2, _)) =>
555 a1.as_str() == a2.as_str(),
556 (&Constant::Char(c1), &Constant::Char(c2)) =>
557 c1 == c2,
558 (&Constant::Fixnum(n1), &Constant::Fixnum(n2)) =>
559 n1 == n2,
560 (&Constant::Fixnum(n1), &Constant::Integer(ref n2)) |
561 (&Constant::Integer(ref n2), &Constant::Fixnum(n1)) => {
562 if let Some(n2) = n2.to_isize() {
563 n1 == n2
564 } else {
565 false
566 }
567 }
568 (&Constant::Integer(ref n1), &Constant::Integer(ref n2)) =>
569 n1 == n2,
570 (&Constant::Rational(ref n1), &Constant::Rational(ref n2)) =>
571 n1 == n2,
572 (&Constant::Float(ref n1), &Constant::Float(ref n2)) =>
573 n1 == n2,
574 (&Constant::String(ref s1), &Constant::String(ref s2)) => {
575 &s1 == &s2
576 }
577 (&Constant::EmptyList, &Constant::EmptyList) =>
578 true,
579 (&Constant::Usize(u1), &Constant::Usize(u2)) =>
580 u1 == u2,
581 _ => false
582 }
583 }
584}
585
586impl Eq for Constant {}
587
588impl Constant {
589 pub fn to_atom(self) -> Option<ClauseName> {
590 match self {
591 Constant::Atom(a, _) => Some(a.defrock_brackets()),
592 _ => None
593 }
594 }
595}
596
597#[derive(Debug, Clone)]
598pub enum ClauseName {
599 BuiltIn(&'static str),
600 User(TabledRc<Atom>)
601}
602
603impl fmt::Display for ClauseName {
604 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
605 write!(f, "{}", self.as_str())
606 }
607}
608
609impl Hash for ClauseName {
610 fn hash<H: Hasher>(&self, state: &mut H) {
611 (*self.as_str()).hash(state)
612 }
613}
614
615impl PartialEq for ClauseName {
616 fn eq(&self, other: &ClauseName) -> bool {
617 *self.as_str() == *other.as_str()
618 }
619}
620
621impl Eq for ClauseName {}
622
623impl Ord for ClauseName {
624 fn cmp(&self, other: &ClauseName) -> Ordering {
625 (*self.as_str()).cmp(other.as_str())
626 }
627}
628
629impl PartialOrd for ClauseName {
630 fn partial_cmp(&self, other: &ClauseName) -> Option<Ordering> {
631 Some(self.cmp(other))
632 }
633}
634
635impl<'a> From<&'a TabledRc<Atom>> for ClauseName {
636 fn from(name: &'a TabledRc<Atom>) -> ClauseName {
637 ClauseName::User(name.clone())
638 }
639}
640
641impl ClauseName {
642 #[inline]
643 pub fn owning_module(&self) -> Self {
644 match self {
645 &ClauseName::User(ref name) => {
646 let module = name.owning_module();
647 ClauseName::User(TabledRc { atom: module.clone(),
648 table: TabledData::new(module) })
649 },
650 _ => clause_name!("user")
651 }
652 }
653
654 #[inline]
655 pub fn to_rc(&self) -> Rc<String> {
656 match self {
657 &ClauseName::BuiltIn(s) => Rc::new(s.to_string()),
658 &ClauseName::User(ref rc) => rc.inner()
659 }
660 }
661
662 #[inline]
663 pub fn with_table(self, atom_tbl: TabledData<Atom>) -> Self {
664 match self {
665 ClauseName::BuiltIn(_) => self,
666 ClauseName::User(mut name) => {
667 name.table = atom_tbl;
668 ClauseName::User(name)
669 }
670 }
671 }
672
673 #[inline]
674 pub fn has_table(&self, atom_tbl: &TabledData<Atom>) -> bool {
675 match self {
676 ClauseName::BuiltIn(_) => false,
677 ClauseName::User(ref name) => &name.table == atom_tbl,
678 }
679 }
680
681 #[inline]
682 pub fn has_table_of(&self, other: &ClauseName) -> bool {
683 match self {
684 ClauseName::BuiltIn(_) => {
685 if let ClauseName::BuiltIn(_) = other {
686 true
687 } else {
688 false
689 }
690 }
691 ClauseName::User(ref name) => {
692 other.has_table(&name.table)
693 }
694 }
695 }
696
697 #[inline]
698 pub fn as_str(&self) -> &str {
699 match self {
700 &ClauseName::BuiltIn(s) => s,
701 &ClauseName::User(ref name) => name.as_ref()
702 }
703 }
704
705 #[inline]
706 pub fn is_char(&self) -> bool {
707 !self.as_str().is_empty() && self.as_str().chars().skip(1).next().is_none()
708 }
709
710 pub fn defrock_brackets(self) -> Self {
711 fn defrock_brackets(s: &str) -> &str {
712 if s.starts_with('(') && s.ends_with(')') {
713 &s[1 .. s.len() - 1]
714 } else {
715 s
716 }
717 }
718
719 match self {
720 ClauseName::BuiltIn(s) =>
721 ClauseName::BuiltIn(defrock_brackets(s)),
722 ClauseName::User(s) =>
723 ClauseName::User(tabled_rc!(defrock_brackets(s.as_str()).to_owned(), s.table))
724 }
725 }
726}
727
728impl AsRef<str> for ClauseName {
729 #[inline]
730 fn as_ref(self: &Self) -> &str {
731 self.as_str()
732 }
733}
734
735#[derive(Debug, PartialEq, Eq, Clone)]
736pub enum Term {
737 AnonVar,
738 Clause(Cell<RegType>, ClauseName, Vec<Box<Term>>, Option<SharedOpDesc>),
739 Cons(Cell<RegType>, Box<Term>, Box<Term>),
740 Constant(Cell<RegType>, Constant),
741 Var(Cell<VarReg>, Rc<Var>)
742}
743
744impl Term {
745 pub fn shared_op_desc(&self) -> Option<SharedOpDesc> {
746 match self {
747 &Term::Clause(_, _, _, ref spec) => spec.clone(),
748 &Term::Constant(_, Constant::Atom(_, ref spec)) => spec.clone(),
749 _ => None
750 }
751 }
752
753 pub fn to_constant(self) -> Option<Constant> {
754 match self {
755 Term::Constant(_, c) => Some(c),
756 _ => None
757 }
758 }
759
760 pub fn first_arg(&self) -> Option<&Term> {
761 match self {
762 &Term::Clause(_, _, ref terms, _) =>
763 terms.first().map(|bt| bt.as_ref()),
764 _ => None
765 }
766 }
767
768 pub fn set_name(&mut self, new_name: ClauseName) {
769 match self {
770 Term::Constant(_, Constant::Atom(ref mut atom, _))
771 | Term::Clause(_, ref mut atom, ..) => {
772 *atom = new_name;
773 }
774 _ => {}
775 }
776 }
777
778 pub fn name(&self) -> Option<ClauseName> {
779 match self {
780 &Term::Constant(_, Constant::Atom(ref atom, _))
781 | &Term::Clause(_, ref atom, ..) => Some(atom.clone()),
782 _ => None
783 }
784 }
785
786 pub fn arity(&self) -> usize {
787 match self {
788 &Term::Clause(_, _, ref child_terms, ..) => child_terms.len(),
789 _ => 0
790 }
791 }
792}
793
794#[derive(Debug, Clone, Copy)]
795pub struct CompositeOp<'a, 'b> {
796 pub op_dir: &'a OpDir,
797 pub static_op_dir: Option<&'b OpDir>
798}
799
800#[macro_export]
801macro_rules! composite_op {
802 ($include_machine_p:expr, $op_dir:expr, $machine_op_dir:expr) => (
803 CompositeOp { op_dir: $op_dir,
804 static_op_dir: if !$include_machine_p {
805 Some($machine_op_dir)
806 } else {
807 None
808 }}
809 );
810 ($op_dir:expr) => (
811 CompositeOp { op_dir: $op_dir, static_op_dir: None }
812 )
813}
814
815impl<'a, 'b> CompositeOp<'a, 'b>
816{
817 #[inline]
818 pub(crate)
819 fn get(&self, name: ClauseName, fixity: Fixity) -> Option<OpDirValue>
820 {
821 let entry =
822 if let Some(ref static_op_dir) = &self.static_op_dir {
823 static_op_dir.get(&(name.clone(), fixity))
824 } else {
825 None
826 };
827
828 entry.or_else(move || self.op_dir.get(&(name, fixity)))
829 .cloned()
830 }
831}
832
833fn unfold_by_str_once(term: &mut Term, s: &str) -> Option<(Term, Term)> {
834 if let &mut Term::Clause(_, ref name, ref mut subterms, _) = term {
835 if name.as_str() == s && subterms.len() == 2 {
836 let snd = *subterms.pop().unwrap();
837 let fst = *subterms.pop().unwrap();
838
839 return Some((fst, snd));
840 }
841 }
842
843 None
844}
845
846pub fn unfold_by_str(mut term: Term, s: &str) -> Vec<Term> {
847 let mut terms = vec![];
848
849 while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) {
850 terms.push(fst);
851 term = snd;
852 }
853
854 terms.push(term);
855 terms
856}
857
858pub type ParsingStream<R> = PutBackN<CodePoints<Bytes<R>>>;
859
860use unicode_reader::BadUtf8Error;
861
862#[inline]
863pub fn parsing_stream<R: Read>(src: R) -> Result<ParsingStream<R>, ParserError> {
864 let mut stream = put_back_n(CodePoints::from(src.bytes()));
865 match stream.peek() {
866 None => Ok(stream), Some(Err(error)) => Err(ParserError::from(error)),
868 Some(Ok(c)) => {
869 if *c == '\u{feff}' {
870 stream.next();
872 }
873 Ok(stream)
874 }
875 }
876}