Skip to main content

anillo/
token.rs

1//! This module provides definitions for the fundamental types used in a
2//! traditional compiler.
3//!
4//! This includes items such as Tokens, AST Nodes, and the AST itself. These
5//! definitions are meant to be able to be passed around between compilation
6//! stages (such as between lexing, parsing, and AST validation). The types
7//! that may exist on their own (such as the Lexer and Parser) exist in their
8//! own modules
9
10use std::iter::zip;
11
12use crate::error::CompilationError;
13
14/// The fundamental unit of a source code file. These are used to represent
15/// the _lexemes_ within a source file
16#[derive(Debug)]
17pub enum Token {
18    KeywordExtern,
19    KeywordWithLevel,
20    KeywordPrivilege(Ring),
21    KeywordIsr,
22    KeywordCall,
23
24    Identifier(String),
25
26    LeftParen,
27    RightParen,
28    LeftBracket,
29    RightBracket,
30    Comma,
31    /// '$' is a special Anillo token only allowed within an ISR. It directly
32    /// refers to the number of the ISR itself.
33    Dollar,
34}
35
36/// A small wrapper around a `Token` that also contains line and column info.
37/// This just lets the lexer and parser output meaningful error messages so
38/// a user knows where a mistake may have been made.
39#[derive(Debug)]
40pub struct TokenInfo {
41    token: Token,
42    line: u32,
43    col: u32,
44}
45
46impl TokenInfo {
47    pub fn new(token: Token, line: u32, col: u32) -> TokenInfo {
48        TokenInfo { token, line, col }
49    }
50
51    /// Simply used to directly pattern match on the internal `token` field.
52    pub fn borrow_token(&self) -> &Token {
53        &self.token
54    }
55
56    pub fn line(&self) -> u32 {
57        self.line
58    }
59
60    pub fn col(&self) -> u32 {
61        self.col
62    }
63}
64
65impl std::fmt::Display for TokenInfo {
66    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        write!(
68            f,
69            "TokenInfo {{token = {}, line = {}, col = {}}}",
70            self.token, self.line, self.col
71        )
72    }
73}
74
75impl std::fmt::Display for Token {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        match self {
78            Token::KeywordExtern => write!(f, "Token::KeywordExtern"),
79            Token::KeywordWithLevel => write!(f, "Token::KeywordWithLevel"),
80            Token::KeywordPrivilege(p) => write!(f, "Token::KeywordPrivilege({})", p),
81            Token::KeywordIsr => write!(f, "Token::KeywordIsr"),
82            Token::Identifier(id) => write!(f, "Token::Identifier({})", id),
83            Token::LeftParen => write!(f, "Token::LeftParen"),
84            Token::RightParen => write!(f, "Token::RightParen"),
85            Token::LeftBracket => write!(f, "Token::LeftBracket"),
86            Token::RightBracket => write!(f, "Token::RightBracket"),
87            Token::Comma => write!(f, "Token::Comma"),
88            Token::Dollar => write!(f, "Token::Dollar"),
89            Token::KeywordCall => write!(f, "Token::KeywordCall"),
90        }
91    }
92}
93
94/// Represents a privilege level of an external function or an ISR
95#[derive(Debug, Clone, Copy)]
96pub enum Ring {
97    Super,
98    User,
99}
100
101/// All of these type traits look suspiciously similar to the Type Classes
102/// covered in lecture...
103impl PartialEq for Ring {
104    fn eq(&self, other: &Self) -> bool {
105        matches!(
106            (self, other),
107            (Self::Super, Self::Super) | (Self::User, Self::User)
108        )
109    }
110}
111
112impl Eq for Ring {}
113
114impl PartialOrd for Ring {
115    fn lt(&self, other: &Self) -> bool {
116        match (self, other) {
117            (Ring::Super, _) => false,
118            (Ring::User, Ring::Super) => true,
119            (Ring::User, Ring::User) => false,
120        }
121    }
122
123    fn le(&self, other: &Self) -> bool {
124        match (self, other) {
125            (Ring::User, _) => true,
126            (Ring::Super, Ring::Super) => true,
127            (Ring::Super, Ring::User) => false,
128        }
129    }
130
131    fn gt(&self, other: &Self) -> bool {
132        match (self, other) {
133            (Ring::Super, Ring::Super) => false,
134            (Ring::Super, _) => true,
135            (Ring::User, _) => false,
136        }
137    }
138
139    fn ge(&self, other: &Self) -> bool {
140        match (self, other) {
141            (Ring::Super, _) => true,
142            (Ring::User, Ring::User) => true,
143            (Ring::User, _) => false,
144        }
145    }
146
147    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
148        Some(self.cmp(other))
149    }
150}
151
152impl Ord for Ring {
153    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
154        if self.gt(other) {
155            std::cmp::Ordering::Greater
156        } else if self.lt(other) {
157            std::cmp::Ordering::Less
158        } else {
159            std::cmp::Ordering::Equal
160        }
161    }
162
163    fn max(self, other: Self) -> Self
164    where
165        Self: Sized,
166    {
167        if self.gt(&other) { self } else { other }
168    }
169
170    fn min(self, other: Self) -> Self
171    where
172        Self: Sized,
173    {
174        if self.lt(&other) { self } else { other }
175    }
176
177    fn clamp(self, _min: Self, _max: Self) -> Self
178    where
179        Self: Sized,
180    {
181        todo!()
182    }
183}
184
185impl std::fmt::Display for Ring {
186    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
187        write!(
188            f,
189            "Ring::({})",
190            match self {
191                Ring::User => "User",
192                Ring::Super => "Super",
193            }
194        )
195    }
196}
197
198/// Some power of 2 in the range [8-64] inclusive
199#[derive(Debug, Clone, Copy)]
200pub enum FuncArgType {
201    U8,
202    I8,
203    U16,
204    I16,
205    U32,
206    I32,
207    U64,
208    I64,
209}
210
211#[derive(Debug)]
212pub struct FuncArg {
213    /// TODO(SEP): Do something with the func arg name when we have arbitrary arg usage
214    _name: String,
215
216    /// `type` is likely reserved by the rust language for use so I can't use the darn name
217    type_t: FuncArgType,
218}
219
220impl FuncArg {
221    pub fn new(name: String, type_t: FuncArgType) -> FuncArg {
222        FuncArg {
223            _name: name,
224            type_t,
225        }
226    }
227}
228
229#[derive(Debug)]
230pub struct ExternalFunctionNode {
231    name: String,
232    args: Vec<FuncArg>,
233    privilege: Option<Ring>,
234}
235
236impl ExternalFunctionNode {
237    pub fn new(name: String, args: Vec<FuncArg>, privilege: Option<Ring>) -> ExternalFunctionNode {
238        ExternalFunctionNode {
239            name,
240            args,
241            privilege,
242        }
243    }
244}
245
246#[derive(Debug)]
247pub enum CallArg {
248    Var(String),
249    Dollar,
250}
251
252#[derive(Debug)]
253pub struct ExternalFunctionCall {
254    name: String,
255    args: Vec<CallArg>,
256}
257
258impl ExternalFunctionCall {
259    pub fn new(name: String, args: Vec<CallArg>) -> ExternalFunctionCall {
260        ExternalFunctionCall { name, args }
261    }
262}
263
264#[derive(Debug)]
265pub struct IsrNode {
266    name: String,
267    id: u8,
268    privilege: Option<Ring>,
269    calling_func: Option<ExternalFunctionCall>,
270}
271
272impl IsrNode {
273    pub fn new(
274        name: String,
275        id: u8,
276        privilege: Option<Ring>,
277        calling_func: Option<ExternalFunctionCall>,
278    ) -> IsrNode {
279        IsrNode {
280            name,
281            id,
282            privilege,
283            calling_func,
284        }
285    }
286}
287
288#[derive(Debug)]
289pub enum Ingot {
290    ExternalFunction(ExternalFunctionNode),
291    Isr(IsrNode),
292}
293
294#[derive(Debug)]
295pub struct Ast(Vec<Ingot>);
296
297impl Ast {
298    pub fn new(vec: Vec<Ingot>) -> Ast {
299        Ast(vec)
300    }
301
302    pub fn verify(&self) -> Result<(), CompilationError> {
303        for node in &self.0 {
304            match node {
305                Ingot::ExternalFunction(extern_func) => {
306                    if extern_func.args.len() > 1 {
307                        eprintln!(
308                            "Warning(Definition): Multiple args in external functions not yet supported"
309                        );
310                        eprintln!("Function: {}", extern_func.name);
311                    }
312                }
313                Ingot::Isr(isr) => match &isr.calling_func {
314                    None => {
315                        eprintln!("Warning: Found ISR with no external function call.",);
316                        eprintln!(
317                            "This will generate code that effectively ignores this interrupt."
318                        );
319                    }
320                    Some(callsite) => {
321                        let calling_func = self
322                            .0
323                            .iter()
324                            .filter_map(|ingot| match ingot {
325                                Ingot::Isr(_) => None,
326                                Ingot::ExternalFunction(candidate) => {
327                                    if candidate.name.eq(&callsite.name) {
328                                        Some(candidate)
329                                    } else {
330                                        None
331                                    }
332                                }
333                            })
334                            .collect::<Vec<&ExternalFunctionNode>>();
335
336                        match calling_func[..] {
337                            [] => {
338                                return Err(CompilationError::new_without_src_info(format!(
339                                    "Attempt to call an undefined function: {} from isr {}",
340                                    callsite.name, isr.name
341                                )));
342                            }
343                            [callee] => {
344                                if callee.args.len() != callsite.args.len() {
345                                    return Err(CompilationError::new_without_src_info(format!(
346                                        "Mismatched arg count between definition and usage of {} within isr {}({})",
347                                        callee.name, isr.name, isr.id
348                                    )));
349                                }
350
351                                if callee.args.len() > 1 {
352                                    eprintln!(
353                                        "Warning(Callsite): Multiple args in external functions not yet supported"
354                                    );
355                                    eprintln!("Function: {}", callee.name);
356                                }
357
358                                for (def_arg, call_arg) in zip(&callee.args, &callsite.args) {
359                                    match (def_arg.type_t, call_arg) {
360                                        // a $ (AKA a U8) can safely upgrade to all other types
361                                        // Except i8
362                                        (FuncArgType::I8, CallArg::Dollar) => {
363                                            return Err(CompilationError::new_without_src_info(
364                                                format!(
365                                                    "At callsite of {} in isr {}({}): '$' (AKA U8) not safely convertable to I8",
366                                                    callee.name, isr.name, isr.name
367                                                ),
368                                            ));
369                                        }
370                                        (_, CallArg::Dollar) => {}
371                                        (_, CallArg::Var(var)) => {
372                                            return Err(CompilationError::new_without_src_info(
373                                                format!(
374                                                    "At callsite of {} in isr {}{}: arbitrary variable expressions ({}) not yet supported",
375                                                    callee.name, isr.name, isr.id, var
376                                                ),
377                                            ));
378                                        }
379                                    }
380                                }
381
382                                // All ISRs run in kernel code. Their privilege is a matter of what
383                                // type of software may trigger them, and thus what type of func
384                                // they are allowed to call.
385                                //
386                                // Also MONAD RETURN MOMENT!!!!
387                                let isr_privilege: Ring = match isr.privilege {
388                                    None => Ring::Super, // implictly more restrictive
389                                    Some(p) => p,
390                                };
391                                let callee_privilege: Ring = match callee.privilege {
392                                    None => Ring::Super,
393                                    Some(p) => p,
394                                };
395
396                                if isr_privilege < callee_privilege {
397                                    return Err(CompilationError::new_without_src_info(format!(
398                                        "Attempt to call higher privilege function ({}) from lower privilege ISR ({})",
399                                        callee.name, isr.name
400                                    )));
401                                }
402                            }
403                            _ => {
404                                return Err(CompilationError::new_without_src_info(format!(
405                                    "Attempt to call ambiguous function: {} from isr {} (Did you accidentally define {} twice?)",
406                                    callsite.name, isr.name, callsite.name
407                                )));
408                            }
409                        }
410                    }
411                },
412            }
413        }
414
415        Ok(())
416    }
417}