Erode
All errors of Rust
Files
-
grammar.lalrpop
strives to catch a minimal Rust like language. It implements both Debug and Display traits, where the former gives the native representation and the latter a pretty printed version. -
ast.rs
the Abstract Syntax Tree for the parsed program. -
check.rs
the type checker (todo). -
tests/*
contains tests for compiler. (Currently only parse tests.)
vm
Memory model
enum Val {
Num(i32),
Bool(bool),
Uninitialized,
Unit,
Ref(Id),
RefMut(id),
}
type IdVal = HashMap<Id, Val>;
struct Mem(VecDeque<IdVal>);
Mem
models the stack memory, as a map from identifiers to values. Scopes are defined from vector of stack frames. Insertion of new stack items (Val
) happens on the local frame (top of stack). Lookup will check the local scope first, and then outer scopes in a nested fashion.
On a function call, the parameters are pushed to the stack, and a new stack frame is generated (on entry of each sequence of statements).
References are handled through Ref(Id)
, and are transitive. You cannot reference memory items in any other way (so this is a limitation compared to real Rust).
check
The check
module performs basic type checking and borrow checking. In the following the basic reasoning is discussed.
pub enum Type {
Unit, // (), // maybe just a special case of tuple, see todo
Never, // !
Bool, // bool
I32, // i32
Ref(Box<Type>), // & mut? Type -- used in parser
Mut(Box<Type>), // mut Type
Unknown, // Not yet assigned
}
pub type IdType = HashMap<Id, Type>;
type Scope = i32;
pub struct VarEnv(VecDeque<IdType>);
The var_env : VarEnv
holds a stack of scopes. A lookup (get(Id)-> Option<(Scope, &Type)>
), returns the type and what scope it is defined in (0, being arguments, 1, function body, 2 ... inner scopes). Inner scopes emerge from blocks, or block statements (if/while etc).