added operator typehinting

This commit is contained in:
Sven Vogel 2022-11-30 19:07:46 +01:00
parent e80a69fb41
commit 2d7cf80101
6 changed files with 161 additions and 40 deletions

View File

@ -64,7 +64,9 @@ 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) {
vmrt::compile(&fs, &ds); if let Ok(prog) = vmrt::compile(&fs, &ds) {
vmrt::execute(&prog);
}
} }
} }

View File

@ -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 { pub fn get_arg_ord(&self, name: &str) -> usize {
if let Some(args) = self.args.as_ref() { if let Some(args) = self.args.as_ref() {
for (x, arg) in args.iter().enumerate() { for (x, arg) in args.iter().enumerate() {

View File

@ -493,7 +493,7 @@ fn collapse_operation(
) -> Result<(), ()> { ) -> Result<(), ()> {
match operation { 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) => { Token::Assign(name, ref mut typ, dbginf) => {
check_var_typ(typ, operands, &dbginf, diagnostics)?; check_var_typ(typ, operands, &dbginf, diagnostics)?;
scope.decl_var((*name).to_owned(), typ.clone()); scope.decl_var((*name).to_owned(), typ.clone());

View File

@ -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( fn present_types(
&self,
operands: &[Prim], operands: &[Prim],
types: &[Prim], types: &[Prim],
r#yield: Prim, r#yield: Prim,
info: &DebugInfo, info: &DebugInfo,
diagnostics: &mut crate::parser::data::Diagnostics, diagnostics: &mut crate::parser::data::Diagnostics,
) -> Result<Option<Prim>, ()> { ) -> Result<(Option<Prim>, Option<Prim>), ()> {
if operands.len() < types.len() { if operands.len() < types.len() {
diagnostics.set_err(info, crate::msg::ERR74, format!( diagnostics.set_err(info, crate::msg::ERR74, format!(
@ -134,27 +144,30 @@ impl Operator {
} }
for (x, typ) in types.iter().enumerate() { for (x, typ) in types.iter().enumerate() {
if typ != &operands[x] { if !typ.is_equal(operands[x]) {
return Ok(None); return Ok((None, None));
} }
} }
Ok(Some(r#yield))
// this combination fits
Ok((Some(r#yield), Self::operation_type(types) ))
} }
fn check_types( fn check_types(
&self,
operands: &[Prim], operands: &[Prim],
types: &[(&[Prim], Prim)], types: &[(&[Prim], Prim)],
dbginf: &DebugInfo, dbginf: &DebugInfo,
diagnostics: &mut crate::parser::data::Diagnostics, diagnostics: &mut crate::parser::data::Diagnostics,
) -> Result<Option<Prim>,()> { ) -> Result<(Option<Prim>, Option<Prim>),()> {
for combination in types.iter() { for combination in types.iter() {
if let Some(result) = if let (result, hint) =
Self::present_types(operands, combination.0, combination.1, dbginf, diagnostics)? 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( pub fn operate(
@ -162,36 +175,36 @@ impl Operator {
operands: &mut Vec<Prim>, operands: &mut Vec<Prim>,
info: &DebugInfo, info: &DebugInfo,
diagnostics: &mut crate::parser::data::Diagnostics, diagnostics: &mut crate::parser::data::Diagnostics,
) -> Result<(),()> { ) -> Result<Prim,()> {
// TODO: insert type hint // TODO: insert type hint
match self { match self {
Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => { Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => {
let types_valid = let (types_valid, hint) =
Self::check_types(operands, ARITHMETIC_TYPES, info, diagnostics)?; self.check_types(operands, ARITHMETIC_TYPES, info, diagnostics)?;
if let Some(result) = types_valid { if let Some(result) = types_valid {
operands.pop(); operands.pop();
operands.pop(); operands.pop();
operands.push(result); operands.push(result);
return Ok(()); return Ok(hint.unwrap());
} else { } else {
diagnostics.set_err(info, crate::msg::ERR73, "expected two numbers"); diagnostics.set_err(info, crate::msg::ERR73, "expected two numbers");
return Err(()); return Err(());
} }
} }
Operator::And | Operator::Or | Operator::Xor => { Operator::And | Operator::Or | Operator::Xor => {
let types_valid = Self::check_types( let types_valid = self.check_types(
operands, operands,
&[(&[Prim::Bool, Prim::Bool], Prim::Bool)], &[(&[Prim::Bool, Prim::Bool], Prim::Bool)],
info, info,
diagnostics, diagnostics,
)?; )?;
if let Some(result) = types_valid { if let (Some(result), Some(hint)) = types_valid {
operands.pop(); operands.pop();
operands.pop(); operands.pop();
operands.push(result); operands.push(result);
return Ok(()) return Ok(hint)
} else { } else {
diagnostics.set_err(info, crate::msg::ERR73, "expected two booleans"); diagnostics.set_err(info, crate::msg::ERR73, "expected two booleans");
return Err(()); return Err(());
@ -203,7 +216,7 @@ impl Operator {
| Operator::Gt | Operator::Gt
| Operator::GtEq | Operator::GtEq
| Operator::LtEq => { | Operator::LtEq => {
let types_valid = Self::check_types( let types_valid = self.check_types(
operands, operands,
&[ &[
(&[Prim::Int, Prim::Int], Prim::Bool), (&[Prim::Int, Prim::Int], Prim::Bool),
@ -225,11 +238,11 @@ impl Operator {
diagnostics, diagnostics,
)?; )?;
if let Some(result) = types_valid { if let (Some(result), Some(hint)) = types_valid {
operands.pop(); operands.pop();
operands.pop(); operands.pop();
operands.push(result); operands.push(result);
return Ok(()); return Ok(hint);
} else { } else {
diagnostics.set_err(info, crate::msg::ERR73, "expected either two booleans or two numbers"); diagnostics.set_err(info, crate::msg::ERR73, "expected either two booleans or two numbers");
return Err(()); 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 { pub fn is_equal(&self, value: Prim) -> bool {
return match self { return match self {
Prim::Bool => *self == value, 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::Type(t, _) => f.write_fmt(format_args!("__Type {:?}", t)),
Token::Word(w, _) => f.write_fmt(format_args!("__Word {:?}", w)), Token::Word(w, _) => f.write_fmt(format_args!("__Word {:?}", w)),
Token::Delemiter(d, _) => f.write_fmt(format_args!("__Delemiter {:?}", d)), 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::Number(n, hint, _) => f.write_fmt(format_args!("Load {:?} {}", hint, n)),
Token::LineBreak(_) => f.write_str("__Line-break"), Token::LineBreak(_) => f.write_str("__Line-break"),
Token::Func(name, _) => f.write_fmt(format_args!("Call {}", name)), Token::Func(name, _) => f.write_fmt(format_args!("Call {}", name)),

View File

@ -1,13 +1,13 @@
use std::collections::{VecDeque, HashMap}; 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 { enum Data {
Int(i64), Int(i64),
Rat(f64), Rat(f64),
Bool(bool), Bool(bool),
Off(usize), Off(u64),
} }
#[derive(Debug)] #[derive(Debug)]
@ -64,7 +64,7 @@ enum Instr {
/// delete the last value from stack /// delete the last value from stack
Pop, 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), 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
Store, Store,
@ -91,10 +91,15 @@ enum Instr {
/// +----------------------------------+ /// +----------------------------------+
/// | Parameter (n) | /// | Parameter (n) |
/// +----------------------------------+ /// +----------------------------------+
struct Proc {
code: Vec<Instr>,
args: usize,
addr: u64,
}
#[derive(Default)] #[derive(Default)]
pub struct Program { pub struct Program {
code: HashMap<u64, Vec<Instr>> code: HashMap<u64, Proc>
} }
#[derive(Default)] #[derive(Default)]
@ -103,7 +108,7 @@ 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>) { 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, _) => {
@ -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())); code.push(Instr::Load(*ct.vartable.get(name).unwrap()));
ct.stacksize += 1; ct.stacksize += 1;
} }
Token::Operator(op, _, _) => { 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)),
crate::token::Operator::Xor => Instr::Operation(Operation::Bool(BoolOp::Xor)), 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!()
},
_ => 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 // 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() { 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 { 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)?,
} }
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(); let mut prog = Program::default();
for (x, func) in funcs.iter().enumerate() { 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 // 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; 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); println!("{:#?}", code);
prog.code.insert(declrs[x].uuid(), 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(());
}
} }

View File

@ -3,18 +3,18 @@ pi:
foo: foo:
Load Int 5 Load Int 5
Load Int 6 Load Int 6
Add Add Int
Store Int x Store Int x
Load Arg x Load Arg x
Load Int 6 Load Int 6
Lt Lt Int
Unless Unless
Load Bool true Load Bool true
Yield Yield
Please Please
Load Arg x Load Arg x
Load Int 6 Load Int 6
Lt Lt Int
Unless Unless
Load Bool true Load Bool true
Yield Yield