aboutsummaryrefslogtreecommitdiffstats
path: root/src/compiler.rs
blob: 59659f4f6d178042ae18dc913d8b3bb346980f86 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use crate::tokenizer::{Token, TokenStream};
use crate::vm::{Value, Block, Op};

struct Compiler {
    curr: usize,
    tokens: TokenStream,
}

impl Compiler {
    pub fn new(tokens: TokenStream) -> Self {
        Self {
            curr: 0,
            tokens,
        }
    }

    fn error(&self, msg: &str) -> ! {
        println!("ERROR: {}", msg);
        panic!();
    }

    fn peek(&self) -> Token {
        if self.tokens.len() < self.curr {
            crate::tokenizer::Token::EOF
        } else {
            self.tokens[self.curr].0.clone()
        }
    }

    fn eat(&mut self) -> Token {
        let t = self.peek();
        self.curr += 1;
        t
    }

    fn value(&mut self) -> Value {
        match self.eat() {
            Token::Float(f) => { Value::Float(f) },
            Token::Int(f) => { Value::Int(f) }
            _ => { self.error("Invalid value.") }
        }
    }

    fn expression(&mut self, block: &mut Block) {
        let a = self.value();
        block.add(Op::Constant(a));

        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);
        }
    }

    pub fn compile(&mut self, name: &str) -> Block {
        let mut block = Block::new(name);

        self.expression(&mut block);
        block.add(Op::Print);
        block.add(Op::Return);

        block
    }
}

pub fn compile(name: &str, tokens: TokenStream) -> Block {
    Compiler::new(tokens).compile(name)
}