M kabel/src/codegen.rs => kabel/src/codegen.rs +4 -28
@@ 1,4 1,4 @@
-use crate::{opcodes::OpCode, parser::{BinOp, Lit, AST}, vm::{Value, VM}};
+use crate::{codegen_binary, opcodes::OpCode, parser::{BinOp, Lit, AST}, vm::{Value, VM}};
pub struct Codegen {
pub vm: VM
@@ 44,33 44,9 @@ impl Codegen {
}
pub fn visit_binary(&mut self, left: AST, oper: BinOp, right: AST) {
use crate::parser::BinOp::*;
- match oper {
- Add => {
- self.visit(right);
- self.visit(left);
- self.vm.chunk.push(OpCode::ADD.into());
- self.vm.lines.last_mut().unwrap().1 += 1;
- }
- Sub => {
- self.visit(right);
- self.visit(left);
- self.vm.chunk.push(OpCode::SUB.into());
- self.vm.lines.last_mut().unwrap().1 += 1;
- }
- Mul => {
- self.visit(right);
- self.visit(left);
- self.vm.chunk.push(OpCode::MUL.into());
- self.vm.lines.last_mut().unwrap().1 += 1;
- }
- Div => {
- self.visit(right);
- self.visit(left);
- self.vm.chunk.push(OpCode::DIV.into());
- self.vm.lines.last_mut().unwrap().1 += 1;
- }
- _ => { panic!("not implemented") }
- }
+ codegen_binary!(self, left, right, oper, Add, ADD, Sub, SUB, Mul, MUL,
+ Div, DIV, Mod, MOD, Eq, EQ, Ne, NE, Gr, GR, Ge, GE, Ls, LS,
+ Le, LE, Or, OR, And, AND);
}
pub fn visit_lit(&mut self, ast: &AST, lit: Lit) {
match lit {
M kabel/src/macros.rs => kabel/src/macros.rs +27 -0
@@ 175,3 175,30 @@ macro_rules! collect_lines {
$string.iter().fold("".to_string(), |acc, string| acc + string + "\n").trim_end().to_string()
};
}
+
+#[macro_export]
+macro_rules! codegen_binary {
+ ($self:expr, $left:expr, $right:expr, $match_to:expr, $( $oper:tt, $code:tt ),*) => {
+ match $match_to {
+ $( $oper => {
+ $self.visit($right);
+ $self.visit($left);
+ $self.vm.chunk.push(OpCode::$code.into());
+ $self.vm.lines.last_mut().unwrap().1 += 1;
+ } )*
+ _ => { panic!("not implemented") }
+ }
+ };
+}
+
+#[macro_export]
+macro_rules! vm_boolean_binary {
+ ($self:expr, $oper:tt) => {
+ match ($self.stack.pop().unwrap(), $self.stack.pop().unwrap()) {
+ (Num(v1), Num(v2)) => $self.stack.push(Bool(v1 $oper v2)),
+ (Str(v1), Str(v2)) => $self.stack.push(Bool(v1 $oper v2)),
+ (Bool(v1), Bool(v2)) => $self.stack.push(Bool(v1 $oper v2)),
+ (_v1, _v2) => $self.stack.push(Bool(false)),
+ }
+ };
+}
M kabel/src/opcodes.rs => kabel/src/opcodes.rs +24 -0
@@ 5,6 5,14 @@ pub enum OpCode {
MUL,
DIV,
MOD,
+ EQ,
+ NE,
+ GR,
+ GE,
+ LS,
+ LE,
+ OR,
+ AND,
PRINT,
ERR,
}
@@ 19,6 27,14 @@ impl From<OpCode> for u8 {
MUL => 0x03,
DIV => 0x04,
MOD => 0x05,
+ EQ => 0x06,
+ NE => 0x07,
+ GR => 0x08,
+ GE => 0x09,
+ LS => 0x0A,
+ LE => 0x0B,
+ OR => 0x0C,
+ AND => 0x0D,
PRINT => 0xFE,
ERR => 0xFF
}
@@ 34,6 50,14 @@ impl From<u8> for OpCode {
0x03 => MUL,
0x04 => DIV,
0x05 => MOD,
+ 0x06 => EQ,
+ 0x07 => NE,
+ 0x08 => GR,
+ 0x09 => GE,
+ 0x0A => LS,
+ 0x0B => LE,
+ 0x0C => OR,
+ 0x0D => AND,
0xFE => PRINT,
_ => ERR
}
M kabel/src/vm.rs => kabel/src/vm.rs +53 -1
@@ 1,4 1,4 @@
-use crate::{mismatched_types, runtime_error::KabelRuntimeError, wrong_type};
+use crate::{mismatched_types, runtime_error::KabelRuntimeError, vm_boolean_binary, wrong_type};
pub struct VM {
ip: usize,
@@ 91,6 91,58 @@ impl VM {
}
}
}
+ 0x05 => { // MOD
+ match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ (Num(v1), Num(v2)) => self.stack.push(Num(v1 % v2)),
+ (Str(_v1), Str(_v2)) => {
+ return Err(wrong_type!(self, "Cannot perform modulus on strings"))
+ },
+ (Bool(_v1), Bool(_v2)) => {
+ return Err(wrong_type!(self, "Cannot perform modulus on booleans"))
+ }
+ (v1, v2) => {
+ return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str()))
+ }
+ }
+ }
+ // EQ
+ 0x06 => vm_boolean_binary!(self, ==),
+ // NE
+ 0x07 => vm_boolean_binary!(self, !=),
+ // GR
+ 0x08 => vm_boolean_binary!(self, >),
+ // GE
+ 0x09 => vm_boolean_binary!(self, >=),
+ // LS
+ 0x0A => vm_boolean_binary!(self, <),
+ // LE
+ 0x0B => vm_boolean_binary!(self, <=),
+ // OR
+ 0x0C => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ (Num(_v1), Num(_v2)) => {
+ return Err(wrong_type!(self, "Cannot perform logical OR on numbers"))
+ }
+ (Str(_v1), Str(_v2)) => {
+ return Err(wrong_type!(self, "Cannot perform logical OR on strings"))
+ },
+ (Bool(v1), Bool(v2)) => self.stack.push(Bool(v1 || v2)),
+ (v1, v2) => {
+ return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str()))
+ }
+ }
+ // AND
+ 0x0D => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ (Num(_v1), Num(_v2)) => {
+ return Err(wrong_type!(self, "Cannot perform logical AND on numbers"))
+ }
+ (Str(_v1), Str(_v2)) => {
+ return Err(wrong_type!(self, "Cannot perform logical AND on strings"))
+ },
+ (Bool(v1), Bool(v2)) => self.stack.push(Bool(v1 && v2)),
+ (v1, v2) => {
+ return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str()))
+ }
+ }
0xFE => { // PRINT
let value = self.stack.pop().unwrap();
M kabel_test/src/main.rs => kabel_test/src/main.rs +1 -1
@@ 9,7 9,7 @@ fn main() {
let program =
fs::read_to_string(args[1].clone()).unwrap();*/
- let program = "print 4 / 5;".to_string();
+ let program = "print 7%3;".to_string();
let mut output = "".to_string();