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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
use crate::entries::{CodeGroup, Entry, ExternEntry};
use crate::program::Program;
use crate::{BuildError, CodeRefError, EvalError};
use lincoln_common::traits::Access;

/// CodeRef is a type refer to a single executable entry.
/// This can be either a entry of a program, an external
/// entry point defined within/without the program,
/// or indicate the end of execution.
///
#[derive(Copy, Clone, Serialize, Deserialize)]
pub enum CodeRef {
    /// An entry refers to a entry point of a program.
    Entry(EntryRef),
    /// Refers to an external function entry defined in a program.
    Extern(ExternRef),    
    /// Indicate the end of execution.
    Termination,
}
impl std::hash::Hash for CodeRef {
    fn hash<H>(&self, state: &mut H)
    where
        H: std::hash::Hasher,
    {
        use CodeRef::*;
        match self {
            Entry(e) => e.hash(state),
            Extern(e) => e.hash(state),
            _ => "".hash(state),
        }
    }
}
impl Eq for CodeRef {}
impl PartialEq for CodeRef {
    fn eq(&self, other: &Self) -> bool {
        use CodeRef::*;
        match (self, other) {
            (Entry(e1), Entry(e2)) => e1 == e2,
            (Extern(e1), Extern(e2)) => e1 == e2,
            (Termination, Termination) => true,
            _ => false,
        }
    }
}
impl std::fmt::Debug for CodeRef {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(fmt, "{}", self)
    }
}
impl std::fmt::Display for CodeRef {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            CodeRef::Entry(e) => write!(fmt, "{}", e),
            CodeRef::Extern(e) => write!(fmt, "{}", e),
            CodeRef::Termination => write!(fmt, "🛑"),
        }
    }
}
impl CodeRef {
    pub fn entry(index: usize) -> Self {
        CodeRef::Entry(EntryRef(index))
    }
    pub fn ext(index: usize) -> Self {
        CodeRef::Extern(ExternRef(index))
    }

}

/// An `EntryRef` refers to an entry of a program.
#[derive(Copy, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EntryRef(pub usize);
impl EntryRef {
    pub fn not_found(&self) -> CodeRefError {
        CodeRefError::EntryNotFound { index: *self }
    }
    pub(crate) fn new_coderef(index: usize) -> CodeRef {
        EntryRef(index).into()
    }
}
impl std::fmt::Debug for EntryRef {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(fmt, "🎯-{}", self.0)
    }
}
impl std::fmt::Display for EntryRef {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(fmt, "{:?}", self)
    }
}
impl From<EntryRef> for CodeRef {
    fn from(e: EntryRef) -> CodeRef {
        CodeRef::Entry(e)
    }
}
impl<'a> Access<'a, Program> for EntryRef {
    type Target = Option<&'a Entry>;
    fn access<'b>(&self, src: &'b Program) -> Option<&'b Entry>
    where
        'b: 'a,
    {
        let len = src.entries.len();
        if self.0 >= len {
            None
        } else {
            Some(&src.entries[self.0])
        }
    }
}

/// An `ExternRef` refers to an external entry defined in a program.
#[derive(Copy, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub struct ExternRef(pub usize);
impl ExternRef {
    pub fn not_found(&self) -> CodeRefError {
        CodeRefError::ExternNotFound { index: *self }
    }
    pub(crate) fn new_coderef(index: usize) -> CodeRef {
        ExternRef(index).into()
    }
}
impl std::fmt::Debug for ExternRef {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(fmt, "🗨-{}", self.0)
    }
}
impl std::fmt::Display for ExternRef {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(fmt, "{:?}", self)
    }
}
impl From<ExternRef> for CodeRef {
    fn from(e: ExternRef) -> CodeRef {
        CodeRef::Extern(e)
    }
}
impl<'a> Access<'a, Program> for ExternRef {
    type Target = Option<&'a ExternEntry>;
    fn access<'b>(&self, src: &'b Program) -> Option<&'a ExternEntry>
    where
        'b: 'a,
    {
        let len = src.externs.len();
        if self.0 >= len {
            None
        } else {
            Some(&src.externs[self.0])
        }
    }
}

/// A `GroupRef` refers to a group of `CodeRef`, used for
/// `Entry::Call` to implement conditional control flow.
///
#[derive(Copy, Clone, Serialize, PartialEq, Eq, Hash)]
pub struct GroupRef(usize);
impl std::fmt::Debug for GroupRef {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(fmt, "🎎-{}", self.0)
    }
}
impl std::fmt::Display for GroupRef {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(fmt, "{:?}", self)
    }
}
impl GroupRef {
    pub(crate) fn new(i: usize) -> GroupRef {
        GroupRef(i)
    }
    pub(crate) fn count(self, prog: &Program) -> Option<u8> {
        let GroupRef(i) = self;
        let len = prog.groups.len();
        if len <= i {
            return None;
        }
        Some(prog.groups[i].len() as u8)
    }
    /// From a program, retrive an entry from this group
    ///
    /// p: the program
    /// idx: the index of the group entries
    ///
    pub fn get_entry(self, p: &Program, idx: u8) -> Result<CodeRef, BuildError> {
        let GroupRef(i) = self;
        let len = p.groups.len();
        if len <= i {
            return Err(BuildError::GroupNotFound(GroupRef(i)));
        } else {
            let g = &p.groups[i];
            if g.len() <= idx as usize {
                return Err(BuildError::VariangOutOfRange {
                    given: idx,
                    max: g.len() as u8,
                });
            } else {
                Ok(g[idx as usize].clone())
            }
        }
    }
    /// Retrive the index value
    pub fn get_index(&self) -> usize {
        let GroupRef(i) = self;
        *i
    }
    pub(crate) fn push_to(&self, c: CodeRef, p: &mut Program) -> Result<(), BuildError> {
        let GroupRef(i) = self;
        if *i > p.groups.len() {
            return Err(BuildError::GroupNotFound(GroupRef(*i)));
        }
        Ok(p.groups[*i].push(c))
    }
    pub(crate) fn get_vec(&self, p: &Program) -> Result<CodeGroup, EvalError> {
        let GroupRef(i) = self;
        if *i > p.groups.len() {
            Err(EvalError::CodeRef(CodeRefError::InvalidGroupIndex {
                index: *self,
            }))
        } else {
            Ok(p.groups[*i].clone())
        }
    }
}