added operator typehinting

This commit is contained in:
Sven Vogel 2022-12-06 15:02:03 +01:00
parent ee1418c673
commit edcfbea81d
10 changed files with 197 additions and 77 deletions

View File

@ -8,6 +8,6 @@ edition = "2021"
[dependencies]
regex = "*"
lazy_static = "1.4.0"
rand = "0.8.5"
rand = "*"
colored = "*"

10
prog.vsasm Normal file
View File

@ -0,0 +1,10 @@
0xc8c7a99bb88e156b:
push int 0x2
push int 0x4
cmp eq int
jump-unless 0x6
push int 0x1
ret
push int 0x0
ret

View File

@ -1,31 +1,40 @@
use crate::parser::data::Diagnostics;
#[derive(Default)]
pub struct Settings {
gen_erpn: bool
gen_erpn: bool,
gen_vsasm: bool,
}
impl Settings {
fn new() -> Self {
Settings {
gen_erpn: false
}
}
pub fn gen_erpn(&self) -> bool {
self.gen_erpn
}
pub fn gen_vsasm(&self) -> bool {
self.gen_vsasm
}
}
pub fn parse_args(diagnostics: &mut Diagnostics) -> Settings {
let args = std::env::args().collect::<Vec<String>>();
let mut settings = Settings::new();
let mut settings = Settings::default();
for arg in args.iter() {
match arg.as_str() {
"--no-info" => diagnostics.set_loglvl(crate::parser::data::LogLvl::Warn),
"--no-warn" => diagnostics.set_loglvl(crate::parser::data::LogLvl::Err),
"--erpn" => settings.gen_erpn = true,
"--vsasm" => settings.gen_vsasm = true,
"-h" => println!(concat!(
"help:\n",
"--no-info: print only warning and errors\n",
"--no-warn: print only errors\n",
"--erpn: write a *.erpn (extended reverse polish notation) summary to disk\n",
"--vsasm: write a .vsasm (virtual simplified assembly language) summary to disk\n",
"-h: print this dialog"
)),
_ => ()
}
}

View File

@ -35,5 +35,6 @@ pub fn convert_to_erpn<'a>(funcs: &mut Vec<Func<'a>>, declrs: &Vec<Declr<'a>>) {
// write down function body
write_expr(&mut file, &mut indent, func.expr.as_ref().unwrap());
writeln!(&mut file).unwrap();
}
}
}

View File

@ -18,20 +18,20 @@ pub fn message<S>(typ: MessageType, msg: S)
where
S: Into<String>,
{
println!("{}: {}", typ.to_colored(), msg.into().bold().bright_white());
println!("{}: {}\n", typ.to_colored(), msg.into().bold().bright_white());
}
fn main() {
let source = r"
foo(x:int) = int {
x / 2
}
-- structs are tables
main() = int {
a = foo(4)
a
unless 2 == 4 {
yield 1;
}
yield 0;
}
";

View File

@ -324,13 +324,14 @@ fn discover_exprs<'a>(
}
expr = VecDeque::new();
blocks.push(Block::new());
continue;
}
'}' => {
// pop topmost block of the stack, storing it in the next lower block
if let Some(block) = blocks.pop() {
if let Some(dst) = blocks.last_mut() {
dst.push_back(Expr::Block(block));
dst.push_back(Expr::Block(block));
} else {
diagnostics.set_err(&top, crate::msg::ERR41, "");
return Err(());
@ -346,7 +347,7 @@ fn discover_exprs<'a>(
}
continue;
}
},
_ => (),
},
_ => (),
@ -356,7 +357,7 @@ fn discover_exprs<'a>(
}
if !expr.is_empty() {
if let Some(block) = blocks.last_mut() {
if let Some(block) = blocks.last_mut() {
block.push_back(Expr::Term(expr));
} else {
diagnostics.set_err(expr.back().unwrap(), crate::msg::ERR40, "");
@ -613,7 +614,13 @@ fn parse_term<'a>(
Token::Assign(_, _, _) => {
op_stack.push(token);
}
Token::Keyword(_, _) => op_stack.push(token),
Token::Keyword(key, _) => {
match key {
Keyword::Unless => (),
_ => ()
}
op_stack.push(token)
},
Token::Delemiter(char, _) => match char {
'(' => op_stack.push(token),
@ -689,6 +696,7 @@ fn parse_term<'a>(
}
_ => (),
}
}
while let Some(mut token) = op_stack.pop() {

View File

@ -161,11 +161,10 @@ impl Operator {
diagnostics: &mut crate::parser::data::Diagnostics,
) -> Result<(Option<Prim>, Option<Prim>),()> {
for combination in types.iter() {
if let (result, hint) =
self.present_types(operands, combination.0, combination.1, dbginf, diagnostics)?
{
return Ok((result, hint));
}
let (result, hint) =
self.present_types(operands, combination.0, combination.1, dbginf, diagnostics)?;
return Ok((result, hint));
}
Ok((None, None))
}
@ -500,7 +499,7 @@ pub enum Token<'a> {
Keyword(Keyword, DebugInfo),
Type(Prim, DebugInfo),
/// Semicolon
Terminator(DebugInfo),
Terminator(DebugInfo)
}
impl<'a> std::fmt::Display for Token<'a> {

View File

@ -12,7 +12,17 @@ enum Data {
Int(i64),
Rat(f64),
Bool(bool),
Off(u64),
}
impl std::fmt::Display for Data {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Data::Int(v) => f.write_fmt(format_args!("int {:#x}", v))?,
Data::Rat(v) => f.write_fmt(format_args!("float {}", v))?,
Data::Bool(v) => f.write_fmt(format_args!("bool {}", v))?
}
Ok(())
}
}
impl Data {
@ -95,7 +105,7 @@ enum Instr {
/// 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,
Store(usize),
Call(u64),
@ -103,9 +113,67 @@ enum Instr {
Operation(Operation),
Jump(usize),
JumpUnless(usize),
Exit,
}
impl std::fmt::Display for Instr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Instr::Pop => f.write_str("\tpop")?,
Instr::Exit => f.write_str("\texit")?,
Instr::Return => f.write_str("\tret")?,
Instr::Load(offset) => f.write_fmt(format_args!("\tload {:#x}", offset))?,
Instr::Push(value) => f.write_fmt(format_args!("\tpush {}", value))?,
Instr::Call(uuid) => f.write_fmt(format_args!("\tcall {:#x}", uuid))?,
Instr::Jump(offset) => f.write_fmt(format_args!("\tjump {:#x}", offset))?,
Instr::JumpUnless(offset) => f.write_fmt(format_args!("\tjump-unless {:#x}", offset))?,
Instr::Operation(op) => {
match op {
Operation::Int(op) => match op {
IntOp::Add => f.write_str("\tadd int")?,
IntOp::Sub => f.write_str("\tsub int")?,
IntOp::Mul => f.write_str("\tmul int")?,
IntOp::Div => f.write_str("\tdiv int")?,
IntOp::CmpEq => f.write_str("\tcmp eq int")?,
IntOp::CmpNEq => f.write_str("\tcmp not-eq int")?,
IntOp::CmpLt => f.write_str("\tcmp lt eq int")?,
IntOp::CmpGt => f.write_str("\tcmp gt int")?,
IntOp::CmpLtEq => f.write_str("\tcmp lt-eq int")?,
IntOp::CmpGtEq => f.write_str("\tcmp gt-eq int")?,
},
Operation::Rat(op) => match op {
RatOp::Add => f.write_str("\tadd float")?,
RatOp::Sub => f.write_str("\tsub float")?,
RatOp::Mul => f.write_str("\tmul float")?,
RatOp::Div => f.write_str("\tdiv float")?,
RatOp::CmpEq => f.write_str("\tcmp eq float")?,
RatOp::CmpNEq => f.write_str("\tcmp not-eq float")?,
RatOp::CmpLt => f.write_str("\tcmp lt eq float")?,
RatOp::CmpGt => f.write_str("\tcmp gt float")?,
RatOp::CmpLtEq => f.write_str("\tcmp lt-eq float")?,
RatOp::CmpGtEq => f.write_str("\tcmp gt-eq float")?,
},
Operation::Bool(op) => match op {
BoolOp::And => f.write_str("\tand")?,
BoolOp::Or => f.write_str("\tor")?,
BoolOp::Xor => f.write_str("\txor")?,
BoolOp::CmpNEq => f.write_str("\tcmp not-eq bool")?,
BoolOp::CmpEq => f.write_str("\tcmp eq bool")?,
}
}
},
Instr::Store(offset) => f.write_fmt(format_args!("\tstore {:#x}", offset))?,
}
Ok(())
}
}
/// function stack layout
/// +----------------------------------+
/// | Parameter (0) |
@ -130,9 +198,16 @@ pub struct Program {
procs: HashMap<u64, Proc>,
}
enum LabelType {
Unless(usize),
Loop(usize),
Pad
}
#[derive(Default)]
struct Compiletime<'a> {
vartable: HashMap<&'a str, usize>,
labels: Vec<LabelType>,
stacksize: usize,
}
@ -143,8 +218,9 @@ fn parse_term<'a>(
ct: &mut Compiletime<'a>,
code: &mut Vec<Instr>,
) -> Result<(), ()> {
for token in term.iter() {
let instr = match token {
match token {
Token::Number(value, hint, _) => {
code.push(Instr::Push(match hint {
NumHint::Int => Data::Int(value.parse::<i64>().unwrap()),
@ -158,12 +234,12 @@ fn parse_term<'a>(
}
Token::Arg(name, _) => {
let off = declr[x].get_arg_ord(name);
code.push(Instr::Load(off));
ct.stacksize += 1;
}
Token::Assign(name, _, _) => {
ct.vartable.insert(name.clone(), ct.stacksize - 1);
code.push(Instr::Store(ct.stacksize - 1));
}
Token::Var(name, _) => {
code.push(Instr::Load(*ct.vartable.get(name).unwrap()));
@ -254,10 +330,13 @@ fn parse_term<'a>(
Token::Keyword(keyword, _) => match keyword {
crate::token::Keyword::Yield | crate::token::Keyword::Return => {
code.push(Instr::Return)
},
crate::token::Keyword::Unless => {
ct.labels.push(LabelType::Unless(code.len()));
code.push(Instr::JumpUnless(0));
}
_ => (),
},
_ => (),
};
}
@ -271,9 +350,24 @@ fn parse_block<'a>(
ct: &mut Compiletime<'a>,
prog: &mut Vec<Instr>,
) -> Result<(), ()> {
ct.labels.push(LabelType::Pad);
for expr in block.iter() {
compile_expr(expr, x, declr, ct, prog)?;
}
// resolve JumpUnless Labels
ct.labels.pop();
if let Some(label) = ct.labels.pop() {
match label {
LabelType::Unless(line) => {
prog[line] = Instr::JumpUnless(prog.len());
},
_ => ()
}
}
Ok(())
}
@ -320,7 +414,9 @@ pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>, settings: &cr
.insert(declrs[x].uuid(), create_proc(&declrs[x], code));
}
if settings.gen_vsasm() {
output::dump_program(&prog);
}
Ok(prog)
}
@ -345,6 +441,14 @@ impl Runtimestack {
pub fn peek(&mut self, index: usize) -> Data {
self.stack[index]
}
pub fn top(&self) -> &Data {
&self.stack[self.stack.len() - 1]
}
pub fn put(&mut self, offset: usize, value: Data) {
self.stack[offset] = value;
}
}
fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result<Option<Data>, ()> {
@ -354,9 +458,10 @@ fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result<Option<Da
for i in 0..proc.args {
stack.push(superstack[superstack.len() - i - 1].clone());
}
for instr in proc.code.iter() {
match instr {
let mut x = 0;
while x < proc.code.len() {
match &proc.code[x] {
Instr::Pop => {
stack.pop();
}
@ -368,11 +473,28 @@ fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result<Option<Da
let v = stack.peek(*offset);
stack.push(v);
},
Instr::Store(offset) => {
let data = stack.top().clone();
stack.put(*offset, data);
},
Instr::Call(addr) => {
if let Some(value) = call_fn(prog, prog.procs.get(addr).unwrap(), &stack.stack)? {
stack.push(value);
}
},
Instr::Jump(addr) => {
x = *addr - 1;
},
Instr::JumpUnless(addr) => {
match stack.pop() {
Some(Data::Bool(false)) => x = *addr - 1,
Some(Data::Bool(true)) => (),
_ => {
crate::message(crate::token::MessageType::Critical, "no condition for unless on stack");
panic!();
}
}
},
Instr::Operation(op) => {
let op0:Data = if let Some(data) = stack.pop() {
data
@ -461,6 +583,7 @@ fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result<Option<Da
}
_ => (),
}
x += 1;
}
Ok(stack.pop())
@ -480,7 +603,7 @@ pub fn execute(prog: &Program) -> Result<i64, ()> {
return Err(());
} else {
crate::message(
crate::token::MessageType::Critical,
crate::token::MessageType::Error,
"Program has no main() = int function",
);
return Err(());

View File

@ -2,7 +2,7 @@ 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)?;
writeln!(file, "\n{:#x}:", proc.0)?;
for instr in proc.1.code.iter() {
writeln!(file, "{}", instr)?;

View File

@ -1,40 +1,10 @@
pi:
Load Rat 5.1415926535
foo:
Load Int 5
Load Int 6
Add Int
Store Int x
Load Arg x
Load Int 6
Lt Int
Unless
Load Bool true
Yield
Please
Load Arg x
Load Int 6
Lt Int
Unless
Load Bool true
Yield
Load Bool true
Yield
main:
Load Int 2
Load Int 4
Store Int a
Call pi
Store Rat b
Load Bool true
Store Bool c
Load Int 3
Load Rat 4.0
Call foo
Store Bool r
Load Int 3
Load Rat 5.0
Call foo
Store Bool h
Load Int 4
Store Int b
Load Int 9
Eq Int
Unless
Load Int 1
Yield
Load Int 0
Yield