diff --git a/src/compiler.rs b/src/compiler.rs index 998061b..cb092d8 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,6 +1,5 @@ -use std::{collections::HashMap, vec}; - -use crate::parser::ASTPart; +use std::{collections::HashMap, process, vec}; +use crate::{errors::{create_error, print_error, ErrorType, ErrorSubType}, parser::ASTPart, Context}; const ASXVERSION: [u8; 3] = [0,1,0]; @@ -10,6 +9,7 @@ pub struct Operation { pub arg1: Option, pub arg2: Option, pub arg3: Option, + pub pos: u32, } #[derive(Debug, Clone)] @@ -139,15 +139,15 @@ fn get_variable_by_name(variables: &Vec, name: &str, position: usize) None } -fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, variables: &mut Vec, next_var_id: &mut u32, strings: &mut HashMap, next_string_id: &mut u32, functions: &mut HashMap, next_function_id: &mut u32, registers: &mut Vec) -> u8 { +fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, variables: &mut Vec, next_var_id: &mut u32, strings: &mut HashMap, next_string_id: &mut u32, functions: &mut HashMap, next_function_id: &mut u32, registers: &mut Vec, ctx: &Context) -> u8 { *op_count += 1; match ast_op { ASTPart::Number(num) => { let reg = allocate_register(registers); if reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: num.pos as u32 }); } - ops.push(Operation { opcode: 3, arg1: Some(reg.register), arg2: Some(num.value), arg3: None }); + ops.push(Operation { opcode: 3, arg1: Some(reg.register), arg2: Some(num.value), arg3: None, pos: num.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: 0, last_used: *op_count }); return reg.register; }, @@ -157,27 +157,27 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va *next_string_id += 1; let reg = allocate_register(registers); if reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: str.pos as u32 }); } - ops.push(Operation { opcode: 1, arg1: Some(reg.register), arg2: Some(str_id as i64), arg3: None }); + ops.push(Operation { opcode: 1, arg1: Some(reg.register), arg2: Some(str_id as i64), arg3: None, pos: str.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: 0, last_used: *op_count }); return reg.register; }, ASTPart::Boolean(bool) => { let reg = allocate_register(registers); if reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: bool.pos as u32 }); } - ops.push(Operation { opcode: 4, arg1: Some(reg.register), arg2: Some(bool.value as i64), arg3: None }); + ops.push(Operation { opcode: 4, arg1: Some(reg.register), arg2: Some(bool.value as i64), arg3: None, pos: bool.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: 0, last_used: *op_count }); return reg.register; }, - ASTPart::Null(_) => { + ASTPart::Null(nul) => { let reg = allocate_register(registers); if reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: nul.pos as u32 }); } - ops.push(Operation { opcode: 6, arg1: Some(reg.register), arg2: Some(0), arg3: None }); + ops.push(Operation { opcode: 6, arg1: Some(reg.register), arg2: Some(0), arg3: None, pos: nul.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: 0, last_used: *op_count }); return reg.register; }, @@ -185,13 +185,13 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va if get_variable_by_name(variables, &var_read.variable, ops.len()).is_none() { let reg = allocate_register(registers); if reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: var_read.pos as u32 }); } let str_id = *next_string_id; strings.insert(str_id, var_read.variable.clone()); *next_string_id += 1; - ops.push(Operation { opcode: 1, arg1: Some(reg.register), arg2: Some(str_id as i64), arg3: None }); - ops.push(Operation { opcode: 30, arg1: Some(0), arg2: Some(reg.register as i64), arg3: Some(reg.register) }); + ops.push(Operation { opcode: 1, arg1: Some(reg.register), arg2: Some(str_id as i64), arg3: None, pos: var_read.pos as u32 }); + ops.push(Operation { opcode: 30, arg1: Some(0), arg2: Some(reg.register as i64), arg3: Some(reg.register), pos: var_read.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: 0, last_used: *op_count }); return reg.register; } @@ -199,9 +199,9 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va if reg.id == 0 { let reg = allocate_register(registers); if reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: var_read.pos as u32 }); } - ops.push(Operation { opcode: 2, arg1: Some(reg.register), arg2: Some(get_variable_by_name(variables, &var_read.variable, ops.len()).expect("Variable should exist").id as i64), arg3: None }); + ops.push(Operation { opcode: 2, arg1: Some(reg.register), arg2: Some(get_variable_by_name(variables, &var_read.variable, ops.len()).expect("Variable should exist").id as i64), arg3: None, pos: var_read.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: get_variable_by_name(variables, &var_read.variable, ops.len()).expect("Variable should exist").id, last_used: *op_count }); return reg.register; } else { @@ -210,47 +210,47 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va }, ASTPart::Function(func) => { let func_id = *next_function_id; - functions.insert(func_id, compile_function(func.body, Some(func.args), registers, next_var_id)); + functions.insert(func_id, compile_function(func.body, Some(func.args), registers, next_var_id, ctx)); *next_function_id += 1; let reg = allocate_register(registers); if reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: func.pos as u32 }); } - ops.push(Operation { opcode: 5, arg1: Some(reg.register), arg2: Some(func_id as i64), arg3: None }); + ops.push(Operation { opcode: 5, arg1: Some(reg.register), arg2: Some(func_id as i64), arg3: None, pos: func.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: 0, last_used: *op_count }); return reg.register; }, ASTPart::Call(call) => { - let func = do_ast_op(*call.function, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); + let func = do_ast_op(*call.function, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); for arg in call.args { - let arg_reg = do_ast_op(arg, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - ops.push(Operation { opcode: 28, arg1: Some(arg_reg), arg2: None, arg3: None }); + let arg_reg = do_ast_op(arg, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + ops.push(Operation { opcode: 28, arg1: Some(arg_reg), arg2: None, arg3: None, pos: call.pos as u32 }); set_register(registers, RegisterState { id: arg_reg, used: false, variable: 0, last_used: 0 }); } let ret_reg = allocate_register(registers); if ret_reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(ret_reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(ret_reg.register), arg2: None, arg3: None, pos: call.pos as u32 }); } - ops.push(Operation { opcode: 27, arg1: Some(func), arg2: Some(ret_reg.register as i64), arg3: None }); + ops.push(Operation { opcode: 27, arg1: Some(func), arg2: Some(ret_reg.register as i64), arg3: None, pos: call.pos as u32 }); return ret_reg.register; }, ASTPart::If(if_part) => { - let condition_reg = do_ast_op(*if_part.condition, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - ops.push(Operation { opcode: 24, arg1: Some(condition_reg), arg2: Some(condition_reg as i64), arg3: None }); + let condition_reg = do_ast_op(*if_part.condition, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + ops.push(Operation { opcode: 24, arg1: Some(condition_reg), arg2: Some(condition_reg as i64), arg3: None, pos: if_part.pos as u32 }); //Update the lastif variable if get_variable_by_name(variables, "__LASTIF", ops.len()).is_none() { variables.push(Variable { name: String::from("__LASTIF"), id: *next_var_id, start: ops.len(), end: 0, no_end: true }); *next_var_id += 1; } - ops.push(Operation { opcode: 7, arg1: Some(condition_reg), arg2: Some(get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id as i64), arg3: None }); + ops.push(Operation { opcode: 7, arg1: Some(condition_reg), arg2: Some(get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id as i64), arg3: None, pos: if_part.pos as u32 }); set_register(registers, RegisterState { id: condition_reg, used: true, variable: get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id, last_used: *op_count }); let op_placeholder = ops.len(); - ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None }); + ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None, pos: if_part.pos as u32 }); let mut fake_vars: Vec = vec![]; for if_op in if_part.body { - do_ast_op(if_op, op_count, ops, &mut fake_vars, next_var_id, strings, next_string_id, functions, next_function_id, registers); + do_ast_op(if_op, op_count, ops, &mut fake_vars, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); } for fake_var in fake_vars { variables.push(Variable { name: fake_var.name, id: fake_var.id, start: fake_var.start, end: ops.len()-1, no_end: false }); @@ -260,39 +260,42 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va arg1: Some(condition_reg), arg2: Some(ops.len() as i64), arg3: None, + pos: if_part.pos as u32, }; //Unbind the lastif variable if get_register_by_id(registers, condition_reg).variable == get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id { - ops.push(Operation { opcode: 8, arg1: Some(condition_reg), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(condition_reg), arg2: None, arg3: None, pos: if_part.pos as u32 }); set_register(registers, RegisterState { id: condition_reg, used: false, variable: 0, last_used: 0 }); } garbage_collect_registers(registers); }, ASTPart::Else(else_part) => { if get_variable_by_name(variables, "__LASTIF", ops.len()).is_none() { - panic!("Else used without an if statement before it"); + let err = create_error(&format!("Else used without an if statement before it"), else_part.pos, ErrorType::SemanticError, ErrorSubType::ElseWithoutIf); + print_error(&err, &ctx); + process::exit(1); } let reg = get_register_by_variable(registers, get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").clone()); let else_condition_reg; if reg.id == 0 { let reg = allocate_register(registers); if reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: else_part.pos as u32 }); } - ops.push(Operation { opcode: 2, arg1: Some(reg.register), arg2: Some(get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id as i64), arg3: None }); + ops.push(Operation { opcode: 2, arg1: Some(reg.register), arg2: Some(get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id as i64), arg3: None, pos: else_part.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id, last_used: *op_count }); else_condition_reg = reg.register; } else { else_condition_reg = reg.id; } - ops.push(Operation { opcode: 24, arg1: Some(else_condition_reg), arg2: Some(else_condition_reg as i64), arg3: None }); + ops.push(Operation { opcode: 24, arg1: Some(else_condition_reg), arg2: Some(else_condition_reg as i64), arg3: None, pos: else_part.pos as u32 }); let op_placeholder = ops.len(); - ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None }); + ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None, pos: else_part.pos as u32 }); let mut fake_vars: Vec = vec![]; for else_op in else_part.body { - do_ast_op(else_op, op_count, ops, &mut fake_vars, next_var_id, strings, next_string_id, functions, next_function_id, registers); + do_ast_op(else_op, op_count, ops, &mut fake_vars, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); } for fake_var in fake_vars { variables.push(Variable { name: fake_var.name, id: fake_var.id, start: fake_var.start, end: ops.len()-1, no_end: false }); @@ -302,46 +305,49 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va arg1: Some(else_condition_reg), arg2: Some(ops.len() as i64), arg3: None, + pos: else_part.pos as u32, }; //Unbind the lastif variable if get_register_by_id(registers, else_condition_reg).variable == get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id { - ops.push(Operation { opcode: 8, arg1: Some(else_condition_reg), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(else_condition_reg), arg2: None, arg3: None, pos: else_part.pos as u32 }); set_register(registers, RegisterState { id: else_condition_reg, used: false, variable: 0, last_used: 0 }); } garbage_collect_registers(registers); }, ASTPart::ElseIf(elseif_part) => { if get_variable_by_name(variables, "__LASTIF", ops.len()).is_none() { - panic!("Else if used without an if statement before it"); + let err = create_error(&format!("Else if used without an if statement before it"), elseif_part.pos, ErrorType::SemanticError, ErrorSubType::ElseWithoutIf); + print_error(&err, &ctx); + process::exit(1); } let reg = get_register_by_variable(registers, get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").clone()); let else_condition_reg; if reg.id == 0 { let reg = allocate_register(registers); if reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: elseif_part.pos as u32 }); } - ops.push(Operation { opcode: 2, arg1: Some(reg.register), arg2: Some(get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id as i64), arg3: None }); + ops.push(Operation { opcode: 2, arg1: Some(reg.register), arg2: Some(get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id as i64), arg3: None, pos: elseif_part.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id, last_used: *op_count }); else_condition_reg = reg.register; } else { else_condition_reg = reg.id; } - ops.push(Operation { opcode: 24, arg1: Some(else_condition_reg), arg2: Some(else_condition_reg as i64), arg3: None }); + ops.push(Operation { opcode: 24, arg1: Some(else_condition_reg), arg2: Some(else_condition_reg as i64), arg3: None, pos: elseif_part.pos as u32 }); - let condition_reg = do_ast_op(*elseif_part.condition, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - ops.push(Operation { opcode: 16, arg1: Some(else_condition_reg), arg2: Some(condition_reg as i64), arg3: Some(condition_reg) }); - ops.push(Operation { opcode: 24, arg1: Some(condition_reg), arg2: Some(condition_reg as i64), arg3: None }); + let condition_reg = do_ast_op(*elseif_part.condition, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + ops.push(Operation { opcode: 16, arg1: Some(else_condition_reg), arg2: Some(condition_reg as i64), arg3: Some(condition_reg), pos: elseif_part.pos as u32 }); + ops.push(Operation { opcode: 24, arg1: Some(condition_reg), arg2: Some(condition_reg as i64), arg3: None, pos: elseif_part.pos as u32 }); //Update the lastif variable - ops.push(Operation { opcode: 7, arg1: Some(condition_reg), arg2: Some(get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id as i64), arg3: None }); + ops.push(Operation { opcode: 7, arg1: Some(condition_reg), arg2: Some(get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id as i64), arg3: None, pos: elseif_part.pos as u32 }); set_register(registers, RegisterState { id: condition_reg, used: true, variable: get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id, last_used: *op_count }); let op_placeholder = ops.len(); - ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None }); + ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None, pos: elseif_part.pos as u32 }); let mut fake_vars: Vec = vec![]; for elseif_op in elseif_part.body { - do_ast_op(elseif_op, op_count, ops, &mut fake_vars, next_var_id, strings, next_string_id, functions, next_function_id, registers); + do_ast_op(elseif_op, op_count, ops, &mut fake_vars, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); } for fake_var in fake_vars { variables.push(Variable { name: fake_var.name, id: fake_var.id, start: fake_var.start, end: ops.len()-1, no_end: false }); @@ -351,44 +357,46 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va arg1: Some(condition_reg), arg2: Some(ops.len() as i64), arg3: None, + pos: elseif_part.pos as u32 }; //Unbind the lastif variable if get_register_by_id(registers, condition_reg).variable == get_variable_by_name(variables, "__LASTIF", ops.len()).expect("__LASTIF should exist").id { - ops.push(Operation { opcode: 8, arg1: Some(condition_reg), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(condition_reg), arg2: None, arg3: None, pos: elseif_part.pos as u32 }); set_register(registers, RegisterState { id: condition_reg, used: false, variable: 0, last_used: 0 }); } garbage_collect_registers(registers); }, ASTPart::While(while_part) => { let start = ops.len(); - let condition_reg = do_ast_op(*while_part.condition, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - ops.push(Operation { opcode: 24, arg1: Some(condition_reg), arg2: Some(condition_reg as i64), arg3: None }); + let condition_reg = do_ast_op(*while_part.condition, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + ops.push(Operation { opcode: 24, arg1: Some(condition_reg), arg2: Some(condition_reg as i64), arg3: None, pos: while_part.pos as u32 }); let op_placeholder = ops.len(); let mut breaks: Vec = vec![]; let mut continues: Vec = vec![]; - ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None }); + ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None, pos: while_part.pos as u32 }); for while_op in while_part.body { match while_op { ASTPart::Break(_) => { breaks.push(ops.len()); - ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None }); + ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None, pos: while_part.pos as u32 }); }, ASTPart::Continue(_) => { continues.push(ops.len()); - ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None }); + ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None, pos: while_part.pos as u32 }); }, _ => { - do_ast_op(while_op, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); + do_ast_op(while_op, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); } } } - ops.push(Operation { opcode: 25, arg1: None, arg2: Some(start as i64), arg3: None }); + ops.push(Operation { opcode: 25, arg1: None, arg2: Some(start as i64), arg3: None, pos: while_part.pos as u32 }); ops[op_placeholder] = Operation { opcode: 26, arg1: Some(condition_reg), arg2: Some(ops.len() as i64), arg3: None, + pos: while_part.pos as u32 }; for brk in breaks { ops[brk] = Operation { @@ -396,6 +404,7 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va arg1: None, arg2: Some(ops.len() as i64), arg3: None, + pos: while_part.pos as u32 }; } for cont in continues { @@ -404,48 +413,54 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va arg1: None, arg2: Some(start as i64), arg3: None, + pos: while_part.pos as u32 }; } }, - ASTPart::Break(_) => { - panic!("Unexpected break outside of loop at {}", op_count); + ASTPart::Break(brk) => { + let err = create_error(&format!("Unexpected break outside of loop"), brk.pos, ErrorType::SemanticError, ErrorSubType::BreakContinueWithoutLoop); + print_error(&err, &ctx); + process::exit(1); }, - ASTPart::Continue(_) => { - panic!("Unexpected continue outside of loop at {}", op_count); + ASTPart::Continue(cont) => { + let err = create_error(&format!("Unexpected continue outside of loop"), cont.pos, ErrorType::SemanticError, ErrorSubType::BreakContinueWithoutLoop); + print_error(&err, &ctx); + process::exit(1); }, ASTPart::For(for_part) => { - do_ast_op(*for_part.init, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); + do_ast_op(*for_part.init, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); let start = ops.len(); - let condition_reg = do_ast_op(*for_part.condition, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - ops.push(Operation { opcode: 24, arg1: Some(condition_reg), arg2: Some(condition_reg as i64), arg3: None }); + let condition_reg = do_ast_op(*for_part.condition, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + ops.push(Operation { opcode: 24, arg1: Some(condition_reg), arg2: Some(condition_reg as i64), arg3: None, pos: for_part.pos as u32 }); let op_placeholder = ops.len(); let mut breaks: Vec = vec![]; let mut continues: Vec = vec![]; - ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None }); + ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None, pos: for_part.pos as u32 }); for for_op in for_part.body { match for_op { ASTPart::Break(_) => { breaks.push(ops.len()); - ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None }); + ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None, pos: for_part.pos as u32 }); }, ASTPart::Continue(_) => { continues.push(ops.len()); - ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None }); + ops.push(Operation { opcode: 0, arg1: None, arg2: None, arg3: None, pos: for_part.pos as u32 }); }, _ => { - do_ast_op(for_op, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); + do_ast_op(for_op, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); } } } - do_ast_op(*for_part.update, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); + do_ast_op(*for_part.update, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); - ops.push(Operation { opcode: 25, arg1: None, arg2: Some(start as i64), arg3: None }); + ops.push(Operation { opcode: 25, arg1: None, arg2: Some(start as i64), arg3: None, pos: for_part.pos as u32 }); ops[op_placeholder] = Operation { opcode: 26, arg1: Some(condition_reg), arg2: Some(ops.len() as i64), arg3: None, + pos: for_part.pos as u32 }; for brk in breaks { ops[brk] = Operation { @@ -453,6 +468,7 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va arg1: None, arg2: Some(ops.len() as i64), arg3: None, + pos: for_part.pos as u32 }; } for cont in continues { @@ -461,19 +477,20 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va arg1: None, arg2: Some(start as i64), arg3: None, + pos: for_part.pos as u32 }; } }, ASTPart::Return(ret) => { - let ret_reg = do_ast_op(*ret.value, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - ops.push(Operation { opcode: 29, arg1: Some(ret_reg), arg2: None, arg3: None }); + let ret_reg = do_ast_op(*ret.value, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + ops.push(Operation { opcode: 29, arg1: Some(ret_reg), arg2: None, arg3: None, pos: ret.pos as u32 }); }, ASTPart::Operation(op) => { - let left_reg = do_ast_op(*op.left, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - let right_reg = do_ast_op(*op.right, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); + let left_reg = do_ast_op(*op.left, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + let right_reg = do_ast_op(*op.right, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); let reg = allocate_register(registers); if reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: op.pos as u32 }); } let opcode = match op.operator.as_str() { "+" => 10, @@ -491,78 +508,86 @@ fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec, va "<" => 22, "<=" => 23, "!" => { - ops.push(Operation { opcode: 24, arg1: Some(left_reg), arg2: Some(reg.register as i64), arg3: None }); + ops.push(Operation { opcode: 24, arg1: Some(left_reg), arg2: Some(reg.register as i64), arg3: None, pos: op.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: 0, last_used: *op_count }); return reg.register; }, - _ => panic!("Unknown operator {}", op.operator), + _ => { + let err = create_error(&format!("Unknown operator `{}`", op.operator), op.pos, ErrorType::SyntaxError, ErrorSubType::UnknownOperation); + print_error(&err, &ctx); + process::exit(1); + }, }; - ops.push(Operation { opcode, arg1: Some(left_reg), arg2: Some(right_reg as i64), arg3: Some(reg.register) }); + ops.push(Operation { opcode, arg1: Some(left_reg), arg2: Some(right_reg as i64), arg3: Some(reg.register), pos: op.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: 0, last_used: *op_count }); return reg.register; }, ASTPart::VarUpdate(upd) => { if get_variable_by_name(variables, &upd.variable, ops.len()).is_none() { - panic!("Variable {} does not exist", upd.variable); + let err = create_error(&format!("Variable `{}` does not exist", upd.variable), upd.pos, ErrorType::SemanticError, ErrorSubType::VariableNotFound); + print_error(&err, &ctx); + process::exit(1); } let reg = get_register_by_variable(registers, get_variable_by_name(variables, &upd.variable, ops.len()).expect("Variable should exist").clone()); if reg.id != 0 { - ops.push(Operation { opcode: 8, arg1: Some(reg.id), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.id), arg2: None, arg3: None, pos: upd.pos as u32 }); set_register(registers, RegisterState { id: reg.id, used: false, variable: 0, last_used: 0 }); } - let value_reg = do_ast_op(*upd.value, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - ops.push(Operation { opcode: 7, arg1: Some(value_reg), arg2: Some(get_variable_by_name(variables, &upd.variable, ops.len()).expect("Variable should exist").id as i64), arg3: None }); + let value_reg = do_ast_op(*upd.value, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + ops.push(Operation { opcode: 7, arg1: Some(value_reg), arg2: Some(get_variable_by_name(variables, &upd.variable, ops.len()).expect("Variable should exist").id as i64), arg3: None, pos: upd.pos as u32 }); set_register(registers, RegisterState { id: value_reg, used: true, variable: get_variable_by_name(variables, &upd.variable, ops.len()).expect("Variable should exist").id, last_used: *op_count }); garbage_collect_registers(registers); }, ASTPart::Assigment(asign) => { if get_variable_by_name(variables, &asign.variable, ops.len()).is_some() { - panic!("Variable {} already exists", asign.variable); + let err = create_error(&format!("Variable `{}` already exists", asign.variable), asign.pos, ErrorType::SemanticError, ErrorSubType::VariableAlreadyExists); + print_error(&err, &ctx); + process::exit(1); } - let reg = do_ast_op(*asign.value, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); + let reg = do_ast_op(*asign.value, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); variables.push(Variable { name: asign.variable.clone(), id: *next_var_id, start: ops.len(), end: 0, no_end: true }); *next_var_id += 1; - ops.push(Operation { opcode: 7, arg1: Some(reg), arg2: Some(get_variable_by_name(variables, &asign.variable, ops.len()).expect("Variable should exist").id as i64), arg3: None }); + ops.push(Operation { opcode: 7, arg1: Some(reg), arg2: Some(get_variable_by_name(variables, &asign.variable, ops.len()).expect("Variable should exist").id as i64), arg3: None, pos: asign.pos as u32 }); set_register(registers, RegisterState { id: reg, used: true, variable: get_variable_by_name(variables, &asign.variable, ops.len()).expect("Variable should exist").id, last_used: *op_count }); garbage_collect_registers(registers); }, ASTPart::Table(tbl) => { let reg = allocate_register(registers); if reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: tbl.pos as u32 }); } - ops.push(Operation { opcode: 6, arg1: Some(reg.register), arg2: Some(1), arg3: None }); + ops.push(Operation { opcode: 6, arg1: Some(reg.register), arg2: Some(1), arg3: None, pos: tbl.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: 0, last_used: *op_count }); for val in tbl.values { - let key_reg = do_ast_op(val.key, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - let value_reg = do_ast_op(val.value, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - ops.push(Operation { opcode: 31, arg1: Some(reg.register), arg2: Some(key_reg as i64), arg3: Some(value_reg) }); + let key_reg = do_ast_op(val.key, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + let value_reg = do_ast_op(val.value, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + ops.push(Operation { opcode: 31, arg1: Some(reg.register), arg2: Some(key_reg as i64), arg3: Some(value_reg), pos: tbl.pos as u32 }); } return reg.register; }, ASTPart::TableGet(tbl_get) => { - let table_reg = do_ast_op(*tbl_get.table, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - let key_reg = do_ast_op(*tbl_get.key, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); + let table_reg = do_ast_op(*tbl_get.table, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + let key_reg = do_ast_op(*tbl_get.key, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); let reg = allocate_register(registers); if reg.unbind_before { - ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None }); + ops.push(Operation { opcode: 8, arg1: Some(reg.register), arg2: None, arg3: None, pos: tbl_get.pos as u32 }); } - ops.push(Operation { opcode: 30, arg1: Some(table_reg), arg2: Some(key_reg as i64), arg3: Some(reg.register) }); + ops.push(Operation { opcode: 30, arg1: Some(table_reg), arg2: Some(key_reg as i64), arg3: Some(reg.register), pos: tbl_get.pos as u32 }); set_register(registers, RegisterState { id: reg.register, used: true, variable: 0, last_used: *op_count }); return reg.register; }, ASTPart::TableSet(tbl_set) => { - let table_reg = do_ast_op(*tbl_set.table, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - let key_reg = do_ast_op(*tbl_set.key, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - let value_reg = do_ast_op(*tbl_set.value, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers); - ops.push(Operation { opcode: 31, arg1: Some(table_reg), arg2: Some(key_reg as i64), arg3: Some(value_reg) }); + let table_reg = do_ast_op(*tbl_set.table, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + let key_reg = do_ast_op(*tbl_set.key, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + let value_reg = do_ast_op(*tbl_set.value, op_count, ops, variables, next_var_id, strings, next_string_id, functions, next_function_id, registers, ctx); + ops.push(Operation { opcode: 31, arg1: Some(table_reg), arg2: Some(key_reg as i64), arg3: Some(value_reg), pos: tbl_set.pos as u32 }); }, _ => {} } return 0; } -fn compile_function(ast: Vec, args: Option>, registers: &mut Vec, next_var_id: &mut u32) -> Compiled { +fn compile_function(ast: Vec, args: Option>, registers: &mut Vec, next_var_id: &mut u32, ctx: &Context) -> Compiled { let mut ops: Vec = vec![]; let mut variables: Vec = vec![]; @@ -575,7 +600,9 @@ fn compile_function(ast: Vec, args: Option>, registers: &mu Some(arg_list) => { for arg in arg_list { if get_variable_by_name(&variables, &arg, 0).is_some() { - panic!("Argument {} already exists", arg); + let err = create_error(&format!("Argument `{}` already exists", arg), 0, ErrorType::SemanticError, ErrorSubType::ArgumentDuplication); + print_error(&err, &ctx); + process::exit(1); } variables.push( Variable { name: arg, id: *next_var_id, start: 0, end: 0, no_end: true }); *next_var_id += 1; @@ -586,9 +613,9 @@ fn compile_function(ast: Vec, args: Option>, registers: &mu let mut op_count = 0; for ast_op in ast { - do_ast_op(ast_op, &mut op_count, &mut ops, &mut variables, next_var_id, &mut strings, &mut next_string_id, &mut functions, &mut next_function_id, registers); + do_ast_op(ast_op, &mut op_count, &mut ops, &mut variables, next_var_id, &mut strings, &mut next_string_id, &mut functions, &mut next_function_id, registers, ctx); } - ops.push(Operation { opcode: 29, arg1: Some(0), arg2: None, arg3: None }); + ops.push(Operation { opcode: 29, arg1: Some(0), arg2: None, arg3: None, pos: ctx.raw_file.len() as u32 }); for var in &mut variables { if var.no_end { var.end = ops.len() - 1; @@ -649,7 +676,7 @@ fn bin_to_num(bin: String) -> usize { return num; } -fn compile_body(compiled: Compiled, fpos: &mut usize) -> Vec { +fn compile_body(compiled: Compiled, fpos: &mut usize, ctx: &Context) -> Vec { let mut output: Vec = vec![]; let mut additional: Vec> = vec![]; //function @@ -671,7 +698,7 @@ fn compile_body(compiled: Compiled, fpos: &mut usize) -> Vec { *fpos += 1; append_be_num(&mut output, 3, *funcs as usize); append_be_num(&mut output, 4, *fpos); - additional.push(compile_body(compiled.functions[funcs].clone(), fpos)); + additional.push(compile_body(compiled.functions[funcs].clone(), fpos, ctx)); } //function body append_be_num(&mut output, 4, compiled.operations.len()); @@ -694,6 +721,7 @@ fn compile_body(compiled: Compiled, fpos: &mut usize) -> Vec { } op_bin.push_str(&num_to_bin(0, 3)); append_binary(&mut output, op_bin); + append_be_num(&mut output, 4, ops.pos as usize); } for addition in additional { output.extend_from_slice(&addition); @@ -702,7 +730,7 @@ fn compile_body(compiled: Compiled, fpos: &mut usize) -> Vec { return output; } -pub fn compile(ast: Vec) -> Vec { +pub fn compile(ast: Vec, ctx: &Context) -> Vec { let mut next_var_id: u32 = 1; let mut registers: Vec = vec![]; for i in 0..17 { @@ -714,7 +742,7 @@ pub fn compile(ast: Vec) -> Vec { }); } - let compiled = compile_function(ast, None, &mut registers, &mut next_var_id); + let compiled = compile_function(ast, None, &mut registers, &mut next_var_id, ctx); let mut output: Vec = vec![]; //doctype specifier @@ -723,10 +751,22 @@ pub fn compile(ast: Vec) -> Vec { output.push(ASXVERSION[0]); output.push(ASXVERSION[1]); output.push(ASXVERSION[2]); + //number of functions + output.push(0); + output.push(0); + output.push(0); + output.push(0); //functions let mut fpos = 0; - let body = compile_body(compiled, &mut fpos); + let body = compile_body(compiled, &mut fpos, ctx); output.extend_from_slice(&body); + //update function count + fpos += 1; + output[6] = ((fpos >> 24) & 0xFF) as u8; + output[7] = ((fpos >> 16) & 0xFF) as u8; + output[8] = ((fpos >> 8) & 0xFF) as u8; + output[9] = (fpos & 0xFF) as u8; + return output; } \ No newline at end of file diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..ccf1fee --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,220 @@ +use std::f32::consts::E; + +use crate::Context; + +pub enum ErrorType { + SyntaxError, + SemanticError, + TypeError, + MathError, + MachineError, +} + +pub enum ErrorSubType { + //Syntax errors + UnexpectedEnd, + Expected, + Unexpected, + UnknownOperation, + InvalidTableKeys, + Unclosed, + //Semantic errors + ElseWithoutIf, + BreakContinueWithoutLoop, + UnexpectedOperation, + VariableNotFound, + VariableAlreadyExists, + ArgumentDuplication, + //Machine errors + RegisterNotFound, + MemoryOutOfBounds, + UnknownOPCode, + UnknownFunction, + UnknownString, + UnknownMemoryLocation, + NonFunctionCall, + //Math errors + DivisionByZero, + //Type errors + InvalidType, + WrongType, + NonStringKey, +} + +pub struct ASLError { + pub message: String, + pub position: usize, + pub typ: ErrorType, + pub subtype: ErrorSubType, + pub code: String, +} + +fn convert_types_to_string(typ: &ErrorType) -> String { + match typ { + ErrorType::SyntaxError => String::from("Syntax Error: "), + ErrorType::TypeError => String::from("Type Error: "), + ErrorType::MathError => String::from("Math Error: "), + ErrorType::SemanticError => String::from("Semantic Error: "), + ErrorType::MachineError => String::from("Machine Error: "), + } +} +fn convert_types_to_short(typ: &ErrorType) -> String { + match typ { + ErrorType::SyntaxError => String::from("ST:"), + ErrorType::TypeError => String::from("TP:"), + ErrorType::MathError => String::from("MT:"), + ErrorType::SemanticError => String::from("SM:"), + ErrorType::MachineError => String::from("MC:"), + } +} +fn convert_subtypes_to_string(stype: &ErrorSubType) -> String { + match stype { + ErrorSubType::UnexpectedEnd => String::from("Unexpected end"), + ErrorSubType::UnexpectedOperation => String::from("Unexpected operation"), + ErrorSubType::Expected => String::from("Expected"), + ErrorSubType::Unexpected => String::from("Unexpected"), + ErrorSubType::InvalidTableKeys => String::from("Invalid table keys"), + ErrorSubType::Unclosed => String::from("Unclosed structure"), + ErrorSubType::ElseWithoutIf => String::from("Else/elseif without if"), + ErrorSubType::BreakContinueWithoutLoop => String::from("Break/continue without loop"), + ErrorSubType::UnknownOperation => String::from("Unknown operation"), + ErrorSubType::VariableNotFound => String::from("Variable not found"), + ErrorSubType::VariableAlreadyExists => String::from("Variable already exists"), + ErrorSubType::ArgumentDuplication => String::from("Argument duplication"), + ErrorSubType::RegisterNotFound => String::from("Register not found"), + ErrorSubType::MemoryOutOfBounds => String::from("Memory out of bounds"), + ErrorSubType::UnknownOPCode => String::from("Unknown OP code"), + ErrorSubType::UnknownFunction => String::from("Unknown function"), + ErrorSubType::UnknownString => String::from("Unknown string"), + ErrorSubType::UnknownMemoryLocation => String::from("Unknown memory location"), + ErrorSubType::NonFunctionCall => String::from("Non-function call"), + ErrorSubType::DivisionByZero => String::from("Division by zero"), + ErrorSubType::InvalidType => String::from("Invalid type"), + ErrorSubType::WrongType => String::from("Wrong type"), + ErrorSubType::NonStringKey => String::from("Non-string key"), + } +} +fn convert_subtypes_to_short(stype: &ErrorSubType) -> String { + match stype { + ErrorSubType::UnexpectedEnd => String::from("UE:"), + ErrorSubType::UnexpectedOperation => String::from("UP:"), + ErrorSubType::Expected => String::from("EX:"), + ErrorSubType::Unexpected => String::from("UN:"), + ErrorSubType::InvalidTableKeys => String::from("IK:"), + ErrorSubType::Unclosed => String::from("UC:"), + ErrorSubType::ElseWithoutIf => String::from("EW:"), + ErrorSubType::BreakContinueWithoutLoop => String::from("BC:"), + ErrorSubType::UnknownOperation => String::from("UO:"), + ErrorSubType::VariableNotFound => String::from("VN:"), + ErrorSubType::VariableAlreadyExists => String::from("VE:"), + ErrorSubType::ArgumentDuplication => String::from("AD:"), + ErrorSubType::RegisterNotFound => String::from("RF:"), + ErrorSubType::MemoryOutOfBounds => String::from("MO:"), + ErrorSubType::UnknownOPCode => String::from("OC:"), + ErrorSubType::UnknownFunction => String::from("UF:"), + ErrorSubType::UnknownString => String::from("US:"), + ErrorSubType::UnknownMemoryLocation => String::from("UM:"), + ErrorSubType::NonFunctionCall => String::from("NF:"), + ErrorSubType::DivisionByZero => String::from("DZ:"), + ErrorSubType::InvalidType => String::from("IT:"), + ErrorSubType::WrongType => String::from("WT:"), + ErrorSubType::NonStringKey => String::from("NS:"), + } +} + +pub fn create_error(message: &str, position: usize, typ: ErrorType, stype: ErrorSubType) -> ASLError { + let mut code = convert_types_to_short(&typ); + code.push_str(&convert_subtypes_to_short(&stype)); + code.push_str(&position.to_string()); + ASLError { + message: String::from(message), + position, + typ, + subtype: stype, + code, + } +} + +fn get_exact_pos(file: &String, pos: usize) -> (usize, usize) { + let mut line = 1; + let mut column = 1; + for (i, c) in file.char_indices() { + if i == pos { + return (line, column); + } + if c == '\n' { + line += 1; + column = 1; + } else { + column += 1; + } + } + (line, column) +} +fn get_sorrunding_lines(file: &String, line: usize) -> (String, String, String) { + let lines = file.lines(); + let mut before = String::new(); + let mut current = String::new(); + let mut after = String::new(); + let mut current_line = 1; + for l in lines { + if current_line == line - 1 { + before = l.to_string(); + } else if current_line == line { + current = l.to_string(); + } else if current_line == line + 1 { + after = l.to_string(); + break; + } + current_line += 1; + } + (before, current, after) +} + +pub fn print_error(error: &ASLError, ctx: &Context) { + let mut out = String::new(); + out.push_str(&convert_types_to_string(&error.typ)); + if error.message.len() > 0 { + out.push_str(&convert_subtypes_to_string(&error.subtype)); + } else { + out.push_str(&error.message); + } + out.push_str(" at position "); + + let (line, column) = get_exact_pos(&ctx.raw_file, error.position); + out.push_str(&ctx.file); + out.push_str(":"); + out.push_str(&line.to_string()); + out.push_str(":"); + out.push_str(&column.to_string()); + + out.push_str("\n"); + let (before, current, after) = get_sorrunding_lines(&ctx.raw_file, line); + if line > 1 { + out.push_str(&(line-1).to_string()); + out.push_str(" | "); + } else { + out.push_str(" | "); + } + out.push_str(&before); + out.push_str("\n"); + out.push_str(&line.to_string()); + out.push_str(" | "); + out.push_str(¤t); + + out.push_str("\n"); + out.push_str(" "); + out.push_str(&" ".repeat(column - 1)); + out.push_str("^ "); + out.push_str(&error.message); + + out.push_str("\n"); + out.push_str(&(line+1).to_string()); + out.push_str(" | "); + out.push_str(&after); + + out.push_str("\n"); + out.push_str("Error Code: "); + out.push_str(&error.code); + println!("{}", out); +} \ No newline at end of file diff --git a/src/lexer.rs b/src/lexer.rs index 1289c5d..33131f9 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -1,3 +1,6 @@ +use std::process; +use crate::{errors::{create_error, print_error, ErrorSubType, ErrorType}, Context}; + #[derive(Debug, PartialEq)] pub enum TokenType { STRING, @@ -46,7 +49,7 @@ fn is_sep(char: &str) -> bool { return chars.contains(&check.as_str()); }*/ -fn read_string(splitted: &Vec<&str>, pos: &mut usize, out: &mut Vec) { +fn read_string(splitted: &Vec<&str>, pos: &mut usize, out: &mut Vec, ctx: &Context) { let mut str = String::from(""); let start_pos = *pos-1; *pos += 5; @@ -61,12 +64,14 @@ fn read_string(splitted: &Vec<&str>, pos: &mut usize, out: &mut Vec) { str += nchar; } if !success { - panic!("Unexpected end of string at {}", pos); + let err = create_error("Unexpected end of string", *pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 5; out.push(Token { typ: TokenType::STRING, value: str, pos: start_pos }); } -fn read_comment(splitted: &Vec<&str>, pos: &mut usize, is_multiline: bool) { +fn read_comment(splitted: &Vec<&str>, pos: &mut usize, is_multiline: bool, ctx: &Context) { let mut str = String::from(""); *pos += 1; let mut success = !is_multiline; @@ -83,7 +88,9 @@ fn read_comment(splitted: &Vec<&str>, pos: &mut usize, is_multiline: bool) { str += nchar; } if !success { - panic!("Unexpected end of comment at {}", pos); + let err = create_error("Unexpected end of comment", *pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; } @@ -204,7 +211,7 @@ fn read_identifier(splitted: &Vec<&str>, pos: &mut usize, out: &mut Vec) out.extend(pre_out); } -pub fn lex(input: String) -> Vec { +pub fn lex(input: String, ctx: &Context) -> Vec { let mut out: Vec = vec![]; let splitted: Vec<&str> = input.split("").collect(); let mut pos = 1; @@ -232,11 +239,11 @@ pub fn lex(input: String) -> Vec { pos -= 1; out.push(Token { typ: TokenType::NUMBER, value: num, pos: start_pos }); } else if splitted.len() >= pos+5 && splitted[(pos-1)..(pos+5)].join("") == "szaft\"" { - read_string(&splitted, &mut pos, &mut out); + read_string(&splitted, &mut pos, &mut out, ctx); } else if splitted.len() >= pos+1 && splitted[(pos-1)..(pos+1)].join("") == "//" { - read_comment(&splitted, &mut pos, false); + read_comment(&splitted, &mut pos, false, ctx); } else if splitted.len() >= pos+1 && splitted[(pos-1)..(pos+1)].join("") == "/*" { - read_comment(&splitted, &mut pos, true); + read_comment(&splitted, &mut pos, true, ctx); } else if is_mul_operator(char, splitted[pos]) { out.push(Token { typ: TokenType::OPERATOR, value: String::from(char) + splitted[pos], pos: pos-1 }); pos += 1; diff --git a/src/main.rs b/src/main.rs index 137b81b..2e159f6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ mod parser; mod enviroment; mod compiler; mod virtualmachine; +mod errors; fn log_ast_part(part: &ASTPart, prefix: String) { match part { @@ -134,23 +135,33 @@ fn log_ast_part(part: &ASTPart, prefix: String) { } } +#[derive(Clone)] +struct Context { + file: String, + raw_file: String, +} + fn main() { let inp = fs::read_to_string("./test.as"); match inp { Result::Ok(data) => { - let lexed = lexer::lex(data); + let ctx = Context { + file: String::from("./test.as"), + raw_file: data.clone(), + }; + let lexed = lexer::lex(data, &ctx); println!("Lexer output: "); for token in &lexed { println!(" {}: {:?}: {}", token.pos, token.typ, token.value); } - let ast = parser::parse(lexed); + let ast = parser::parse(lexed, &ctx); println!("AST: "); for part in &ast { log_ast_part(part, String::from(" ")); } - let compiled = compiler::compile(ast); + let compiled = compiler::compile(ast, &ctx); println!("Compiled output: {:?}", compiled); - let mut vm = Machine::new(); + let mut vm = Machine::new(vec![ctx]); vm.load(compiled); vm.run(); println!("Registers: {:?}", vm.registers); diff --git a/src/parser.rs b/src/parser.rs index 400fab9..807c818 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,4 +1,6 @@ -use crate::lexer::{Token, TokenType}; +use crate::{lexer::{Token, TokenType}, Context}; +use std::process; +use crate::errors::{create_error, print_error, ErrorSubType, ErrorType}; #[derive(Debug, Clone, PartialEq)] pub enum ASTPart { @@ -158,7 +160,7 @@ fn is_end(input: &Token, end: &Vec) -> bool { return false; } -fn read_call(variable: ASTPart, pos: &mut usize, input: &Vec) -> ASTPart { +fn read_call(variable: ASTPart, pos: &mut usize, input: &Vec, ctx: &Context) -> ASTPart { let mut args: Vec = vec![]; *pos += 1; let start_pos = input[*pos-1].pos; @@ -176,7 +178,7 @@ fn read_call(variable: ASTPart, pos: &mut usize, input: &Vec) -> ASTPart Token { typ: TokenType::SEPARATOR, value: String::from(","), pos: 0 }, Token { typ: TokenType::SEPARATOR, value: String::from(")"), pos: 0 } ]; - let arg = read_exp(pos, input, &ends, &ends); + let arg = read_exp(pos, input, &ends, &ends, ctx); args.push(arg); } return ASTPart::Call(AstCall { function: Box::new(variable), args: args, pos: start_pos }); @@ -193,7 +195,7 @@ fn operator_precedence(op: &str) -> i64 { } } -fn shunt(input: Vec) -> ASTPart { +fn shunt(input: Vec, ctx: &Context) -> ASTPart { let mut output: Vec = vec![]; let mut stack: Vec = vec![]; for part in input { @@ -262,7 +264,9 @@ fn shunt(input: Vec) -> ASTPart { if op.operator == "!" { println!("{:?}", output); if i < 1 { - panic!("Unexpected operation at {}", op.pos); + let err = create_error(&format!("Unexpected operation `{}`", op.operator), op.pos, ErrorType::SemanticError, ErrorSubType::UnexpectedOperation); + print_error(&err, &ctx); + process::exit(1); } let left = output[i-1].clone(); output[i] = ASTPart::Operation(AstOperation { @@ -274,7 +278,9 @@ fn shunt(input: Vec) -> ASTPart { output.remove(i-1); } else { if i < 2 { - panic!("Unexpected operation at {}", op.pos); + let err = create_error(&format!("Unexpected operation `{}`", op.operator), op.pos, ErrorType::SemanticError, ErrorSubType::UnexpectedOperation); + print_error(&err, &ctx); + process::exit(1); } let left = output[i-2].clone(); let right = output[i-1].clone(); @@ -296,12 +302,14 @@ fn shunt(input: Vec) -> ASTPart { } return output[0].clone(); } -fn read_function(input: &Vec, pos: &mut usize, with_args: bool) -> ASTPart { +fn read_function(input: &Vec, pos: &mut usize, with_args: bool, ctx: &Context) -> ASTPart { let mut args: Vec = vec![]; let start_pos = input[*pos].pos; if with_args { if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "(" { - panic!("Expected ( at {}", input[*pos].pos); + let err = create_error(&format!("Expected `(`"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; while pos < &mut input.len() { @@ -316,16 +324,22 @@ fn read_function(input: &Vec, pos: &mut usize, with_args: bool) -> ASTPar if token.typ == TokenType::IDENTIFIER { args.push(token.value.clone()); } else { - panic!("Unexpected {:?}({}) at {}", token.typ, token.value, token.pos); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); + print_error(&err, &ctx); + process::exit(1); } } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" { - panic!("Unexpected end of arguments at {}", input[*pos].pos); + let err = create_error(&format!("Unexpected end of arguments"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "{" { - panic!("Expected {{ at {}", input[*pos].pos); + let err = create_error(&format!("Expected {{"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; let op_ends: Vec = vec![ @@ -336,15 +350,17 @@ fn read_function(input: &Vec, pos: &mut usize, with_args: bool) -> ASTPar let parse_ends: Vec = vec![ Token { typ: TokenType::SEPARATOR, value: String::from("}"), pos: 0 } ]; - let body = parse_internal(input, &op_ends, &parse_ends, pos); + let body = parse_internal(input, &op_ends, &parse_ends, pos, ctx); if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "}" { - panic!("Unexpected end of function at {}", input[*pos].pos); + let err = create_error(&format!("Unexpected end of function"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; return ASTPart::Function(AstFunction { args: args, body: body, pos: start_pos }); } -fn read_table(input: &Vec, pos: &mut usize) -> ASTPart { +fn read_table(input: &Vec, pos: &mut usize, ctx: &Context) -> ASTPart { let start_pos = input[*pos].pos; let key_ends: Vec = vec![ Token { typ: TokenType::SEPARATOR, value: String::from("]"), pos: 0 } @@ -358,28 +374,36 @@ fn read_table(input: &Vec, pos: &mut usize) -> ASTPart { while *pos < input.len() { if input[*pos].typ == TokenType::SEPARATOR && input[*pos].value == "[" { *pos += 1; - let keyy = read_exp(pos, input, &key_ends, &key_ends); + let keyy = read_exp(pos, input, &key_ends, &key_ends, ctx); match keyy { ASTPart::Table(_) => { - panic!("Table keys cannot be tables at {}", input[*pos].pos); + let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); + print_error(&err, &ctx); + process::exit(1); }, ASTPart::Function(_) => { - panic!("Table keys cannot be functions at {}", input[*pos].pos); + let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); + print_error(&err, &ctx); + process::exit(1); }, _ => {} } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "]" { - panic!("Unexpected end of key at {}", input[*pos].pos); + let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "=" { - panic!("Expected = after key at {}", input[*pos].pos); + let err = create_error(&format!("Expected `=` after key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; - let value = read_exp(pos, input, &ends, &ends); + let value = read_exp(pos, input, &ends, &ends, ctx); tbl.push(TableValue { key: keyy, value: value, pos: input[*pos].pos }); } else { - let value = read_exp(pos, input, &ends, &ends); + let value = read_exp(pos, input, &ends, &ends, ctx); tbl.push(TableValue { key: ASTPart::Number(AstNumber { value: key, pos: 0 }), value: value, pos: input[*pos].pos }); key += 1; } @@ -390,13 +414,15 @@ fn read_table(input: &Vec, pos: &mut usize) -> ASTPart { *pos += 1; continue; } else { - panic!("Unexpected end of table at {}", input[*pos].pos); + let err = create_error(&format!("Unexpected end of table"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } } return ASTPart::Table(AstTable { values: tbl, pos: start_pos }); } -fn read_exp(pos: &mut usize, input: &Vec, ends: &Vec, parse_ends: &Vec) -> ASTPart { +fn read_exp(pos: &mut usize, input: &Vec, ends: &Vec, parse_ends: &Vec, ctx: &Context) -> ASTPart { let mut expressions: Vec = vec![]; while pos < &mut input.len() { let token = &input[*pos]; @@ -427,33 +453,41 @@ fn read_exp(pos: &mut usize, input: &Vec, ends: &Vec, parse_ends: } else if token.value == "nincs hám" { expressions.push(ASTPart::Null(AstNull { pos: token.pos })); } else if token.value == "lőcsve" { - let func = read_function(input, pos, true); + let func = read_function(input, pos, true, ctx); expressions.push(func); } else { - panic!("Unexpected {:?}({}) at {}", token.typ, token.value, token.pos); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); + print_error(&err, &ctx); + process::exit(1); } } else if token.typ == TokenType::IDENTIFIER { if next_token.typ == TokenType::SEPARATOR && next_token.value == "(" { let var = ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: token.pos }); - expressions.push(read_call(var, pos, input)); + expressions.push(read_call(var, pos, input, ctx)); } else if next_token.typ == TokenType::SEPARATOR && next_token.value == "[" { let var_pos = token.pos; let key_ends: Vec = vec![ Token { typ: TokenType::SEPARATOR, value: String::from("]"), pos: 0 } ]; *pos += 1; - let keyy = read_exp(pos, input, &key_ends, &key_ends); + let keyy = read_exp(pos, input, &key_ends, &key_ends, ctx); match keyy { ASTPart::Table(_) => { - panic!("Table keys cannot be tables at {}", input[*pos].pos); + let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); + print_error(&err, &ctx); + process::exit(1); }, ASTPart::Function(_) => { - panic!("Table keys cannot be functions at {}", input[*pos].pos); + let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); + print_error(&err, &ctx); + process::exit(1); }, _ => {} } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "]" { - panic!("Unexpected end of key at {}", input[*pos].pos); + let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; expressions.push(ASTPart::TableGet(AstTableGet { table: Box::new(ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: var_pos })), key: Box::new(keyy), pos: var_pos+1 })); @@ -468,28 +502,34 @@ fn read_exp(pos: &mut usize, input: &Vec, ends: &Vec, parse_ends: let ends: Vec = vec![ Token { typ: TokenType::SEPARATOR, value: String::from(")"), pos: 0 } ]; - let exp = read_exp(pos, input, &ends, &ends); + let exp = read_exp(pos, input, &ends, &ends, ctx); if input[*pos].typ == TokenType::SEPARATOR && input[*pos].value == ")" { *pos += 1; } else { - panic!("Unclosed parenthesis at {}", token.pos); + let err = create_error(&format!("Unclosed parenthesis"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Unclosed); + print_error(&err, &ctx); + process::exit(1); } expressions.push(exp); } else if token.value == "{" { - let tbl = read_table(input, pos); + let tbl = read_table(input, pos, ctx); expressions.push(tbl); } else { - panic!("Unexpected {:?}({}) at {}", token.typ, token.value, token.pos); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); + print_error(&err, &ctx); + process::exit(1); } } else { - panic!("Unexpected {:?}({}) at {}", token.typ, token.value, token.pos); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); + print_error(&err, &ctx); + process::exit(1); } } - let shunted = shunt(expressions); + let shunted = shunt(expressions, ctx); return shunted; } -fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, parse_ends: &Vec) -> ASTPart { +fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, parse_ends: &Vec, ctx: &Context) -> ASTPart { let token = &input[*pos]; let mut next_token = &Token { typ: TokenType::OPEND, @@ -511,173 +551,233 @@ fn next_operation(pos: &mut usize, input: &Vec, op_ends: &Vec, par let variable = &input[*pos]; *pos += 1; if variable.typ != TokenType::IDENTIFIER { - panic!("Unexpected {:?} at {}", variable.typ, variable.pos) + let err = create_error(&format!("Unexpected `{:?}`", variable.typ,), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); + print_error(&err, &ctx); + process::exit(1); } let eq = &input[*pos]; if eq.typ == TokenType::SEPARATOR && eq.value == "=" { *pos += 1; } - let value = read_exp(pos, input, op_ends, parse_ends); + let value = read_exp(pos, input, op_ends, parse_ends, ctx); return ASTPart::Assigment(AstAssigment { variable: variable.value.clone(), value: Box::new(value), pos: token.pos }); } else if token.value == "ha geny" { if next_token.typ != TokenType::SEPARATOR || next_token.value != "(" { - panic!("Expected ( at {}", token.pos); + let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; let condition_end = vec![ Token { typ: TokenType::SEPARATOR, value: String::from(")"), pos: 0 } ]; - let condition = read_exp(pos, input, &condition_end, &condition_end); + let condition = read_exp(pos, input, &condition_end, &condition_end, ctx); if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" { - panic!("Unexpected end of condition at {}", token.pos); + let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; - let body = read_function(input, pos, false); + let body = read_function(input, pos, false, ctx); let real_body = match body { ASTPart::Function(func) => func.body, - _ => panic!("Expected function body at {}", token.pos) + _ => { + let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); + } }; return ASTPart::If(AstIf { condition: Box::new(condition), body: real_body, pos: token.pos }); } else if token.value == "amíg geny" { if next_token.typ != TokenType::SEPARATOR || next_token.value != "(" { - panic!("Expected ( at {}", token.pos); + let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; let condition_end = vec![ Token { typ: TokenType::SEPARATOR, value: String::from(")"), pos: 0 } ]; - let condition = read_exp(pos, input, &condition_end, &condition_end); + let condition = read_exp(pos, input, &condition_end, &condition_end, ctx); if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" { - panic!("Unexpected end of condition at {}", token.pos); + let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; - let body = read_function(input, pos, false); + let body = read_function(input, pos, false, ctx); let real_body = match body { ASTPart::Function(func) => func.body, - _ => panic!("Expected function body at {}", token.pos) + _ => { + let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); + } }; return ASTPart::While(AstWhile { condition: Box::new(condition), body: real_body, pos: token.pos }); } else if token.value == "kraf" { return ASTPart::Break(AstBreak { pos: token.pos }); } else if token.value == "kopva" { if next_token.typ != TokenType::SEPARATOR || next_token.value != "(" { - panic!("Expected ( at {}", token.pos); + let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; let ends = vec![ Token { typ: TokenType::SEPARATOR, value: String::from(")"), pos: 0 }, Token { typ: TokenType::OPEND, value: String::from(";"), pos: 0 } ]; - let init = parse_internal(input, &ends, &ends, pos); + let init = parse_internal(input, &ends, &ends, pos, ctx); if init.len() != 1 { - panic!("Only one expression is expected for init at {}", token.pos); + let err = create_error(&format!("Only one expression is expected for init"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); } if input[*pos].typ != TokenType::OPEND || input[*pos].value != ";" { - panic!("Unexpected end of init at {}", token.pos); + let err = create_error(&format!("Unexpected end of init"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; - let condition = read_exp(pos, input, &ends, &ends); + let condition = read_exp(pos, input, &ends, &ends, ctx); if input[*pos].typ != TokenType::OPEND || input[*pos].value != ";" { - panic!("Unexpected end of condition at {}", token.pos); + let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; - let update = parse_internal(input, &ends, &ends, pos); + let update = parse_internal(input, &ends, &ends, pos, ctx); if update.len() != 1 { - panic!("Only one expression is expected for update at {}", token.pos); + let err = create_error(&format!("Only one expression is expected for update"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" { - panic!("Unexpected end of update at {}", token.pos); + let err = create_error(&format!("Unexpected end of update"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; - let body = read_function(input, pos, false); + let body = read_function(input, pos, false, ctx); let real_body = match body { ASTPart::Function(func) => func.body, - _ => panic!("Expected function body at {}", token.pos) + _ => { + let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); + } }; return ASTPart::For(AstFor { init: Box::new(init[0].clone()), condition: Box::new(condition), update: Box::new(update[0].clone()), body: real_body, pos: token.pos }); } else if token.value == "szard le" { return ASTPart::Continue(AstContinue { pos: token.pos }); } else if token.value == "ha nem geny akkor geny" { if next_token.typ != TokenType::SEPARATOR || next_token.value != "(" { - panic!("Expected ( at {}", token.pos); + let err = create_error(&format!("Expected `(`"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; let condition_end = vec![ Token { typ: TokenType::SEPARATOR, value: String::from(")"), pos: 0 } ]; - let condition = read_exp(pos, input, &condition_end, &condition_end); + let condition = read_exp(pos, input, &condition_end, &condition_end, ctx); if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != ")" { - panic!("Unexpected end of condition at {}", token.pos); + let err = create_error(&format!("Unexpected end of condition"), token.pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; - let body = read_function(input, pos, false); + let body = read_function(input, pos, false, ctx); let real_body = match body { ASTPart::Function(func) => func.body, - _ => panic!("Expected function body at {}", token.pos) + _ => { + let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); + } }; return ASTPart::ElseIf(AstElseIf { condition: Box::new(condition), body: real_body, pos: token.pos }); } else if token.value == "ha nem geny" { - let body = read_function(input, pos, false); + let body = read_function(input, pos, false, ctx); let real_body = match body { ASTPart::Function(func) => func.body, - _ => panic!("Expected function body at {}", token.pos) + _ => { + let err = create_error(&format!("Expected function body"), token.pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); + } }; return ASTPart::Else(AstElse { body: real_body, pos: token.pos }); } else if token.value == "reti" { if is_end(next_token, op_ends) || is_end(next_token, parse_ends) { return ASTPart::Return(AstReturn { value: Box::new(ASTPart::Null(AstNull { pos: token.pos })), pos: token.pos }); } else { - let value = read_exp(pos, input, op_ends, parse_ends); + let value = read_exp(pos, input, op_ends, parse_ends, ctx); return ASTPart::Return(AstReturn { value: Box::new(value), pos: token.pos }); } } else { - panic!("Unexpected {:?}({}) at {}", token.typ, token.value, token.pos); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); + print_error(&err, &ctx); + process::exit(1); } } else if token.typ == TokenType::IDENTIFIER { if next_token.typ == TokenType::SEPARATOR && next_token.value == "(" { let var = ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: token.pos }); - return read_call(var, pos, input); + return read_call(var, pos, input, ctx); } else if next_token.typ == TokenType::SEPARATOR && next_token.value == "[" { *pos += 1; let key_ends: Vec = vec![ Token { typ: TokenType::SEPARATOR, value: String::from("]"), pos: 0 } ]; - let keyy = read_exp(pos, input, &key_ends, &key_ends); + let keyy = read_exp(pos, input, &key_ends, &key_ends, ctx); match keyy { ASTPart::Table(_) => { - panic!("Table keys cannot be tables at {}", input[*pos].pos); + let err = create_error(&format!("Table keys cannot be tables"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); + print_error(&err, &ctx); + process::exit(1); }, ASTPart::Function(_) => { - panic!("Table keys cannot be functions at {}", input[*pos].pos); + let err = create_error(&format!("Table keys cannot be functions"), input[*pos].pos, ErrorType::SemanticError, ErrorSubType::InvalidTableKeys); + print_error(&err, &ctx); + process::exit(1); }, _ => {} } if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "]" { - panic!("Unexpected end of key at {}", input[*pos].pos); + let err = create_error(&format!("Unexpected end of key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::UnexpectedEnd); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; if input[*pos].typ != TokenType::SEPARATOR || input[*pos].value != "=" { - panic!("Expected = after key at {}", input[*pos].pos); + let err = create_error(&format!("Expected `=` after key"), input[*pos].pos, ErrorType::SyntaxError, ErrorSubType::Expected); + print_error(&err, &ctx); + process::exit(1); } *pos += 1; - let value = read_exp(pos, input, op_ends, parse_ends); + let value = read_exp(pos, input, op_ends, parse_ends, ctx); return ASTPart::TableSet(AstTableSet { table: Box::new(ASTPart::VarRead(AstVarRead { variable: token.value.clone(), pos: token.pos })), key: Box::new(keyy), value: Box::new(value), pos: token.pos }); } else if next_token.typ == TokenType::SEPARATOR && next_token.value == "=" { *pos += 1; - let value = read_exp(pos, input, op_ends, parse_ends); + let value = read_exp(pos, input, op_ends, parse_ends, ctx); return ASTPart::VarUpdate(AstVarUpdate { variable: token.value.clone(), value: Box::new(value), pos: token.pos }); } else { - panic!("Unexpected {:?}({}) at {}", token.typ, token.value, token.pos); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); + print_error(&err, &ctx); + process::exit(1); } } else { - panic!("Unexpected {:?}({}) at {}", token.typ, token.value, token.pos); + let err = create_error(&format!("Unexpected `{:?}({})`", token.typ, token.value), token.pos, ErrorType::SyntaxError, ErrorSubType::Unexpected); + print_error(&err, &ctx); + process::exit(1); } } -fn parse_internal(input: &Vec, op_ends: &Vec, parse_ends: &Vec, pos: &mut usize) -> Vec { +fn parse_internal(input: &Vec, op_ends: &Vec, parse_ends: &Vec, pos: &mut usize, ctx: &Context) -> Vec { let mut out: Vec = vec![]; while *pos < input.len() { - let op = next_operation(pos, &input, &op_ends, &parse_ends); + let op = next_operation(pos, &input, &op_ends, &parse_ends, ctx); match op { ASTPart::NOOP => {}, _ => { @@ -690,7 +790,7 @@ fn parse_internal(input: &Vec, op_ends: &Vec, parse_ends: &Vec) -> Vec { +pub fn parse(input: Vec, ctx: &Context) -> Vec { let op_ends: Vec = vec![ Token { typ: TokenType::OPEND, value: String::from("\n"), pos: 0 }, Token { typ: TokenType::OPEND, value: String::from(";"), pos: 0 }, @@ -699,6 +799,6 @@ pub fn parse(input: Vec) -> Vec { let parse_ends: Vec = vec![ Token { typ: TokenType::OPEND, value: String::from("EOF"), pos: 0 } ]; - let out = parse_internal(&input, &op_ends, &parse_ends, &mut 0); + let out = parse_internal(&input, &op_ends, &parse_ends, &mut 0, ctx); return out; } \ No newline at end of file diff --git a/src/virtualmachine.rs b/src/virtualmachine.rs index 4b96fc2..a1f0bc5 100644 --- a/src/virtualmachine.rs +++ b/src/virtualmachine.rs @@ -1,6 +1,5 @@ -use std::collections::HashMap; - -use crate::enviroment; +use std::{collections::HashMap, process, vec}; +use crate::{enviroment, errors::{create_error, print_error, ErrorSubType, ErrorType}, Context}; const ASXVERSION: [u8; 3] = [0,1,0]; @@ -68,6 +67,7 @@ struct DecompiledOperation { arg1: u8, arg2: i64, arg3: u8, + pos: usize, } #[derive(Debug, Clone)] @@ -96,7 +96,8 @@ pub struct Machine { pub stack: Vec, pub registers: Vec, pub call_stack: Vec, - pub env: HashMap + pub env: HashMap, + pub ctx: Vec, } fn read_be_num(input: &[u8]) -> usize { @@ -228,18 +229,22 @@ fn get_mem_tbl_val(tbl: &VMMemoryTable, key: VMMemory) -> Option<&VMMemory> { None } -fn do_operation_operation(registers: &mut Vec, memory: &mut Vec, operation: &DecompiledOperation) { +fn do_operation_operation(registers: &mut Vec, memory: &mut Vec, operation: &DecompiledOperation, ctx: &Context) { let reg_clone = registers.clone(); let reg1 = get_register_by_id(®_clone, operation.arg1); let reg2 = get_register_by_id(®_clone, operation.arg2 as u8); let reg3 = get_register_by_id(®_clone, operation.arg3); if reg1.is_none() || reg2.is_none() || reg3.is_none() { - panic!("One or more registers not found for operation"); + let err = create_error(&format!("One or more registers not found for operation"), operation.pos, ErrorType::MachineError, ErrorSubType::RegisterNotFound); + print_error(&err, &ctx); + process::exit(1); } let mem1 = reg1.unwrap().pointer; let mem2 = reg2.unwrap().pointer; if mem1 >= memory.len() || mem2 >= memory.len() || mem1 < 1 || mem2 < 1 { - panic!("Memory location out of bounds for registers {} and {}", operation.arg1, operation.arg2); + let err = create_error(&format!("Memory location out of bounds `{}` or `{}`", mem1, mem2), operation.pos, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds); + print_error(&err, &ctx); + process::exit(1); } let mut result: VMMemory; match (&memory[mem1], &memory[mem2]) { @@ -256,7 +261,9 @@ fn do_operation_operation(registers: &mut Vec, memory: &mut Vec { if num2.value == 0 { - panic!("Division by zero"); + let err = create_error(&format!("Division by zero"), operation.pos, ErrorType::MathError, ErrorSubType::DivisionByZero); + print_error(&err, &ctx); + process::exit(1); } result = VMMemory::Number(VMMemoryNumber { value: num1.value / num2.value, variable_id: 0 }); }, @@ -285,7 +292,9 @@ fn do_operation_operation(registers: &mut Vec, memory: &mut Vec { - panic!("Unknown operation code for number operation: {}", operation.opcode); + let err = create_error(&format!("Unknown operation code for number operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode); + print_error(&err, &ctx); + process::exit(1); } }; }, @@ -301,7 +310,9 @@ fn do_operation_operation(registers: &mut Vec, memory: &mut Vec { - panic!("Unknown operation code for string operation: {}", operation.opcode); + let err = create_error(&format!("Unknown operation code for string operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode); + print_error(&err, &ctx); + process::exit(1); } }; }, @@ -320,7 +331,9 @@ fn do_operation_operation(registers: &mut Vec, memory: &mut Vec { - panic!("Unknown operation code for boolean operation: {}", operation.opcode); + let err = create_error(&format!("Unknown operation code for boolean operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode); + print_error(&err, &ctx); + process::exit(1); } }; }, @@ -333,12 +346,16 @@ fn do_operation_operation(registers: &mut Vec, memory: &mut Vec { - panic!("Unknown operation code for null operation: {}", operation.opcode); + let err = create_error(&format!("Unknown operation code for null operation: `{}`", operation.opcode), operation.pos, ErrorType::MachineError, ErrorSubType::UnknownOPCode); + print_error(&err, &ctx); + process::exit(1); } }; }, _ => { - panic!("Invalid memory types for operation: {} and {}", mem1, mem2); + let err = create_error(&format!("Invalid memory types for operation: `{}` and `{}`", mem1, mem2), operation.pos, ErrorType::TypeError, ErrorSubType::InvalidType); + print_error(&err, &ctx); + process::exit(1); } } let mut reg3_pointer = reg3.unwrap().pointer; @@ -431,11 +448,14 @@ fn load_func(data: Vec, offset: &mut usize) -> DecompiledFunction { let arg1 = bin_to_num(op[5..9].to_string()); let arg2 = bin_to_snum(op[9..73].to_string()); let arg3 = bin_to_num(op[73..77].to_string()); + let pos = read_be_num(&data[*offset..*offset + 4]); + *offset += 4; body.push(DecompiledOperation { opcode: op_code as u8, arg1: arg1 as u8, arg2: arg2, arg3: arg3 as u8, + pos: pos, }); } println!("Variables: {:?}", variables); @@ -450,7 +470,7 @@ fn load_func(data: Vec, offset: &mut usize) -> DecompiledFunction { } impl Machine { - pub fn new() -> Self { + pub fn new(ctx: Vec) -> Self { let mut registers = Vec::new(); for i in 0..17 { registers.push(Register { @@ -470,7 +490,8 @@ impl Machine { return_reg: 0, pc: 0, }], - env: enviroment::generate() + env: enviroment::generate(), + ctx: ctx, }; } @@ -481,6 +502,7 @@ impl Machine { if data[3..6] != ASXVERSION { panic!("Unsupported ASX version"); } + let _func_count = read_be_num(&data[6..10]); let mut offset = 6; while offset < data.len() { let func = load_func(data.clone(), &mut offset); @@ -494,11 +516,13 @@ impl Machine { } let func_clone = self.functions.clone(); let executed_func = func_clone.get(self.call_stack[self.call_stack.len()-1].func); + let mut executed_stack = self.call_stack.len()-1; if executed_func.is_none() { - panic!("Current function not found!"); + let err = create_error(&format!("Current function not found"), 0, ErrorType::MachineError, ErrorSubType::UnknownFunction); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let mut executed_func = executed_func.unwrap(); - let mut executed_stack = self.call_stack.len()-1; while self.call_stack[executed_stack].pc < executed_func.body.len() { let operation = &executed_func.body[self.call_stack[executed_stack].pc]; self.call_stack[executed_stack].pc += 1; @@ -511,7 +535,9 @@ impl Machine { //LDS let str = executed_func.strings.get(&(operation.arg2 as u32)); if str.is_none() { - panic!("String with ID {} not found", operation.arg2); + let err = create_error(&format!("String with ID `{}` not found", operation.arg2), 0, ErrorType::MachineError, ErrorSubType::UnknownString); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let str = str.unwrap(); self.memory.push(VMMemory::String(VMMemoryString { value: str.clone(), variable_id: 0 })); @@ -521,11 +547,15 @@ impl Machine { //LDM let mem = get_mem_pos_by_var_id(&self.memory, operation.arg2 as u32); if mem.is_none() { - panic!("Memory with variable ID {} not found", operation.arg2); + let err = create_error(&format!("Memory with variable ID `{}` not found", operation.arg2), 0, ErrorType::MachineError, ErrorSubType::UnknownMemoryLocation); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let mem = mem.unwrap(); if mem >= self.memory.len() || mem < 1 { - panic!("Memory location out of bounds for variable ID {}", operation.arg2); + let err = create_error(&format!("Memory location out of bounds for variable ID `{}`", operation.arg2), 0, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let mut nmem = self.memory[mem].clone(); match &mut nmem { @@ -568,12 +598,16 @@ impl Machine { //LDF let func_pos = executed_func.functions.get(&(operation.arg2 as u32)); if func_pos.is_none() { - panic!("Function with ID {} not found", operation.arg2); + let err = create_error(&format!("Function with ID `{}` not found", operation.arg2), 0, ErrorType::MachineError, ErrorSubType::UnknownFunction); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let func_pos = func_pos.unwrap(); let func = self.functions.get(*func_pos as usize); if func.is_none() { - panic!("Function with position {} not found", func_pos); + let err = create_error(&format!("Function with position `{}` not found", func_pos), 0, ErrorType::MachineError, ErrorSubType::UnknownFunction); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } self.memory.push(VMMemory::Function(VMMemoryFunction { id: *func_pos as usize, @@ -595,11 +629,15 @@ impl Machine { //ASS let reg = get_register_by_id(&self.registers, operation.arg1); if reg.is_none() { - panic!("Register {} not found", operation.arg1); + let err = create_error(&format!("Register `{}` not found", operation.arg1), 0, ErrorType::MachineError, ErrorSubType::RegisterNotFound); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let reg = reg.unwrap(); if reg.pointer >= self.memory.len() || reg.pointer < 1 { - panic!("Register {} points to an invalid memory location", operation.arg1); + let err = create_error(&format!("Register `{}` points to an invalid memory location", operation.arg1), 0, ErrorType::MachineError, ErrorSubType::MemoryOutOfBounds); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let used_var = get_mem_pos_by_var_id(&self.memory, operation.arg2 as u32); if let Some(pos) = used_var { @@ -660,13 +698,15 @@ impl Machine { let temp_regs = self.registers.clone(); let reg1 = get_register_by_id(&temp_regs, operation.arg1); if reg1.is_none() { - panic!("Register {} not found", operation.arg1); + let err = create_error(&format!("Register `{}` not found", operation.arg1), 0, ErrorType::MachineError, ErrorSubType::RegisterNotFound); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let reg1 = reg1.unwrap(); set_register(&mut self.registers, Register { id: operation.arg2 as u8, pointer: reg1.pointer }); }, 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 => { - do_operation_operation(&mut self.registers, &mut self.memory, operation); + do_operation_operation(&mut self.registers, &mut self.memory, operation, &self.ctx[self.call_stack[executed_stack].func].clone()); }, 24 => { //NOT @@ -674,7 +714,9 @@ impl Machine { let reg1 = get_register_by_id(®_clone, operation.arg1); let reg2 = get_register_by_id(®_clone, operation.arg2 as u8); if reg1.is_none() || reg2.is_none() { - panic!("One or more registers not found for operation"); + let err = create_error(&format!("Register `{}` or `{}` not found", operation.arg1, operation.arg2), 0, ErrorType::MachineError, ErrorSubType::RegisterNotFound); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let mem1 = reg1.unwrap().pointer; if mem1 >= self.memory.len() || mem1 < 1 { @@ -737,7 +779,9 @@ impl Machine { //CJP let reg = get_register_by_id(&self.registers, operation.arg1); if reg.is_none() { - panic!("Register {} not found", operation.arg1); + let err = create_error(&format!("Register `{}` not found", operation.arg1), 0, ErrorType::MachineError, ErrorSubType::RegisterNotFound); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let reg = reg.unwrap(); let mem = self.memory.get(reg.pointer); @@ -758,7 +802,9 @@ impl Machine { //CAL let reg = get_register_by_id(&self.registers, operation.arg1); if reg.is_none() { - panic!("Register {} doesn't exist", operation.arg1); + let err = create_error(&format!("Register `{}` not found", operation.arg1), 0, ErrorType::MachineError, ErrorSubType::RegisterNotFound); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let reg = reg.unwrap(); let mem = self.memory.get(reg.pointer); @@ -818,7 +864,9 @@ impl Machine { //PSH let reg = get_register_by_id(&self.registers, operation.arg1); if reg.is_none() { - panic!("Register {} not found", operation.arg1); + let err = create_error(&format!("Register `{}` not found", operation.arg1), 0, ErrorType::MachineError, ErrorSubType::RegisterNotFound); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let reg = reg.unwrap(); let mem = self.memory.get(reg.pointer); @@ -833,7 +881,9 @@ impl Machine { let target_reg = get_register_by_id(&self.registers, self.call_stack[executed_stack].return_reg as u8); let ret_reg = get_register_by_id(&self.registers, operation.arg1); if target_reg.is_none() || ret_reg.is_none() { - panic!("Return register or target register not found"); + let err = create_error(&format!("Register `{}` or `{}` not found", self.call_stack[executed_stack].return_reg, operation.arg1), 0, ErrorType::MachineError, ErrorSubType::RegisterNotFound); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let ret_mem = self.memory.get(ret_reg.unwrap().pointer); if ret_mem.is_none() { @@ -859,7 +909,9 @@ impl Machine { let reg2 = get_register_by_id(®_clone, operation.arg2 as u8); let reg3 = get_register_by_id(®_clone, operation.arg3); if reg2.is_none() || reg3.is_none() { - panic!("One or more registers not found for GET operation"); + let err = create_error(&format!("Register `{}` or `{}` not found", operation.arg2, operation.arg3), 0, ErrorType::MachineError, ErrorSubType::RegisterNotFound); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let mem2 = self.memory.get(reg2.unwrap().pointer); if mem2.is_none() { @@ -925,7 +977,9 @@ impl Machine { let reg2 = get_register_by_id(®_clone, operation.arg2 as u8); let reg3 = get_register_by_id(®_clone, operation.arg3); if reg.is_none() || reg2.is_none() || reg3.is_none() { - panic!("One or more registers not found for SET operation"); + let err = create_error(&format!("Register `{}` or `{}` or `{}` not found", operation.arg1, operation.arg2, operation.arg3), 0, ErrorType::MachineError, ErrorSubType::RegisterNotFound); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let mem1 = self.memory.get(reg.unwrap().pointer); let mem2 = self.memory.get(reg2.unwrap().pointer); @@ -994,7 +1048,9 @@ impl Machine { let reg2 = get_register_by_id(&self.registers, operation.arg2 as u8); let reg3 = get_register_by_id(&self.registers, operation.arg3); if reg.is_none() || reg2.is_none() || reg3.is_none() { - panic!("One or more registers not found for SET operation"); + let err = create_error(&format!("Register `{}` or `{}` or `{}` not found", operation.arg1, operation.arg2, operation.arg3), 0, ErrorType::MachineError, ErrorSubType::RegisterNotFound); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } let mem1 = self.memory.get(reg.unwrap().pointer); let mem2 = self.memory.get(reg2.unwrap().pointer); @@ -1015,7 +1071,9 @@ impl Machine { } }, _ => { - panic!("Unknown operation code: {}", operation.opcode); + let err = create_error(&format!("Unknown operation code: `{}`", operation.opcode), 0, ErrorType::MachineError, ErrorSubType::UnknownOPCode); + print_error(&err, &self.ctx[self.call_stack[executed_stack].func].clone()); + process::exit(1); } } }