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
119
120
121
122
123
124
125
126
127
128
129
///! Enum-based static dispatch for `MetaObject`

use crate::language::{IntType, FloatType};
use crate::runtime::Variant;
use crate::runtime::gc::Gc;
use crate::runtime::function::{Call, Function, NativeFunction};
use crate::runtime::strings::StringValue;
use crate::runtime::types::{Type, MetaObject, Tuple, UserData, Nil, Marker, IterState, UserIterator};
use crate::runtime::errors::{ExecResult, RuntimeError};


/// Newtype wrapper for `Variant` that impls `MetaObject` using enum-based static dispatch.
struct MetaDispatch<'a>(&'a Variant);

impl Variant {
    #[inline]
    pub fn as_meta(&self) -> impl MetaObject + '_ {
        MetaDispatch(self)
    }
    
    pub fn type_tag(&self) -> Type {
        self.as_meta().type_tag()
    }
    
    pub fn type_name(&self) -> ExecResult<StringValue> {
        self.as_meta().type_name()
    }
}

macro_rules! static_dispatch {
    { fn $name:tt ( $( $arg:tt : $argty:ty ),* ) -> $return:ty } => {
        fn $name (&self, $( $arg : $argty ),* ) -> $return {
            match self.0 {
                Variant::Nil => <Nil as MetaObject>::$name(&Nil, $( $arg ),* ),
                Variant::BoolTrue => <bool as MetaObject>::$name(&true, $( $arg ),* ),
                Variant::BoolFalse => <bool as MetaObject>::$name(&false, $( $arg ),* ),
                
                Variant::Marker(marker) => <Marker as MetaObject>::$name(marker, $( $arg ),* ),
                
                Variant::Integer(value) => <IntType as MetaObject>::$name(value, $( $arg ),* ),
                Variant::Float(value) => <FloatType as MetaObject>::$name(value, $( $arg ),* ),
                
                Variant::InternStr(symbol) => <StringValue as MetaObject>::$name(&(*symbol).into(), $( $arg ),* ),
                Variant::InlineStr(inline) => <StringValue as MetaObject>::$name(&(*inline).into(), $( $arg ),* ),
                Variant::GCStr(gc_str) => <StringValue as MetaObject>::$name(&(*gc_str).into(), $( $arg ),* ),
                
                Variant::Tuple(tuple) => <Tuple as MetaObject>::$name(tuple, $( $arg ),* ),
                
                Variant::Function(fun) => <Gc<Function> as MetaObject>::$name(fun, $( $arg ),* ),
                Variant::NativeFunction(fun) => <Gc<NativeFunction> as MetaObject>::$name(fun, $( $arg ),* ),
                
                Variant::Error(error) => <Gc<RuntimeError> as MetaObject>::$name(error, $( $arg ),* ),
                
                Variant::Iterator(iter) => <Gc<dyn UserIterator> as MetaObject>::$name(iter, $( $arg ),* ),
                
                Variant::UserData(data) => <(dyn UserData + 'static) as MetaObject>::$name(&**data, $( $arg ),* ),
            }
        }
    };
}

impl MetaObject for MetaDispatch<'_> {
    
    static_dispatch!{ fn type_tag() -> Type }
    static_dispatch!{ fn type_name() -> ExecResult<StringValue> }
    
    static_dispatch!{ fn fmt_echo() -> ExecResult<StringValue> }
    
    static_dispatch!{ fn as_bool() -> ExecResult<bool> }
    static_dispatch!{ fn as_bits() -> Option<ExecResult<IntType>> }
    static_dispatch!{ fn as_int() -> Option<ExecResult<IntType>> }
    static_dispatch!{ fn as_float() -> Option<ExecResult<FloatType>> }
    
    // iterators
    static_dispatch!{ fn iter_init() -> Option<ExecResult<IterState>> }
    static_dispatch!{ fn iter_get(state: &Variant) -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn iter_next(state: &Variant) -> Option<ExecResult<Variant>> }
    
    // collections
    static_dispatch!{ fn len() -> Option<ExecResult<usize>> }
    
    // callable
    static_dispatch!{ fn invoke(args: &[Variant]) -> Option<ExecResult<Call>> }
    
    // unary operators
    static_dispatch!{ fn op_neg() -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn op_pos() -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn op_inv() -> Option<ExecResult<Variant>> }

    // arithmetic operators
    static_dispatch!{ fn op_mul(rhs: &Variant) -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn op_rmul(lhs: &Variant) -> Option<ExecResult<Variant>> }
    
    static_dispatch!{ fn op_div(rhs: &Variant) -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn op_rdiv(lhs: &Variant) -> Option<ExecResult<Variant>> }
    
    static_dispatch!{ fn op_mod(rhs: &Variant) -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn op_rmod(lhs: &Variant) -> Option<ExecResult<Variant>> }
    
    static_dispatch!{ fn op_add(rhs: &Variant) -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn op_radd(lhs: &Variant) -> Option<ExecResult<Variant>> }
    
    static_dispatch!{ fn op_sub(rhs: &Variant) -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn op_rsub(lhs: &Variant) -> Option<ExecResult<Variant>> }
    
    // bitwise operators
    static_dispatch!{ fn op_and(rhs: &Variant) -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn op_rand(lhs: &Variant) -> Option<ExecResult<Variant>> }
    
    static_dispatch!{ fn op_xor(rhs: &Variant) -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn op_rxor(lhs: &Variant) -> Option<ExecResult<Variant>> }
    
    static_dispatch!{ fn op_or(rhs: &Variant) -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn op_ror(lhs: &Variant) -> Option<ExecResult<Variant>> }
    
    static_dispatch!{ fn op_shl(rhs: &Variant) -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn op_rshl(lhs: &Variant) -> Option<ExecResult<Variant>> }
    
    static_dispatch!{ fn op_shr(rhs: &Variant) -> Option<ExecResult<Variant>> }
    static_dispatch!{ fn op_rshr(lhs: &Variant) -> Option<ExecResult<Variant>> }
    
    // comparisons
    
    static_dispatch!{ fn cmp_eq(other: &Variant) -> Option<ExecResult<bool>> }
    static_dispatch!{ fn cmp_lt(other: &Variant) -> Option<ExecResult<bool>> }
    static_dispatch!{ fn cmp_le(other: &Variant) -> Option<ExecResult<bool>> }
    
    
}