fixed variable store
This commit is contained in:
parent
2d7cf80101
commit
ee1418c673
39
src/main.rs
39
src/main.rs
|
@ -23,38 +23,15 @@ where
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let source = r"
|
let source = r"
|
||||||
# surely this is pi
|
|
||||||
pi = rat 5.1415926535
|
|
||||||
|
|
||||||
foo(x:int, y:rat) = bool {
|
foo(x:int) = int {
|
||||||
x:int = 5 + 6
|
x / 2
|
||||||
|
|
||||||
unless (x < 6) {
|
|
||||||
yield true
|
|
||||||
|
|
||||||
please {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
unless(x < 6) {
|
|
||||||
yield true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- comment
|
|
||||||
yield true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main() = int {
|
main() = int {
|
||||||
|
a = foo(4)
|
||||||
a = 4
|
|
||||||
b = pi
|
a
|
||||||
c = true
|
|
||||||
r = foo(3, 4.0)
|
|
||||||
h = foo(3,5.0)
|
|
||||||
b:int = 4
|
|
||||||
|
|
||||||
9
|
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
|
|
||||||
|
@ -64,8 +41,10 @@ main() = int {
|
||||||
|
|
||||||
if let Ok(mut tokens) = tokenize(source, &mut diagnostics) {
|
if let Ok(mut tokens) = tokenize(source, &mut diagnostics) {
|
||||||
if let Ok((fs, ds)) = parse(&mut tokens, &mut diagnostics, &settings) {
|
if let Ok((fs, ds)) = parse(&mut tokens, &mut diagnostics, &settings) {
|
||||||
if let Ok(prog) = vmrt::compile(&fs, &ds) {
|
if let Ok(prog) = vmrt::compile(&fs, &ds, &settings) {
|
||||||
vmrt::execute(&prog);
|
if let Ok(exit_code) = vmrt::execute(&prog) {
|
||||||
|
crate::message(MessageType::Info, format!("Program exited with {}", exit_code));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
332
src/vmrt/mod.rs
332
src/vmrt/mod.rs
|
@ -1,6 +1,11 @@
|
||||||
use std::collections::{VecDeque, HashMap};
|
mod output;
|
||||||
|
|
||||||
use crate::{parser::data::*, token::{Token, NumHint, Prim}};
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
parser::data::*,
|
||||||
|
token::{NumHint, Prim, Token},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum Data {
|
enum Data {
|
||||||
|
@ -10,6 +15,29 @@ enum Data {
|
||||||
Off(u64),
|
Off(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Data {
|
||||||
|
fn to_int(&self) -> Result<i64, ()> {
|
||||||
|
return match self {
|
||||||
|
Data::Int(v) => Ok(*v),
|
||||||
|
_ => Err(()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_float(&self) -> Result<f64, ()> {
|
||||||
|
return match self {
|
||||||
|
Data::Rat(v) => Ok(*v),
|
||||||
|
_ => Err(()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_bool(&self) -> Result<bool, ()> {
|
||||||
|
return match self {
|
||||||
|
Data::Bool(v) => Ok(*v),
|
||||||
|
_ => Err(()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum IntOp {
|
enum IntOp {
|
||||||
CmpEq,
|
CmpEq,
|
||||||
|
@ -22,7 +50,7 @@ enum IntOp {
|
||||||
Add,
|
Add,
|
||||||
Sub,
|
Sub,
|
||||||
Mul,
|
Mul,
|
||||||
Div
|
Div,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -37,24 +65,24 @@ enum RatOp {
|
||||||
Add,
|
Add,
|
||||||
Sub,
|
Sub,
|
||||||
Mul,
|
Mul,
|
||||||
Div
|
Div,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum BoolOp {
|
enum BoolOp {
|
||||||
CmpEq,
|
CmpEq,
|
||||||
CmpNEq,
|
CmpNEq,
|
||||||
|
|
||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
Xor
|
Xor,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Operation {
|
enum Operation {
|
||||||
Int(IntOp),
|
Int(IntOp),
|
||||||
Rat(RatOp),
|
Rat(RatOp),
|
||||||
Bool(BoolOp)
|
Bool(BoolOp),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -63,7 +91,7 @@ enum Instr {
|
||||||
Push(Data),
|
Push(Data),
|
||||||
/// delete the last value from stack
|
/// delete the last value from stack
|
||||||
Pop,
|
Pop,
|
||||||
|
|
||||||
/// push the value stored at offset from the local stack onto the local stack
|
/// push the value stored at offset from the local stack onto the local stack
|
||||||
Load(usize),
|
Load(usize),
|
||||||
/// store the value stored at the stack[0](offset) stack[1](value) onto the stack
|
/// store the value stored at the stack[0](offset) stack[1](value) onto the stack
|
||||||
|
@ -75,14 +103,11 @@ enum Instr {
|
||||||
|
|
||||||
Operation(Operation),
|
Operation(Operation),
|
||||||
|
|
||||||
Exit
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// function stack layout
|
/// function stack layout
|
||||||
/// +----------------------------------+
|
/// +----------------------------------+
|
||||||
/// | Return address |
|
|
||||||
/// +----------------------------------+
|
|
||||||
/// | Parameter (0) |
|
/// | Parameter (0) |
|
||||||
/// +----------------------------------+
|
/// +----------------------------------+
|
||||||
/// | Parameter (1) |
|
/// | Parameter (1) |
|
||||||
|
@ -92,14 +117,17 @@ enum Instr {
|
||||||
/// | Parameter (n) |
|
/// | Parameter (n) |
|
||||||
/// +----------------------------------+
|
/// +----------------------------------+
|
||||||
struct Proc {
|
struct Proc {
|
||||||
|
// executable code
|
||||||
code: Vec<Instr>,
|
code: Vec<Instr>,
|
||||||
|
// number of expected arguments
|
||||||
args: usize,
|
args: usize,
|
||||||
|
// hashed declaration is used as "address"
|
||||||
addr: u64,
|
addr: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
code: HashMap<u64, Proc>
|
procs: HashMap<u64, Proc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -108,35 +136,40 @@ struct Compiletime<'a> {
|
||||||
stacksize: usize,
|
stacksize: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_term<'a>(term: &VecDeque<Token<'a>>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, code: &mut Vec<Instr>) -> Result<(), ()>{
|
fn parse_term<'a>(
|
||||||
|
term: &VecDeque<Token<'a>>,
|
||||||
|
x: usize,
|
||||||
|
declr: &Vec<Declr<'a>>,
|
||||||
|
ct: &mut Compiletime<'a>,
|
||||||
|
code: &mut Vec<Instr>,
|
||||||
|
) -> Result<(), ()> {
|
||||||
for token in term.iter() {
|
for token in term.iter() {
|
||||||
let instr = match token {
|
let instr = match token {
|
||||||
Token::Number(value, hint, _) => {
|
Token::Number(value, hint, _) => {
|
||||||
code.push(Instr::Push(match hint {
|
code.push(Instr::Push(match hint {
|
||||||
NumHint::Int => Data::Int(value.parse::<i64>().unwrap()),
|
NumHint::Int => Data::Int(value.parse::<i64>().unwrap()),
|
||||||
NumHint::Rat => Data::Rat(value.parse::<f64>().unwrap()),
|
NumHint::Rat => Data::Rat(value.parse::<f64>().unwrap()),
|
||||||
}));
|
}));
|
||||||
ct.stacksize += 1;
|
ct.stacksize += 1;
|
||||||
},
|
}
|
||||||
Token::Bool(value, _) => {
|
Token::Bool(value, _) => {
|
||||||
code.push(Instr::Push(Data::Bool(*value)));
|
code.push(Instr::Push(Data::Bool(*value)));
|
||||||
ct.stacksize += 1;
|
ct.stacksize += 1;
|
||||||
},
|
}
|
||||||
Token::Arg(name, _) => {
|
Token::Arg(name, _) => {
|
||||||
let off = declr[x].get_arg_ord(name);
|
let off = declr[x].get_arg_ord(name);
|
||||||
|
|
||||||
code.push(Instr::Load(off + 1));
|
code.push(Instr::Load(off));
|
||||||
ct.stacksize += 1;
|
ct.stacksize += 1;
|
||||||
},
|
}
|
||||||
Token::Assign(name, _, _) => {
|
Token::Assign(name, _, _) => {
|
||||||
ct.vartable.insert(name.clone(), ct.stacksize - 1);
|
ct.vartable.insert(name.clone(), ct.stacksize - 1);
|
||||||
},
|
}
|
||||||
Token::Var(name, _) => {
|
Token::Var(name, _) => {
|
||||||
code.push(Instr::Load(*ct.vartable.get(name).unwrap()));
|
code.push(Instr::Load(*ct.vartable.get(name).unwrap()));
|
||||||
ct.stacksize += 1;
|
ct.stacksize += 1;
|
||||||
}
|
}
|
||||||
Token::Operator(op, hint, _) => {
|
Token::Operator(op, hint, _) => {
|
||||||
|
|
||||||
code.push(match op {
|
code.push(match op {
|
||||||
crate::token::Operator::Or => Instr::Operation(Operation::Bool(BoolOp::Or)),
|
crate::token::Operator::Or => Instr::Operation(Operation::Bool(BoolOp::Or)),
|
||||||
crate::token::Operator::And => Instr::Operation(Operation::Bool(BoolOp::And)),
|
crate::token::Operator::And => Instr::Operation(Operation::Bool(BoolOp::And)),
|
||||||
|
@ -145,96 +178,112 @@ fn parse_term<'a>(term: &VecDeque<Token<'a>>, x: usize, declr: &Vec<Declr<'a>>,
|
||||||
crate::token::Operator::Add => match hint.unwrap() {
|
crate::token::Operator::Add => match hint.unwrap() {
|
||||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::Add)),
|
Prim::Int => Instr::Operation(Operation::Int(IntOp::Add)),
|
||||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Add)),
|
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Add)),
|
||||||
_ => panic!()
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
crate::token::Operator::Sub => match hint.unwrap() {
|
crate::token::Operator::Sub => match hint.unwrap() {
|
||||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::Sub)),
|
Prim::Int => Instr::Operation(Operation::Int(IntOp::Sub)),
|
||||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Sub)),
|
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Sub)),
|
||||||
_ => panic!()
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
crate::token::Operator::Mul => match hint.unwrap() {
|
crate::token::Operator::Mul => match hint.unwrap() {
|
||||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::Mul)),
|
Prim::Int => Instr::Operation(Operation::Int(IntOp::Mul)),
|
||||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Mul)),
|
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Mul)),
|
||||||
_ => panic!()
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
crate::token::Operator::Div => match hint.unwrap() {
|
crate::token::Operator::Div => match hint.unwrap() {
|
||||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::Div)),
|
Prim::Int => Instr::Operation(Operation::Int(IntOp::Div)),
|
||||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Div)),
|
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Div)),
|
||||||
_ => panic!()
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
|
|
||||||
crate::token::Operator::Eq => match hint.unwrap() {
|
crate::token::Operator::Eq => match hint.unwrap() {
|
||||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpEq)),
|
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpEq)),
|
||||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpEq)),
|
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpEq)),
|
||||||
Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpEq)),
|
Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpEq)),
|
||||||
_ => panic!()
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
crate::token::Operator::NotEq => match hint.unwrap() {
|
crate::token::Operator::NotEq => match hint.unwrap() {
|
||||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpNEq)),
|
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpNEq)),
|
||||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpNEq)),
|
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpNEq)),
|
||||||
Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpNEq)),
|
Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpNEq)),
|
||||||
_ => panic!()
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
crate::token::Operator::Lt => match hint.unwrap() {
|
crate::token::Operator::Lt => match hint.unwrap() {
|
||||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLt)),
|
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLt)),
|
||||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLt)),
|
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLt)),
|
||||||
_ => panic!()
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
crate::token::Operator::Gt => match hint.unwrap() {
|
crate::token::Operator::Gt => match hint.unwrap() {
|
||||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGt)),
|
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGt)),
|
||||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGt)),
|
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGt)),
|
||||||
_ => panic!()
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
crate::token::Operator::GtEq => match hint.unwrap() {
|
crate::token::Operator::GtEq => match hint.unwrap() {
|
||||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGtEq)),
|
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGtEq)),
|
||||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGtEq)),
|
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGtEq)),
|
||||||
_ => panic!()
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
crate::token::Operator::LtEq => match hint.unwrap() {
|
crate::token::Operator::LtEq => match hint.unwrap() {
|
||||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLtEq)),
|
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLtEq)),
|
||||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLtEq)),
|
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLtEq)),
|
||||||
_ => panic!()
|
_ => panic!(),
|
||||||
},
|
},
|
||||||
|
|
||||||
crate::token::Operator::Assign => {
|
crate::token::Operator::Assign => {
|
||||||
crate::message(crate::token::MessageType::Critical, format!("Invalid operator: {:?}", op));
|
crate::message(
|
||||||
|
crate::token::MessageType::Critical,
|
||||||
|
format!("Invalid operator: {:?}", op),
|
||||||
|
);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: operatiors
|
|
||||||
// we pop 2 values as arguments and push 1 as result (-2 + 1 = 1)
|
|
||||||
ct.stacksize -= 1;
|
ct.stacksize -= 1;
|
||||||
},
|
}
|
||||||
Token::Func(name, _) => {
|
Token::Func(name, _) => {
|
||||||
for decl in declr.iter() {
|
for decl in declr.iter() {
|
||||||
if decl.name.as_ref().unwrap() == name {
|
if decl.name.as_ref().unwrap() == name {
|
||||||
code.push(Instr::Call(decl.uuid()))
|
code.push(Instr::Call(decl.uuid()));
|
||||||
|
|
||||||
|
if decl.results {
|
||||||
|
ct.stacksize += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Token::Keyword(keyword, _) => {
|
Token::Keyword(keyword, _) => match keyword {
|
||||||
match keyword {
|
crate::token::Keyword::Yield | crate::token::Keyword::Return => {
|
||||||
crate::token::Keyword::Yield | crate::token::Keyword::Return => code.push(Instr::Return),
|
code.push(Instr::Return)
|
||||||
_ => ()
|
|
||||||
}
|
}
|
||||||
}
|
_ => (),
|
||||||
|
},
|
||||||
|
|
||||||
_ => ()
|
_ => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block<'a>(block: &VecDeque<Expr<'a>>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, prog: &mut Vec<Instr>) -> Result<(), ()> {
|
fn parse_block<'a>(
|
||||||
|
block: &VecDeque<Expr<'a>>,
|
||||||
|
x: usize,
|
||||||
|
declr: &Vec<Declr<'a>>,
|
||||||
|
ct: &mut Compiletime<'a>,
|
||||||
|
prog: &mut Vec<Instr>,
|
||||||
|
) -> Result<(), ()> {
|
||||||
for expr in block.iter() {
|
for expr in block.iter() {
|
||||||
compile_expr(expr, x, declr, ct, prog)?;
|
compile_expr(expr, x, declr, ct, prog)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_expr<'a>(expr: &Expr<'a>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, prog: &mut Vec<Instr>) -> Result<(), ()> {
|
fn compile_expr<'a>(
|
||||||
|
expr: &Expr<'a>,
|
||||||
|
x: usize,
|
||||||
|
declr: &Vec<Declr<'a>>,
|
||||||
|
ct: &mut Compiletime<'a>,
|
||||||
|
prog: &mut Vec<Instr>,
|
||||||
|
) -> Result<(), ()> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Block(block) => parse_block(block, x, declr, ct, prog)?,
|
Expr::Block(block) => parse_block(block, x, declr, ct, prog)?,
|
||||||
Expr::Term(term) => parse_term(term, x, declr, ct, prog)?,
|
Expr::Term(term) => parse_term(term, x, declr, ct, prog)?,
|
||||||
|
@ -243,34 +292,197 @@ fn compile_expr<'a>(expr: &Expr<'a>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>) -> Result<Program, ()> {
|
fn create_proc(declr: &Declr, code: Vec<Instr>) -> Proc {
|
||||||
|
Proc {
|
||||||
|
code,
|
||||||
|
args: if let Some(args) = &declr.args {
|
||||||
|
args.len()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
addr: declr.uuid(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>, settings: &crate::conf::Settings) -> Result<Program, ()> {
|
||||||
let mut prog = Program::default();
|
let mut prog = Program::default();
|
||||||
|
|
||||||
for (x, func) in funcs.iter().enumerate() {
|
for (x, func) in funcs.iter().enumerate() {
|
||||||
let mut code = vec![];
|
let mut code = vec![];
|
||||||
let mut ct = Compiletime::default();
|
let mut ct = Compiletime::default();
|
||||||
|
|
||||||
// at beginn the is the return address and the parameter on the stack
|
//at the beginning there are all parameters on the stack
|
||||||
ct.stacksize = declrs[x].args.as_ref().unwrap_or(&vec![]).len() + 1;
|
ct.stacksize = declrs[x].args.as_ref().unwrap_or(&vec![]).len();
|
||||||
|
|
||||||
compile_expr(func.expr.as_ref().unwrap(), x, declrs, &mut ct, &mut code)?;
|
compile_expr(func.expr.as_ref().unwrap(), x, declrs, &mut ct, &mut code)?;
|
||||||
|
|
||||||
println!("{:#?}", code);
|
prog.procs
|
||||||
|
.insert(declrs[x].uuid(), create_proc(&declrs[x], code));
|
||||||
prog.code.insert(declrs[x].uuid(), code);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ok(prog)
|
Ok(prog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Runtimestack {
|
||||||
|
stack: Vec<Data>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Runtimestack {
|
||||||
|
pub fn new() -> Runtimestack {
|
||||||
|
Self { stack: vec![] }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, data: Data) {
|
||||||
|
self.stack.push(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self) -> Option<Data> {
|
||||||
|
self.stack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peek(&mut self, index: usize) -> Data {
|
||||||
|
self.stack[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result<Option<Data>, ()> {
|
||||||
|
let mut stack = Runtimestack::new();
|
||||||
|
|
||||||
|
// build local procedure stack
|
||||||
|
for i in 0..proc.args {
|
||||||
|
stack.push(superstack[superstack.len() - i - 1].clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
for instr in proc.code.iter() {
|
||||||
|
match instr {
|
||||||
|
Instr::Pop => {
|
||||||
|
stack.pop();
|
||||||
|
}
|
||||||
|
Instr::Return => {
|
||||||
|
return Ok(stack.pop());
|
||||||
|
}
|
||||||
|
Instr::Push(data) => stack.push(*data),
|
||||||
|
Instr::Load(offset) => {
|
||||||
|
let v = stack.peek(*offset);
|
||||||
|
stack.push(v);
|
||||||
|
},
|
||||||
|
Instr::Call(addr) => {
|
||||||
|
if let Some(value) = call_fn(prog, prog.procs.get(addr).unwrap(), &stack.stack)? {
|
||||||
|
stack.push(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Instr::Operation(op) => {
|
||||||
|
let op0:Data = if let Some(data) = stack.pop() {
|
||||||
|
data
|
||||||
|
} else {
|
||||||
|
return Err(());
|
||||||
|
};
|
||||||
|
let op1:Data = if let Some(data) = stack.pop() {
|
||||||
|
data
|
||||||
|
} else {
|
||||||
|
return Err(());
|
||||||
|
};
|
||||||
|
|
||||||
|
match op {
|
||||||
|
Operation::Int(op) => match op {
|
||||||
|
IntOp::Add => stack.push(Data::Int(op1.to_int()? + op0.to_int()?)),
|
||||||
|
IntOp::Sub => stack.push(Data::Int(op1.to_int()? - op0.to_int()?)),
|
||||||
|
IntOp::Mul => stack.push(Data::Int(op1.to_int()? * op0.to_int()?)),
|
||||||
|
IntOp::Div => stack.push(Data::Int(op1.to_int()? / op0.to_int()?)),
|
||||||
|
|
||||||
|
IntOp::CmpEq => {
|
||||||
|
stack.push(Data::Bool(op1.to_int()? == op0.to_int()?))
|
||||||
|
}
|
||||||
|
IntOp::CmpNEq => {
|
||||||
|
stack.push(Data::Bool(op1.to_int()? != op0.to_int()?))
|
||||||
|
}
|
||||||
|
IntOp::CmpLt => stack.push(Data::Bool(op1.to_int()? < op0.to_int()?)),
|
||||||
|
IntOp::CmpGt => stack.push(Data::Bool(op1.to_int()? > op0.to_int()?)),
|
||||||
|
IntOp::CmpGtEq => {
|
||||||
|
stack.push(Data::Bool(op1.to_int()? <= op0.to_int()?))
|
||||||
|
}
|
||||||
|
IntOp::CmpLtEq => {
|
||||||
|
stack.push(Data::Bool(op1.to_int()? >= op0.to_int()?))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Operation::Rat(op) => match op {
|
||||||
|
RatOp::Add => {
|
||||||
|
stack.push(Data::Rat(op1.to_float()? + op0.to_float()?))
|
||||||
|
}
|
||||||
|
RatOp::Sub => {
|
||||||
|
stack.push(Data::Rat(op1.to_float()? - op0.to_float()?))
|
||||||
|
}
|
||||||
|
RatOp::Mul => {
|
||||||
|
stack.push(Data::Rat(op1.to_float()? * op0.to_float()?))
|
||||||
|
}
|
||||||
|
RatOp::Div => {
|
||||||
|
stack.push(Data::Rat(op1.to_float()? / op0.to_float()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
RatOp::CmpEq => {
|
||||||
|
stack.push(Data::Bool(op1.to_float()? == op0.to_float()?))
|
||||||
|
}
|
||||||
|
RatOp::CmpNEq => {
|
||||||
|
stack.push(Data::Bool(op1.to_float()? != op0.to_float()?))
|
||||||
|
}
|
||||||
|
RatOp::CmpLt => {
|
||||||
|
stack.push(Data::Bool(op1.to_float()? < op0.to_float()?))
|
||||||
|
}
|
||||||
|
RatOp::CmpGt => {
|
||||||
|
stack.push(Data::Bool(op1.to_float()? > op0.to_float()?))
|
||||||
|
}
|
||||||
|
RatOp::CmpGtEq => {
|
||||||
|
stack.push(Data::Bool(op1.to_float()? <= op0.to_float()?))
|
||||||
|
}
|
||||||
|
RatOp::CmpLtEq => {
|
||||||
|
stack.push(Data::Bool(op1.to_float()? >= op0.to_float()?))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Operation::Bool(op) => match op {
|
||||||
|
BoolOp::Or => {
|
||||||
|
stack.push(Data::Bool(op1.to_bool()? || op0.to_bool()?))
|
||||||
|
}
|
||||||
|
BoolOp::And => {
|
||||||
|
stack.push(Data::Bool(op1.to_bool()? && op0.to_bool()?))
|
||||||
|
}
|
||||||
|
BoolOp::Xor => {
|
||||||
|
stack.push(Data::Bool(op1.to_bool()? ^ op0.to_bool()?))
|
||||||
|
}
|
||||||
|
BoolOp::CmpEq => {
|
||||||
|
stack.push(Data::Bool(op1.to_bool()? == op0.to_bool()?))
|
||||||
|
}
|
||||||
|
BoolOp::CmpNEq => {
|
||||||
|
stack.push(Data::Bool(op1.to_bool()? != op0.to_bool()?))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(stack.pop())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn execute(prog: &Program) -> Result<i64, ()> {
|
pub fn execute(prog: &Program) -> Result<i64, ()> {
|
||||||
// declaration of entry function
|
// declaration of entry function
|
||||||
let main_fn_declr = crate::parser::data::Declr::main();
|
let main_fn_declr = crate::parser::data::Declr::main();
|
||||||
|
|
||||||
if let Some(main_fn) = prog.code.get(&main_fn_declr.uuid()) {
|
if let Some(main_fn) = prog.procs.get(&main_fn_declr.uuid()) {
|
||||||
|
|
||||||
Ok(0)
|
if let Some(exit_code) = call_fn(prog, main_fn, &[])? {
|
||||||
|
return Ok(exit_code.to_int()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::message(crate::token::MessageType::Critical, "main procedure did not return exit code");
|
||||||
|
return Err(());
|
||||||
} else {
|
} else {
|
||||||
crate::message(crate::token::MessageType::Critical, "Program has no main() = int function");
|
crate::message(
|
||||||
|
crate::token::MessageType::Critical,
|
||||||
|
"Program has no main() = int function",
|
||||||
|
);
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
fn print_to_file(file: &mut std::fs::File, prog: &crate::vmrt::Program) -> std::io::Result<()> {
|
||||||
|
for proc in prog.procs.iter() {
|
||||||
|
writeln!(file, "\n0x{:#x}:", proc.0)?;
|
||||||
|
|
||||||
|
for instr in proc.1.code.iter() {
|
||||||
|
writeln!(file, "{}", instr)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dump_program(prog: &crate::vmrt::Program) {
|
||||||
|
let mut file = std::fs::OpenOptions::new().write(true).create(true).truncate(true).open("prog.vsasm").unwrap();
|
||||||
|
|
||||||
|
if print_to_file(&mut file, prog).is_err() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue