1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// TODO:
//   [x] Port all tests
//   [x] NaN, inf, -inf are valid.  problem?  no because my parser thinks they're vars.
//   [x] e() pi() ... or should i prefer variables?  Provide a default layer of variables?  Vars don't work well with TV symbols.
//   [x] Profile, boost critical sections.
//   [x] optimize the peek/read process -- be able to read N bytes if we peek successfully.
//   [x] optimize after parse
//   [x] custom functions  (i.e. Variables With Arguments)
//   [x] REPL Example with Variables
//   [x] Copy smart tests from other libs.
//   [x] Reduce work: Parser obj --> functions.  EvalNS --> BTreeMap.
//   [x] #[inline] last, using profile as a guide.
//   [ ] More examples:  UnsafeVar.  Mini Language.
//   [ ] Readme
//   [ ] Documentation
//
//   [ ] sprintf

//#![warn(missing_docs)]


#[macro_export]
macro_rules! eval_instr {
    ($evaler:ident, $slab_ref:expr, $ns_mut:expr) => {
        if let al::IConst(c) = $evaler {
            c
        } else {
            #[cfg(feature="unsafe-vars")]
            {
                if let al::IUnsafeVar{name:_,ptr} = $evaler {
                    unsafe { *ptr }
                } else {
                    $evaler.eval($slab_ref, $ns_mut)?
                }
            }

            #[cfg(not(feature="unsafe-vars"))]
            $evaler.eval($slab_ref, $ns_mut)?
        }
    };
    ($evaler:expr, $slab_ref:expr, $ns_mut:expr) => {
        {
            let evaler = $evaler;
            eval_instr!(evaler, $slab_ref, $ns_mut)
        }
    };
}

#[macro_export]
macro_rules! eval_instr_ref {
    ($evaler:ident, $slab_ref:expr, $ns_mut:expr) => {
        if let al::IConst(c) = $evaler {
            *c
        } else {
            #[cfg(feature="unsafe-vars")]
            {
                if let al::IUnsafeVar{name:_,ptr} = $evaler {
                    unsafe { **ptr }
                } else {
                    $evaler.eval($slab_ref, $ns_mut)?
                }
            }

            #[cfg(not(feature="unsafe-vars"))]
            $evaler.eval($slab_ref, $ns_mut)?
        }
    };
    ($evaler:expr, $slab_ref:expr, $ns_mut:expr) => {
        {
            let evaler = $evaler;
            eval_instr_ref!(evaler, $slab_ref, $ns_mut)
        }
    };
}

#[macro_export]
macro_rules! eval_instr_ref_or_panic {
    ($evaler:ident, $slab_ref:expr, $ns_mut:expr) => {
        if let al::IConst(c) = $evaler {
            *c
        } else {
            #[cfg(feature="unsafe-vars")]
            {
                if let al::IUnsafeVar{name:_,ptr} = $evaler {
                    unsafe { **ptr }
                } else {
                    $evaler.eval($slab_ref, $ns_mut).unwrap()
                }
            }

            #[cfg(not(feature="unsafe-vars"))]
            $evaler.eval($slab_ref, $ns_mut).unwrap()
        }
    };
    ($evaler:expr, $slab_ref:expr, $ns_mut:expr) => {
        {
            let evaler = $evaler;
            eval_instr_ref_or_panic!(evaler, $slab_ref, $ns_mut)
        }
    };
}

pub mod parser;
pub mod compiler;
pub mod evaler;
pub mod slab;
pub mod evalns;
pub mod ez;

pub use self::parser::{parse, Parser, Expression, ExpressionI, Value, ValueI};
pub use self::compiler::{Compiler, Instruction::{self, IConst}, InstructionI};
#[cfg(feature="unsafe-vars")]
pub use self::compiler::Instruction::IUnsafeVar;
pub use self::evaler::Evaler;
pub use self::slab::Slab;
pub use self::evalns::{EvalNamespace, EmptyNamespace, FlatNamespace, ScopedNamespace};
pub use self::ez::ez_eval;