added operator typehinting
This commit is contained in:
parent
ee1418c673
commit
edcfbea81d
|
@ -8,6 +8,6 @@ edition = "2021"
|
|||
[dependencies]
|
||||
regex = "*"
|
||||
lazy_static = "1.4.0"
|
||||
rand = "0.8.5"
|
||||
rand = "*"
|
||||
colored = "*"
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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"
|
||||
)),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -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;
|
||||
}
|
||||
";
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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> {
|
||||
|
|
143
src/vmrt/mod.rs
143
src/vmrt/mod.rs
|
@ -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(());
|
||||
|
|
|
@ -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)?;
|
||||
|
|
46
test.erpn
46
test.erpn
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue