M kabel/opcodes.txt => kabel/opcodes.txt +21 -20
@@ 1,28 1,29 @@
CONSTANT VAL ; 0x00
VAR STACKPTR ; 0x01
+ASSIGN PTR ; 0x02
-ADD ; 0x02
-SUB ; 0x03
-MUL ; 0x04
-DIV ; 0x05
-MOD ; 0x06
-BITAND ; 0x07
-BITXOR ; 0x08
-BITOR ; 0x09
-EQ ; 0x0A
-NE ; 0x0B
-GR ; 0x0C
-GE ; 0x0D
-LS ; 0x0E
-LE ; 0x0F
-OR ; 0x10
-AND ; 0x11
+ADD ; 0x03
+SUB ; 0x04
+MUL ; 0x05
+DIV ; 0x06
+MOD ; 0x07
+BITAND ; 0x08
+BITXOR ; 0x09
+BITOR ; 0x0a
+EQ ; 0x0B
+NE ; 0x0C
+GR ; 0x0D
+GE ; 0x0E
+LS ; 0x0F
+LE ; 0x10
+OR ; 0x11
+AND ; 0x12
-NOT ; 0x12
-NEG ; 0x13
+NOT ; 0x13
+NEG ; 0x14
-JMP LOC ; 0x14
-IF_NE ELSE ; 0x15
+JMP LOC ; 0x15
+IF_NE ELSE ; 0x16
POP ; 0xFD
PRINT ; 0xFE
M kabel/src/codegen.rs => kabel/src/codegen.rs +57 -14
@@ 1,16 1,16 @@
-use std::collections::HashMap;
-
use crate::{ast::{ASTType, BinOp, Lit, Name, UnOp, AST}, codegen_binary, codegen_unary, extension::Extension, opcodes::OpCode, vm::{Value, VM}};
pub struct Codegen {
- pub vm: VM
+ pub vm: VM,
+ pub scopes: Vec<usize>, // number of variables declared in the scope
}
impl Codegen {
pub fn new(text: String) -> Self {
Codegen {
vm: VM::new(Vec::new(), Vec::new(),
- Vec::new(), HashMap::new(), text),
+ Vec::new(), text),
+ scopes: vec![0],
}
}
pub fn visit(&mut self, ast: AST) {
@@ 24,8 24,8 @@ impl Codegen {
If(condition, block, else_expr) => {
self.visit_if(*condition, *block, *else_expr);
}
- Block(stmts) => {
- self.visit_block(stmts);
+ Block(ref stmts) => {
+ self.visit_block(&ast, stmts.clone());
}
Decl(ref name, ref expr) => {
self.visit_decl(&ast, name.clone(), *expr.clone());
@@ 37,6 37,9 @@ impl Codegen {
Print(ref expr) => {
self.visit_print(&ast, *expr.clone());
}
+ Assign(ref name, ref expr) => {
+ self.visit_assign(&ast, name.clone(), *expr.clone());
+ }
Binary(left, oper, right) => {
self.visit_binary(*left, oper, *right);
}
@@ 94,22 97,32 @@ impl Codegen {
self.visit(ast);
self.patch_jump(end_jmp_loc); // jmp to after else
}
- _ => {}
+ _ => { println!("unimplemented"); }
}
} else {
self.patch_jump(start_jmp_loc);
}
}
- pub fn visit_block(&mut self, stmts: Vec<AST>) {
+ pub fn visit_block(&mut self, ast: &AST, stmts: Vec<AST>) {
+ self.scopes.push(0);
for stmt in stmts {
self.visit(stmt);
}
+ let variables = self.scopes.pop().expect("popped scope in block");
+ for _ in 0..variables {
+ self.vm.chunk.push(OpCode::POP.into());
+ if self.vm.lines.last().unwrap().0 != ast.end_line {
+ self.vm.lines.push((ast.end_line, 1));
+ } else {
+ self.vm.lines.last_mut().unwrap().1 += 1;
+ }
+ }
}
- pub fn visit_decl(&mut self, ast: &AST, name: Name, expr: AST) {
+ pub fn visit_decl(&mut self, ast: &AST, _name: Name, expr: AST) {
self.visit(expr);
#[allow(irrefutable_let_patterns)]
- if let Extension::Resolution(ptr) = ast.extensions[0] {
- self.vm.local.insert(name.name, ptr as u8);
+ if let Extension::Resolution(_scope, _ptr) = ast.extensions[0] {
+ *self.scopes.last_mut().expect("codegen scopes vec was empty") += 1;
}
}
pub fn visit_expr_stmt(&mut self, ast: &AST, expr: AST) {
@@ 131,6 144,25 @@ impl Codegen {
self.vm.lines.last_mut().unwrap().1 += 1;
}
}
+ pub fn visit_assign(&mut self, ast: &AST, _name: Name, expr: AST) {
+ self.visit(expr);
+ // pop stack to get value. then find variable in stack. set variable to value.
+ self.vm.chunk.push(OpCode::ASSIGN.into());
+ #[allow(irrefutable_let_patterns)]
+ if let Extension::Resolution(_scope, ptr) = ast.extensions[0] {
+ self.vm.chunk.push(ptr as u8);
+ if self.vm.lines.last().unwrap().0 != ast.end_line {
+ self.vm.lines.push((ast.end_line, 1));
+ } else {
+ self.vm.lines.last_mut().unwrap().1 += 1;
+ }
+ }
+ if self.vm.lines.last().unwrap().0 != ast.end_line {
+ self.vm.lines.push((ast.end_line, 1));
+ } else {
+ self.vm.lines.last_mut().unwrap().1 += 1;
+ }
+ }
pub fn visit_binary(&mut self, left: AST, oper: BinOp, right: AST) {
use crate::ast::BinOp::*;
codegen_binary!(self, left, right, oper, Add, ADD, Sub, SUB, Mul, MUL,
@@ 173,10 205,21 @@ impl Codegen {
self.vm.lines.last_mut().unwrap().1 += 2;
}
}
- Lit::Ident(name) => {
+ Lit::Ident(_name) => {
self.vm.chunk.push(OpCode::VAR.into());
- let slot = self.vm.local.get(&name).unwrap();
- self.vm.chunk.push(*slot);
+ #[allow(irrefutable_let_patterns)]
+ if let Extension::Resolution(_scope, ptr) = ast.extensions[0] {
+ /*println!("line: {} ptr: {} locals: {:?}", ast.end_line, ptr, self.locals);
+ let (_scope, slot) = self.locals.get(ptr).unwrap();
+ println!("slot: {}", *slot);
+ self.vm.chunk.push(*slot);*/
+ self.vm.chunk.push(ptr as u8);
+ if self.vm.lines.len() == 0 || self.vm.lines.last().unwrap().0 != ast.end_line {
+ self.vm.lines.push((ast.end_line, 2));
+ } else {
+ self.vm.lines.last_mut().unwrap().1 += 2;
+ }
+ }
}
_ => {}
}
M kabel/src/debug.rs => kabel/src/debug.rs +46 -43
@@ 1,4 1,4 @@
-use crate::{lexer::Token, ast::AST, push_output, vm::Value};
+use crate::{ast::AST, lexer::Token, push_codegen, push_output, vm::{Value, VM}};
pub fn debug_token_array(tokens: Vec<Token>) -> String {
let mut output = "".to_string();
@@ 201,69 201,72 @@ pub fn debug_ast(ast: AST, level: usize) -> String {
output
}
-pub fn debug_bytecode(code: &Vec<u8>) -> String {
+pub fn debug_bytecode(vm: &VM) -> String {
use crate::opcodes::OpCode::*;
- let mut ip = 0;
+ //let mut ip = 0;
let mut output = "".to_string();
- while ip < code.len() {
- match code[ip].into() {
+ let mut vm = vm.clone();
+ while vm.ip < vm.chunk.len() {
+ // remove PRINT later
+ push_codegen!(vm.chunk[vm.ip].into(), vm, output, ADD, SUB, MUL, DIV, MOD, BITAND,
+ BITXOR, BITOR, EQ, NE, GR, GE, LS, LE, OR, AND, NOT, NEG, POP,
+ PRINT, ERR);
+ match vm.chunk[vm.ip].into() {
LOAD => {
- output += &ip.to_string();
+ output += &vm.ip.to_string();
+ output += " ";
+ output += &vm.find_line().to_string();
output += " CONSTANT ";
- ip += 1;
- output += &code[ip].to_string();
+ vm.ip += 1;
+ output += &vm.chunk[vm.ip].to_string();
output += "\n";
}
VAR => {
- output += &ip.to_string();
+ output += &vm.ip.to_string();
+ output += " ";
+ output += &vm.find_line().to_string();
output += " VAR ";
- ip += 1;
- output += &code[ip].to_string();
+ vm.ip += 1;
+ output += &vm.chunk[vm.ip].to_string();
output += "\n";
}
- ADD => { output += &ip.to_string(); output += " ADD\n" }
- SUB => { output += &ip.to_string(); output += " SUB\n" }
- MUL => { output += &ip.to_string(); output += " MUL\n" }
- DIV => { output += &ip.to_string(); output += " DIV\n" }
- MOD => { output += &ip.to_string(); output += " MOD\n" }
- BITAND => { output += &ip.to_string(); output += " BITAND\n" }
- BITXOR => { output += &ip.to_string(); output += " BITXOR\n" }
- BITOR => { output += &ip.to_string(); output += " BITOR\n" }
- EQ => { output += &ip.to_string(); output += " EQ\n" }
- NE => { output += &ip.to_string(); output += " NE\n" }
- GR => { output += &ip.to_string(); output += " GR\n" }
- GE => { output += &ip.to_string(); output += " GE\n" }
- LS => { output += &ip.to_string(); output += " LS\n" }
- LE => { output += &ip.to_string(); output += " LE\n" }
- OR => { output += &ip.to_string(); output += " OR\n" }
- AND => { output += &ip.to_string(); output += " AND\n" }
- NOT => { output += &ip.to_string(); output += " NOT\n" }
- NEG => { output += &ip.to_string(); output += " NEG\n" }
+ ASSIGN => {
+ output += &vm.ip.to_string();
+ output += " ";
+ output += &vm.find_line().to_string();
+ output += " ASSIGN ";
+ vm.ip += 1;
+ output += &vm.chunk[vm.ip].to_string();
+ output += "\n";
+ }
+
JMP => {
- output += &ip.to_string();
+ output += &vm.ip.to_string();
+ output += " ";
+ output += &vm.find_line().to_string();
output += " JMP ";
- ip += 1;
- let byte_one = (code[ip] as u16) << 8;
- ip += 1;
- let byte_two = code[ip] as u16;
+ vm.ip += 1;
+ let byte_one = (vm.chunk[vm.ip] as u16) << 8;
+ vm.ip += 1;
+ let byte_two = vm.chunk[vm.ip] as u16;
output += &(byte_one | byte_two).to_string();
output += "\n";
}
IF_NE => {
- output += &ip.to_string();
+ output += &vm.ip.to_string();
+ output += " ";
+ output += &vm.find_line().to_string();
output += " IF_NE ";
- ip += 1;
- let byte_one = (code[ip] as u16) << 8;
- ip += 1;
- let byte_two = code[ip] as u16;
+ vm.ip += 1;
+ let byte_one = (vm.chunk[vm.ip] as u16) << 8;
+ vm.ip += 1;
+ let byte_two = vm.chunk[vm.ip] as u16;
output += &(byte_one | byte_two).to_string();
output += "\n";
}
- POP => { output += &ip.to_string(); output += " POP\n" }
- PRINT => { output += &ip.to_string(); output += " PRINT\n" }
- ERR => output += "ERR\n",
+ _ => {}
}
- ip += 1;
+ vm.ip += 1;
}
output
}
M kabel/src/extension.rs => kabel/src/extension.rs +1 -1
@@ 1,4 1,4 @@
#[derive(Debug, Clone)]
pub enum Extension {
- Resolution(usize), // pointer to local table
+ Resolution(usize, usize), // scope, pointer to local table
}
M kabel/src/macros.rs => kabel/src/macros.rs +16 -0
@@ 206,6 206,22 @@ macro_rules! codegen_unary {
}
};
}
+#[macro_export]
+macro_rules! push_codegen {
+ ($match_to:expr, $vm:expr, $output:expr, $( $code:tt ), *) => {
+ match $match_to {
+ $( $code => {
+ $output += &$vm.ip.to_string();
+ $output += " ";
+ $output += &$vm.find_line().to_string();
+ $output += " ";
+ $output += stringify!($code);
+ $output += "\n";
+ } )*
+ _ => {}
+ }
+ };
+}
#[macro_export]
macro_rules! vm_boolean_binary {
M kabel/src/main.rs => kabel/src/main.rs +14 -12
@@ 5,20 5,18 @@ use std::{env, fs};
use kabel::{debug::{debug_ast, debug_bytecode, debug_stack, debug_token_array}, run_codegen, run_lexer, run_parser, run_semantic_analysis};
fn main() {
- let args: Vec<String> = env::args().collect();
+ /*let args: Vec<String> = env::args().collect();
let program =
- fs::read_to_string(args[1].clone()).unwrap();
+ fs::read_to_string(args[1].clone()).unwrap();*/
- /*let program =
+ let program =
"var a = 2;
-var b = 3;
-print a+b;
{
- var b = 7;
- var c = 4;
- print c;
+ var a = 3;
+ print a;
}
-".to_string();*/
+print a;
+".to_string();
let mut output = "".to_string();
@@ 45,7 43,7 @@ print a+b;
println!("{}", output);
return;
}
- output += &debug_ast(ast.clone(), 0);
+ //output += &debug_ast(ast.clone(), 0);
output += "\n\n";
//output += &format!("{:#?}", ast);
let (ast, analyzer) = run_semantic_analysis(program.to_string(), ast.clone());
@@ 57,12 55,16 @@ print a+b;
println!("{}", output);
return;
}
- //output += &format!("{:#?}", ast);
+ output += &debug_ast(ast.clone(), 0);
+ output += "\n";
let codegen = run_codegen(program.to_string(), ast);
let mut vm = codegen.vm;
- output += &debug_bytecode(&vm.chunk);
+ output += &debug_bytecode(&vm);
+ output += "\n";
+ //output += &format!("{:?}", codegen.local);
+
output += "\n";
match vm.run(&mut output) {
Ok(()) => {}
M kabel/src/name_resolution.rs => kabel/src/name_resolution.rs +31 -6
@@ 5,7 5,8 @@ use crate::{ast::{ASTType, AST}, ast_from_ast, collect_lines, error::{ErrorKind,
pub struct Resolver {
text: Vec<String>,
symbol_table: Vec<HashMap<String, (Symbol, usize)>>, // (Symbol, reference to locals)
- pub locals: Vec<usize>, // reference to stack
+ pub locals: Vec<usize>, // scope
+ pub scope: usize,
pub errors: Vec<KabelError>,
}
@@ 15,6 16,7 @@ impl Resolver {
text: text.lines().collect::<Vec<&str>>().iter().map(|s| s.to_string()).collect(),
symbol_table: vec![HashMap::new()],
locals: Vec::new(),
+ scope: 0,
errors: Vec::new(),
}
}
@@ 89,20 91,34 @@ impl Resolver {
}
Block(stmts) => {
self.symbol_table.push(HashMap::new());
+ self.scope += 1;
let mut n_stmts = Vec::new();
for stmt in stmts {
n_stmts.push(self.visit(stmt));
}
+ /*for (index, scope) in self.locals.clone().iter().enumerate() {
+ if self.scope == *scope {
+ self.locals.remove(index);
+ }
+ }*/
+ while let Some(scope) = self.locals.last() {
+ if self.scope == *scope {
+ self.locals.pop();
+ } else {
+ break;
+ }
+ }
+ self.scope -= 1;
self.symbol_table.pop();
ast_from_ast!(Block(n_stmts), ast, ast)
}
Decl(name, expr) => {
let expr = self.visit(*expr);
- self.locals.push(0);
+ self.locals.push(self.scope);
self.symbol_table.last_mut().unwrap().insert(name.name.clone(), (Symbol::Var, self.locals.len()-1));
AST {
ast_type: Decl(name, Box::new(expr)),
- extensions: vec![Extension::Resolution(self.locals.len()-1)],
+ extensions: vec![Extension::Resolution(self.scope, self.locals.len()-1)],
start_line: ast.start_line,
end_line: ast.end_line,
start_column: ast.start_column,
@@ 120,10 136,18 @@ impl Resolver {
}
Assign(name, expr) => {
let expr = self.visit(*expr);
- if !self.symbol_table.last().unwrap().contains_key(&name.name) {
+ let resolution = self.resolve_var(&name.name);
+ if !resolution.0 {
self.errors.push(out_of_scope_var!(self, "Variable \"{}\" not in scope", name, ast));
}
- ast_from_ast!(Assign(name, Box::new(expr)), ast, ast)
+ AST {
+ ast_type: Assign(name, Box::new(expr)),
+ extensions: vec![Extension::Resolution(self.scope, resolution.1)],
+ start_line: ast.start_line,
+ end_line: ast.end_line,
+ start_column: ast.start_column,
+ end_column: ast.end_column,
+ }
}
Ternary(condition, true_expr, false_expr) => {
let condition = self.visit(*condition);
@@ 155,7 179,7 @@ impl Resolver {
} else {
return AST {
ast_type: Lit(lit),
- extensions: vec![Extension::Resolution(resolution.1)],
+ extensions: vec![Extension::Resolution(self.scope, resolution.1)],
start_line: ast.start_line,
end_line: ast.end_line,
start_column: ast.start_column,
@@ 224,6 248,7 @@ impl Resolver {
}
}
+#[derive(Debug, Clone, Copy)]
pub enum Symbol {
Var,
Function(usize),
M kabel/src/opcodes.rs => kabel/src/opcodes.rs +44 -40
@@ 1,8 1,10 @@
#![allow(non_camel_case_types)]
+#[derive(Debug)]
pub enum OpCode {
LOAD,
VAR,
+ ASSIGN,
ADD,
SUB,
@@ 38,29 40,30 @@ impl From<OpCode> for u8 {
match value {
LOAD => 0x00,
VAR => 0x01,
+ ASSIGN => 0x02,
- ADD => 0x02,
- SUB => 0x03,
- MUL => 0x04,
- DIV => 0x05,
- MOD => 0x06,
- BITAND => 0x07,
- BITXOR => 0x08,
- BITOR => 0x09,
- EQ => 0x0A,
- NE => 0x0B,
- GR => 0x0C,
- GE => 0x0D,
- LS => 0x0E,
- LE => 0x0F,
- OR => 0x10,
- AND => 0x11,
+ ADD => 0x03,
+ SUB => 0x04,
+ MUL => 0x05,
+ DIV => 0x06,
+ MOD => 0x07,
+ BITAND => 0x08,
+ BITXOR => 0x09,
+ BITOR => 0x0a,
+ EQ => 0x0B,
+ NE => 0x0C,
+ GR => 0x0D,
+ GE => 0x0E,
+ LS => 0x0F,
+ LE => 0x10,
+ OR => 0x11,
+ AND => 0x12,
- NOT => 0x12,
- NEG => 0x13,
+ NOT => 0x13,
+ NEG => 0x14,
- JMP => 0x14,
- IF_NE => 0x15,
+ JMP => 0x15,
+ IF_NE => 0x16,
POP => 0xFD,
PRINT => 0xFE,
@@ 74,29 77,30 @@ impl From<u8> for OpCode {
match value {
0x00 => LOAD,
0x01 => VAR,
+ 0x02 => ASSIGN,
- 0x02 => ADD,
- 0x03 => SUB,
- 0x04 => MUL,
- 0x05 => DIV,
- 0x06 => MOD,
- 0x07 => BITAND,
- 0x08 => BITXOR,
- 0x09 => BITOR,
- 0x0A => EQ,
- 0x0B => NE,
- 0x0C => GR,
- 0x0D => GE,
- 0x0E => LS,
- 0x0F => LE,
- 0x10 => OR,
- 0x11 => AND,
+ 0x03 => ADD,
+ 0x04 => SUB,
+ 0x05 => MUL,
+ 0x06 => DIV,
+ 0x07 => MOD,
+ 0x08 => BITAND,
+ 0x09 => BITXOR,
+ 0x0a => BITOR,
+ 0x0B => EQ,
+ 0x0C => NE,
+ 0x0D => GR,
+ 0x0E => GE,
+ 0x0F => LS,
+ 0x10 => LE,
+ 0x11 => OR,
+ 0x12 => AND,
- 0x12 => NOT,
- 0x13 => NEG,
+ 0x13 => NOT,
+ 0x14 => NEG,
- 0x14 => JMP,
- 0x15 => IF_NE,
+ 0x15 => JMP,
+ 0x16 => IF_NE,
0xFD => POP,
0xFE => PRINT,
M kabel/src/vm.rs => kabel/src/vm.rs +33 -28
@@ 1,34 1,31 @@
use std::collections::HashMap;
-use crate::{mismatched_types, runtime_error::KabelRuntimeError, vm_boolean_binary, wrong_type};
+use crate::{mismatched_types, opcodes::OpCode, runtime_error::KabelRuntimeError, vm_boolean_binary, wrong_type};
+#[derive(Clone)]
pub struct VM {
- ip: usize,
+ pub ip: usize,
pub chunk: Vec<u8>,
pub stack: Vec<Value>,
pub pool: Vec<Value>,
- pub local: HashMap<String, u8>, // (name, stack pointer)
pub lines: Vec<(usize, usize)>, // line #, repeats number of instructions
text: Vec<String>
}
impl VM {
pub fn new(bytecode: Vec<u8>, lines: Vec<(usize, usize)>, pool: Vec<Value>,
- local: HashMap<String, u8>, text: String) -> Self {
- println!("{:#?}", text);
+ text: String) -> Self {
Self {
ip: 0,
chunk: bytecode,
stack: Vec::new(),
pool,
- local,
lines,
text: text.lines().map(|s| s.to_string()).collect::<Vec<String>>(),
}
}
pub fn run(&mut self, output: &mut String) -> Result<(), KabelRuntimeError> {
use Value::*;
- println!("{:#?}", self.text);
while self.ip < self.chunk.len() {
match self.read() {
0x00 => { // LOAD
@@ 39,7 36,14 @@ impl VM {
let ptr = self.read() as usize;
self.stack.push(self.stack[ptr].clone());
}
- 0x02 => { // ADD
+ // ASSIGN
+ 0x02 => {
+ let value = self.stack.pop().unwrap();
+ let ptr = self.read();
+ self.stack[ptr as usize] = value.clone();
+ self.stack.push(value);
+ }
+ 0x03 => { // ADD
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => self.stack.push(Num(v1 + v2)),
(Str(v1), Str(v2)) => {
@@ 53,7 57,7 @@ impl VM {
}
}
}
- 0x03 => { // SUB
+ 0x04 => { // SUB
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => self.stack.push(Num(v1 - v2)),
(Str(_v1), Str(_v2)) => {
@@ 67,7 71,7 @@ impl VM {
}
}
}
- 0x04 => { // MUL
+ 0x05 => { // MUL
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => self.stack.push(Num(v1 * v2)),
(Str(v1), Num(v2)) => {
@@ 88,7 92,7 @@ impl VM {
}
}
}
- 0x05 => { // DIV
+ 0x06 => { // DIV
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => self.stack.push(Num(v1 / v2)),
(Str(_v1), Str(_v2)) => {
@@ 102,7 106,7 @@ impl VM {
}
}
}
- 0x06 => { // MOD
+ 0x07 => { // MOD
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => self.stack.push(Num(v1 % v2)),
(Str(_v1), Str(_v2)) => {
@@ 116,7 120,7 @@ impl VM {
}
}
}
- 0x07 => { // BITAND
+ 0x08 => { // BITAND
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
@@ 138,7 142,7 @@ impl VM {
}
}
}
- 0x08 => { // BITXOR
+ 0x09 => { // BITXOR
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
@@ 160,7 164,7 @@ impl VM {
}
}
}
- 0x09 => { // BITOR
+ 0x0A => { // BITOR
match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(v1), Num(v2)) => {
if v1.fract() != 0.0 {
@@ 183,19 187,19 @@ impl VM {
}
}
// EQ
- 0x0a => vm_boolean_binary!(self, ==),
+ 0x0b => vm_boolean_binary!(self, ==),
// NE
- 0x0B => vm_boolean_binary!(self, !=),
+ 0x0C => vm_boolean_binary!(self, !=),
// GR
- 0x0C => vm_boolean_binary!(self, >),
+ 0x0D => vm_boolean_binary!(self, >),
// GE
- 0x0D => vm_boolean_binary!(self, >=),
+ 0x0E => vm_boolean_binary!(self, >=),
// LS
- 0x0E => vm_boolean_binary!(self, <),
+ 0x0F => vm_boolean_binary!(self, <),
// LE
- 0x0F => vm_boolean_binary!(self, <=),
+ 0x10 => vm_boolean_binary!(self, <=),
// OR
- 0x10 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ 0x11 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(_v1), Num(_v2)) => {
return Err(wrong_type!(self, "Cannot perform logical OR on numbers"))
}
@@ 208,7 212,7 @@ impl VM {
}
}
// AND
- 0x11 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
+ 0x12 => match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) {
(Num(_v1), Num(_v2)) => {
return Err(wrong_type!(self, "Cannot perform logical AND on numbers"))
}
@@ 221,7 225,7 @@ impl VM {
}
}
// NOT
- 0x12 => match self.stack.pop().unwrap() {
+ 0x13 => match self.stack.pop().unwrap() {
Num(_v1) => {
return Err(wrong_type!(self, "Cannot perform logical NOT on numbers"))
}
@@ 231,7 235,7 @@ impl VM {
Bool(v1) => self.stack.push(Bool(!v1)),
}
// NEG
- 0x13 => match self.stack.pop().unwrap() {
+ 0x14 => match self.stack.pop().unwrap() {
Num(v1) => self.stack.push(Num(-v1)),
Str(_v1) => {
return Err(wrong_type!(self, "Cannot negate strings"))
@@ 241,12 245,12 @@ impl VM {
}
}
// JMP
- 0x14 => {
+ 0x15 => {
let loc = self.read_u16();
self.ip += loc as usize;
}
// IF_NE
- 0x15 => {
+ 0x16 => {
let condition = self.stack.pop().unwrap();
if let Value::Bool(condition) = condition {
if !condition {
@@ 289,7 293,7 @@ impl VM {
self.ip += 1;
byte_one | byte_two
}
- pub fn find_line(&mut self) -> usize { // returns line # at ip
+ pub fn find_line(&self) -> usize { // returns line # at ip
let mut line_ip = 0;
for (line, rep) in self.lines.clone() {
if line_ip + rep > self.ip {
@@ 297,6 301,7 @@ impl VM {
}
line_ip += rep;
}
+ println!("{} {}", line_ip, self.ip);
panic!("Something went wrong in finding line for error")
}
}
A kabel/test/runtime/variable.kab => kabel/test/runtime/variable.kab +30 -0
@@ 0,0 1,30 @@
+var x = 1;
+print x + 2; // 3
+
+{
+ x = 3;
+ print x; // 3
+}
+print x; // 3
+
+var y = 0;
+print y; // 0
+print x; // 3
+
+{
+ var y = 5;
+ print y + 2; // 7
+}
+print y; // 0
+
+if(x == 3) {
+ var y = 6;
+} else {
+ var y = 5;
+ print y; // not run
+}
+print y; // 0
+if(y != 1) {
+ y = 1;
+}
+print y; // 1
A kabel/test/runtime/variable.out => kabel/test/runtime/variable.out +9 -0