diff options
| author | Edvard Thörnros <edvard.thornros@gmail.com> | 2021-01-11 13:01:22 +0100 |
|---|---|---|
| committer | Edvard Thörnros <edvard.thornros@gmail.com> | 2021-01-11 13:01:22 +0100 |
| commit | e89a65fe2ea7911fa20502818e0af6d702d68be8 (patch) | |
| tree | 4da2952c00681a6faf538781bd3811a980a1f307 | |
| parent | a1e0b7c7fb6e1dc066e61cc302f17466777a488b (diff) | |
| download | sylt-e89a65fe2ea7911fa20502818e0af6d702d68be8.tar.gz | |
Variables and scoping
| -rw-r--r-- | src/compiler.rs | 60 | ||||
| -rw-r--r-- | src/vm.rs | 2 | ||||
| -rw-r--r-- | tests/simple.tdy | 29 | ||||
| -rw-r--r-- | todo | 53 |
4 files changed, 126 insertions, 18 deletions
diff --git a/src/compiler.rs b/src/compiler.rs index 1fd64d7..f691922 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -31,8 +31,8 @@ macro_rules! error { macro_rules! expect { ($thing:expr, $exp:pat, $msg:expr) => { match $thing.peek() { - $exp => { $thing.eat(); }, - _ => error!($thing, $msg), + $exp => { $thing.eat(); true }, + _ => { error!($thing, $msg); false } , } }; } @@ -46,7 +46,9 @@ nextable_enum!(Prec { Factor }); +#[derive(Copy, Clone)] enum Type { + NoType, UnkownType, Int, Float, @@ -69,6 +71,7 @@ impl TryFrom<&str> for Type { struct Variable { name: String, typ: Type, + level: usize, } struct Compiler { @@ -76,6 +79,7 @@ struct Compiler { tokens: TokenStream, current_file: PathBuf, + level: usize, stack: Vec<Variable>, panic: bool, @@ -89,6 +93,7 @@ impl Compiler { tokens, current_file: PathBuf::from(current_file), + level: 0, stack: vec![], panic: false, @@ -278,38 +283,40 @@ impl Compiler { } } - fn find_local(&self, name: &str, block: &Block) -> Option<usize> { + fn find_local(&self, name: &str, block: &Block) -> Option<(usize, Type, usize)> { self.stack.iter() - .rev() .enumerate() - .find_map(|x| if x.1.name == name { Some(x.0) } else { None} ) + .rev() + .find_map(|x| if x.1.name == name { Some((x.0, x.1.typ, x.1.level)) } else { None} ) } fn variable_expression(&mut self, block: &mut Block) { let name = match self.eat() { Token::Identifier(name) => name, - _ => unreachable!(), + __ => unreachable!(), }; - if let Some(id) = self.find_local(&name, block) { - block.add(Op::ReadLocal(id), self.line()); + if let Some((slot, _, _)) = self.find_local(&name, block) { + block.add(Op::ReadLocal(slot), self.line()); } else { error!(self, format!("Using undefined variable {}.", name)); } } fn define_variable(&mut self, name: &str, typ: Type, block: &mut Block) { - if self.find_local(&name, block).is_some() { - error!(self, format!("Multiple definitions of {}.", name)); - return; + if let Some((_, _, level)) = self.find_local(&name, block) { + if level == self.level { + error!(self, format!("Multiple definitions of {} in this block.", name)); + return; + } } self.expression(block); - self.stack.push(Variable { name: String::from(name), typ }); + self.stack.push(Variable { name: String::from(name), level: self.level, typ }); } fn assign(&mut self, name: &str, block: &mut Block) { - if let Some(slot) = self.find_local(&name, block) { + if let Some((slot, _, _)) = self.find_local(&name, block) { self.expression(block); block.add(Op::Assign(slot), self.line()); } else { @@ -317,6 +324,29 @@ impl Compiler { } } + fn scope(&mut self, block: &mut Block) { + if !expect!(self, Token::LeftBrace, "Expected '{' at start of block.") { + return; + } + + self.level += 1; + let h = self.stack.len(); + + while !matches!(self.peek(), Token::RightBrace | Token::EOF) { + self.statement(block); + } + + self.level -= 1; + + for _ in h..self.stack.len() { + block.add(Op::Pop, self.line()); + } + + self.stack.truncate(h); + + expect!(self, Token::RightBrace, "Expected '}' at end of block."); + } + fn statement(&mut self, block: &mut Block) { self.clear_panic(); @@ -350,6 +380,10 @@ impl Compiler { self.assign(&name, block); } + (Token::LeftBrace, _, _, _) => { + self.scope(block); + } + (Token::Newline, _, _, _) => {} _ => { @@ -135,7 +135,7 @@ impl VM { } pub fn run(&mut self) -> Result<(), Error>{ - const PRINT_WHILE_RUNNING: bool = true; + const PRINT_WHILE_RUNNING: bool = false; const PRINT_BLOCK: bool = true; if PRINT_BLOCK { diff --git a/tests/simple.tdy b/tests/simple.tdy index 7822739..9d05b40 100644 --- a/tests/simple.tdy +++ b/tests/simple.tdy @@ -2,9 +2,30 @@ // // asdlkjasl // print 1 + 3 // // OwO -a int := 1 + +// a int := 0 +// b int := 1 +// c int := 3 +// d int := 2 +// +// print a +// print b +// print d +// print c + +a int := 0 +b int := 3 +{ + a int := a + 1 + print a + + { + b int := 2 + print b + } + print b +} +a = 4 print a -print a + a + a -a = 3 + 3 -print a + a + a +// 1, 2, 3, 4 @@ -0,0 +1,53 @@ + - [x] Better error messages + - [x] Rustify the thingy + - [x] Return errors from runtime +---[-]-REPR---- + - [x] Pass files + + - [?] Globals + - [x] Variables + - [x] Scoping + - [ ] Jumps + - [ ] Type annotations + - [ ] If + - [ ] Listor + - [ ] For + - [ ] Prepass, for typeing + - [ ] Typing + - [ ] Functions + + +global_names = {"name" => idx} +gloabls [(type var1), (type var2), (type var3)...] + +==== q.tdy ==== +use z +// Is this a closure? Yes. +f := () -> { + print a +} + +f := () -> { +} + +<Var> <Typ> + +a int := a + 1 +a int := 3 +a := 3 + +let <Var>:<Typ> + +a : int = 123 +a := z.a + +==== z.tdy ==== +use q // Will we need imports? Yes. + +q.f() // What does this print? 123. q has a different scope. + +g := () -> { + print a +} + +a := q.a // Compilation error |
