begin new error system, unfinished

This commit is contained in:
afonya2 2025-06-06 22:01:53 +02:00
parent 32c2a20697
commit 532fffe725
Signed by: afonya
GPG key ID: EBB9C4CAFAAFB2DC
6 changed files with 673 additions and 237 deletions

View file

@ -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<u8>,
pub arg2: Option<i64>,
pub arg3: Option<u8>,
pub pos: u32,
}
#[derive(Debug, Clone)]
@ -139,15 +139,15 @@ fn get_variable_by_name(variables: &Vec<Variable>, name: &str, position: usize)
None
}
fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec<Operation>, variables: &mut Vec<Variable>, next_var_id: &mut u32, strings: &mut HashMap<u32, String>, next_string_id: &mut u32, functions: &mut HashMap<u32, Compiled>, next_function_id: &mut u32, registers: &mut Vec<RegisterState>) -> u8 {
fn do_ast_op(ast_op: ASTPart, op_count: &mut usize, ops: &mut Vec<Operation>, variables: &mut Vec<Variable>, next_var_id: &mut u32, strings: &mut HashMap<u32, String>, next_string_id: &mut u32, functions: &mut HashMap<u32, Compiled>, next_function_id: &mut u32, registers: &mut Vec<RegisterState>, 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<Operation>, 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<Operation>, 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<Operation>, 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<Operation>, 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<Variable> = 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<Operation>, 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<Variable> = 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<Operation>, 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<Variable> = 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<Operation>, 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<usize> = vec![];
let mut continues: Vec<usize> = 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<Operation>, 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<Operation>, 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<usize> = vec![];
let mut continues: Vec<usize> = 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<Operation>, 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<Operation>, 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<Operation>, 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<ASTPart>, args: Option<Vec<String>>, registers: &mut Vec<RegisterState>, next_var_id: &mut u32) -> Compiled {
fn compile_function(ast: Vec<ASTPart>, args: Option<Vec<String>>, registers: &mut Vec<RegisterState>, next_var_id: &mut u32, ctx: &Context) -> Compiled {
let mut ops: Vec<Operation> = vec![];
let mut variables: Vec<Variable> = vec![];
@ -575,7 +600,9 @@ fn compile_function(ast: Vec<ASTPart>, args: Option<Vec<String>>, 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<ASTPart>, args: Option<Vec<String>>, 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<u8> {
fn compile_body(compiled: Compiled, fpos: &mut usize, ctx: &Context) -> Vec<u8> {
let mut output: Vec<u8> = vec![];
let mut additional: Vec<Vec<u8>> = vec![];
//function
@ -671,7 +698,7 @@ fn compile_body(compiled: Compiled, fpos: &mut usize) -> Vec<u8> {
*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<u8> {
}
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<u8> {
return output;
}
pub fn compile(ast: Vec<ASTPart>) -> Vec<u8> {
pub fn compile(ast: Vec<ASTPart>, ctx: &Context) -> Vec<u8> {
let mut next_var_id: u32 = 1;
let mut registers: Vec<RegisterState> = vec![];
for i in 0..17 {
@ -714,7 +742,7 @@ pub fn compile(ast: Vec<ASTPart>) -> Vec<u8> {
});
}
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<u8> = vec![];
//doctype specifier
@ -723,10 +751,22 @@ pub fn compile(ast: Vec<ASTPart>) -> Vec<u8> {
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;
}