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((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 {
if let Some(args) = self.args.as_ref() {
for (x, arg) in args.iter().enumerate() {

View File

@ -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());

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(
&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)),

View File

@ -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!()
},
_ => 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(());
}
}

View File

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