From aee322a55f4e43823d50abee49b074b9eac7af50 Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Sat, 17 Aug 2024 00:02:11 -0500 Subject: [PATCH] no redeclaration, also added hints to errors --- kabel/src/codegen.rs | 1 - kabel/src/error.rs | 26 ++++++++-- kabel/src/lexer.rs | 3 ++ kabel/src/macros.rs | 86 ++++++++++++++++++++++++++++++-- kabel/src/name_resolution.rs | 55 ++++++++++++++++++-- kabel/src/parser.rs | 5 ++ kabel/src/runtime_error.rs | 10 +++- kabel/src/vm.rs | 85 +++++++++++++++---------------- kabel/test/runtime/fibonacci.kab | 11 ++++ kabel/test/runtime/fibonacci.out | 30 +++++++++++ kabel/tmp.kab | 10 +--- 11 files changed, 256 insertions(+), 66 deletions(-) create mode 100644 kabel/test/runtime/fibonacci.kab create mode 100644 kabel/test/runtime/fibonacci.out diff --git a/kabel/src/codegen.rs b/kabel/src/codegen.rs index e30bc3c864c62b707aa5cdb527d7860f80f01eab..2efdbf6b0a67a58f774c1bdc15d4e5574e55b668 100644 --- a/kabel/src/codegen.rs +++ b/kabel/src/codegen.rs @@ -262,7 +262,6 @@ impl Codegen { self.vm.lines.last_mut().unwrap().1 += 3; } - println!("jmp: {}", self.vm.chunk.len()); self.patch_jump(start_jmp_loc, 0); self.visit(ast); self.patch_jump(end_jmp_loc, 0); diff --git a/kabel/src/error.rs b/kabel/src/error.rs index ea280fde38fa8eb7075c5d54e1e8fe9d6b862b86..736dc9c7ef936f26e8f3da0c834f70a7f2b51558 100644 --- a/kabel/src/error.rs +++ b/kabel/src/error.rs @@ -2,16 +2,18 @@ pub struct KabelError { pub kind: ErrorKind, pub message: String, + pub hint: Option, pub line: usize, pub column: usize, pub code: String, } impl KabelError { - pub fn new(kind: ErrorKind, message: String, line: usize, column: usize, code: String) -> Self { + pub fn new(kind: ErrorKind, message: String, hint: Option, line: usize, column: usize, code: String) -> Self { Self { kind, message, + hint, line, column, code, @@ -32,19 +34,27 @@ impl std::fmt::Display for KabelError { self.column + 1, self.code, caret_space - )) + ))?; + if let Some(ref hint) = self.hint { + f.write_str(&format!("\n{0}{1}", caret_space, hint))?; + } + Ok(()) } } impl std::error::Error for KabelError {} -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum ErrorKind { UnexpectedEof, UnexpectedCharacter, UnexpectedToken, MissingDelimiter, OutOfScope, + VariableAlreadyDeclaredVariable, + VariableAlreadyDeclaredFunction, + FunctionAlreadyDeclaredVariable, + FunctionAlreadyDeclaredFunction, IncorrectArity, } @@ -57,6 +67,10 @@ impl std::fmt::Display for ErrorKind { UnexpectedToken => f.write_str("Unrecognized Token"), MissingDelimiter => f.write_str("Missing delimiter"), OutOfScope => f.write_str("Out of scope"), + VariableAlreadyDeclaredVariable => f.write_str("Variable already declared variable"), + VariableAlreadyDeclaredFunction => f.write_str("Variable already declared function"), + FunctionAlreadyDeclaredVariable => f.write_str("Function already declared variable"), + FunctionAlreadyDeclaredFunction => f.write_str("Function already declared function"), IncorrectArity => f.write_str("Incorrect arity"), } } @@ -71,7 +85,11 @@ impl From for usize { UnexpectedToken => 0x02, MissingDelimiter => 0x03, OutOfScope => 0x04, - IncorrectArity => 0x05, + VariableAlreadyDeclaredVariable => 0x05, + VariableAlreadyDeclaredFunction => 0x06, + FunctionAlreadyDeclaredVariable => 0x07, + FunctionAlreadyDeclaredFunction => 0x08, + IncorrectArity => 0x09, } } } diff --git a/kabel/src/lexer.rs b/kabel/src/lexer.rs index b6d68125d97705d1bf9b1321058ba93427696da5..1caca511f2a6b50bc28045fc643433d41dfc6233 100644 --- a/kabel/src/lexer.rs +++ b/kabel/src/lexer.rs @@ -302,6 +302,7 @@ impl Lexer { self.errors.push(KabelError::new( ErrorKind::UnexpectedToken, format!("Stray \"{0}\"", c as char), + None, self.line, self.column, self.input[self.line_start..self.current].iter().collect(), @@ -319,6 +320,7 @@ impl Lexer { return Err(KabelError::new( ErrorKind::UnexpectedEof, message.to_string(), + None, self.line, self.column, self.input[self.line_start..self.current].iter().collect(), @@ -337,6 +339,7 @@ impl Lexer { return Err(KabelError::new( ErrorKind::UnexpectedEof, message.to_string(), + None, self.line, self.column, self.input[self.line_start..self.current].iter().collect(), diff --git a/kabel/src/macros.rs b/kabel/src/macros.rs index 6d8d0e859f4acae409879511bf22fe08d2d42cc7..7b74d2828342d2f668fb364a874a15fcb4b6cace 100644 --- a/kabel/src/macros.rs +++ b/kabel/src/macros.rs @@ -108,12 +108,24 @@ macro_rules! push_output { } } + #[macro_export] macro_rules! unexpected_token { + ($self:expr, $message:expr, $token:expr, $hint:expr) => { + $crate::error::KabelError::new( + $crate::error::ErrorKind::UnexpectedToken, + format!($message, $self.text[$token.line][$token.start_column..$token.end_column].to_string()), + Some($hint), + $token.line, + $token.start_column, + $self.text[$token.line].to_string(), + ) + }; ($self:expr, $message:expr, $token:expr) => { $crate::error::KabelError::new( $crate::error::ErrorKind::UnexpectedToken, format!($message, $self.text[$token.line][$token.start_column..$token.end_column].to_string()), + None, $token.line, $token.start_column, $self.text[$token.line].to_string(), @@ -122,8 +134,32 @@ macro_rules! unexpected_token { } #[macro_export] +macro_rules! ast_error { + ($self:expr, $type:expr, $expr:expr, $message:expr $(, $message_fmt:expr )* ; $hint:expr $(, $hint_fmt:expr )* ) => { + $crate::error::KabelError::new( + $type, + format!($message, $( $message_fmt ),* ), + Some(format!($hint, $( $hint_fmt ),*)), + $expr.start_line, + $expr.start_column, + $crate::collect_lines!($self.text[$expr.start_line..$expr.end_line+1]), + ) + }; + ($self:expr, $type:expr, $expr:expr, $message:expr $(, $message_fmt:expr )*) => { + $crate::error::KabelError::new( + $type, + format!($message, $( $message_fmt ),* ), + None, + $expr.start_line, + $expr.start_column, + $crate::collect_lines!($self.text[$expr.start_line..$expr.end_line+1]), + ) + }; +} + +/*#[macro_export] macro_rules! out_of_scope { - ($self:expr, $message:expr, $name:expr, $expr:expr) => { + ($self:expr, $message:expr, $name:expr, $expr:expr, $hint:expr) => { $crate::error::KabelError::new( $crate::error::ErrorKind::OutOfScope, format!($message, $name), @@ -132,20 +168,60 @@ macro_rules! out_of_scope { $crate::collect_lines!($self.text[$expr.start_line..$expr.end_line+1]), ) }; -} +}*/ #[macro_export] macro_rules! out_of_scope_var { - ($self:expr, $message:expr, $name:expr, $expr:expr) => { + ($self:expr, $type:expr, $expr:expr, $message:expr, $name:expr ; $hint:expr $(, $hint_fmt:expr )* ) => { $crate::error::KabelError::new( - $crate::error::ErrorKind::OutOfScope, + $type, + format!($message, $name.name), + Some(format!($hint, $( $hint_fmt ),*)), + $expr.start_line, + $name.start_column, + $crate::collect_lines!($self.text[$expr.start_line..$expr.end_line+1]), + ) + }; + ($self:expr, $type:expr, $expr:expr, $message:expr, $name:expr) => { + $crate::error::KabelError::new( + $type, format!($message, $name.name), + None, $expr.start_line, $name.start_column, $crate::collect_lines!($self.text[$expr.start_line..$expr.end_line+1]), ) }; } + #[macro_export] +macro_rules! vm_error { + ($self:expr, $type:expr, $message:expr $(, $message_fmt:expr )* ; $hint:expr $(, $hint_fmt:expr )* ) => { + { + let line = $self.find_line(); + $crate::runtime_error::KabelRuntimeError::new( + $type, + format!($message, $( $message_fmt ),* ), + Some(format!(hint, $( $hint_fmt ),*)), + line, + $self.text[line].to_string(), + ) + } + }; + ($self:expr, $type:expr, $message:expr $(, $message_fmt:expr )*) => { + { + let line = $self.find_line(); + $crate::runtime_error::KabelRuntimeError::new( + $type, + format!($message, $( $message_fmt ),* ), + None, + line, + $self.text[line].to_string(), + ) + } + }; +} + +/*#[macro_export] macro_rules! mismatched_types { ($self:expr, $message:expr, $( $args:expr ),*) => { { @@ -172,7 +248,7 @@ macro_rules! wrong_type { ) } }; -} +}*/ #[macro_export] macro_rules! collect_lines { diff --git a/kabel/src/name_resolution.rs b/kabel/src/name_resolution.rs index 1e323d88c96851ea26d58421a1acdb6908e934b4..4dc2eb4458cc996810e63e6e1eec337e5114b091 100644 --- a/kabel/src/name_resolution.rs +++ b/kabel/src/name_resolution.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::{ast::{ASTType, AST}, ast_from_ast, collect_lines, error::{ErrorKind, KabelError}, extension::Extension, out_of_scope, out_of_scope_var}; +use crate::{ast::{ASTType, AST}, ast_error, ast_from_ast, collect_lines, error::{ErrorKind, KabelError}, extension::Extension, out_of_scope_var}; pub struct Resolver { text: Vec, @@ -39,6 +39,28 @@ impl Resolver { } } Function(name, args, block) => { + if self.resolve_var(&name.name).0 { + self.errors.push(out_of_scope_var!(self, + ErrorKind::FunctionAlreadyDeclaredVariable, ast, + "Function \"{}\" already declared", name ; + "hint: has variable \"{}\" already been declared?", name.name)); + } else { + let resolution = self.resolve_function(&name.name, 0); + if resolution.is_ok() { + self.errors.push(out_of_scope_var!(self, + ErrorKind::FunctionAlreadyDeclaredFunction, ast, + "Function \"{}\" already declared", name ; + "hint: has function \"{}\" already been declared?", name.name)); + } + if let Err((kind, _, _)) = resolution { + if kind == ErrorKind::IncorrectArity { + self.errors.push(out_of_scope_var!(self, + ErrorKind::FunctionAlreadyDeclaredFunction, ast, + "Function \"{}\" already declared", name ; + "hint: has function \"{}\" already been declared?", name.name)); + } else {} + } + } self.symbol_table.last_mut().unwrap().insert(name.name.clone(), (Symbol::Function(args.len()),0)); self.symbol_table.push(HashMap::new()); for arg in args.clone() { @@ -128,6 +150,28 @@ impl Resolver { Decl(name, expr) => { let expr = self.visit(*expr); self.locals.push(self.scope); + if self.resolve_var(&name.name).0 { + self.errors.push(out_of_scope_var!(self, + ErrorKind::VariableAlreadyDeclaredVariable, ast, + "Variable \"{}\" already declared", name ; + "hint: has variable \"{}\" already been declared?", name.name)); + } else { + let resolution = self.resolve_function(&name.name, 0); + if resolution.is_ok() { + self.errors.push(out_of_scope_var!(self, + ErrorKind::VariableAlreadyDeclaredFunction, ast, + "Variable \"{}\" already declared", name ; + "hint: has function \"{}\" already been declared?", name.name)); + } + if let Err((kind, _, _)) = resolution { + if kind == ErrorKind::IncorrectArity { + self.errors.push(out_of_scope_var!(self, + ErrorKind::VariableAlreadyDeclaredFunction, ast, + "Variable \"{}\" already declared", name ; + "hint: has function \"{}\" already been declared?", name.name)); + } else {} + } + } self.symbol_table.last_mut().unwrap().insert(name.name.clone(), (Symbol::Var, self.locals.len()-1)); AST { ast_type: Decl(name, Box::new(expr)), @@ -151,7 +195,9 @@ impl Resolver { let expr = self.visit(*expr); let resolution = self.resolve_var(&name.name); if !resolution.0 { - self.errors.push(out_of_scope_var!(self, "Variable \"{}\" not in scope", name, ast)); + self.errors.push(out_of_scope_var!(self, + ErrorKind::OutOfScope, ast, + "Variable \"{}\" not in scope", name)); } AST { ast_type: Assign(name, Box::new(expr)), @@ -188,7 +234,7 @@ impl Resolver { crate::ast::Lit::Ident(ref name) => { let resolution = self.resolve_var(name); if !resolution.0 { - self.errors.push(out_of_scope!(self, "Variable \"{}\" not in scope", name, ast)) + self.errors.push(ast_error!(self, ErrorKind::OutOfScope, ast, "Variable \"{}\" not in scope", name)) } else { return AST { ast_type: Lit(lit), @@ -207,12 +253,13 @@ impl Resolver { Call(ident, args) => { if let Err(e) = self.resolve_function(&ident.name, args.len()) { match e { - (ErrorKind::OutOfScope, _, _) => self.errors.push(out_of_scope!(self, "Function \"{}\" not in scope", ident.name, ast)), + (ErrorKind::OutOfScope, _, _) => self.errors.push(ast_error!(self, ErrorKind::OutOfScope, ast, "Function \"{}\" not in scope", ident.name)), (ErrorKind::IncorrectArity, Some(f_arity), Some(arity)) => { self.errors.push( KabelError::new( ErrorKind::IncorrectArity, format!("Function {} has {} argument, provided {}", ident.name, f_arity, arity), + None, ast.start_line, ast.start_column, collect_lines!(self.text[ast.start_line-1..ast.end_line-1]), diff --git a/kabel/src/parser.rs b/kabel/src/parser.rs index 2d07102b9dbbe2f9263c7af067f907c7dd81cf61..50b28a81bd11254cd2a256f6388e08ced78d8a54 100644 --- a/kabel/src/parser.rs +++ b/kabel/src/parser.rs @@ -372,6 +372,7 @@ impl Parser { return Err(KabelError::new( ErrorKind::UnexpectedEof, "Unexpected end of file, expected ;".to_string(), + None, expression.start_line, last.end_column, self.text[last.line].to_string(), @@ -1034,6 +1035,7 @@ impl Parser { return Err(KabelError::new( ErrorKind::MissingDelimiter, "Missing right parenthesis".to_string(), + None, right_paren.line, right_paren.start_column, self.text[left_paren.line..right_paren.line].iter().fold("".to_string(), |acc, string| acc + string + "\n"), @@ -1050,6 +1052,7 @@ impl Parser { return Err(KabelError::new( ErrorKind::MissingDelimiter, "Missing right parenthesis".to_string(), + None, e.line, e.column, collect_lines!(self.text[left_paren.line..expr.end_line]), @@ -1064,6 +1067,7 @@ impl Parser { return Err(KabelError::new( ErrorKind::UnexpectedEof, "Unexpected end of file".to_string(), + None, last_token.line, last_token.start_column, self.text[last_token.line].clone(), @@ -1079,6 +1083,7 @@ impl Parser { return Err(KabelError::new( ErrorKind::UnexpectedEof, "Unexpected end of file".to_string(), + None, last_token.line, last_token.start_column, self.text[last_token.line].clone(), diff --git a/kabel/src/runtime_error.rs b/kabel/src/runtime_error.rs index 9b82acbe6d97011918e87138087637146fdbc04a..b143a9ab158b37744561a5a781828d891b11686d 100644 --- a/kabel/src/runtime_error.rs +++ b/kabel/src/runtime_error.rs @@ -2,15 +2,17 @@ pub struct KabelRuntimeError { pub kind: RuntimeErrorKind, pub message: String, + pub hint: Option, pub line: usize, pub code: String, } impl KabelRuntimeError { - pub fn new(kind: RuntimeErrorKind, message: String, line: usize, code: String) -> Self { + pub fn new(kind: RuntimeErrorKind, message: String, hint: Option, line: usize, code: String) -> Self { Self { kind, message, + hint, line, code, } @@ -26,7 +28,11 @@ impl std::fmt::Display for KabelRuntimeError { self.message, self.line + 1, self.code, - )) + ))?; + if let Some(ref hint) = self.hint { + f.write_str(&format!("\n{0}", hint))?; + } + Ok(()) } } diff --git a/kabel/src/vm.rs b/kabel/src/vm.rs index 67046585b2ebd99266efbe59373c02b9a369fb38..bbd8cd05ed62074dfa24d882e5bba5a7276e2b9e 100644 --- a/kabel/src/vm.rs +++ b/kabel/src/vm.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; -use crate::{mismatched_types, opcodes::OpCode, runtime_error::KabelRuntimeError, vm_boolean_binary, wrong_type}; +use crate::{opcodes::OpCode, runtime_error::{KabelRuntimeError, RuntimeErrorKind}, vm, vm_boolean_binary}; +use crate::vm_error; #[derive(Clone)] pub struct VM { @@ -50,10 +51,10 @@ impl VM { self.stack.push(Str(v1 + &v2)); }, (Bool(_v1), Bool(_v2)) => { - return Err(wrong_type!(self, "Cannot add booleans")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot add booleans")) } (v1, v2) => { - return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) + return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } @@ -61,13 +62,13 @@ impl VM { 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 subtract strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot subtract strings")) }, (Bool(_v1), Bool(_v2)) => { - return Err(wrong_type!(self, "Cannot subtract booleans")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot subtract booleans")) } (v1, v2) => { - return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) + return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } @@ -78,17 +79,17 @@ impl VM { if v2.fract() == 0.0 { self.stack.push(Str(v1.repeat(v2 as usize))); } else { - return Err(wrong_type!(self, "Number must be an integer")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Number must be an integer")) } } (Str(_v1), Str(_v2)) => { - return Err(wrong_type!(self, "Cannot multiply strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot multiply strings")) }, (Bool(_v1), Bool(_v2)) => { - return Err(wrong_type!(self, "Cannot multiply booleans")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot multiply booleans")) } (v1, v2) => { - return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) + return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } @@ -96,13 +97,13 @@ impl VM { 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 divide strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot divide strings")) }, (Bool(_v1), Bool(_v2)) => { - return Err(wrong_type!(self, "Cannot divide booleans")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot divide booleans")) } (v1, v2) => { - return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) + return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } @@ -110,13 +111,13 @@ impl VM { 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")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform modulus on strings")) }, (Bool(_v1), Bool(_v2)) => { - return Err(wrong_type!(self, "Cannot perform modulus on booleans")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform modulus on booleans")) } (v1, v2) => { - return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) + return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } @@ -124,21 +125,21 @@ impl VM { match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => { if v1.fract() != 0.0 { - return Err(wrong_type!(self, "Cannot perform bitwise AND on {}", v1)) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on {}", v1)) } if v2.fract() != 0.0 { - return Err(wrong_type!(self, "Cannot perform bitwise AND on {}", v2)) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on {}", v2)) } self.stack.push(Num((v1 as u32 & v2 as u32) as f32)) } (Str(_v1), Str(_v2)) => { - return Err(wrong_type!(self, "Cannot perform bitwise AND on strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on strings")) }, (Bool(_v1), Bool(_v2)) => { - return Err(wrong_type!(self, "Cannot perform bitwise AND on booleans")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise AND on booleans")) } (v1, v2) => { - return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) + return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } @@ -146,21 +147,21 @@ impl VM { match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => { if v1.fract() != 0.0 { - return Err(wrong_type!(self, "Cannot perform bitwise XOR on {}", v1)) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on {}", v1)) } if v2.fract() != 0.0 { - return Err(wrong_type!(self, "Cannot perform bitwise XOR on {}", v2)) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on {}", v2)) } self.stack.push(Num((v1 as u32 ^ v2 as u32) as f32)) } (Str(_v1), Str(_v2)) => { - return Err(wrong_type!(self, "Cannot perform bitwise XOR on strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on strings")) }, (Bool(_v1), Bool(_v2)) => { - return Err(wrong_type!(self, "Cannot perform bitwise XOR on booleans")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise XOR on booleans")) } (v1, v2) => { - return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) + return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } @@ -168,21 +169,21 @@ impl VM { match (self.stack.pop().unwrap(), self.stack.pop().unwrap()) { (Num(v1), Num(v2)) => { if v1.fract() != 0.0 { - return Err(wrong_type!(self, "Cannot perform bitwise OR on {}", v1)) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on {}", v1)) } if v2.fract() != 0.0 { - return Err(wrong_type!(self, "Cannot perform bitwise OR on {}", v2)) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on {}", v2)) } self.stack.push(Num((v1 as u32 | v2 as u32) as f32)) } (Str(_v1), Str(_v2)) => { - return Err(wrong_type!(self, "Cannot perform bitwise OR on strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on strings")) }, (Bool(_v1), Bool(_v2)) => { - return Err(wrong_type!(self, "Cannot perform bitwise OR on booleans")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform bitwise OR on booleans")) } (v1, v2) => { - return Err(mismatched_types!(self, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) + return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } } @@ -201,36 +202,36 @@ impl VM { // OR 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")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical OR on numbers")) } (Str(_v1), Str(_v2)) => { - return Err(wrong_type!(self, "Cannot perform logical OR on strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "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())) + return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } // AND 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")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical AND on numbers")) } (Str(_v1), Str(_v2)) => { - return Err(wrong_type!(self, "Cannot perform logical AND on strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "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())) + return Err(vm_error!(self, RuntimeErrorKind::MismatchedTypes, "Mismatched types: {} and {}", v1.type_str(), v2.type_str())) } } // NOT 0x13 => match self.stack.pop().unwrap() { Num(_v1) => { - return Err(wrong_type!(self, "Cannot perform logical NOT on numbers")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical NOT on numbers")) } Str(_v1) => { - return Err(wrong_type!(self, "Cannot perform logical NOT on strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot perform logical NOT on strings")) } Bool(v1) => self.stack.push(Bool(!v1)), } @@ -238,10 +239,10 @@ impl VM { 0x14 => match self.stack.pop().unwrap() { Num(v1) => self.stack.push(Num(-v1)), Str(_v1) => { - return Err(wrong_type!(self, "Cannot negate strings")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot negate strings")) } Bool(_v1) => { - return Err(wrong_type!(self, "Cannot negate bools")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "Cannot negate bools")) } } // JMP @@ -265,7 +266,7 @@ impl VM { self.read_u16(); } } else { - return Err(wrong_type!(self, "if must have condition of type boolean")) + return Err(vm_error!(self, RuntimeErrorKind::WrongType, "if must have condition of type boolean")) } } diff --git a/kabel/test/runtime/fibonacci.kab b/kabel/test/runtime/fibonacci.kab new file mode 100644 index 0000000000000000000000000000000000000000..dc89170f2cb1546731de2df9df8c89d638b0a601 --- /dev/null +++ b/kabel/test/runtime/fibonacci.kab @@ -0,0 +1,11 @@ +var iters = 30; + +var x = 0; +var y = 1; +var z = 0; +for(var i = 0; i < iters; i++) { + print x; + z = (x + y); + x = y; + y = z; +} diff --git a/kabel/test/runtime/fibonacci.out b/kabel/test/runtime/fibonacci.out new file mode 100644 index 0000000000000000000000000000000000000000..29780856ac602dbd3c7178c6be5734110b6c0b23 --- /dev/null +++ b/kabel/test/runtime/fibonacci.out @@ -0,0 +1,30 @@ +0 +1 +1 +2 +3 +5 +8 +13 +21 +34 +55 +89 +144 +233 +377 +610 +987 +1597 +2584 +4181 +6765 +10946 +17711 +28657 +46368 +75025 +121393 +196418 +317811 +514229 diff --git a/kabel/tmp.kab b/kabel/tmp.kab index d889a14c35e2d315bbc310ca1894a5cb5f8d7031..1276cf98e64db8682a7e37c047a08aec564cc160 100644 --- a/kabel/tmp.kab +++ b/kabel/tmp.kab @@ -1,8 +1,2 @@ -for (var i = 1; i < 101; i++) { - //if (i % 3 != 0 && i % 5 != 0) { print i; } - //else if (i % 3 == 0 && i % 5 != 0) { print "Fizz"; } - //else if (i % 3 != 0 && i % 5 == 0) { print "Buzz"; } - //else if (i % 3 == 0 && i % 5 == 0) { print "FizzBuzz"; } - print i; - break; -} +var i = 0; +function i() {}