M kabel/src/codegen.rs => kabel/src/codegen.rs +0 -1
@@ 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);
M kabel/src/error.rs => kabel/src/error.rs +22 -4
@@ 2,16 2,18 @@
pub struct KabelError {
pub kind: ErrorKind,
pub message: String,
+ pub hint: Option<String>,
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<String>, 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<ErrorKind> for usize {
UnexpectedToken => 0x02,
MissingDelimiter => 0x03,
OutOfScope => 0x04,
- IncorrectArity => 0x05,
+ VariableAlreadyDeclaredVariable => 0x05,
+ VariableAlreadyDeclaredFunction => 0x06,
+ FunctionAlreadyDeclaredVariable => 0x07,
+ FunctionAlreadyDeclaredFunction => 0x08,
+ IncorrectArity => 0x09,
}
}
}
M kabel/src/lexer.rs => kabel/src/lexer.rs +3 -0
@@ 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(),
M kabel/src/macros.rs => kabel/src/macros.rs +81 -5
@@ 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 {
M kabel/src/name_resolution.rs => kabel/src/name_resolution.rs +51 -4
@@ 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<String>,
@@ 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]),
M kabel/src/parser.rs => kabel/src/parser.rs +5 -0
@@ 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(),
M kabel/src/runtime_error.rs => kabel/src/runtime_error.rs +8 -2
@@ 2,15 2,17 @@
pub struct KabelRuntimeError {
pub kind: RuntimeErrorKind,
pub message: String,
+ pub hint: Option<String>,
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<String>, 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(())
}
}
M kabel/src/vm.rs => kabel/src/vm.rs +43 -42
@@ 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"))
}
}
A kabel/test/runtime/fibonacci.kab => kabel/test/runtime/fibonacci.kab +11 -0
@@ 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;
+}
A kabel/test/runtime/fibonacci.out => kabel/test/runtime/fibonacci.out +30 -0
@@ 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
M kabel/tmp.kab => kabel/tmp.kab +2 -8
@@ 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() {}