aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/compiler.rs60
-rw-r--r--src/vm.rs2
-rw-r--r--tests/simple.tdy29
-rw-r--r--todo53
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, _, _, _) => {}
_ => {
diff --git a/src/vm.rs b/src/vm.rs
index 8f2c631..1d66c12 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -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
diff --git a/todo b/todo
new file mode 100644
index 0000000..d4bde7e
--- /dev/null
+++ b/todo
@@ -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