finished yard

This commit is contained in:
Sven Vogel 2023-01-02 12:06:24 +01:00
parent ba0d6837f3
commit a506f51f71
11 changed files with 578 additions and 254 deletions

View File

@ -1,16 +1,57 @@
section[text]
0xc8c7a99bb88e156b:
push int 0x0
store 0x0
load 0x0
push int 0x4
push int 0x9
cmp gt int
jump-unless 0x19
load 0x0
push int 0x5
cmp not-eq int
jump-unless 0xf
load 0x0
push int 0x1
add int
store 0x0
load 0x0
push int 0x10
cmp lt eq int
jump-unless 0xb
jump 0xc
jump 0x2
push string ""
load 0x0
cat
call 0xa451e518c3d4dbea
call 0x396ceaf58c7ab783
load 0x0
push int 0x1
add int
store 0x0
jump 0x2
jump 0x1b
jump 0x2
push int 0x0
ret
extern builtin 0x396ceaf58c7ab783
extern builtin 0x608aa48c89877fc5
0x967b65e0e8f1394:
load 0x0
push int 0x1
cmp not-eq int
jump-unless 0x6
push int 0x1
ret
load 0x0
push int 0x1
sub int
call 0x967b65e0e8f1394
load 0x0
mul int
ret
extern builtin 0xdcd0c37eed9c3ddf
extern builtin 0x6d3c1164316ec324
extern builtin 0xa451e518c3d4dbea

View File

@ -1,9 +1,12 @@
use crate::parser::data::Diagnostics;
use crate::{parser::data::LogLvl, srcio::CodeSrc};
#[derive(Default)]
pub struct Settings {
gen_erpn: bool,
gen_vsasm: bool,
loglvl: LogLvl,
srcs: Vec<CodeSrc>
}
impl Settings {
@ -14,17 +17,25 @@ impl Settings {
pub fn gen_vsasm(&self) -> bool {
self.gen_vsasm
}
pub fn get_source(&self) -> &Vec<CodeSrc> {
&self.srcs
}
pub fn parse_args(diagnostics: &mut Diagnostics) -> Settings {
pub fn loglvl(&self) -> LogLvl {
self.loglvl
}
}
pub fn parse_args() -> Result<Settings, String> {
let args = std::env::args().collect::<Vec<String>>();
let mut settings = Settings::default();
for arg in args.iter() {
for arg in args.iter().skip(1) {
match arg.as_str() {
"--no-info" => diagnostics.set_loglvl(crate::parser::data::LogLvl::Warn),
"--no-warn" => diagnostics.set_loglvl(crate::parser::data::LogLvl::Err),
"--no-info" => settings.loglvl = crate::parser::data::LogLvl::Warn,
"--no-warn" => settings.loglvl = crate::parser::data::LogLvl::Err,
"--erpn" => settings.gen_erpn = true,
"--vsasm" => settings.gen_vsasm = true,
"-h" => println!(concat!(
@ -35,9 +46,9 @@ pub fn parse_args(diagnostics: &mut Diagnostics) -> Settings {
"--vsasm: write a .vsasm (virtual simplified assembly language) summary to disk\n",
"-h: print this dialog"
)),
_ => ()
_ => settings.srcs.push(CodeSrc::new(arg)?)
}
}
settings
Ok(settings)
}

View File

@ -23,18 +23,26 @@ fn write_block(file: &mut std::fs::File, indent: &mut String, block: &std::colle
indent.pop();
}
pub fn convert_to_erpn<'a>(funcs: &mut Vec<Func<'a>>, declrs: &Vec<Declr<'a>>) {
pub fn convert_to_erpn<'a>(parser: &crate::Parser) {
let mut file = std::fs::OpenOptions::new().write(true).create(true).truncate(true).open("test.erpn").unwrap();
let mut indent = String::new();
for (x, func) in funcs.iter().enumerate() {
// write function name
write!(&mut file, "{}:\n", declrs[x].name.unwrap()).unwrap();
for (x, func) in parser.funcs.iter().enumerate() {
if func.is_builtin {
write!(&mut file, "extern function {}\n\n", parser.declrs[x].name.unwrap()).unwrap();
continue;
}
// write function name
write!(&mut file, "{}:\n", parser.declrs[x].name.unwrap()).unwrap();
if !func.is_builtin {
// write down function body
write_expr(&mut file, &mut indent, func.expr.as_ref().unwrap());
}
writeln!(&mut file).unwrap();
}
}

View File

@ -7,9 +7,14 @@ mod parser;
mod inter;
mod conf;
mod vmrt;
mod srcio;
mod builtin;
mod direct;
use builtin::BuiltinFun;
use colored::Colorize;
use parser::*;
use conf::Settings;
use parser::{*, data::{Declr, Func}};
use token::*;
use crate::parser::data::Diagnostics;
@ -21,33 +26,20 @@ where
println!("{}: {}\n", typ.to_colored(), msg.into().bold().bright_white());
}
fn main() {
let source = r"
-- structs are tables
fn compile(settings: &Settings) -> Option<(Vec<Func>, Vec<Declr>, Vec<BuiltinFun>)> {
main() = int {
for src in settings.get_source().iter() {
let code = src.code();
x:rat = 0.0;
let mut diagnostics = Diagnostics::new(&settings, code);
loop {
x = x + 4
if let Ok(mut tokens) = tokenize(code, &mut diagnostics) {
let specs = crate::direct::resolve_directives(&mut tokens);
unless x < 16 {
break
}
}
let mut parser = Parser::new(&specs);
yield x;
}
";
let mut diagnostics = Diagnostics::new(source);
let settings = conf::parse_args(&mut diagnostics);
if let Ok(mut tokens) = tokenize(source, &mut diagnostics) {
if let Ok((fs, ds)) = parse(&mut tokens, &mut diagnostics, &settings) {
if let Ok(prog) = vmrt::compile(&fs, &ds, &settings) {
if let Ok((funcs, declrs, builtin)) = parser.parse(&mut tokens, &mut diagnostics, &settings) {
if let Ok(prog) = vmrt::compile(&funcs, &declrs, builtin, &settings) {
if let Ok(exit_code) = vmrt::execute(&prog) {
crate::message(MessageType::Info, format!("Program exited with {}", exit_code));
}
@ -56,4 +48,15 @@ main() = int {
}
println!("{}", diagnostics);
continue;
}
None
}
fn main() {
if let Ok(settings) = conf::parse_args() {
compile(&settings);
}
}

View File

@ -1,3 +1,6 @@
use rand::RngCore;
use crate::conf::Settings;
use crate::token::{DebugInfo, DebugNotice, Token, MessageType};
use crate::Prim;
use core::panic;
@ -15,6 +18,12 @@ pub enum LogLvl {
Err,
}
impl Default for LogLvl {
fn default() -> Self {
Self::Info
}
}
pub struct Diagnostics<'a> {
/// terminating factor on error
err: Option<DebugNotice<'a>>,
@ -28,26 +37,23 @@ pub struct Diagnostics<'a> {
}
impl<'a> Diagnostics<'a> {
pub fn new(source: &'a str) -> Self {
pub fn new(settings: &Settings, source: &'a str) -> Diagnostics<'a> {
Self {
err: None,
hints: vec![],
source,
loglvl: LogLvl::Info
loglvl: settings.loglvl()
}
}
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>,
S: Into<DebugInfo> + Clone,
{
if self.err.is_some() {
panic!("Error already set");
crate::message(MessageType::Warning, "Multiple Errors occured during compilation");
return;
}
let info: DebugInfo = source.clone().into();
@ -100,12 +106,14 @@ impl<'a> std::fmt::Display for Diagnostics<'a> {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Func<'a> {
/// raw tokens
pub raw: Option<VecDeque<Token<'a>>>,
/// parsed content
pub expr: Option<Expr<'a>>,
pub is_builtin:bool,
}
impl<'a> Func<'a> {
@ -113,6 +121,7 @@ impl<'a> Func<'a> {
Self {
raw: None,
expr: None,
is_builtin: false
}
}
}
@ -131,10 +140,29 @@ pub struct Declr<'a> {
/// debug info
pub info: Option<DebugInfo>,
pub is_builtin: bool,
uuid: u64
}
impl<'a> Declr<'a> {
pub fn generate_builtin(name: &'static str, args: Vec<(&'static str, Prim)>, ret: Option<Prim>) -> Declr {
Declr {
name: Some(name),
args: if args.is_empty() {
None
} else {
Some(args)
},
results: ret.is_some(),
result_typ: ret,
info: None,
is_builtin: true,
uuid: rand::thread_rng().next_u64()
}
}
pub fn new() -> Self {
Self {
name: None,
@ -142,6 +170,7 @@ impl<'a> Declr<'a> {
results: false,
result_typ: None,
info: None,
is_builtin: false,
uuid: 0,
}
}
@ -153,6 +182,7 @@ impl<'a> Declr<'a> {
results: true,
result_typ: Some(Prim::Int),
info: None,
is_builtin: false,
uuid: 0
};
@ -233,11 +263,10 @@ pub enum Expr<'a> {
Term(VecDeque<Token<'a>>),
}
pub struct Scope<'a> {
pub args: Option<&'a Vec<(&'a str, Prim)>>,
pub struct Scope {
pub declr: usize,
/// stack of scoped block variables
pub vars: Vec<Vec<(String, Option<Prim>)>>,
pub func_return_typ: Option<Prim>,
/// if we safely yielded sth
pub yields: bool,
/// if the last expr yielded a result
@ -245,7 +274,7 @@ pub struct Scope<'a> {
pub cond_count: usize,
}
impl<'a> Scope<'a> {
impl Scope {
pub fn alloc_scope(&mut self) {
self.vars.push(Vec::new())
}
@ -258,8 +287,8 @@ impl<'a> Scope<'a> {
self.vars.last_mut().unwrap().push((name, typ))
}
pub fn is_arg(&self, name: &'a str) -> bool {
if let Some(args) = self.args {
pub fn is_arg(&self, name: &str, declrs: &Vec<Declr>) -> bool {
if let Some(args) = &declrs[self.declr].args {
for arg in args.iter() {
if arg.0 == name {
return true;
@ -269,8 +298,8 @@ impl<'a> Scope<'a> {
false
}
pub fn get_arg_type(&self, name: &'a str) -> Prim {
if let Some(args) = self.args {
pub fn get_arg_type(&self, name: &str, declrs: &Vec<Declr>) -> Prim {
if let Some(args) = &declrs[self.declr].args {
for arg in args.iter() {
if arg.0 == name {
return arg.1;
@ -280,7 +309,7 @@ impl<'a> Scope<'a> {
panic!("No argument of name: {name}");
}
pub fn get_var_type(&self, name: &'a str) -> Prim {
pub fn get_var_type(&self, name: &str) -> Prim {
// create an owned version of the string
let owned = &name.to_owned();
@ -294,7 +323,7 @@ impl<'a> Scope<'a> {
panic!("No variable of name: {name}");
}
pub fn is_var(&self, name: &'a str) -> Option<Prim> {
pub fn is_var(&self, name: &str) -> Option<Prim> {
// create an owned version of the string
let owned = &name.to_owned();
@ -309,11 +338,10 @@ impl<'a> Scope<'a> {
None
}
pub fn new<'b>() -> Scope<'b> {
pub fn new() -> Scope {
Scope {
args: None,
declr: 0,
vars: vec![],
func_return_typ: None,
expr_yield: false,
yields: false,
cond_count: 0,

View File

@ -1,4 +1,4 @@
use crate::{token::{Assoc, DebugInfo, Keyword, Operator, Prim, Token}, conf::Settings};
use crate::{token::{Assoc, DebugInfo, Keyword, Operator, Prim, Token}, conf::Settings, builtin::{BuiltinFun, get_builtin_funs}, direct::LangSpecs};
use core::panic;
use std::{collections::VecDeque, vec};
@ -7,15 +7,34 @@ pub mod msg;
use data::*;
pub struct Parser<'a> {
pub declrs: Vec<Declr<'a>>,
pub funcs: Vec<Func<'a>>,
pub scope: Scope,
pub builtin: Vec<BuiltinFun>,
}
impl<'a> Parser<'a> {
pub fn new(specs: &LangSpecs) -> Parser<'a> {
let builtin = get_builtin_funs(specs.features());
Self {
declrs: builtin.iter().map(|bf| bf.declr()).collect(),
funcs: builtin.iter().map(|bf| bf.func()).collect(),
scope: Scope::new(),
builtin
}
}
/// simple brace-counting parser to detect functions
fn discover_functions<'a>(
fn discover_functions(
&mut self,
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();
) -> Result<(), ()> {
// function to currently identifiy
let mut func = Func::new();
let mut declr = Declr::new();
@ -29,7 +48,7 @@ fn discover_functions<'a>(
macro_rules! finish_func {
($token:expr) => {
// check if the function is already declared
if declrs.contains(&declr) {
if self.declrs.contains(&declr) {
diagnostics.set_err(
$token,
crate::msg::ERR10,
@ -47,8 +66,8 @@ fn discover_functions<'a>(
declr.gen_uuid();
// store new function and its declaration
funcs.push(func);
declrs.push(declr);
self.funcs.push(func);
self.declrs.push(declr);
// create new empty function
declr = Declr::new();
@ -106,7 +125,7 @@ fn discover_functions<'a>(
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.
// then check if we even need to return Err(()) sth.
if declr.results {
declr.result_typ = Some(*typ);
continue;
@ -181,7 +200,7 @@ fn discover_functions<'a>(
}
Token::Assign(name, _, info) => {
// check if we already marked a return type
// check if we already marked a return Err(()) type
// we dont want a double assignment
if declr.results {
diagnostics.set_err(&top, crate::msg::ERR17, "");
@ -282,19 +301,22 @@ fn discover_functions<'a>(
}
}
Ok((funcs, declrs))
Ok(())
}
/// parse the functions raw content to expr for easy compilation using a brace-counter.
/// - ```{...}``` surround a block
/// - line breaks seperate expressions
fn discover_exprs<'a>(
functions: &mut Vec<Func<'a>>,
_: &Vec<Declr<'a>>,
fn discover_exprs(
&mut self,
diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> {
for func in functions.iter_mut() {
for func in self.funcs.iter_mut() {
if func.is_builtin {
continue;
}
let mut blocks = vec![Block::new()];
let mut expr = VecDeque::new();
@ -369,7 +391,8 @@ fn discover_exprs<'a>(
func.expr = Some(Expr::Block(block));
}
}
Ok(())
return Ok(())
}
fn check_var_typ(
@ -412,13 +435,14 @@ fn check_var_typ(
diagnostics.set_err(info, crate::msg::ERR52, "");
return Err(()) ;
}
Ok(())
}
fn process_keyword(
&mut self,
info: &DebugInfo,
keyword: Keyword,
scope: &mut Scope,
operands: &mut Vec<Prim>,
diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> {
@ -444,7 +468,7 @@ fn process_keyword(
}
}
Keyword::Return => {
if scope.func_return_typ.is_some() {
if self.declrs[self.scope.declr].result_typ.is_some() {
diagnostics.set_err(info, crate::msg::ERR54, "perhaps use `yield`");
return Err(());
}
@ -460,7 +484,7 @@ fn process_keyword(
}
if let Some(operand) = operands.pop() {
if let Some(typ) = scope.func_return_typ {
if let Some(typ) = self.declrs[self.scope.declr].result_typ {
if !typ.is_equal(operand) {
diagnostics.set_err(
info,
@ -469,7 +493,7 @@ fn process_keyword(
);
return Err(());
}
scope.yields = scope.cond_count == 1;
self.scope.yields = self.scope.cond_count == 1;
} else {
diagnostics.set_err(info, crate::msg::ERR57, "");
return Err(());
@ -486,9 +510,8 @@ fn process_keyword(
}
fn collapse_operation(
&mut self,
operation: &mut Token,
declrs: &Vec<Declr>,
scope: &mut Scope,
operands: &mut Vec<Prim>,
diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> {
@ -496,14 +519,14 @@ fn collapse_operation(
match operation {
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());
Self::check_var_typ(typ, operands, &dbginf, diagnostics)?;
self.scope.decl_var((*name).to_owned(), typ.clone());
}
Token::Func(name, dbginf) => {
call_func(name, declrs, operands, &dbginf, diagnostics)?;
self.call_func(name, operands, &dbginf, diagnostics)?;
},
Token::Keyword(keyword, dbginf) => {
process_keyword(dbginf, *keyword, scope, operands, diagnostics)?;
self.process_keyword(dbginf, *keyword, operands, diagnostics)?;
}
_ => (),
}
@ -512,15 +535,15 @@ fn collapse_operation(
}
fn call_func(
&mut self,
name: &str,
declrs: &Vec<Declr>,
operands: &mut Vec<Prim>,
info: &DebugInfo,
diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> {
// find the function in our function declarations by its name
for declr in declrs {
for declr in self.declrs.iter() {
// check if declaration name matches the function name
if let Some(declr_name) = declr.name {
if declr_name != name {
@ -543,9 +566,8 @@ fn call_func(
// 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();
// fetch next operand which is ontop of the stack
let operand = operands.last().unwrap();
// check types
if !operand.is_equal(arg.1) {
diagnostics.set_err(info, crate::msg::ERR61, format!("expected {:?} got {:?} as {}th argument", arg, operand, x));
@ -563,14 +585,14 @@ fn call_func(
}
break;
}
Ok(())
}
/// parse a single term using a modified shunting yard
fn parse_term<'a>(
fn parse_term(
&mut self,
term: &mut VecDeque<Token<'a>>,
declrs: &Vec<Declr<'a>>,
scope: &mut Scope,
diagnostics: &mut data::Diagnostics,
) -> Result<(),()> {
@ -583,19 +605,19 @@ fn parse_term<'a>(
// resolve word to either a function, parameter or variable
Token::Word(text, dbginf) => {
// test for function
if is_func(declrs, text) {
if self.is_func(&self.declrs, text) || self.is_func(&self.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));
} else if self.scope.is_arg(text, &self.declrs) {
value_stack.push(self.scope.get_arg_type(text, &self.declrs));
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));
} else if self.scope.is_var(text).is_some() {
value_stack.push(self.scope.get_var_type(text));
output.push_back(Token::Var(text, *dbginf));
continue;
}
@ -610,6 +632,10 @@ fn parse_term<'a>(
Token::Number(_, hint, _) => {
output.push_back(token.clone());
value_stack.push(Prim::Num(*hint))
},
Token::String(_, _) => {
output.push_back(token.clone());
value_stack.push(Prim::Str)
}
Token::Assign(_, _, _) => {
op_stack.push(token);
@ -617,7 +643,7 @@ fn parse_term<'a>(
Token::Label(_, _) => output.push_back(token),
Token::Keyword(key, _) => {
match key {
Keyword::Unless => (),
Keyword::While => output.push_back(Token::LoopStart),
_ => ()
}
op_stack.push(token)
@ -634,10 +660,8 @@ fn parse_term<'a>(
match &next {
Token::Func(_, _) => {
let mut token = op_stack.pop().unwrap();
collapse_operation(
self.collapse_operation(
&mut token,
declrs,
scope,
&mut value_stack,
diagnostics,
)?;
@ -650,10 +674,8 @@ fn parse_term<'a>(
}
}
_ => {
collapse_operation(
self.collapse_operation(
&mut token,
declrs,
scope,
&mut value_stack,
diagnostics,
)?;
@ -678,10 +700,8 @@ fn parse_term<'a>(
let prec1 = op1.prec();
if prec1 > prec0 || prec0 == prec1 && op.assoc() == Assoc::Left {
collapse_operation(
self.collapse_operation(
&mut top,
declrs,
scope,
&mut value_stack,
diagnostics,
)?;
@ -709,7 +729,7 @@ fn parse_term<'a>(
}
}
_ => {
collapse_operation(&mut token, declrs, scope, &mut value_stack, diagnostics)?;
self.collapse_operation(&mut token, &mut value_stack, diagnostics)?;
output.push_back(token)
}
}
@ -720,18 +740,18 @@ fn parse_term<'a>(
return Err(());
}
scope.expr_yield = value_stack.len() == 1;
if scope.expr_yield {
self.scope.expr_yield = value_stack.len() == 1;
if self.scope.expr_yield {
let yielded = value_stack.pop().unwrap();
if !yielded.is_equal(scope.func_return_typ.unwrap()) {
if !yielded.is_equal(self.declrs[self.scope.declr].result_typ.unwrap()) {
diagnostics.set_err(
&output[0],
crate::msg::ERR59,
format!(
"expected {:?} got {:?}",
scope.func_return_typ.unwrap(),
self.declrs[self.scope.declr].result_typ.unwrap(),
yielded
),
);
@ -744,7 +764,7 @@ fn parse_term<'a>(
Ok(())
}
fn is_func(declrs: &[Declr], text: &str) -> bool {
fn is_func(&self, declrs: &[Declr], text: &str) -> bool {
for declr in declrs {
if declr.name.is_some() && declr.name.unwrap() == text {
return true;
@ -753,51 +773,55 @@ fn is_func(declrs: &[Declr], text: &str) -> bool {
return false;
}
fn parse_block<'a>(
fn parse_block(
&mut self,
block: &mut Block<'a>,
declrs: &Vec<Declr<'a>>,
scope: &mut Scope,
diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> {
scope.cond_count += 1;
scope.alloc_scope();
self.scope.cond_count += 1;
self.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) => self.parse_block(block, diagnostics)?,
Expr::Term(term) => self.parse_term(term, diagnostics)?,
}
}
scope.pop_scope();
scope.cond_count -= 1;
self.scope.pop_scope();
self.scope.cond_count -= 1;
Ok(())
}
fn parse_exprs<'a>(
funcs: &mut Vec<Func<'a>>,
declrs: &Vec<Declr<'a>>,
fn parse_exprs(
&mut self,
diagnostics: &mut data::Diagnostics,
) -> Result<(),()> {
let mut scope = Scope::new();
for (x, func) in funcs.iter_mut().enumerate() {
match func.expr.as_mut().expect("Function has no body") {
Expr::Block(block) => {
scope.args = declrs[x].args.as_ref();
scope.func_return_typ = declrs[x].result_typ;
scope.yields = false;
scope.cond_count = 0;
parse_block(block, declrs, &mut scope, diagnostics)?;
if scope.func_return_typ.is_some() && !scope.yields && !scope.expr_yield {
diagnostics.set_err(declrs[x].info.as_ref().unwrap(), crate::msg::ERR56, format!("for function: {}", declrs[x]));
return Err(());
for x in 0..self.funcs.len() {
if self.declrs[x].is_builtin {
continue;
}
let mut block = match self.funcs[x].expr.as_mut().expect("Function has no body") {
Expr::Block(block) => {
block.clone()
}
_ => {
crate::message(crate::token::MessageType::Critical, "Fatal-Compilier-Error: function must have a block");
crate::message(crate::token::MessageType::Critical, "Fatal-Compiler-Error: function must have a block");
panic!();
},
};
self.scope.declr = x;
self.scope.yields = false;
self.scope.cond_count = 0;
self.parse_block(&mut block, diagnostics)?;
self.funcs[x].expr = Some(Expr::Block(block));
if self.declrs[self.scope.declr].result_typ.is_some() && !self.scope.yields && !self.scope.expr_yield {
diagnostics.set_err(self.declrs[x].info.as_ref().unwrap(), crate::msg::ERR56, format!("for function: {}", self.declrs[x]));
return Err(());
}
}
Ok(())
@ -806,16 +830,17 @@ 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) -> Result<(Vec<Func<'a>>, Vec<Declr<'a>>), ()> {
pub fn parse(&'a mut self, tokens: &mut VecDeque<crate::Token<'a>>, diagnostics: &mut data::Diagnostics, settings: &Settings) -> Result<(&mut Vec<Func>, &mut Vec<Declr>, &mut Vec<BuiltinFun>), ()> {
let (mut funcs, declrs) = discover_functions(tokens, diagnostics)?;
self.discover_functions(tokens, diagnostics)?;
discover_exprs(&mut funcs, &declrs, diagnostics)?;
parse_exprs(&mut funcs, &declrs, diagnostics)?;
self.discover_exprs(diagnostics)?;
self.parse_exprs(diagnostics)?;
if settings.gen_erpn() {
crate::inter::convert_to_erpn(&mut funcs, &declrs);
crate::inter::convert_to_erpn(self);
}
return Ok((funcs, declrs));
return Ok((&mut self.funcs, &mut self.declrs, &mut self.builtin));
}
}

View File

@ -1,7 +1,6 @@
use crate::token::DebugMsg;
use crate::token::MessageType::Error;
use crate::token::MessageType::Info;
//use crate::token::MessageType::Warning;
pub const ERR10: &DebugMsg = &DebugMsg {
typ: Error,

View File

@ -1,5 +1,5 @@
use colored::{ColoredString, Colorize};
use std::{collections::VecDeque, fmt::format};
use std::{collections::VecDeque};
use crate::parser::data::Diagnostics;
@ -25,6 +25,9 @@ pub enum Operator {
Div,
Assign,
// concatonate primitve data types to string
Cat
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@ -78,11 +81,11 @@ impl Operator {
"-" => Operator::Sub,
"*" => Operator::Mul,
"/" => Operator::Div,
"=" => {
Operator::Assign },
"=" => Operator::Assign,
".." => Operator::Cat,
_ => {
crate::message(MessageType::Critical, "Unknown operator");
crate::message(MessageType::Critical, format!("Unknown operator: {}", str));
panic!();
}
};
@ -107,6 +110,8 @@ impl Operator {
Operator::Div => 4,
Operator::Assign => 0,
Operator::Cat => 0
};
}
@ -145,8 +150,8 @@ impl Operator {
}
for (x, typ) in types.iter().enumerate() {
if !typ.is_equal(operands[x]) {
return Ok((None, None));
if *typ != operands[x] {
return Err(());
}
}
@ -162,11 +167,12 @@ impl Operator {
diagnostics: &mut crate::parser::data::Diagnostics,
) -> Result<(Option<Prim>, Option<Prim>),()> {
for combination in types.iter() {
let (result, hint) =
self.present_types(operands, combination.0, combination.1, dbginf, diagnostics)?;
if let Ok((result, hint)) =
self.present_types(operands, combination.0, combination.1, dbginf, diagnostics) {
return Ok((result, hint));
}
}
Ok((None, None))
}
@ -178,15 +184,22 @@ impl Operator {
) -> Result<Prim,()> {
// TODO: insert type hint
match self {
Operator::Cat => {
operands.pop();
operands.pop();
operands.push(Prim::Str);
return Ok(Prim::Str);
},
Operator::Add | Operator::Sub | Operator::Mul | Operator::Div => {
let (types_valid, hint) =
let (types_valid, _) =
self.check_types(operands, ARITHMETIC_TYPES, info, diagnostics)?;
if let Some(result) = types_valid {
operands.pop();
operands.pop();
operands.push(result);
return Ok(hint.unwrap());
return Ok(types_valid.unwrap());
} else {
diagnostics.set_err(info, crate::msg::ERR73, "expected two numbers");
return Err(());
@ -276,11 +289,12 @@ lazy_static::lazy_static! {
static ref GOTO_REGEX: regex::Regex = regex::Regex::new(GOTO_REGEX_SRC).unwrap();
}
impl<'a> Keyword<'a> {
pub fn parse(text: &'a str) -> Keyword<'a> {
return match text {
"unless" => Keyword::Unless,
"while" => Keyword::While,
"despite" => Keyword::Unless,
"until" => Keyword::While,
"loop" => Keyword::Loop,
"break" => Keyword::Break,
"cont" => Keyword::Continue,
@ -326,6 +340,7 @@ pub enum Prim {
Rat,
Bool,
Num(NumHint),
Str,
}
impl Prim {
@ -334,6 +349,7 @@ impl Prim {
"int" => Ok(Prim::Int),
"rat" => Ok(Prim::Rat),
"bool" => Ok(Prim::Bool),
"str" => Ok(Prim::Str),
_ => {
diagnostics.set_err(info, crate::msg::ERR70, format!("token is not a type: {}", text));
return Err(())
@ -353,12 +369,14 @@ impl Prim {
pub fn is_equal(&self, value: Prim) -> bool {
return match self {
Prim::Str => *self == value,
Prim::Bool => *self == value,
Prim::Rat => {
return match value {
Prim::Num(NumHint::Int) => true,
Prim::Num(NumHint::Rat) => true,
_ => *self == value,
Prim::Rat => true,
_ => false,
}
}
Prim::Int => {
@ -389,7 +407,8 @@ impl std::fmt::Display for Prim {
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))?
Prim::Num(_) => f.write_fmt(format_args!("{:?}", self))?,
Prim::Str => f.write_str("Str")?,
}
Ok(())
}
@ -419,7 +438,7 @@ impl<'a> std::fmt::Display for DebugNotice<'a> {
self.msg.typ.to_colored(),
self.msg.code,
self.msg.msg.bold().bright_white(),
self.info.line,
self.info.line + 1,
self.ext
))?;
// write additional information
@ -435,7 +454,7 @@ impl<'a> std::fmt::Display for DebugNotice<'a> {
))
.unwrap();
(0..self.info.start + 6)
(0..self.info.start + 7)
.into_iter()
.for_each(|_| f.write_str(" ").unwrap());
(self.info.start..self.info.end)
@ -514,7 +533,10 @@ pub enum Token<'a> {
Type(Prim, DebugInfo),
/// Semicolon
Terminator(DebugInfo),
Label(&'a str, DebugInfo)
Label(&'a str, DebugInfo),
CompilerDirective(&'a str, DebugInfo),
String(&'a str, DebugInfo),
LoopStart,
}
impl<'a> std::fmt::Display for Token<'a> {
@ -535,6 +557,9 @@ impl<'a> std::fmt::Display for Token<'a> {
Token::Bool(b, _) => f.write_fmt(format_args!("Load Bool {}", b)),
Token::Keyword(k, _) => f.write_fmt(format_args!("{:?}", k)),
Token::Terminator(_) => f.write_str("__Terminator"),
Token::CompilerDirective(_, _) => f.write_str("compiler-directive"),
Token::String(mat, _) => f.write_fmt(format_args!("Load String \"{}\"", mat)),
Token::LoopStart => f.write_str("Loopstart"),
}
}
}
@ -557,11 +582,31 @@ impl<'a> Into<DebugInfo> for Token<'a> {
Token::Keyword(_, d) => d,
Token::Terminator(d) => d,
Token::Label(_, d) => d,
Token::CompilerDirective(_, d) => d,
Token::String(_, d) => d,
Token::LoopStart => panic!("loop start has no debug info"),
}
}
}
const TOKEN_REGEX_SRC: &'static str = r"(#.*|--.*)|'([a-zA-Z0-9]+)|(goto\s+[a-zA-Z0-9]+|unless|while|loop|break|cont|ret|yield|please)|(int|rat|bool)|(true|false|ye|no|maybe)|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))?\s*=[^=]|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))|([A-Za-z_]+)|(\d*\.?\d+)|(!=|==|<=|<=|[&|+\-*/<>=])|([(){}])|(\n)|(;)";
const TOKEN_REGEX_SRC: &'static str = concat!(
r"(#.*|--.*|//.*)", // comments
r"|(@.*)", // interpreter directives
"|\"([^\"]*)\"", // string literal
r"|'([a-zA-Z0-9_]+)", // labels: 'example
r"|(goto\s+[a-zA-Z0-9_]+", // goto example
r"|despite|until|loop|break|cont|ret|yield|please)", // keywords
r"|\W(int|rat|bool|str)\W", // raw data types
r"|(true|false|ye|no|maybe)", // boolean values
r"|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9_]+))?\s*=[^=]", // assignment var:int=
r"|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9_]+))", // declaration var:int
r"|([A-Za-z_]+)", // symbol
r"|(\d*\.?\d+)", // number
r"|(!=|==|<=|<=|\.\.|[&|+\-*/<>=])", // operator
r"|([(){}])", // delemeiter
r"|(\n)", // line break
r"|(;)" // expression terminator
);
lazy_static::lazy_static! {
static ref TOKEN_REGEX: regex::Regex = regex::Regex::new(TOKEN_REGEX_SRC).unwrap();
@ -574,6 +619,8 @@ pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result<Ve
let mut line_count = 0;
let mut line_start = 0;
let mut new_line = false;
for cap in TOKEN_REGEX.captures_iter(source.as_ref()) {
let mut enumerator = cap.iter().enumerate();
loop {
@ -592,6 +639,11 @@ pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result<Ve
// if we have a match, save it as token
if let Some(mat) = group {
if new_line {
line_start = mat.start();
new_line = false;
}
let debug_info = DebugInfo {
start: mat.start() - line_start,
end: mat.end() - line_start,
@ -599,11 +651,13 @@ pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result<Ve
};
tokens.push_back(match i {
2 => Token::Label(mat.as_str(), debug_info),
3 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info),
4 => Token::Type(Prim::from(mat.as_str(), &debug_info, diagnostics)?, debug_info),
5 => Token::Bool(parse_bool(mat.as_str()), debug_info),
6 => {
2 => Token::CompilerDirective(mat.as_str(), debug_info),
3 => Token::String(mat.as_str(), debug_info),
4 => Token::Label(mat.as_str(), debug_info),
5 => Token::Keyword(Keyword::parse(mat.as_str()), debug_info),
6 => Token::Type(Prim::from(mat.as_str(), &debug_info, diagnostics)?, debug_info),
7 => Token::Bool(parse_bool(mat.as_str()), debug_info),
8 => {
let var_type = if let Some(mat) = enumerator.next().unwrap().1 {
Some(Prim::from(mat.as_str(), &debug_info, diagnostics)?)
} else {
@ -611,21 +665,21 @@ pub fn tokenize<'a>(source: &'a str, diagnostics: &mut Diagnostics) -> Result<Ve
};
Token::Assign(mat.as_str(), var_type, debug_info)
}
8 => {
10 => {
let var_type =
Prim::from(enumerator.next().unwrap().1.unwrap().as_str(), &debug_info, diagnostics)?;
Token::Decl(mat.as_str(), var_type, debug_info)
}
10 => Token::Word(mat.as_str(), debug_info),
11 => Token::Number(mat.as_str(), NumHint::from(mat.as_str()), debug_info),
12 => Token::Operator(Operator::parse(mat.as_str()), None, debug_info),
13 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info),
14 => {
12 => Token::Word(mat.as_str(), debug_info),
13 => Token::Number(mat.as_str(), NumHint::from(mat.as_str()), debug_info),
14 => Token::Operator(Operator::parse(mat.as_str()), None, debug_info),
15 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info),
16 => {
line_count += 1;
line_start = mat.start();
new_line = true;
Token::LineBreak(debug_info)
}
15 => Token::Terminator(debug_info),
17 => Token::Terminator(debug_info),
_ => {
diagnostics.set_err(&debug_info, crate::msg::ERR71, format!("token: {}", mat.as_str()));

View File

@ -1,17 +1,18 @@
mod output;
use std::collections::{HashMap, VecDeque};
use std::{collections::{HashMap, VecDeque}, vec};
use crate::{
parser::data::*,
token::{NumHint, Prim, Token},
token::{NumHint, Prim, Token}, builtin::{BuiltinFun},
};
#[derive(Debug, Clone, Copy)]
enum Data {
#[derive(Debug, Clone)]
pub enum Data {
Int(i64),
Rat(f64),
Bool(bool),
Str(String),
}
impl std::fmt::Display for Data {
@ -19,33 +20,50 @@ impl std::fmt::Display for Data {
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))?
Data::Bool(v) => f.write_fmt(format_args!("bool {}", v))?,
Data::Str(v) => f.write_fmt(format_args!("string \"{}\"", &v))?
}
Ok(())
}
}
impl Data {
fn to_int(&self) -> Result<i64, ()> {
pub fn to_int(&self) -> Result<i64, ()> {
return match self {
Data::Int(v) => Ok(*v),
_ => Err(()),
};
}
fn to_float(&self) -> Result<f64, ()> {
pub fn to_float(&self) -> Result<f64, ()> {
return match self {
Data::Rat(v) => Ok(*v),
_ => Err(()),
};
}
fn to_bool(&self) -> Result<bool, ()> {
pub fn to_bool(&self) -> Result<bool, ()> {
return match self {
Data::Bool(v) => Ok(*v),
_ => Err(()),
};
}
pub fn to_str(&self) -> Result<String, ()> {
return match self {
Data::Str(v) => Ok(v.clone()),
_ => Err(()),
};
}
fn as_str(&self) -> String {
return match self {
Data::Str(v) => v.clone(),
Data::Bool(b) => format!("{}", b),
Data::Rat(b) => format!("{}", b),
Data::Int(b) => format!("{}", b),
};
}
}
#[derive(Debug)]
@ -93,9 +111,11 @@ enum Operation {
Int(IntOp),
Rat(RatOp),
Bool(BoolOp),
Cat,
}
#[derive(Debug)]
#[allow(unused)]
enum Instr {
/// load some data onto the stack
Push(Data),
@ -115,6 +135,7 @@ enum Instr {
Jump(usize),
JumpUnless(usize),
JumpRandom(usize),
Exit,
}
@ -130,8 +151,10 @@ impl std::fmt::Display for Instr {
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::JumpRandom(offset) => f.write_fmt(format_args!("\tjump-random {:#x}", offset))?,
Instr::Operation(op) => {
match op {
Operation::Cat => f.write_str("\tcat")?,
Operation::Int(op) => match op {
IntOp::Add => f.write_str("\tadd int")?,
IntOp::Sub => f.write_str("\tsub int")?,
@ -165,7 +188,7 @@ impl std::fmt::Display for Instr {
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))?,
@ -184,25 +207,31 @@ impl std::fmt::Display for Instr {
/// +----------------------------------+
/// | Parameter (n) |
/// +----------------------------------+
struct Proc {
#[allow(unused)]
struct Proc<'a> {
// executable code
code: Vec<Instr>,
// number of expected arguments
args: usize,
// hashed declaration is used as "address"
addr: u64,
builtin: Option<&'a BuiltinFun>
}
#[derive(Default)]
pub struct Program {
procs: HashMap<u64, Proc>,
pub struct Program<'a> {
procs: HashMap<u64, Proc<'a>>,
}
enum LabelType {
Unless(usize),
Loop(usize),
Break(usize),
Pad
Pad,
JumpRandom(usize),
While(usize),
LoopStart(usize),
}
#[derive(Default)]
@ -234,7 +263,11 @@ fn parse_term<'a>(
Token::Bool(value, _) => {
code.push(Instr::Push(Data::Bool(*value)));
ct.stacksize += 1;
}
},
Token::String(value, _) => {
code.push(Instr::Push(Data::Str(String::from(*value))));
ct.stacksize += 1;
},
Token::Arg(name, _) => {
let off = declr[x].get_arg_ord(name);
code.push(Instr::Load(off));
@ -253,10 +286,14 @@ fn parse_term<'a>(
ct.stacksize += 1;
},
Token::Label(name, _) => {
ct.marker.insert(name, ct.stacksize + 1);
ct.marker.insert(name, code.len());
},
Token::LoopStart => {
ct.lopctl.push(LabelType::LoopStart(code.len()));
},
Token::Operator(op, hint, _) => {
code.push(match op {
crate::token::Operator::Cat => Instr::Operation(Operation::Cat),
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)),
@ -333,6 +370,7 @@ fn parse_term<'a>(
if decl.results {
ct.stacksize += 1;
ct.stacksize -= decl.args.as_ref().unwrap_or(&Vec::new()).len();
}
}
}
@ -349,14 +387,34 @@ fn parse_term<'a>(
code.push(Instr::JumpUnless(0));
},
crate::token::Keyword::Goto(label) => {
let index = ct.marker.get(label).unwrap();
let index = ct.marker.get(*label).unwrap();
code.push(Instr::Jump(*index));
},
crate::token::Keyword::Break => {
ct.lopctl.push(LabelType::Break(code.len()));
code.push(Instr::Jump(0));
}
},
crate::token::Keyword::Please => {
ct.labels.push(LabelType::JumpRandom(code.len()));
code.push(Instr::JumpRandom(0));
},
crate::token::Keyword::While => {
ct.labels.push(LabelType::While(code.len()));
code.push(Instr::JumpUnless(0));
},
crate::token::Keyword::Continue => {
// make cont work in loop
for label in ct.lopctl.iter().rev() {
match label {
LabelType::LoopStart(line) => {
code.push(Instr::Jump(*line));
break;
},
_ => (),
}
}
},
},
_ => (),
};
@ -385,9 +443,24 @@ fn parse_block<'a>(
LabelType::Unless(line) => {
prog[line] = Instr::JumpUnless(prog.len());
},
LabelType::JumpRandom(line) => {
prog[line] = Instr::JumpRandom(prog.len());
},
LabelType::While(whilepos) => {
if let Some(label) = ct.lopctl.pop() {
match label {
LabelType::LoopStart(loopstart) => {
prog.push(Instr::Jump(loopstart));
prog[whilepos] = Instr::JumpUnless(prog.len());
},
_ => ()
}
}
},
LabelType::Loop(line) => {
prog.push(Instr::Jump(line));
// multiple breaks?
if let Some(label) = ct.lopctl.pop() {
match label {
LabelType::Break(line) => {
@ -419,7 +492,7 @@ fn compile_expr<'a>(
Ok(())
}
fn create_proc(declr: &Declr, code: Vec<Instr>) -> Proc {
fn create_proc(declr: &Declr, code: Vec<Instr>) -> Proc<'static> {
Proc {
code,
args: if let Some(args) = &declr.args {
@ -428,13 +501,24 @@ fn create_proc(declr: &Declr, code: Vec<Instr>) -> Proc {
0
},
addr: declr.uuid(),
builtin: None,
}
}
pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>, settings: &crate::conf::Settings) -> Result<Program, ()> {
pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>, builtin: &'a Vec<BuiltinFun>, settings: &crate::conf::Settings) -> Result<Program<'a>, ()> {
let mut prog = Program::default();
for (x, func) in funcs.iter().enumerate() {
if func.is_builtin {
for builtin in builtin.iter() {
if builtin.declr().name == declrs[x].name {
prog.procs.insert(declrs[x].uuid(), create_builtin_proc(builtin));
break;
}
}
} else {
let mut code = vec![];
let mut ct = Compiletime::default();
@ -447,6 +531,8 @@ 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);
}
@ -454,6 +540,10 @@ pub fn compile<'a>(funcs: &Vec<Func<'a>>, declrs: &Vec<Declr<'a>>, settings: &cr
Ok(prog)
}
fn create_builtin_proc(func: &BuiltinFun) -> Proc {
Proc { code: Vec::new(), args: func.declr().args.unwrap_or(vec![]).len(), addr: 0, builtin: Some(func) }
}
struct Runtimestack {
stack: Vec<Data>,
}
@ -472,7 +562,7 @@ impl Runtimestack {
}
pub fn peek(&mut self, index: usize) -> Data {
self.stack[index]
self.stack[index].clone()
}
pub fn top(&self) -> &Data {
@ -484,12 +574,16 @@ impl Runtimestack {
}
}
fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result<Option<Data>, ()> {
fn call_fn(prog: &Program, proc: &Proc, superstack: &mut Vec<Data>) -> Result<Option<Data>, ()> {
let mut stack = Runtimestack::new();
// build local procedure stack
for i in 0..proc.args {
stack.push(superstack[superstack.len() - i - 1].clone());
for _ in 0..proc.args {
stack.push(superstack.pop().unwrap());
}
if let Some(builtin) = proc.builtin {
return builtin.get_function()(&stack.stack[..]);
}
let mut x = 0;
@ -501,7 +595,9 @@ fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result<Option<Da
Instr::Return => {
return Ok(stack.pop());
}
Instr::Push(data) => stack.push(*data),
Instr::Push(data) => {
stack.push(data.clone());
},
Instr::Load(offset) => {
let v = stack.peek(*offset);
stack.push(v);
@ -511,16 +607,26 @@ fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result<Option<Da
stack.put(*offset, data);
},
Instr::Call(addr) => {
if let Some(value) = call_fn(prog, prog.procs.get(addr).unwrap(), &stack.stack)? {
if let Some(value) = call_fn(prog, prog.procs.get(addr).unwrap(), &mut stack.stack)? {
stack.push(value);
}
},
Instr::Jump(addr) => {
x = *addr - 1;
x = *addr;
continue;
},
Instr::JumpRandom(addr) => {
if rand::random() {
x = *addr;
continue;
}
},
Instr::JumpUnless(addr) => {
match stack.pop() {
Some(Data::Bool(true)) => x = *addr - 1,
Some(Data::Bool(true)) => {
x = *addr;
continue;
},
Some(Data::Bool(false)) => (),
_ => {
crate::message(crate::token::MessageType::Critical, "no condition for unless on stack");
@ -541,6 +647,9 @@ fn call_fn(prog: &Program, proc: &Proc, superstack: &[Data]) -> Result<Option<Da
};
match op {
Operation::Cat => {
stack.push(Data::Str(format!("{}{}", op1.as_str(), op0.as_str())));
},
Operation::Int(op) => match op {
IntOp::Add => stack.push(Data::Int(op1.to_int()? + op0.to_int()?)),
IntOp::Sub => stack.push(Data::Int(op1.to_int()? - op0.to_int()?)),
@ -628,7 +737,7 @@ pub fn execute(prog: &Program) -> Result<i64, ()> {
if let Some(main_fn) = prog.procs.get(&main_fn_declr.uuid()) {
if let Some(exit_code) = call_fn(prog, main_fn, &[])? {
if let Some(exit_code) = call_fn(prog, main_fn, &mut Vec::new())? {
return Ok(exit_code.to_int()?);
}

View File

@ -1,7 +1,13 @@
use std::io::Write;
fn print_to_file(file: &mut std::fs::File, prog: &crate::vmrt::Program) -> std::io::Result<()> {
writeln!(file, "section[text]")?;
for proc in prog.procs.iter() {
if proc.1.builtin.is_some() {
writeln!(file, "\nextern builtin {:#x}", proc.0)?;
continue;
}
writeln!(file, "\n{:#x}:", proc.0)?;
for instr in proc.1.code.iter() {
@ -15,6 +21,7 @@ pub fn dump_program(prog: &crate::vmrt::Program) {
let mut file = std::fs::OpenOptions::new().write(true).create(true).truncate(true).open("prog.vsasm").unwrap();
if print_to_file(&mut file, prog).is_err() {
crate::message(crate::token::MessageType::Critical, "Failed dumping program");
panic!();
}
}

View File

@ -1,16 +1,55 @@
extern function say_hello
extern function print
extern function println
extern function print
extern function println
fac:
Load Arg x
Load Int 1
NotEq Int
Unless
Load Int 1
Yield
Load Arg x
Load Int 1
Sub Int
Call fac
Load Arg x
Mul Int
Yield
main:
Load Int 0
Store Int x
Loop
Loopstart
Load Var x
Load Int 4
Load Int 9
Gt Int
While
Load Var x
Load Int 5
NotEq Int
Unless
Load Var x
Load Int 1
Add Int
Store Int x
Continue
Load String ""
Load Var x
Load Int 16
Lt Int
Unless
Cat Str
Call println
Load Var x
Load Int 1
Add Int
Store Int x
Break
Load Var x
Load Int 0
Yield