aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler.rs128
-rw-r--r--src/main.rs4
-rw-r--r--src/vm.rs12
3 files changed, 123 insertions, 21 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index 59659f4..ca4fcd3 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -6,6 +6,10 @@ struct Compiler {
tokens: TokenStream,
}
+const PREC_NO: u64 = 0;
+const PREC_TERM: u64 = 1;
+const PREC_FACTOR: u64 = 2;
+
impl Compiler {
pub fn new(tokens: TokenStream) -> Self {
Self {
@@ -15,12 +19,12 @@ impl Compiler {
}
fn error(&self, msg: &str) -> ! {
- println!("ERROR: {}", msg);
+ println!("ERROR: {} range {:?}", msg, self.tokens[self.curr].1);
panic!();
}
fn peek(&self) -> Token {
- if self.tokens.len() < self.curr {
+ if self.tokens.len() <= self.curr {
crate::tokenizer::Token::EOF
} else {
self.tokens[self.curr].0.clone()
@@ -33,39 +37,121 @@ impl Compiler {
t
}
- fn value(&mut self) -> Value {
- match self.eat() {
+ fn precedence(&self, token: Token) -> u64 {
+ match token {
+ Token::Minus => PREC_TERM,
+ Token::Plus => PREC_TERM,
+
+ Token::Star => PREC_FACTOR,
+ Token::Slash => PREC_FACTOR,
+
+ _ => PREC_NO,
+ }
+ }
+
+ fn prefix(&mut self, token: Token, block: &mut Block) -> bool {
+ match token {
+ Token::LeftParen => self.grouping(block),
+ Token::Minus => self.unary(block),
+
+ Token::Float(_) => self.value(block),
+ Token::Int(_) => self.value(block),
+
+ _ => { return false; },
+ }
+ return true;
+ }
+
+
+ fn infix(&mut self, token: Token, block: &mut Block) -> bool {
+ match token {
+ Token::Minus => self.binary(block),
+ Token::Plus => self.binary(block),
+
+ Token::Slash => self.binary(block),
+ Token::Star => self.binary(block),
+
+ _ => { return false; },
+ }
+ return true;
+ }
+
+ fn value(&mut self, block: &mut Block) {
+ let value = match self.eat() {
Token::Float(f) => { Value::Float(f) },
Token::Int(f) => { Value::Int(f) }
_ => { self.error("Invalid value.") }
+ };
+ block.add(Op::Constant(value));
+ }
+
+ fn grouping(&mut self, block: &mut Block) {
+ if Token::LeftParen != self.eat() {
+ self.error("Expected left parentasis around expression.");
}
+
+ self.expression(block);
+
+ if Token::RightParen != self.eat() {
+ self.error("Expected closing parentasis after expression.");
+ }
+ }
+
+ fn unary(&mut self, block: &mut Block) {
+ if Token::Minus != self.eat() {
+ self.error("Expected minus at start of negation.");
+ }
+ self.value(block);
+ block.add(Op::Neg);
+ }
+
+ fn binary(&mut self, block: &mut Block) {
+ let op = self.eat();
+
+ self.parse_precedence(block, self.precedence(op.clone()) + 1);
+
+ let op = match op {
+ Token::Plus => Op::Add,
+ Token::Minus => Op::Sub,
+ Token::Star => Op::Mul,
+ Token::Slash => Op::Div,
+ _ => { self.error("Illegal operator"); }
+ };
+ block.add(op);
}
fn expression(&mut self, block: &mut Block) {
- let a = self.value();
- block.add(Op::Constant(a));
+ self.parse_precedence(block, PREC_NO);
+ }
- loop {
- println!("{:?}", self.peek());
- let op = match self.eat() {
- Token::Plus => Op::Add,
- Token::Minus => Op::Sub,
- Token::Star => Op::Mul,
- Token::Slash => Op::Div,
- _ => { break; }
- };
-
- let b = self.value();
- block.add(Op::Constant(b));
- block.add(op);
+ fn parse_precedence(&mut self, block: &mut Block, precedence: u64) {
+ println!("-- {:?}", self.peek());
+ if !self.prefix(self.peek(), block) {
+ self.error("Expected expression.");
+ }
+
+ while precedence <= self.precedence(self.peek()) {
+ if !self.infix(self.peek(), block) {
+ break;
+ }
}
}
pub fn compile(&mut self, name: &str) -> Block {
let mut block = Block::new(name);
- self.expression(&mut block);
- block.add(Op::Print);
+ loop {
+ if self.peek() == Token::EOF {
+ break;
+ }
+
+ self.expression(&mut block);
+ block.add(Op::Print);
+
+ if self.eat() != Token::Newline {
+ self.error("Invalid expression");
+ }
+ }
block.add(Op::Return);
block
diff --git a/src/main.rs b/src/main.rs
index c9a7602..afe09ca 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,6 +5,10 @@ mod compiler;
fn main() {
let tokens = tokenizer::file_to_tokens("tests/simple.tdy");
+ for token in tokens.iter() {
+ println!("{:?}", token);
+ }
+
let block = compiler::compile("main", tokens);
vm::run_block(block);
diff --git a/src/vm.rs b/src/vm.rs
index 6b64928..7ab2235 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -10,10 +10,13 @@ pub enum Value {
pub enum Op {
Pop,
Constant(Value),
+
Add,
Sub,
Mul,
Div,
+ Neg,
+
Print,
Return,
}
@@ -91,6 +94,15 @@ impl VM {
self.stack.push(value);
}
+ Op::Neg => {
+ let a = self.stack.pop().unwrap();
+ match a {
+ Value::Float(a) => self.stack.push(Value::Float(-a)),
+ Value::Int(a) => self.stack.push(Value::Int(-a)),
+ _ => unimplemented!("Cannot negate '{:?}'.", a),
+ }
+ }
+
Op::Add => {
let b = self.stack.pop().unwrap();
let a = self.stack.pop().unwrap();