added argument flags
This commit is contained in:
parent
d3f121640a
commit
fda09066c7
|
@ -0,0 +1,34 @@
|
|||
use crate::parser::data::Diagnostics;
|
||||
|
||||
pub struct Settings {
|
||||
gen_erpn: bool
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
fn new() -> Self {
|
||||
Settings {
|
||||
gen_erpn: false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_erpn(&self) -> bool {
|
||||
self.gen_erpn
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_args(diagnostics: &mut Diagnostics) -> Settings {
|
||||
let args = std::env::args().collect::<Vec<String>>();
|
||||
|
||||
let mut settings = Settings::new();
|
||||
|
||||
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,
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
settings
|
||||
}
|
18
src/main.rs
18
src/main.rs
|
@ -5,11 +5,14 @@ mod parser;
|
|||
// translate a tree of functions and expressions to pseudo assembly
|
||||
// designed for a virtual stack machiene
|
||||
mod inter;
|
||||
mod conf;
|
||||
|
||||
use colored::Colorize;
|
||||
use parser::*;
|
||||
use token::*;
|
||||
|
||||
use crate::parser::data::Diagnostics;
|
||||
|
||||
pub fn message<S>(typ: MessageType, msg: S)
|
||||
where
|
||||
S: Into<String>,
|
||||
|
@ -19,7 +22,7 @@ where
|
|||
|
||||
fn main() {
|
||||
let source = r"
|
||||
# this is pi
|
||||
# surely this is pi
|
||||
pi = rat 5.1415926535
|
||||
|
||||
foo(x:int, y:rat) = bool {
|
||||
|
@ -38,19 +41,26 @@ foo(x:int, y:rat) = bool {
|
|||
}
|
||||
|
||||
-- comment
|
||||
yield false
|
||||
yield true
|
||||
}
|
||||
|
||||
main() = int {
|
||||
|
||||
a = 4
|
||||
b = 5.5
|
||||
c = true
|
||||
r = foo(3, 3.4)
|
||||
r = foo(3, ffalsee)
|
||||
0
|
||||
}
|
||||
";
|
||||
|
||||
let diagnostics = parse(&mut tokenize(source), source);
|
||||
let mut diagnostics = Diagnostics::new(source);
|
||||
|
||||
let settings = conf::parse_args(&mut diagnostics);
|
||||
|
||||
if let Ok(mut tokens) = tokenize(source, &mut diagnostics) {
|
||||
parse(&mut tokens, &mut diagnostics, &settings);
|
||||
}
|
||||
|
||||
println!("{}", diagnostics);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
use crate::token::{DebugInfo, DebugNotice, Token};
|
||||
use crate::token::{DebugInfo, DebugNotice, Token, MessageType};
|
||||
use crate::Prim;
|
||||
use core::panic;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum LogLvl {
|
||||
/// print everything
|
||||
Info,
|
||||
/// print only errors and warning
|
||||
Warn,
|
||||
/// print only errors
|
||||
Err,
|
||||
}
|
||||
|
||||
pub struct Diagnostics<'a> {
|
||||
/// terminating factor on error
|
||||
err: Option<DebugNotice<'a>>,
|
||||
|
@ -11,6 +21,8 @@ pub struct Diagnostics<'a> {
|
|||
hints: Vec<DebugNotice<'a>>,
|
||||
/// source string
|
||||
source: &'a str,
|
||||
/// flags
|
||||
loglvl: LogLvl,
|
||||
}
|
||||
|
||||
impl<'a> Diagnostics<'a> {
|
||||
|
@ -19,9 +31,14 @@ impl<'a> Diagnostics<'a> {
|
|||
err: None,
|
||||
hints: vec![],
|
||||
source,
|
||||
loglvl: LogLvl::Info
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_loglvl(&mut self, lvl: LogLvl) {
|
||||
self.loglvl = lvl;
|
||||
}
|
||||
|
||||
pub fn set_err<T, S>(&mut self, source: &S, message: &'static crate::token::DebugMsg, ext: T)
|
||||
where
|
||||
T: Into<String>,
|
||||
|
@ -60,6 +77,16 @@ impl<'a> Diagnostics<'a> {
|
|||
impl<'a> std::fmt::Display for Diagnostics<'a> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for hint in self.hints.iter() {
|
||||
match hint.msg.typ {
|
||||
MessageType::Info => if self.loglvl != LogLvl::Info {
|
||||
continue;
|
||||
},
|
||||
MessageType::Warning => if self.loglvl == LogLvl::Err {
|
||||
continue;
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
|
||||
f.write_fmt(format_args!("{}\n\n", hint)).unwrap();
|
||||
}
|
||||
|
||||
|
@ -98,6 +125,9 @@ pub struct Declr<'a> {
|
|||
pub results: bool,
|
||||
/// type of result
|
||||
pub result_typ: Option<Prim>,
|
||||
|
||||
/// debug info
|
||||
pub info: Option<DebugInfo>
|
||||
}
|
||||
|
||||
impl<'a> Declr<'a> {
|
||||
|
@ -107,6 +137,7 @@ impl<'a> Declr<'a> {
|
|||
args: None,
|
||||
results: false,
|
||||
result_typ: None,
|
||||
info: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,6 +165,10 @@ impl<'a> std::fmt::Display for Declr<'a> {
|
|||
f.write_str(" =")?;
|
||||
}
|
||||
|
||||
if let Some(typ) = self.result_typ {
|
||||
f.write_fmt(format_args!(" {:?}", typ))?;
|
||||
}
|
||||
|
||||
f.write_str(" {}")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::token::{Assoc, DebugInfo, Keyword, Operator, Prim, Token};
|
||||
use crate::{token::{Assoc, DebugInfo, Keyword, Operator, Prim, Token}, conf::Settings};
|
||||
use core::panic;
|
||||
use std::{collections::VecDeque, vec};
|
||||
|
||||
|
@ -12,6 +12,7 @@ fn discover_functions<'a>(
|
|||
tokens: &mut VecDeque<crate::Token<'a>>,
|
||||
diagnostics: &mut data::Diagnostics,
|
||||
) -> Result<(Vec<Func<'a>>, Vec<Declr<'a>>), ()> {
|
||||
|
||||
let mut funcs = Vec::new();
|
||||
let mut declrs = Vec::new();
|
||||
|
||||
|
@ -27,6 +28,7 @@ fn discover_functions<'a>(
|
|||
|
||||
macro_rules! finish_func {
|
||||
($token:expr) => {
|
||||
// check if the function is already declared
|
||||
if declrs.contains(&declr) {
|
||||
diagnostics.set_err(
|
||||
$token,
|
||||
|
@ -36,13 +38,17 @@ fn discover_functions<'a>(
|
|||
return Err(());
|
||||
}
|
||||
|
||||
// check if the function returns sth but no return value is given
|
||||
if declr.results && declr.result_typ.is_none() {
|
||||
diagnostics.set_err($token, crate::msg::ERR11, format!("for function {declr}"));
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// store new function and its declaration
|
||||
funcs.push(func);
|
||||
declrs.push(declr);
|
||||
|
||||
// create new empty function
|
||||
declr = Declr::new();
|
||||
func = Func::new();
|
||||
single_line = false;
|
||||
|
@ -53,17 +59,20 @@ fn discover_functions<'a>(
|
|||
// function body detection
|
||||
// has highest priority
|
||||
match &top {
|
||||
Token::Delemiter(char, dbginf) => match char {
|
||||
Token::Delemiter(char, _) => match char {
|
||||
// open body
|
||||
'{' => {
|
||||
brace_cnt += 1;
|
||||
|
||||
// we have an found open function body
|
||||
if brace_cnt == 1 {
|
||||
// check if we have a name for our function
|
||||
if declr.name.is_none() {
|
||||
diagnostics.set_err(&top, crate::msg::ERR12, "");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// check if the parameter list was closed
|
||||
if paren_cnt > 0 {
|
||||
diagnostics.set_err(&top, crate::msg::ERR13, "");
|
||||
return Err(());
|
||||
|
@ -92,8 +101,10 @@ fn discover_functions<'a>(
|
|||
_ => (),
|
||||
},
|
||||
|
||||
Token::Type(typ, dbginf) => {
|
||||
Token::Type(typ, _) => {
|
||||
// check if we already have a result type
|
||||
if declr.result_typ.is_none() {
|
||||
// then check if we even need to return sth.
|
||||
if declr.results {
|
||||
declr.result_typ = Some(*typ);
|
||||
continue;
|
||||
|
@ -101,10 +112,13 @@ fn discover_functions<'a>(
|
|||
diagnostics.set_err(&top, crate::msg::ERR16, "");
|
||||
return Err(());
|
||||
}
|
||||
} else {
|
||||
diagnostics.set_err(&top, crate::msg::ERR24, "");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
Token::LineBreak(dbginf) => {
|
||||
Token::LineBreak(_) => {
|
||||
if single_line {
|
||||
finish_func!(&top);
|
||||
continue;
|
||||
|
@ -120,12 +134,15 @@ fn discover_functions<'a>(
|
|||
|
||||
if func.raw.is_none() {
|
||||
match &top {
|
||||
Token::Operator(op, dbginf) => match op {
|
||||
Token::Operator(op, _) => match op {
|
||||
Operator::Assign => {
|
||||
// check if we already have an assign
|
||||
if declr.results {
|
||||
diagnostics.set_err(&top, crate::msg::ERR17, "");
|
||||
return Err(());
|
||||
}
|
||||
// check if we even have a function name
|
||||
// which must always be first
|
||||
if declr.name.is_none() {
|
||||
diagnostics.set_err(&top, crate::msg::ERR12, "");
|
||||
return Err(());
|
||||
|
@ -138,26 +155,38 @@ fn discover_functions<'a>(
|
|||
_ => (),
|
||||
},
|
||||
|
||||
Token::Word(text, dbginf) => {
|
||||
Token::Word(text, info) => {
|
||||
// check if we have a function name
|
||||
if declr.name.is_some() {
|
||||
// we have a function name check if we have no open argument list.
|
||||
// if so this word is missplaced
|
||||
if declr.args.is_none() {
|
||||
diagnostics.set_err(&top, crate::msg::ERR18, "");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// function body is open and we have no function name
|
||||
} else if brace_cnt > 0 {
|
||||
diagnostics.set_err(&top, crate::msg::ERR13, "");
|
||||
return Err(());
|
||||
|
||||
// this must be a valid function name
|
||||
} else {
|
||||
declr.name = Some(text);
|
||||
declr.info = Some(info.to_owned());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Token::Assign(name, _, dbginf) => {
|
||||
Token::Assign(name, _, info) => {
|
||||
// check if we already marked a return type
|
||||
// we dont want a double assignment
|
||||
if declr.results {
|
||||
diagnostics.set_err(&top, crate::msg::ERR17, "");
|
||||
return Err(());
|
||||
}
|
||||
// check if we already set function name
|
||||
// then we dont want to reassign
|
||||
if declr.name.is_some() {
|
||||
diagnostics.set_err(&top, crate::msg::ERR18, "");
|
||||
return Err(());
|
||||
|
@ -165,16 +194,22 @@ fn discover_functions<'a>(
|
|||
|
||||
func.raw = Some(VecDeque::new());
|
||||
declr.name = Some(name);
|
||||
declr.info = Some(info.to_owned());
|
||||
declr.results = true;
|
||||
single_line = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
Token::Delemiter(char, dbginf) => match char {
|
||||
Token::Delemiter(char, _) => match char {
|
||||
'(' => {
|
||||
// check for no existing function body
|
||||
// if we have none we can open an parameter list
|
||||
if func.raw.is_none() {
|
||||
paren_cnt += 1;
|
||||
// check if we have one open parenthsis
|
||||
if paren_cnt == 1 {
|
||||
// we have some arguments then we have a double parameter list
|
||||
// dont want that
|
||||
if declr.args.is_some() {
|
||||
diagnostics.set_err(&top, crate::msg::ERR19, "");
|
||||
return Err(());
|
||||
|
@ -198,9 +233,14 @@ fn discover_functions<'a>(
|
|||
}
|
||||
|
||||
if let Some(body) = &mut func.raw {
|
||||
// if we have an open function body
|
||||
// drop all token in there till it closes
|
||||
body.push_back(top);
|
||||
continue;
|
||||
|
||||
// check for open parameter list
|
||||
} else if let Some(args) = &mut declr.args {
|
||||
// the parameter list is closed
|
||||
if paren_cnt == 0 {
|
||||
diagnostics.set_err(&top, crate::msg::ERR20, "");
|
||||
return Err(());
|
||||
|
@ -208,7 +248,9 @@ fn discover_functions<'a>(
|
|||
|
||||
match &top {
|
||||
Token::Decl(name, typ, _dbginf) => args.push((name, *typ)),
|
||||
Token::Word(_, dbginf) => {
|
||||
|
||||
// as parameter we only accept declarations
|
||||
Token::Word(_, _) => {
|
||||
diagnostics.set_err(&top, crate::msg::ERR21, "");
|
||||
return Err(());
|
||||
}
|
||||
|
@ -231,6 +273,7 @@ fn discover_functions<'a>(
|
|||
}
|
||||
|
||||
if let Some(raw) = func.raw {
|
||||
// still some raw unused tokens left over
|
||||
if let Some(front) = raw.front() {
|
||||
diagnostics.set_err(front, crate::msg::ERR15, "");
|
||||
return Err(());
|
||||
|
@ -247,7 +290,8 @@ fn discover_exprs<'a>(
|
|||
functions: &mut Vec<Func<'a>>,
|
||||
_: &Vec<Declr<'a>>,
|
||||
diagnostics: &mut data::Diagnostics,
|
||||
) {
|
||||
) -> Result<(),()> {
|
||||
|
||||
for func in functions.iter_mut() {
|
||||
let mut blocks = vec![Block::new()];
|
||||
|
||||
|
@ -255,27 +299,27 @@ fn discover_exprs<'a>(
|
|||
|
||||
while let Some(top) = func.raw.as_mut().unwrap().pop_front() {
|
||||
match &top {
|
||||
Token::LineBreak(dbginf) | Token::Terminator(dbginf) => {
|
||||
Token::LineBreak(_) | Token::Terminator(_) => {
|
||||
if !expr.is_empty() {
|
||||
if let Some(blocks) = blocks.last_mut() {
|
||||
blocks.push_back(Expr::Term(expr))
|
||||
} else {
|
||||
diagnostics.set_err(&top, crate::msg::ERR41, "");
|
||||
return;
|
||||
return Err(());
|
||||
}
|
||||
expr = VecDeque::new();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Token::Delemiter(char, dbginf) => match char {
|
||||
Token::Delemiter(char, _) => match char {
|
||||
'{' => {
|
||||
blocks
|
||||
.last_mut()
|
||||
.unwrap_or_else(|| {
|
||||
|
||||
if let Some(block) = blocks.last_mut() {
|
||||
block.push_back(Expr::Term(expr));
|
||||
} else {
|
||||
diagnostics.set_err(&top, crate::msg::ERR41, "");
|
||||
panic!()
|
||||
})
|
||||
.push_back(Expr::Term(expr));
|
||||
return Err(());
|
||||
}
|
||||
expr = VecDeque::new();
|
||||
blocks.push(Block::new());
|
||||
continue;
|
||||
|
@ -283,17 +327,22 @@ fn discover_exprs<'a>(
|
|||
'}' => {
|
||||
// pop topmost block of the stack, storing it in the next lower block
|
||||
if let Some(block) = blocks.pop() {
|
||||
blocks
|
||||
.last_mut()
|
||||
.unwrap_or_else(|| {
|
||||
//println!("{}", dbginf.make_msg(crate::msg::ERR41));
|
||||
panic!()
|
||||
})
|
||||
.push_back(Expr::Block(block));
|
||||
if let Some(dst) = blocks.last_mut() {
|
||||
dst.push_back(Expr::Block(block));
|
||||
} else {
|
||||
//println!("{}", dbginf.make_msg(crate::msg::ERR40));
|
||||
panic!()
|
||||
diagnostics.set_err(&top, crate::msg::ERR41, "");
|
||||
return Err(());
|
||||
}
|
||||
} else {
|
||||
diagnostics.set_err(&top, crate::msg::ERR40, "");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
if blocks.is_empty() {
|
||||
diagnostics.set_err(&top, crate::msg::ERR41, "");
|
||||
return Err(());
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
_ => (),
|
||||
|
@ -305,21 +354,19 @@ fn discover_exprs<'a>(
|
|||
}
|
||||
|
||||
if !expr.is_empty() {
|
||||
blocks
|
||||
.last_mut()
|
||||
.unwrap_or_else(|| {
|
||||
if let Some(block) = blocks.last_mut() {
|
||||
block.push_back(Expr::Term(expr));
|
||||
} else {
|
||||
diagnostics.set_err(expr.back().unwrap(), crate::msg::ERR40, "");
|
||||
panic!()
|
||||
})
|
||||
.push_back(Expr::Term(expr));
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(block) = blocks.pop() {
|
||||
func.expr = Some(Expr::Block(block));
|
||||
} else {
|
||||
panic!("curly brace missmatch")
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_var_typ(
|
||||
|
@ -328,7 +375,7 @@ fn check_var_typ(
|
|||
info: &crate::token::DebugInfo,
|
||||
diagnostics: &mut data::Diagnostics,
|
||||
) -> Result<(), ()> {
|
||||
if let Some(value) = operands.pop() {
|
||||
if let Some(mut value) = operands.pop() {
|
||||
if !operands.is_empty() {
|
||||
diagnostics.set_err(info, crate::msg::ERR50, "");
|
||||
return Err(());
|
||||
|
@ -345,6 +392,17 @@ fn check_var_typ(
|
|||
}
|
||||
} else {
|
||||
diagnostics.hint(info, crate::msg::INF51, format!("gessed type: {:?}", value));
|
||||
|
||||
// resolve to concrete typ
|
||||
// i.e all Prim::Num(hint) will convert to their hints.
|
||||
value = match value {
|
||||
Prim::Num(hint) => match hint {
|
||||
crate::token::NumHint::Int => Prim::Int,
|
||||
crate::token::NumHint::Rat => Prim::Rat,
|
||||
}
|
||||
_ => value
|
||||
};
|
||||
|
||||
*typ = Some(value);
|
||||
}
|
||||
} else {
|
||||
|
@ -362,7 +420,7 @@ fn process_keyword(
|
|||
diagnostics: &mut data::Diagnostics,
|
||||
) -> Result<(), ()> {
|
||||
match keyword {
|
||||
Keyword::If | Keyword::While => {
|
||||
Keyword::Unless | Keyword::While => {
|
||||
if operands.len() != 1 {
|
||||
diagnostics.set_err(
|
||||
info,
|
||||
|
@ -431,70 +489,78 @@ fn collapse_operation(
|
|||
operands: &mut Vec<Prim>,
|
||||
diagnostics: &mut data::Diagnostics,
|
||||
) -> Result<(), ()> {
|
||||
|
||||
match operation {
|
||||
Token::Operator(op, dbginf) => op.operate(operands, &dbginf, diagnostics),
|
||||
Token::Assign(name, mut typ, dbginf) => {
|
||||
check_var_typ(&mut typ, operands, &dbginf, diagnostics)?;
|
||||
scope.decl_var((*name).to_owned(), typ);
|
||||
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());
|
||||
}
|
||||
Token::Func(name, dbginf) => call_func(name, declrs, scope, operands, &dbginf, diagnostics),
|
||||
Token::Func(name, dbginf) => {
|
||||
call_func(name, declrs, operands, &dbginf, diagnostics)?;
|
||||
},
|
||||
Token::Keyword(keyword, dbginf) => {
|
||||
process_keyword(dbginf, *keyword, scope, operands, diagnostics)?
|
||||
process_keyword(dbginf, *keyword, scope, operands, diagnostics)?;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn call_func(
|
||||
name: &str,
|
||||
declrs: &Vec<Declr>,
|
||||
_: &mut Scope,
|
||||
operands: &mut Vec<Prim>,
|
||||
dbginf: &crate::token::DebugInfo,
|
||||
info: &DebugInfo,
|
||||
diagnostics: &mut data::Diagnostics,
|
||||
) {
|
||||
) -> Result<(), ()> {
|
||||
|
||||
// find the function in our function declarations by its name
|
||||
for declr in declrs {
|
||||
if declr.name.is_some() && declr.name.unwrap() == name {
|
||||
// check if declaration name matches the function name
|
||||
if let Some(declr_name) = declr.name {
|
||||
if declr_name != name {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// some critical compiler error
|
||||
crate::message(crate::token::MessageType::Critical, "Missing function name in declaration");
|
||||
panic!();
|
||||
}
|
||||
|
||||
if let Some(args) = &declr.args {
|
||||
// check if we have enough parameter on the stack
|
||||
// note that the stack may contain more than just the functions
|
||||
// // parameters
|
||||
if args.len() > operands.len() {
|
||||
/*
|
||||
println!(
|
||||
"{}",
|
||||
dbginf.make_msg_w_ext(
|
||||
crate::msg::ERR60,
|
||||
format!("expected {:?} got {:?}", args.len(), operands.len())
|
||||
)
|
||||
);*/
|
||||
panic!()
|
||||
diagnostics.set_err(info, crate::msg::ERR60, format!("expected {:?} got {:?}", args.len(), operands.len()));
|
||||
return Err(());
|
||||
}
|
||||
|
||||
// check parameter types
|
||||
for (x, arg) in args.iter().enumerate() {
|
||||
// parameter are in reverse order on the stack
|
||||
// so they are placed at the bottom
|
||||
let operand = operands.first().unwrap();
|
||||
|
||||
// check types
|
||||
if !operand.is_equal(arg.1) {
|
||||
/*
|
||||
println!(
|
||||
"{}",
|
||||
dbginf.make_msg_w_ext(
|
||||
crate::msg::ERR61,
|
||||
format!("expected {:?} got {:?}", arg, operand)
|
||||
)
|
||||
);*/
|
||||
panic!()
|
||||
diagnostics.set_err(info, crate::msg::ERR61, format!("expected {:?} got {:?} as {}th argument", arg, operand, x));
|
||||
return Err(());
|
||||
}
|
||||
|
||||
operands.remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
// if the function returns sth. we will add
|
||||
// its type to the stack
|
||||
// assuming the execution was successfull
|
||||
if let Some(typ) = declr.result_typ {
|
||||
operands.push(typ);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// parse a single term using a modified shunting yard
|
||||
|
@ -503,28 +569,36 @@ fn parse_term<'a>(
|
|||
declrs: &Vec<Declr<'a>>,
|
||||
scope: &mut Scope,
|
||||
diagnostics: &mut data::Diagnostics,
|
||||
) {
|
||||
) -> Result<(),()> {
|
||||
|
||||
let mut op_stack = vec![];
|
||||
let mut output = VecDeque::with_capacity(term.len());
|
||||
let mut value_stack = vec![];
|
||||
|
||||
'outer: while let Some(token) = term.pop_front() {
|
||||
match &token {
|
||||
// resolve word to either a function, parameter or variable
|
||||
Token::Word(text, dbginf) => {
|
||||
// test for function
|
||||
if is_func(declrs, text) {
|
||||
op_stack.push(Token::Func(text, *dbginf));
|
||||
continue;
|
||||
|
||||
// test for function parameter
|
||||
} else if scope.is_arg(text) {
|
||||
value_stack.push(scope.get_arg_type(text));
|
||||
output.push_back(Token::Arg(text, *dbginf));
|
||||
continue;
|
||||
|
||||
// test for variable in scope
|
||||
} else if scope.is_var(text).is_some() {
|
||||
value_stack.push(scope.get_var_type(text));
|
||||
output.push_back(Token::Var(text, *dbginf));
|
||||
continue;
|
||||
}
|
||||
//println!("{}", dbginf.make_msg(crate::msg::ERR62));
|
||||
panic!()
|
||||
// word was not reolved to anything
|
||||
diagnostics.set_err(&token, crate::msg::ERR62, "");
|
||||
return Err(());
|
||||
}
|
||||
Token::Bool(_, _) => {
|
||||
output.push_back(token);
|
||||
|
@ -539,7 +613,7 @@ fn parse_term<'a>(
|
|||
}
|
||||
Token::Keyword(_, _) => op_stack.push(token),
|
||||
|
||||
Token::Delemiter(char, dbginf) => match char {
|
||||
Token::Delemiter(char, _) => match char {
|
||||
'(' => op_stack.push(token),
|
||||
')' => {
|
||||
while let Some(mut token) = op_stack.pop() {
|
||||
|
@ -556,7 +630,7 @@ fn parse_term<'a>(
|
|||
scope,
|
||||
&mut value_stack,
|
||||
diagnostics,
|
||||
);
|
||||
)?;
|
||||
output.push_back(token);
|
||||
}
|
||||
_ => (),
|
||||
|
@ -572,17 +646,17 @@ fn parse_term<'a>(
|
|||
scope,
|
||||
&mut value_stack,
|
||||
diagnostics,
|
||||
);
|
||||
)?;
|
||||
output.push_back(token)
|
||||
}
|
||||
}
|
||||
}
|
||||
//println!("{}", dbginf.make_msg(crate::msg::ERR64));
|
||||
panic!();
|
||||
diagnostics.set_err(&token, crate::msg::ERR64, "");
|
||||
return Err(());
|
||||
}
|
||||
_ => {
|
||||
//println!("{}", dbginf.make_msg(crate::msg::ERR65));
|
||||
panic!()
|
||||
diagnostics.set_err(&token, crate::msg::ERR65, "");
|
||||
return Err(());
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -600,7 +674,7 @@ fn parse_term<'a>(
|
|||
scope,
|
||||
&mut value_stack,
|
||||
diagnostics,
|
||||
);
|
||||
)?;
|
||||
output.push_back(op_stack.pop().unwrap());
|
||||
continue;
|
||||
}
|
||||
|
@ -617,13 +691,14 @@ fn parse_term<'a>(
|
|||
|
||||
while let Some(mut token) = op_stack.pop() {
|
||||
match &token {
|
||||
Token::Delemiter(char, dbginf) => {
|
||||
Token::Delemiter(char, _) => {
|
||||
if *char == '(' {
|
||||
//println!("{}", dbginf.make_msg(crate::msg::ERR63));
|
||||
diagnostics.set_err(&token, crate::msg::ERR63, "");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
collapse_operation(&mut token, declrs, scope, &mut value_stack, diagnostics);
|
||||
collapse_operation(&mut token, declrs, scope, &mut value_stack, diagnostics)?;
|
||||
output.push_back(token)
|
||||
}
|
||||
}
|
||||
|
@ -631,7 +706,7 @@ fn parse_term<'a>(
|
|||
|
||||
if value_stack.len() > 1 {
|
||||
diagnostics.set_err(&output[0], crate::msg::ERR50, "");
|
||||
return;
|
||||
return Err(());
|
||||
}
|
||||
|
||||
scope.expr_yield = value_stack.len() == 1;
|
||||
|
@ -652,6 +727,8 @@ fn parse_term<'a>(
|
|||
}
|
||||
|
||||
term.append(&mut output);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_func(declrs: &[Declr], text: &str) -> bool {
|
||||
|
@ -668,24 +745,25 @@ fn parse_block<'a>(
|
|||
declrs: &Vec<Declr<'a>>,
|
||||
scope: &mut Scope,
|
||||
diagnostics: &mut data::Diagnostics,
|
||||
) {
|
||||
) -> Result<(), ()> {
|
||||
scope.cond_count += 1;
|
||||
scope.alloc_scope();
|
||||
for expr in block.iter_mut() {
|
||||
match expr {
|
||||
Expr::Block(block) => parse_block(block, declrs, scope, diagnostics),
|
||||
Expr::Term(term) => parse_term(term, declrs, scope, diagnostics),
|
||||
Expr::Block(block) => parse_block(block, declrs, scope, diagnostics)?,
|
||||
Expr::Term(term) => parse_term(term, declrs, scope, diagnostics)?,
|
||||
}
|
||||
}
|
||||
scope.pop_scope();
|
||||
scope.cond_count -= 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_exprs<'a>(
|
||||
funcs: &mut Vec<Func<'a>>,
|
||||
declrs: &Vec<Declr<'a>>,
|
||||
diagnostics: &mut data::Diagnostics,
|
||||
) {
|
||||
) -> Result<(),()> {
|
||||
let mut scope = Scope::new();
|
||||
|
||||
for (x, func) in funcs.iter_mut().enumerate() {
|
||||
|
@ -696,31 +774,35 @@ fn parse_exprs<'a>(
|
|||
scope.yields = false;
|
||||
scope.cond_count = 0;
|
||||
|
||||
parse_block(block, declrs, &mut scope, diagnostics);
|
||||
parse_block(block, declrs, &mut scope, diagnostics)?;
|
||||
|
||||
if scope.func_return_typ.is_some() && !scope.yields && !scope.expr_yield {
|
||||
//token.create_msg_w_ext(crate::msg::ERR56, format!("at function {}", declrs[x]));
|
||||
diagnostics.set_err(declrs[x].info.as_ref().unwrap(), crate::msg::ERR56, format!("for function: {}", declrs[x]));
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
crate::message(crate::token::MessageType::Critical, "Fatal-Compilier-Error: function must have a block");
|
||||
panic!();
|
||||
},
|
||||
}
|
||||
}
|
||||
_ => panic!("Fatal-Compilier-Error: function must have a block"),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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>>, source: &'a str) -> Diagnostics<'a> {
|
||||
let mut dias = data::Diagnostics::new(source);
|
||||
pub fn parse<'a>(tokens: &mut VecDeque<crate::Token<'a>>, diagnostics: &mut data::Diagnostics, settings: &Settings) {
|
||||
|
||||
if let Ok((mut funcs, declrs)) = discover_functions(tokens, &mut dias) {
|
||||
// make all of this shit return a mutable diagnostics struct.
|
||||
discover_exprs(&mut funcs, &declrs, &mut dias);
|
||||
parse_exprs(&mut funcs, &declrs, &mut dias);
|
||||
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) {
|
||||
|
||||
if settings.gen_erpn() {
|
||||
crate::inter::convert_to_erpn(&mut funcs, &declrs);
|
||||
}
|
||||
|
||||
dias
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::token::DebugMsg;
|
||||
use crate::token::MessageType::Error;
|
||||
use crate::token::MessageType::Info;
|
||||
use crate::token::MessageType::Warning;
|
||||
//use crate::token::MessageType::Warning;
|
||||
|
||||
pub const ERR10: &DebugMsg = &DebugMsg {
|
||||
typ: Error,
|
||||
|
@ -73,6 +73,12 @@ pub const ERR23: &DebugMsg = &DebugMsg {
|
|||
code: 23,
|
||||
msg: "token must be declaration",
|
||||
};
|
||||
pub const ERR24: &DebugMsg = &DebugMsg {
|
||||
typ: Error,
|
||||
code: 24,
|
||||
msg: "function already has return type",
|
||||
};
|
||||
|
||||
|
||||
pub const ERR40: &DebugMsg = &DebugMsg {
|
||||
typ: Error,
|
||||
|
@ -183,11 +189,7 @@ pub const ERR71: &DebugMsg = &DebugMsg {
|
|||
code: 71,
|
||||
msg: "Unable to identify characters as token",
|
||||
};
|
||||
pub const ERR72: &DebugMsg = &DebugMsg {
|
||||
typ: Error,
|
||||
code: 72,
|
||||
msg: "Unknown operator",
|
||||
};
|
||||
|
||||
pub const ERR73: &DebugMsg = &DebugMsg {
|
||||
typ: Error,
|
||||
code: 73,
|
||||
|
|
125
src/token/mod.rs
125
src/token/mod.rs
|
@ -1,6 +1,8 @@
|
|||
use colored::{ColoredString, Colorize};
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use crate::parser::data::Diagnostics;
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)]
|
||||
pub enum Operator {
|
||||
// bitwise boolean operations
|
||||
|
@ -117,31 +119,26 @@ impl Operator {
|
|||
operands: &[Prim],
|
||||
types: &[Prim],
|
||||
r#yield: Prim,
|
||||
dbginf: &DebugInfo,
|
||||
info: &DebugInfo,
|
||||
diagnostics: &mut crate::parser::data::Diagnostics,
|
||||
) -> Option<Prim> {
|
||||
) -> Result<Option<Prim>, ()> {
|
||||
|
||||
if operands.len() < types.len() {
|
||||
/*
|
||||
println!(
|
||||
"{}",
|
||||
dbginf.make_msg_w_ext(
|
||||
crate::msg::ERR74,
|
||||
format!(
|
||||
diagnostics.set_err(info, crate::msg::ERR74, format!(
|
||||
"required {} got {}",
|
||||
types.len() - operands.len(),
|
||||
operands.len()
|
||||
)
|
||||
)
|
||||
);*/
|
||||
panic!()
|
||||
);
|
||||
return Err(());
|
||||
}
|
||||
|
||||
for (x, typ) in types.iter().enumerate() {
|
||||
if typ != &operands[x] {
|
||||
return None;
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
Some(r#yield)
|
||||
Ok(Some(r#yield))
|
||||
}
|
||||
|
||||
fn check_types(
|
||||
|
@ -149,60 +146,54 @@ impl Operator {
|
|||
types: &[(&[Prim], Prim)],
|
||||
dbginf: &DebugInfo,
|
||||
diagnostics: &mut crate::parser::data::Diagnostics,
|
||||
) -> Option<Prim> {
|
||||
) -> Result<Option<Prim>,()> {
|
||||
for combination in types.iter() {
|
||||
if let Some(result) =
|
||||
Self::present_types(operands, combination.0, combination.1, dbginf, diagnostics)
|
||||
Self::present_types(operands, combination.0, combination.1, dbginf, diagnostics)?
|
||||
{
|
||||
return Some(result);
|
||||
return Ok(Some(result));
|
||||
}
|
||||
}
|
||||
None
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn operate(
|
||||
&self,
|
||||
operands: &mut Vec<Prim>,
|
||||
dbginf: &DebugInfo,
|
||||
info: &DebugInfo,
|
||||
diagnostics: &mut crate::parser::data::Diagnostics,
|
||||
) {
|
||||
) -> Result<(),()> {
|
||||
match self {
|
||||
Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => {
|
||||
let types_valid =
|
||||
Self::check_types(operands, ARITHMETIC_TYPES, dbginf, diagnostics);
|
||||
Self::check_types(operands, ARITHMETIC_TYPES, info, diagnostics)?;
|
||||
|
||||
if let Some(result) = types_valid {
|
||||
operands.pop();
|
||||
operands.pop();
|
||||
operands.push(result);
|
||||
return Ok(());
|
||||
} else {
|
||||
/*
|
||||
println!(
|
||||
"{}",
|
||||
dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two numbers")
|
||||
);*/
|
||||
panic!()
|
||||
diagnostics.set_err(info, crate::msg::ERR73, "expected two numbers");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
Operator::And | Operator::Or | Operator::Xor => {
|
||||
let types_valid = Self::check_types(
|
||||
operands,
|
||||
&[(&[Prim::Bool, Prim::Bool], Prim::Bool)],
|
||||
dbginf,
|
||||
info,
|
||||
diagnostics,
|
||||
);
|
||||
)?;
|
||||
|
||||
if let Some(result) = types_valid {
|
||||
operands.pop();
|
||||
operands.pop();
|
||||
operands.push(result);
|
||||
return Ok(())
|
||||
} else {
|
||||
/*
|
||||
println!(
|
||||
"{}",
|
||||
dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two booleans")
|
||||
);*/
|
||||
panic!()
|
||||
diagnostics.set_err(info, crate::msg::ERR73, "expected two booleans");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
Operator::Eq
|
||||
|
@ -229,21 +220,18 @@ impl Operator {
|
|||
Prim::Bool,
|
||||
),
|
||||
],
|
||||
dbginf,
|
||||
info,
|
||||
diagnostics,
|
||||
);
|
||||
)?;
|
||||
|
||||
if let Some(result) = types_valid {
|
||||
operands.pop();
|
||||
operands.pop();
|
||||
operands.push(result);
|
||||
return Ok(());
|
||||
} else {
|
||||
/*
|
||||
println!(
|
||||
"{}",
|
||||
dbginf.make_msg_w_ext(crate::msg::ERR73, "expected two numbers")
|
||||
);*/
|
||||
panic!()
|
||||
diagnostics.set_err(info, crate::msg::ERR73, "expected either two booleans or two numbers");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -255,7 +243,7 @@ impl Operator {
|
|||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub enum Keyword {
|
||||
If,
|
||||
Unless,
|
||||
While,
|
||||
/// while(true) loop
|
||||
Loop,
|
||||
|
@ -269,7 +257,7 @@ pub enum Keyword {
|
|||
impl Keyword {
|
||||
pub fn parse<'a>(text: &'a str) -> Keyword {
|
||||
return match text {
|
||||
"unless" => Keyword::If,
|
||||
"unless" => Keyword::Unless,
|
||||
"while" => Keyword::While,
|
||||
"loop" => Keyword::Loop,
|
||||
"break" => Keyword::Break,
|
||||
|
@ -314,14 +302,14 @@ pub enum Prim {
|
|||
}
|
||||
|
||||
impl Prim {
|
||||
fn from<'a>(text: &'a str, dbginf: &DebugInfo) -> Prim {
|
||||
fn from<'a>(text: &'a str, info: &DebugInfo, diagnostics: &mut Diagnostics) -> Result<Prim, ()> {
|
||||
return match text {
|
||||
"int" => Prim::Int,
|
||||
"rat" => Prim::Rat,
|
||||
"bool" => Prim::Bool,
|
||||
"int" => Ok(Prim::Int),
|
||||
"rat" => Ok(Prim::Rat),
|
||||
"bool" => Ok(Prim::Bool),
|
||||
_ => {
|
||||
//println!("{}", dbginf.make_msg(&crate::msg::ERR70));
|
||||
panic!()
|
||||
diagnostics.set_err(info, crate::msg::ERR70, format!("token is not a type: {}", text));
|
||||
return Err(())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -358,6 +346,18 @@ impl Prim {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Prim {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Prim::Int => f.write_str("Int")?,
|
||||
Prim::Rat => f.write_str("Rat")?,
|
||||
Prim::Bool => f.write_str("Bool")?,
|
||||
Prim::Num(_) => f.write_fmt(format_args!("{:?}", self))?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DebugMsg {
|
||||
pub code: i32,
|
||||
pub typ: MessageType,
|
||||
|
@ -384,7 +384,7 @@ impl<'a> std::fmt::Display for DebugNotice<'a> {
|
|||
self.msg.msg.bold().bright_white(),
|
||||
self.info.line,
|
||||
self.ext
|
||||
));
|
||||
))?;
|
||||
// write additional information
|
||||
f.write_fmt(format_args!(
|
||||
" somewhere in here:\n --> `{}`\n",
|
||||
|
@ -446,7 +446,7 @@ impl MessageType {
|
|||
}
|
||||
|
||||
impl std::fmt::Display for DebugInfo {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -491,7 +491,7 @@ impl<'a> std::fmt::Display for Token<'a> {
|
|||
Token::Func(name, _) => f.write_fmt(format_args!("Call {}", name)),
|
||||
Token::Var(v, _) => f.write_fmt(format_args!("Load Var {}", v)),
|
||||
Token::Arg(a, _) => f.write_fmt(format_args!("Load Arg {}", a)),
|
||||
Token::Assign(a, typ, _) => f.write_fmt(format_args!("Store {:?} {}", typ, a)),
|
||||
Token::Assign(a, typ, _) => f.write_fmt(format_args!("Store {} {}", typ.unwrap(), a)),
|
||||
Token::Decl(d, typ, _) => f.write_fmt(format_args!("__Decl {:?} as {}", typ, d)),
|
||||
Token::Bool(b, _) => f.write_fmt(format_args!("Load Bool {}", b)),
|
||||
Token::Keyword(k, _) => f.write_fmt(format_args!("{:?}", k)),
|
||||
|
@ -528,7 +528,7 @@ lazy_static::lazy_static! {
|
|||
}
|
||||
|
||||
/// creates a vector of tokens from the specified str.
|
||||
pub fn tokenize(source: &str) -> VecDeque<Token> {
|
||||
pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result<VecDeque<Token<'a>>, ()> {
|
||||
let mut tokens = VecDeque::new();
|
||||
|
||||
let mut line_count = 0;
|
||||
|
@ -560,11 +560,11 @@ pub fn tokenize(source: &str) -> VecDeque<Token> {
|
|||
|
||||
tokens.push_back(match i {
|
||||
2 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info),
|
||||
3 => Token::Type(Prim::from(mat.as_str(), &debug_info), debug_info),
|
||||
3 => Token::Type(Prim::from(mat.as_str(), &debug_info, diagnostics)?, debug_info),
|
||||
4 => Token::Bool(parse_bool(mat.as_str()), debug_info),
|
||||
5 => {
|
||||
let var_type = if let Some(mat) = enumerator.next().unwrap().1 {
|
||||
Some(Prim::from(mat.as_str(), &debug_info))
|
||||
Some(Prim::from(mat.as_str(), &debug_info, diagnostics)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -572,7 +572,7 @@ pub fn tokenize(source: &str) -> VecDeque<Token> {
|
|||
}
|
||||
7 => {
|
||||
let var_type =
|
||||
Prim::from(enumerator.next().unwrap().1.unwrap().as_str(), &debug_info);
|
||||
Prim::from(enumerator.next().unwrap().1.unwrap().as_str(), &debug_info, diagnostics)?;
|
||||
Token::Decl(mat.as_str(), var_type, debug_info)
|
||||
}
|
||||
9 => Token::Word(mat.as_str(), debug_info),
|
||||
|
@ -587,8 +587,8 @@ pub fn tokenize(source: &str) -> VecDeque<Token> {
|
|||
14 => Token::Terminator(debug_info),
|
||||
|
||||
_ => {
|
||||
//println!("{}", debug_info.make_msg(crate::msg::ERR71));
|
||||
panic!()
|
||||
diagnostics.set_err(&debug_info, crate::msg::ERR71, format!("token: {}", mat.as_str()));
|
||||
return Err(());
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
@ -596,7 +596,7 @@ pub fn tokenize(source: &str) -> VecDeque<Token> {
|
|||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
return Ok(tokens);
|
||||
}
|
||||
|
||||
fn parse_bool(text: &str) -> bool {
|
||||
|
@ -604,6 +604,9 @@ fn parse_bool(text: &str) -> bool {
|
|||
"true" | "ye" => true,
|
||||
"false" | "no" => false,
|
||||
"maybe" => rand::random(),
|
||||
_ => panic!("Not a recognized boolean {text}"),
|
||||
_ => {
|
||||
crate::message(MessageType::Critical, format!("token: {}", text));
|
||||
panic!();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
16
test.erpn
16
test.erpn
|
@ -4,31 +4,31 @@ foo:
|
|||
Load Int 5
|
||||
Load Int 6
|
||||
Add
|
||||
Store Some(Int) x
|
||||
Store Int x
|
||||
Load Arg x
|
||||
Load Int 6
|
||||
Lt
|
||||
If
|
||||
Unless
|
||||
Load Bool true
|
||||
Yield
|
||||
Please
|
||||
Load Arg x
|
||||
Load Int 6
|
||||
Lt
|
||||
If
|
||||
Unless
|
||||
Load Bool true
|
||||
Yield
|
||||
Load Bool false
|
||||
Load Bool true
|
||||
Yield
|
||||
main:
|
||||
Load Int 4
|
||||
Store None a
|
||||
Store Int a
|
||||
Load Rat 5.5
|
||||
Store None b
|
||||
Store Rat b
|
||||
Load Bool true
|
||||
Store None c
|
||||
Store Bool c
|
||||
Load Int 3
|
||||
Load Rat 3.4
|
||||
Call foo
|
||||
Store None r
|
||||
Store Bool r
|
||||
Load Int 0
|
||||
|
|
Loading…
Reference in New Issue