aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGustav Sörnäs <gustav@sornas.net>2021-01-09 19:57:39 +0100
committerGustav Sörnäs <gustav@sornas.net>2021-01-09 19:57:39 +0100
commit4e589cac364edffb08caf7e09a12cc05894271ac (patch)
tree7325c7717ae1b1ead6ad09e6113933cddfe4e3e4 /src
parent011e7b31e63864a83627c79c1b2d10d7dc0662b0 (diff)
downloadsylt-4e589cac364edffb08caf7e09a12cc05894271ac.tar.gz
boolean {comparisons,algebra}
Diffstat (limited to 'src')
-rw-r--r--src/compiler.rs76
-rw-r--r--src/tokenizer.rs9
-rw-r--r--src/vm.rs90
3 files changed, 129 insertions, 46 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index d3d4c2c..4b9e74c 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -8,9 +8,10 @@ struct Compiler {
//TODO rustify
const PREC_NO: u64 = 0;
-const PREC_COMP: u64 = 1;
-const PREC_TERM: u64 = 2;
-const PREC_FACTOR: u64 = 3;
+const PREC_BOOL: u64 = 1;
+const PREC_COMP: u64 = 2;
+const PREC_TERM: u64 = 3;
+const PREC_FACTOR: u64 = 4;
impl Compiler {
pub fn new(tokens: TokenStream) -> Self {
@@ -41,13 +42,19 @@ impl Compiler {
fn precedence(&self, token: Token) -> u64 {
match token {
- Token::Minus => PREC_TERM,
- Token::Plus => PREC_TERM,
+ Token::Star | Token::Slash => PREC_FACTOR,
- Token::Star => PREC_FACTOR,
- Token::Slash => PREC_FACTOR,
+ Token::Minus | Token::Plus => PREC_TERM,
- Token::EqualEqual => PREC_COMP,
+ Token::EqualEqual
+ | Token::Greater
+ | Token::GreaterEqual
+ | Token::Less
+ | Token::LessEqual
+ | Token::NotEqual
+ => PREC_COMP,
+
+ Token::And | Token::Or => PREC_BOOL,
_ => PREC_NO,
}
@@ -60,6 +67,9 @@ impl Compiler {
Token::Float(_) => self.value(block),
Token::Int(_) => self.value(block),
+ Token::Bool(_) => self.value(block),
+
+ Token::Not => self.unary(block),
_ => { return false; },
}
@@ -69,13 +79,19 @@ impl Compiler {
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),
-
- Token::EqualEqual => self.binary(block),
+ Token::Minus
+ | Token::Plus
+ | Token::Slash
+ | Token::Star
+ => self.binary(block),
+
+ Token::EqualEqual
+ | Token::Greater
+ | Token::GreaterEqual
+ | Token::Less
+ | Token::LessEqual
+ | Token::NotEqual
+ => self.comparison(block),
_ => { return false; },
}
@@ -85,7 +101,8 @@ impl Compiler {
fn value(&mut self, block: &mut Block) {
let value = match self.eat() {
Token::Float(f) => { Value::Float(f) },
- Token::Int(f) => { Value::Int(f) }
+ Token::Int(i) => { Value::Int(i) }
+ Token::Bool(b) => { Value::Bool(b) }
_ => { self.error("Invalid value.") }
};
block.add(Op::Constant(value));
@@ -104,11 +121,13 @@ impl Compiler {
}
fn unary(&mut self, block: &mut Block) {
- if Token::Minus != self.eat() {
- self.error("Expected minus at start of negation.");
- }
+ let op = match self.eat() {
+ Token::Minus => Op::Neg,
+ Token::Not => Op::Not,
+ _ => self.error("Invalid unary operator"),
+ };
self.value(block);
- block.add(Op::Neg);
+ block.add(op);
}
fn binary(&mut self, block: &mut Block) {
@@ -121,12 +140,27 @@ impl Compiler {
Token::Minus => Op::Sub,
Token::Star => Op::Mul,
Token::Slash => Op::Div,
- Token::EqualEqual => Op::CompEq,
_ => { self.error("Illegal operator"); }
};
block.add(op);
}
+ fn comparison(&mut self, block: &mut Block) {
+ let op = self.eat();
+ self.parse_precedence(block, self.precedence(op.clone()) + 1);
+
+ let op: &[Op] = match op {
+ Token::EqualEqual => &[Op::Equal],
+ Token::Less => &[Op::Less],
+ Token::Greater => &[Op::Greater],
+ Token::NotEqual => &[Op::Equal, Op::Not],
+ Token::LessEqual => &[Op::Greater, Op::Not],
+ Token::GreaterEqual => &[Op::Less, Op::Not],
+ _ => { self.error("Illegal comparison operator"); }
+ };
+ block.add_from(op);
+ }
+
fn expression(&mut self, block: &mut Block) {
self.parse_precedence(block, PREC_NO);
}
diff --git a/src/tokenizer.rs b/src/tokenizer.rs
index a12285b..1882b48 100644
--- a/src/tokenizer.rs
+++ b/src/tokenizer.rs
@@ -59,6 +59,8 @@ pub enum Token {
Equal,
#[token("==")]
EqualEqual,
+ #[token("!=")]
+ NotEqual,
#[token("(")]
LeftParen,
@@ -84,6 +86,13 @@ pub enum Token {
#[token("<=")]
LessEqual,
+ #[token("&&")]
+ And,
+ #[token("||")]
+ Or,
+ #[token("!")]
+ Not,
+
#[token(".")]
Dot,
#[token("->")]
diff --git a/src/vm.rs b/src/vm.rs
index 7ba7f19..9102f81 100644
--- a/src/vm.rs
+++ b/src/vm.rs
@@ -1,12 +1,12 @@
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub enum Value {
Float(f64),
Int(i64),
Bool(bool),
}
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
pub enum Op {
Pop,
Constant(Value),
@@ -17,7 +17,13 @@ pub enum Op {
Div,
Neg,
- CompEq,
+ And,
+ Or,
+ Not,
+
+ Equal, // ==
+ Less, // <
+ Greater, // >
Print,
Return,
@@ -38,8 +44,17 @@ impl Block {
}
pub fn add(&mut self, op: Op) -> usize {
+ let len = self.ops.len();
self.ops.push(op);
- self.ops.len()
+ len
+ }
+
+ pub fn add_from(&mut self, ops: &[Op]) -> usize {
+ let len = self.ops.len();
+ for op in ops {
+ self.add(*op);
+ }
+ len
}
}
@@ -63,6 +78,11 @@ pub fn run_block(block: Block) {
}
impl VM {
+ fn pop_twice(&mut self) -> (Value, Value) {
+ let (a, b) = (self.stack.pop().unwrap(), self.stack.pop().unwrap());
+ (b, a)
+ }
+
pub fn run(&mut self) {
const PRINT_WHILE_RUNNING: bool = true;
const PRINT_BLOCK: bool = true;
@@ -76,7 +96,6 @@ impl VM {
}
loop {
-
if PRINT_WHILE_RUNNING {
print!(" [");
for s in self.stack.iter() {
@@ -106,51 +125,73 @@ impl VM {
}
Op::Add => {
- let b = self.stack.pop().unwrap();
- let a = self.stack.pop().unwrap();
- match (a, b) {
+ match self.pop_twice() {
(Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(b + a)),
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(b + a)),
- _ => unimplemented!("Cannot add '{:?}' and '{:?}'.", a, b),
+ (a, b) => unimplemented!("Cannot add '{:?}' and '{:?}'.", a, b),
}
}
Op::Sub => {
- let b = self.stack.pop().unwrap();
- let a = self.stack.pop().unwrap();
- match (a, b) {
+ match self.pop_twice() {
(Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(b - a)),
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(b - a)),
- _ => unimplemented!("Cannot sub '{:?}' and '{:?}'.", a, b),
+ (a, b) => unimplemented!("Cannot sub '{:?}' and '{:?}'.", a, b),
}
}
Op::Mul => {
- let b = self.stack.pop().unwrap();
- let a = self.stack.pop().unwrap();
- match (a, b) {
+ match self.pop_twice() {
(Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(b * a)),
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(b * a)),
- _ => unimplemented!("Cannot mul '{:?}' and '{:?}'.", a, b),
+ (a, b) => unimplemented!("Cannot mul '{:?}' and '{:?}'.", a, b),
}
}
Op::Div => {
- let b = self.stack.pop().unwrap();
- let a = self.stack.pop().unwrap();
- match (a, b) {
+ match self.pop_twice() {
(Value::Float(a), Value::Float(b)) => self.stack.push(Value::Float(b / a)),
(Value::Int(a), Value::Int(b)) => self.stack.push(Value::Int(b / a)),
- _ => unimplemented!("Cannot mul '{:?}' and '{:?}'.", a, b),
+ (a, b) => unimplemented!("Cannot mul '{:?}' and '{:?}'.", a, b),
}
}
- Op::CompEq => {
- let b = self.stack.pop().unwrap();
- let a = self.stack.pop().unwrap();
+ Op::Equal => {
+ let (a, b) = self.pop_twice();
self.stack.push(Value::Bool(a == b));
}
+ Op::Less => {
+ let (a, b) = self.pop_twice();
+ self.stack.push(Value::Bool(a < b));
+ }
+
+ Op::Greater => {
+ let (a, b) = self.pop_twice();
+ self.stack.push(Value::Bool(a > b));
+ }
+
+ Op::And => {
+ match self.pop_twice() {
+ (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a && b)),
+ (a, b) => unimplemented!("Cannot 'and' {:?} and {:?}", a, b),
+ }
+ }
+
+ Op::Or => {
+ match self.pop_twice() {
+ (Value::Bool(a), Value::Bool(b)) => self.stack.push(Value::Bool(a || b)),
+ (a, b) => unimplemented!("Cannot 'or' {:?} and {:?}", a, b),
+ }
+ }
+
+ Op::Not => {
+ match self.stack.pop().unwrap() {
+ Value::Bool(a) => self.stack.push(Value::Bool(!a)),
+ a => unimplemented!("Cannot 'not' {:?}", a),
+ }
+ }
+
Op::Print => {
println!("PRINT: {:?}", self.stack.pop());
}
@@ -159,7 +200,6 @@ impl VM {
return;
}
}
-
self.ip += 1;
}
}