added vmrt module
This commit is contained in:
parent
fda09066c7
commit
e80a69fb41
14
src/main.rs
14
src/main.rs
|
@ -6,6 +6,7 @@ mod parser;
|
|||
// designed for a virtual stack machiene
|
||||
mod inter;
|
||||
mod conf;
|
||||
mod vmrt;
|
||||
|
||||
use colored::Colorize;
|
||||
use parser::*;
|
||||
|
@ -47,10 +48,13 @@ foo(x:int, y:rat) = bool {
|
|||
main() = int {
|
||||
|
||||
a = 4
|
||||
b = 5.5
|
||||
b = pi
|
||||
c = true
|
||||
r = foo(3, ffalsee)
|
||||
0
|
||||
r = foo(3, 4.0)
|
||||
h = foo(3,5.0)
|
||||
b:int = 4
|
||||
|
||||
9
|
||||
}
|
||||
";
|
||||
|
||||
|
@ -59,7 +63,9 @@ main() = int {
|
|||
let settings = conf::parse_args(&mut diagnostics);
|
||||
|
||||
if let Ok(mut tokens) = tokenize(source, &mut diagnostics) {
|
||||
parse(&mut tokens, &mut diagnostics, &settings);
|
||||
if let Ok((fs, ds)) = parse(&mut tokens, &mut diagnostics, &settings) {
|
||||
vmrt::compile(&fs, &ds);
|
||||
}
|
||||
}
|
||||
|
||||
println!("{}", diagnostics);
|
||||
|
|
|
@ -2,6 +2,8 @@ use crate::token::{DebugInfo, DebugNotice, Token, MessageType};
|
|||
use crate::Prim;
|
||||
use core::panic;
|
||||
use std::collections::VecDeque;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum LogLvl {
|
||||
|
@ -127,7 +129,9 @@ pub struct Declr<'a> {
|
|||
pub result_typ: Option<Prim>,
|
||||
|
||||
/// debug info
|
||||
pub info: Option<DebugInfo>
|
||||
pub info: Option<DebugInfo>,
|
||||
|
||||
uuid: u64
|
||||
}
|
||||
|
||||
impl<'a> Declr<'a> {
|
||||
|
@ -138,8 +142,39 @@ impl<'a> Declr<'a> {
|
|||
results: false,
|
||||
result_typ: None,
|
||||
info: None,
|
||||
uuid: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_arg_ord(&self, name: &str) -> usize {
|
||||
if let Some(args) = self.args.as_ref() {
|
||||
for (x, arg) in args.iter().enumerate() {
|
||||
if arg.0 == name {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
pub fn gen_uuid(&mut self) {
|
||||
let mut hasher = DefaultHasher::default();
|
||||
|
||||
self.name.unwrap().hash(&mut hasher);
|
||||
|
||||
if let Some(args) = self.args.as_ref() {
|
||||
for arg in args.iter() {
|
||||
arg.0.hash(&mut hasher);
|
||||
arg.1.hash(&mut hasher);
|
||||
}
|
||||
}
|
||||
|
||||
self.uuid = hasher.finish()
|
||||
}
|
||||
|
||||
pub fn uuid(&self) -> u64 {
|
||||
self.uuid
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::fmt::Display for Declr<'a> {
|
||||
|
|
|
@ -44,6 +44,8 @@ fn discover_functions<'a>(
|
|||
return Err(());
|
||||
}
|
||||
|
||||
declr.gen_uuid();
|
||||
|
||||
// store new function and its declaration
|
||||
funcs.push(func);
|
||||
declrs.push(declr);
|
||||
|
@ -134,7 +136,7 @@ fn discover_functions<'a>(
|
|||
|
||||
if func.raw.is_none() {
|
||||
match &top {
|
||||
Token::Operator(op, _) => match op {
|
||||
Token::Operator(op, _, _) => match op {
|
||||
Operator::Assign => {
|
||||
// check if we already have an assign
|
||||
if declr.results {
|
||||
|
@ -458,7 +460,7 @@ fn process_keyword(
|
|||
|
||||
if let Some(operand) = operands.pop() {
|
||||
if let Some(typ) = scope.func_return_typ {
|
||||
if typ != operand {
|
||||
if !typ.is_equal(operand) {
|
||||
diagnostics.set_err(
|
||||
info,
|
||||
crate::msg::ERR59,
|
||||
|
@ -491,7 +493,7 @@ fn collapse_operation(
|
|||
) -> Result<(), ()> {
|
||||
|
||||
match operation {
|
||||
Token::Operator(op, dbginf) => op.operate(operands, &dbginf, diagnostics)?,
|
||||
Token::Operator(op, _, dbginf) => 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());
|
||||
|
@ -660,11 +662,11 @@ fn parse_term<'a>(
|
|||
}
|
||||
},
|
||||
|
||||
Token::Operator(op, _) => {
|
||||
Token::Operator(op, _, _) => {
|
||||
let prec0 = op.prec();
|
||||
while let Some(mut top) = op_stack.last_mut() {
|
||||
match &top {
|
||||
Token::Operator(op1, _) => {
|
||||
Token::Operator(op1, _, _) => {
|
||||
let prec1 = op1.prec();
|
||||
|
||||
if prec1 > prec0 || prec0 == prec1 && op.assoc() == Assoc::Left {
|
||||
|
@ -712,7 +714,9 @@ fn parse_term<'a>(
|
|||
scope.expr_yield = value_stack.len() == 1;
|
||||
if scope.expr_yield {
|
||||
let yielded = value_stack.pop().unwrap();
|
||||
|
||||
if !yielded.is_equal(scope.func_return_typ.unwrap()) {
|
||||
|
||||
diagnostics.set_err(
|
||||
&output[0],
|
||||
crate::msg::ERR59,
|
||||
|
@ -722,7 +726,7 @@ fn parse_term<'a>(
|
|||
yielded
|
||||
),
|
||||
);
|
||||
panic!();
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -793,16 +797,16 @@ fn parse_exprs<'a>(
|
|||
/// reorder and organize a listing of instructions to a RPN based format:
|
||||
/// any program is made out of functions.
|
||||
/// A function has a name followed by an optional parameter list, followed by an optional equal sign and block.
|
||||
pub fn parse<'a>(tokens: &mut VecDeque<crate::Token<'a>>, diagnostics: &mut data::Diagnostics, settings: &Settings) {
|
||||
pub fn parse<'a>(tokens: &mut VecDeque<crate::Token<'a>>, diagnostics: &mut data::Diagnostics, settings: &Settings) -> Result<(Vec<Func<'a>>, Vec<Declr<'a>>), ()> {
|
||||
|
||||
if let Ok((mut funcs, declrs)) = discover_functions(tokens, diagnostics) {
|
||||
if let Ok(()) = discover_exprs(&mut funcs, &declrs, diagnostics) {
|
||||
if let Ok(()) = parse_exprs(&mut funcs, &declrs, diagnostics) {
|
||||
let (mut funcs, declrs) = discover_functions(tokens, diagnostics)?;
|
||||
|
||||
if settings.gen_erpn() {
|
||||
crate::inter::convert_to_erpn(&mut funcs, &declrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
discover_exprs(&mut funcs, &declrs, diagnostics)?;
|
||||
parse_exprs(&mut funcs, &declrs, diagnostics)?;
|
||||
|
||||
if settings.gen_erpn() {
|
||||
crate::inter::convert_to_erpn(&mut funcs, &declrs);
|
||||
}
|
||||
|
||||
return Ok((funcs, declrs));
|
||||
}
|
||||
|
|
|
@ -163,6 +163,7 @@ impl Operator {
|
|||
info: &DebugInfo,
|
||||
diagnostics: &mut crate::parser::data::Diagnostics,
|
||||
) -> Result<(),()> {
|
||||
// TODO: insert type hint
|
||||
match self {
|
||||
Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => {
|
||||
let types_valid =
|
||||
|
@ -459,7 +460,7 @@ pub enum Token<'a> {
|
|||
Word(&'a str, DebugInfo),
|
||||
/// Single symbol delemiter like ```(```,```}```
|
||||
Delemiter(char, DebugInfo),
|
||||
Operator(Operator, DebugInfo),
|
||||
Operator(Operator, Option<Prim>, DebugInfo),
|
||||
Number(&'a str, NumHint, DebugInfo),
|
||||
LineBreak(DebugInfo),
|
||||
Func(&'a str, DebugInfo),
|
||||
|
@ -485,7 +486,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, _, _) => f.write_fmt(format_args!("{:?}", o)),
|
||||
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)),
|
||||
|
@ -506,7 +507,7 @@ impl<'a> Into<DebugInfo> for Token<'a> {
|
|||
Token::Type(_, d) => d,
|
||||
Token::Word(_, d) => d,
|
||||
Token::Delemiter(_, d) => d,
|
||||
Token::Operator(_, d) => d,
|
||||
Token::Operator(_, _, d) => d,
|
||||
Token::Number(_, _, d) => d,
|
||||
Token::LineBreak(d) => d,
|
||||
Token::Func(_, d) => d,
|
||||
|
@ -577,7 +578,7 @@ pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result<Ve
|
|||
}
|
||||
9 => Token::Word(mat.as_str(), debug_info),
|
||||
10 => Token::Number(mat.as_str(), NumHint::from(mat.as_str()), debug_info),
|
||||
11 => Token::Operator(Operator::parse(mat.as_str()), debug_info),
|
||||
11 => Token::Operator(Operator::parse(mat.as_str()), None, debug_info),
|
||||
12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info),
|
||||
13 => {
|
||||
line_count += 1;
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
use std::collections::{VecDeque, HashMap};
|
||||
|
||||
use crate::{parser::data::*, token::{Token, NumHint}};
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Data {
|
||||
Int(i64),
|
||||
Rat(f64),
|
||||
Bool(bool),
|
||||
Off(usize),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum IntOp {
|
||||
CmpEq,
|
||||
CmpNEq,
|
||||
CmpLt,
|
||||
CmpGt,
|
||||
CmpLtEq,
|
||||
CmpGtEq,
|
||||
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum RatOp {
|
||||
CmpEq,
|
||||
CmpNEq,
|
||||
CmpLt,
|
||||
CmpGt,
|
||||
CmpLtEq,
|
||||
CmpGtEq,
|
||||
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum BoolOp {
|
||||
CmpEq,
|
||||
CmpNEq,
|
||||
|
||||
And,
|
||||
Or,
|
||||
Xor
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Operation {
|
||||
Int(IntOp),
|
||||
Rat(RatOp),
|
||||
Bool(BoolOp)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Instr {
|
||||
/// load some data onto the stack
|
||||
Push(Data),
|
||||
/// delete the last value from stack
|
||||
Pop,
|
||||
|
||||
/// push the value stored at offset onto the stack
|
||||
Load(usize),
|
||||
/// store the value stored at the stack[0](offset) stack[1](value) onto the stack
|
||||
Store,
|
||||
|
||||
Call(u64),
|
||||
|
||||
Return,
|
||||
|
||||
Operation(Operation),
|
||||
|
||||
Exit
|
||||
}
|
||||
|
||||
|
||||
/// function stack layout
|
||||
/// +----------------------------------+
|
||||
/// | Return address |
|
||||
/// +----------------------------------+
|
||||
/// | Parameter (0) |
|
||||
/// +----------------------------------+
|
||||
/// | Parameter (1) |
|
||||
/// +----------------------------------+
|
||||
/// | Parameter (2) |
|
||||
/// +----------------------------------+
|
||||
/// | Parameter (n) |
|
||||
/// +----------------------------------+
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Program {
|
||||
code: HashMap<u64, Vec<Instr>>
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Compiletime<'a> {
|
||||
vartable: HashMap<&'a str, 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>) {
|
||||
for token in term.iter() {
|
||||
let instr = match token {
|
||||
Token::Number(value, hint, _) => {
|
||||
code.push(Instr::Push(match hint {
|
||||
NumHint::Int => Data::Int(value.parse::<i64>().unwrap()),
|
||||
NumHint::Rat => Data::Rat(value.parse::<f64>().unwrap()),
|
||||
}));
|
||||
ct.stacksize += 1;
|
||||
},
|
||||
Token::Bool(value, _) => {
|
||||
code.push(Instr::Push(Data::Bool(*value)));
|
||||
ct.stacksize += 1;
|
||||
},
|
||||
Token::Arg(name, _) => {
|
||||
let off = declr[x].get_arg_ord(name);
|
||||
|
||||
code.push(Instr::Load(off + 1));
|
||||
ct.stacksize += 1;
|
||||
},
|
||||
Token::Assign(name, _, _) => {
|
||||
ct.vartable.insert(name.clone(), ct.stacksize - 1);
|
||||
},
|
||||
Token::Var(name, _) => {
|
||||
code.push(Instr::Load(*ct.vartable.get(name).unwrap()));
|
||||
ct.stacksize += 1;
|
||||
}
|
||||
Token::Operator(op, _, _) => {
|
||||
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)),
|
||||
|
||||
_ => panic!()
|
||||
});
|
||||
|
||||
// TODO: operatiors
|
||||
// we pop 2 values as arguments and push 1 as result (-2 + 1 = 1)
|
||||
ct.stacksize -= 1;
|
||||
},
|
||||
Token::Func(name, _) => {
|
||||
for decl in declr.iter() {
|
||||
if decl.name.as_ref().unwrap() == name {
|
||||
code.push(Instr::Call(decl.uuid()))
|
||||
}
|
||||
}
|
||||
}
|
||||
Token::Keyword(keyword, _) => {
|
||||
match keyword {
|
||||
crate::token::Keyword::Yield | crate::token::Keyword::Return => code.push(Instr::Return),
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_ => ()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_block<'a>(block: &VecDeque<Expr<'a>>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, prog: &mut Vec<Instr>) {
|
||||
for expr in block.iter() {
|
||||
compile_expr(expr, x, declr, ct, prog);
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_expr<'a>(expr: &Expr<'a>, x: usize, declr: &Vec<Declr<'a>>, ct: &mut Compiletime<'a>, prog: &mut Vec<Instr>) {
|
||||
match expr {
|
||||
Expr::Block(block) => parse_block(block, x, declr, ct, prog),
|
||||
Expr::Term(term) => parse_term(term, x, declr, ct, prog),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>) {
|
||||
let mut prog = Program::default();
|
||||
|
||||
for (x, func) in funcs.iter().enumerate() {
|
||||
let mut code = vec![];
|
||||
let mut ct = Compiletime::default();
|
||||
|
||||
// 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);
|
||||
|
||||
println!("{:#?}", code);
|
||||
|
||||
prog.code.insert(declrs[x].uuid(), code);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue