added operator typehinting
This commit is contained in:
parent
e80a69fb41
commit
2d7cf80101
|
@ -64,7 +64,9 @@ main() = int {
|
|||
|
||||
if let Ok(mut tokens) = tokenize(source, &mut diagnostics) {
|
||||
if let Ok((fs, ds)) = parse(&mut tokens, &mut diagnostics, &settings) {
|
||||
vmrt::compile(&fs, &ds);
|
||||
if let Ok(prog) = vmrt::compile(&fs, &ds) {
|
||||
vmrt::execute(&prog);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -146,6 +146,21 @@ impl<'a> Declr<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn main() -> Self {
|
||||
let mut main = Declr {
|
||||
name: Some("main"),
|
||||
args: None,
|
||||
results: true,
|
||||
result_typ: Some(Prim::Int),
|
||||
info: None,
|
||||
uuid: 0
|
||||
};
|
||||
|
||||
main.gen_uuid();
|
||||
|
||||
main
|
||||
}
|
||||
|
||||
pub fn get_arg_ord(&self, name: &str) -> usize {
|
||||
if let Some(args) = self.args.as_ref() {
|
||||
for (x, arg) in args.iter().enumerate() {
|
||||
|
|
|
@ -493,7 +493,7 @@ fn collapse_operation(
|
|||
) -> Result<(), ()> {
|
||||
|
||||
match operation {
|
||||
Token::Operator(op, _, dbginf) => op.operate(operands, &dbginf, diagnostics)?,
|
||||
Token::Operator(op, ref mut typehint, dbginf) => *typehint = Some(op.operate(operands, &dbginf, diagnostics)?),
|
||||
Token::Assign(name, ref mut typ, dbginf) => {
|
||||
check_var_typ(typ, operands, &dbginf, diagnostics)?;
|
||||
scope.decl_var((*name).to_owned(), typ.clone());
|
||||
|
|
|
@ -115,13 +115,23 @@ impl Operator {
|
|||
}
|
||||
}
|
||||
|
||||
fn operation_type(operands: &[Prim]) -> Option<Prim> {
|
||||
let mut typ = None;
|
||||
for op in operands.iter() {
|
||||
op.merge_types(&mut typ);
|
||||
}
|
||||
|
||||
typ
|
||||
}
|
||||
|
||||
fn present_types(
|
||||
&self,
|
||||
operands: &[Prim],
|
||||
types: &[Prim],
|
||||
r#yield: Prim,
|
||||
info: &DebugInfo,
|
||||
diagnostics: &mut crate::parser::data::Diagnostics,
|
||||
) -> Result<Option<Prim>, ()> {
|
||||
) -> Result<(Option<Prim>, Option<Prim>), ()> {
|
||||
|
||||
if operands.len() < types.len() {
|
||||
diagnostics.set_err(info, crate::msg::ERR74, format!(
|
||||
|
@ -134,27 +144,30 @@ impl Operator {
|
|||
}
|
||||
|
||||
for (x, typ) in types.iter().enumerate() {
|
||||
if typ != &operands[x] {
|
||||
return Ok(None);
|
||||
if !typ.is_equal(operands[x]) {
|
||||
return Ok((None, None));
|
||||
}
|
||||
}
|
||||
Ok(Some(r#yield))
|
||||
|
||||
// this combination fits
|
||||
Ok((Some(r#yield), Self::operation_type(types) ))
|
||||
}
|
||||
|
||||
fn check_types(
|
||||
&self,
|
||||
operands: &[Prim],
|
||||
types: &[(&[Prim], Prim)],
|
||||
dbginf: &DebugInfo,
|
||||
diagnostics: &mut crate::parser::data::Diagnostics,
|
||||
) -> Result<Option<Prim>,()> {
|
||||
) -> Result<(Option<Prim>, Option<Prim>),()> {
|
||||
for combination in types.iter() {
|
||||
if let Some(result) =
|
||||
Self::present_types(operands, combination.0, combination.1, dbginf, diagnostics)?
|
||||
if let (result, hint) =
|
||||
self.present_types(operands, combination.0, combination.1, dbginf, diagnostics)?
|
||||
{
|
||||
return Ok(Some(result));
|
||||
return Ok((result, hint));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
Ok((None, None))
|
||||
}
|
||||
|
||||
pub fn operate(
|
||||
|
@ -162,36 +175,36 @@ impl Operator {
|
|||
operands: &mut Vec<Prim>,
|
||||
info: &DebugInfo,
|
||||
diagnostics: &mut crate::parser::data::Diagnostics,
|
||||
) -> Result<(),()> {
|
||||
) -> Result<Prim,()> {
|
||||
// TODO: insert type hint
|
||||
match self {
|
||||
Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => {
|
||||
let types_valid =
|
||||
Self::check_types(operands, ARITHMETIC_TYPES, info, diagnostics)?;
|
||||
let (types_valid, hint) =
|
||||
self.check_types(operands, ARITHMETIC_TYPES, info, diagnostics)?;
|
||||
|
||||
if let Some(result) = types_valid {
|
||||
operands.pop();
|
||||
operands.pop();
|
||||
operands.push(result);
|
||||
return Ok(());
|
||||
return Ok(hint.unwrap());
|
||||
} else {
|
||||
diagnostics.set_err(info, crate::msg::ERR73, "expected two numbers");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
Operator::And | Operator::Or | Operator::Xor => {
|
||||
let types_valid = Self::check_types(
|
||||
let types_valid = self.check_types(
|
||||
operands,
|
||||
&[(&[Prim::Bool, Prim::Bool], Prim::Bool)],
|
||||
info,
|
||||
diagnostics,
|
||||
)?;
|
||||
|
||||
if let Some(result) = types_valid {
|
||||
if let (Some(result), Some(hint)) = types_valid {
|
||||
operands.pop();
|
||||
operands.pop();
|
||||
operands.push(result);
|
||||
return Ok(())
|
||||
return Ok(hint)
|
||||
} else {
|
||||
diagnostics.set_err(info, crate::msg::ERR73, "expected two booleans");
|
||||
return Err(());
|
||||
|
@ -203,7 +216,7 @@ impl Operator {
|
|||
| Operator::Gt
|
||||
| Operator::GtEq
|
||||
| Operator::LtEq => {
|
||||
let types_valid = Self::check_types(
|
||||
let types_valid = self.check_types(
|
||||
operands,
|
||||
&[
|
||||
(&[Prim::Int, Prim::Int], Prim::Bool),
|
||||
|
@ -225,11 +238,11 @@ impl Operator {
|
|||
diagnostics,
|
||||
)?;
|
||||
|
||||
if let Some(result) = types_valid {
|
||||
if let (Some(result), Some(hint)) = types_valid {
|
||||
operands.pop();
|
||||
operands.pop();
|
||||
operands.push(result);
|
||||
return Ok(());
|
||||
return Ok(hint);
|
||||
} else {
|
||||
diagnostics.set_err(info, crate::msg::ERR73, "expected either two booleans or two numbers");
|
||||
return Err(());
|
||||
|
@ -315,6 +328,16 @@ impl Prim {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn merge_types(&self, current: &mut Option<Prim>) {
|
||||
if let Some(prim) = current {
|
||||
if !prim.is_equal(*self) {
|
||||
*current = None;
|
||||
}
|
||||
} else {
|
||||
*current = Some(*self);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_equal(&self, value: Prim) -> bool {
|
||||
return match self {
|
||||
Prim::Bool => *self == value,
|
||||
|
@ -486,7 +509,7 @@ impl<'a> std::fmt::Display for Token<'a> {
|
|||
Token::Type(t, _) => f.write_fmt(format_args!("__Type {:?}", t)),
|
||||
Token::Word(w, _) => f.write_fmt(format_args!("__Word {:?}", w)),
|
||||
Token::Delemiter(d, _) => f.write_fmt(format_args!("__Delemiter {:?}", d)),
|
||||
Token::Operator(o, _, _) => f.write_fmt(format_args!("{:?}", o)),
|
||||
Token::Operator(o, hint, _) => f.write_fmt(format_args!("{:?} {:?}", o, hint.unwrap())),
|
||||
Token::Number(n, hint, _) => f.write_fmt(format_args!("Load {:?} {}", hint, n)),
|
||||
Token::LineBreak(_) => f.write_str("__Line-break"),
|
||||
Token::Func(name, _) => f.write_fmt(format_args!("Call {}", name)),
|
||||
|
|
109
src/vmrt/mod.rs
109
src/vmrt/mod.rs
|
@ -1,13 +1,13 @@
|
|||
use std::collections::{VecDeque, HashMap};
|
||||
|
||||
use crate::{parser::data::*, token::{Token, NumHint}};
|
||||
use crate::{parser::data::*, token::{Token, NumHint, Prim}};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum Data {
|
||||
Int(i64),
|
||||
Rat(f64),
|
||||
Bool(bool),
|
||||
Off(usize),
|
||||
Off(u64),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -64,7 +64,7 @@ enum Instr {
|
|||
/// delete the last value from stack
|
||||
Pop,
|
||||
|
||||
/// push the value stored at offset onto the stack
|
||||
/// push the value stored at offset from the local stack onto the local stack
|
||||
Load(usize),
|
||||
/// store the value stored at the stack[0](offset) stack[1](value) onto the stack
|
||||
Store,
|
||||
|
@ -91,10 +91,15 @@ enum Instr {
|
|||
/// +----------------------------------+
|
||||
/// | Parameter (n) |
|
||||
/// +----------------------------------+
|
||||
struct Proc {
|
||||
code: Vec<Instr>,
|
||||
args: usize,
|
||||
addr: u64,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Program {
|
||||
code: HashMap<u64, Vec<Instr>>
|
||||
code: HashMap<u64, Proc>
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -103,7 +108,7 @@ struct Compiletime<'a> {
|
|||
stacksize: usize,
|
||||
}
|
||||
|
||||
fn parse_term<'a>(term: &VecDeque<Token<'a>>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, code: &mut Vec<Instr>) {
|
||||
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() {
|
||||
let instr = match token {
|
||||
Token::Number(value, hint, _) => {
|
||||
|
@ -130,13 +135,71 @@ fn parse_term<'a>(term: &VecDeque<Token<'a>>, x: usize, declr: &Vec<Declr<'a>>,
|
|||
code.push(Instr::Load(*ct.vartable.get(name).unwrap()));
|
||||
ct.stacksize += 1;
|
||||
}
|
||||
Token::Operator(op, _, _) => {
|
||||
Token::Operator(op, hint, _) => {
|
||||
|
||||
code.push(match op {
|
||||
crate::token::Operator::Or => Instr::Operation(Operation::Bool(BoolOp::Or)),
|
||||
crate::token::Operator::And => Instr::Operation(Operation::Bool(BoolOp::And)),
|
||||
crate::token::Operator::Xor => Instr::Operation(Operation::Bool(BoolOp::Xor)),
|
||||
|
||||
crate::token::Operator::Add => match hint.unwrap() {
|
||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::Add)),
|
||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Add)),
|
||||
_ => panic!()
|
||||
},
|
||||
crate::token::Operator::Sub => match hint.unwrap() {
|
||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::Sub)),
|
||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Sub)),
|
||||
_ => panic!()
|
||||
},
|
||||
crate::token::Operator::Mul => match hint.unwrap() {
|
||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::Mul)),
|
||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Mul)),
|
||||
_ => panic!()
|
||||
},
|
||||
crate::token::Operator::Div => match hint.unwrap() {
|
||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::Div)),
|
||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::Div)),
|
||||
_ => panic!()
|
||||
},
|
||||
|
||||
crate::token::Operator::Eq => match hint.unwrap() {
|
||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpEq)),
|
||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpEq)),
|
||||
Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpEq)),
|
||||
_ => panic!()
|
||||
},
|
||||
crate::token::Operator::NotEq => match hint.unwrap() {
|
||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpNEq)),
|
||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpNEq)),
|
||||
Prim::Bool => Instr::Operation(Operation::Bool(BoolOp::CmpNEq)),
|
||||
_ => panic!()
|
||||
},
|
||||
crate::token::Operator::Lt => match hint.unwrap() {
|
||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLt)),
|
||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLt)),
|
||||
_ => panic!()
|
||||
},
|
||||
crate::token::Operator::Gt => match hint.unwrap() {
|
||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGt)),
|
||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGt)),
|
||||
_ => panic!()
|
||||
},
|
||||
crate::token::Operator::GtEq => match hint.unwrap() {
|
||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpGtEq)),
|
||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpGtEq)),
|
||||
_ => panic!()
|
||||
},
|
||||
crate::token::Operator::LtEq => match hint.unwrap() {
|
||||
Prim::Int => Instr::Operation(Operation::Int(IntOp::CmpLtEq)),
|
||||
Prim::Rat => Instr::Operation(Operation::Rat(RatOp::CmpLtEq)),
|
||||
_ => panic!()
|
||||
},
|
||||
|
||||
crate::token::Operator::Assign => {
|
||||
crate::message(crate::token::MessageType::Critical, format!("Invalid operator: {:?}", op));
|
||||
return Err(());
|
||||
}
|
||||
});
|
||||
|
||||
// TODO: operatiors
|
||||
|
@ -161,22 +224,26 @@ fn parse_term<'a>(term: &VecDeque<Token<'a>>, x: usize, declr: &Vec<Declr<'a>>,
|
|||
_ => ()
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_block<'a>(block: &VecDeque<Expr<'a>>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, prog: &mut Vec<Instr>) {
|
||||
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() {
|
||||
compile_expr(expr, x, declr, ct, prog);
|
||||
compile_expr(expr, x, declr, ct, prog)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_expr<'a>(expr: &Expr<'a>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, prog: &mut Vec<Instr>) {
|
||||
fn compile_expr<'a>(expr: &Expr<'a>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, prog: &mut Vec<Instr>) -> Result<(), ()> {
|
||||
match expr {
|
||||
Expr::Block(block) => parse_block(block, x, declr, ct, prog),
|
||||
Expr::Term(term) => parse_term(term, x, declr, ct, prog),
|
||||
Expr::Block(block) => parse_block(block, x, declr, ct, prog)?,
|
||||
Expr::Term(term) => parse_term(term, x, declr, ct, prog)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>) {
|
||||
pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>) -> Result<Program, ()> {
|
||||
let mut prog = Program::default();
|
||||
|
||||
for (x, func) in funcs.iter().enumerate() {
|
||||
|
@ -186,10 +253,24 @@ pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>) {
|
|||
// at beginn the is the return address and the parameter on the stack
|
||||
ct.stacksize = declrs[x].args.as_ref().unwrap_or(&vec![]).len() + 1;
|
||||
|
||||
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.code.insert(declrs[x].uuid(), code);
|
||||
}
|
||||
Ok(prog)
|
||||
}
|
||||
|
||||
pub fn execute(prog: &Program) -> Result<i64, ()> {
|
||||
// declaration of entry function
|
||||
let main_fn_declr = crate::parser::data::Declr::main();
|
||||
|
||||
if let Some(main_fn) = prog.code.get(&main_fn_declr.uuid()) {
|
||||
|
||||
Ok(0)
|
||||
} else {
|
||||
crate::message(crate::token::MessageType::Critical, "Program has no main() = int function");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue