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: 0xc8c7a99bb88e156b:
push int 0x0 push int 0x0
store 0x0 store 0x0
load 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 add int
store 0x0 store 0x0
load 0x0
push int 0x10
cmp lt eq int
jump-unless 0xb
jump 0xc
jump 0x2 jump 0x2
push string ""
load 0x0 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 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)] #[derive(Default)]
pub struct Settings { pub struct Settings {
gen_erpn: bool, gen_erpn: bool,
gen_vsasm: bool, gen_vsasm: bool,
loglvl: LogLvl,
srcs: Vec<CodeSrc>
} }
impl Settings { impl Settings {
@ -14,17 +17,25 @@ impl Settings {
pub fn gen_vsasm(&self) -> bool { pub fn gen_vsasm(&self) -> bool {
self.gen_vsasm self.gen_vsasm
} }
pub fn get_source(&self) -> &Vec<CodeSrc> {
&self.srcs
}
pub fn loglvl(&self) -> LogLvl {
self.loglvl
}
} }
pub fn parse_args(diagnostics: &mut Diagnostics) -> Settings { pub fn parse_args() -> Result<Settings, String> {
let args = std::env::args().collect::<Vec<String>>(); let args = std::env::args().collect::<Vec<String>>();
let mut settings = Settings::default(); let mut settings = Settings::default();
for arg in args.iter() { for arg in args.iter().skip(1) {
match arg.as_str() { match arg.as_str() {
"--no-info" => diagnostics.set_loglvl(crate::parser::data::LogLvl::Warn), "--no-info" => settings.loglvl = crate::parser::data::LogLvl::Warn,
"--no-warn" => diagnostics.set_loglvl(crate::parser::data::LogLvl::Err), "--no-warn" => settings.loglvl = crate::parser::data::LogLvl::Err,
"--erpn" => settings.gen_erpn = true, "--erpn" => settings.gen_erpn = true,
"--vsasm" => settings.gen_vsasm = true, "--vsasm" => settings.gen_vsasm = true,
"-h" => println!(concat!( "-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", "--vsasm: write a .vsasm (virtual simplified assembly language) summary to disk\n",
"-h: print this dialog" "-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(); 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 file = std::fs::OpenOptions::new().write(true).create(true).truncate(true).open("test.erpn").unwrap();
let mut indent = String::new(); let mut indent = String::new();
for (x, func) in funcs.iter().enumerate() { for (x, func) in parser.funcs.iter().enumerate() {
// write function name if func.is_builtin {
write!(&mut file, "{}:\n", declrs[x].name.unwrap()).unwrap(); write!(&mut file, "extern function {}\n\n", parser.declrs[x].name.unwrap()).unwrap();
continue;
}
// write down function body // write function name
write_expr(&mut file, &mut indent, func.expr.as_ref().unwrap()); 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(); writeln!(&mut file).unwrap();
} }
} }

View File

@ -7,9 +7,14 @@ mod parser;
mod inter; mod inter;
mod conf; mod conf;
mod vmrt; mod vmrt;
mod srcio;
mod builtin;
mod direct;
use builtin::BuiltinFun;
use colored::Colorize; use colored::Colorize;
use parser::*; use conf::Settings;
use parser::{*, data::{Declr, Func}};
use token::*; use token::*;
use crate::parser::data::Diagnostics; use crate::parser::data::Diagnostics;
@ -21,39 +26,37 @@ where
println!("{}: {}\n", typ.to_colored(), msg.into().bold().bright_white()); println!("{}: {}\n", typ.to_colored(), msg.into().bold().bright_white());
} }
fn main() { fn compile(settings: &Settings) -> Option<(Vec<Func>, Vec<Declr>, Vec<BuiltinFun>)> {
let source = r"
-- structs are tables
main() = int { for src in settings.get_source().iter() {
let code = src.code();
x:rat = 0.0;
loop { let mut diagnostics = Diagnostics::new(&settings, code);
x = x + 4
if let Ok(mut tokens) = tokenize(code, &mut diagnostics) {
let specs = crate::direct::resolve_directives(&mut tokens);
unless x < 16 { let mut parser = Parser::new(&specs);
break
}
}
yield x;
}
";
let mut diagnostics = Diagnostics::new(source); if let Ok((funcs, declrs, builtin)) = parser.parse(&mut tokens, &mut diagnostics, &settings) {
if let Ok(prog) = vmrt::compile(&funcs, &declrs, builtin, &settings) {
let settings = conf::parse_args(&mut diagnostics); if let Ok(exit_code) = vmrt::execute(&prog) {
crate::message(MessageType::Info, format!("Program exited with {}", exit_code));
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(exit_code) = vmrt::execute(&prog) {
crate::message(MessageType::Info, format!("Program exited with {}", exit_code));
} }
} }
} }
println!("{}", diagnostics);
continue;
} }
println!("{}", diagnostics); 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::token::{DebugInfo, DebugNotice, Token, MessageType};
use crate::Prim; use crate::Prim;
use core::panic; use core::panic;
@ -15,6 +18,12 @@ pub enum LogLvl {
Err, Err,
} }
impl Default for LogLvl {
fn default() -> Self {
Self::Info
}
}
pub struct Diagnostics<'a> { pub struct Diagnostics<'a> {
/// terminating factor on error /// terminating factor on error
err: Option<DebugNotice<'a>>, err: Option<DebugNotice<'a>>,
@ -28,26 +37,23 @@ pub struct Diagnostics<'a> {
} }
impl<'a> Diagnostics<'a> { impl<'a> Diagnostics<'a> {
pub fn new(source: &'a str) -> Self { pub fn new(settings: &Settings, source: &'a str) -> Diagnostics<'a> {
Self { Self {
err: None, err: None,
hints: vec![], hints: vec![],
source, 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) pub fn set_err<T, S>(&mut self, source: &S, message: &'static crate::token::DebugMsg, ext: T)
where where
T: Into<String>, T: Into<String>,
S: Into<DebugInfo> + Clone, S: Into<DebugInfo> + Clone,
{ {
if self.err.is_some() { 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(); 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> { pub struct Func<'a> {
/// raw tokens /// raw tokens
pub raw: Option<VecDeque<Token<'a>>>, pub raw: Option<VecDeque<Token<'a>>>,
/// parsed content /// parsed content
pub expr: Option<Expr<'a>>, pub expr: Option<Expr<'a>>,
pub is_builtin:bool,
} }
impl<'a> Func<'a> { impl<'a> Func<'a> {
@ -113,6 +121,7 @@ impl<'a> Func<'a> {
Self { Self {
raw: None, raw: None,
expr: None, expr: None,
is_builtin: false
} }
} }
} }
@ -131,10 +140,29 @@ pub struct Declr<'a> {
/// debug info /// debug info
pub info: Option<DebugInfo>, pub info: Option<DebugInfo>,
pub is_builtin: bool,
uuid: u64 uuid: u64
} }
impl<'a> Declr<'a> { 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 { pub fn new() -> Self {
Self { Self {
name: None, name: None,
@ -142,6 +170,7 @@ impl<'a> Declr<'a> {
results: false, results: false,
result_typ: None, result_typ: None,
info: None, info: None,
is_builtin: false,
uuid: 0, uuid: 0,
} }
} }
@ -153,6 +182,7 @@ impl<'a> Declr<'a> {
results: true, results: true,
result_typ: Some(Prim::Int), result_typ: Some(Prim::Int),
info: None, info: None,
is_builtin: false,
uuid: 0 uuid: 0
}; };
@ -233,11 +263,10 @@ pub enum Expr<'a> {
Term(VecDeque<Token<'a>>), Term(VecDeque<Token<'a>>),
} }
pub struct Scope<'a> { pub struct Scope {
pub args: Option<&'a Vec<(&'a str, Prim)>>, pub declr: usize,
/// stack of scoped block variables /// stack of scoped block variables
pub vars: Vec<Vec<(String, Option<Prim>)>>, pub vars: Vec<Vec<(String, Option<Prim>)>>,
pub func_return_typ: Option<Prim>,
/// if we safely yielded sth /// if we safely yielded sth
pub yields: bool, pub yields: bool,
/// if the last expr yielded a result /// if the last expr yielded a result
@ -245,7 +274,7 @@ pub struct Scope<'a> {
pub cond_count: usize, pub cond_count: usize,
} }
impl<'a> Scope<'a> { impl Scope {
pub fn alloc_scope(&mut self) { pub fn alloc_scope(&mut self) {
self.vars.push(Vec::new()) self.vars.push(Vec::new())
} }
@ -258,8 +287,8 @@ impl<'a> Scope<'a> {
self.vars.last_mut().unwrap().push((name, typ)) self.vars.last_mut().unwrap().push((name, typ))
} }
pub fn is_arg(&self, name: &'a str) -> bool { pub fn is_arg(&self, name: &str, declrs: &Vec<Declr>) -> bool {
if let Some(args) = self.args { if let Some(args) = &declrs[self.declr].args {
for arg in args.iter() { for arg in args.iter() {
if arg.0 == name { if arg.0 == name {
return true; return true;
@ -269,8 +298,8 @@ impl<'a> Scope<'a> {
false false
} }
pub fn get_arg_type(&self, name: &'a str) -> Prim { pub fn get_arg_type(&self, name: &str, declrs: &Vec<Declr>) -> Prim {
if let Some(args) = self.args { if let Some(args) = &declrs[self.declr].args {
for arg in args.iter() { for arg in args.iter() {
if arg.0 == name { if arg.0 == name {
return arg.1; return arg.1;
@ -280,7 +309,7 @@ impl<'a> Scope<'a> {
panic!("No argument of name: {name}"); 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 // create an owned version of the string
let owned = &name.to_owned(); let owned = &name.to_owned();
@ -294,7 +323,7 @@ impl<'a> Scope<'a> {
panic!("No variable of name: {name}"); 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 // create an owned version of the string
let owned = &name.to_owned(); let owned = &name.to_owned();
@ -309,11 +338,10 @@ impl<'a> Scope<'a> {
None None
} }
pub fn new<'b>() -> Scope<'b> { pub fn new() -> Scope {
Scope { Scope {
args: None, declr: 0,
vars: vec![], vars: vec![],
func_return_typ: None,
expr_yield: false, expr_yield: false,
yields: false, yields: false,
cond_count: 0, 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 core::panic;
use std::{collections::VecDeque, vec}; use std::{collections::VecDeque, vec};
@ -7,15 +7,34 @@ pub mod msg;
use data::*; 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 /// simple brace-counting parser to detect functions
fn discover_functions<'a>( fn discover_functions(
&mut self,
tokens: &mut VecDeque<crate::Token<'a>>, tokens: &mut VecDeque<crate::Token<'a>>,
diagnostics: &mut data::Diagnostics, diagnostics: &mut data::Diagnostics,
) -> Result<(Vec<Func<'a>>, Vec<Declr<'a>>), ()> { ) -> Result<(), ()> {
let mut funcs = Vec::new();
let mut declrs = Vec::new();
// function to currently identifiy // function to currently identifiy
let mut func = Func::new(); let mut func = Func::new();
let mut declr = Declr::new(); let mut declr = Declr::new();
@ -29,17 +48,17 @@ fn discover_functions<'a>(
macro_rules! finish_func { macro_rules! finish_func {
($token:expr) => { ($token:expr) => {
// check if the function is already declared // check if the function is already declared
if declrs.contains(&declr) { if self.declrs.contains(&declr) {
diagnostics.set_err( diagnostics.set_err(
$token, $token,
crate::msg::ERR10, crate::msg::ERR10,
format!("Multiple definitions: {declr}"), format!("Multiple definitions: {declr}"),
); );
return Err(()); return Err(());
} }
// check if the function returns sth but no return value is given // check if the function returns sth but no return value is given
if declr.results && declr.result_typ.is_none() { if declr.results &&declr.result_typ.is_none() {
diagnostics.set_err($token, crate::msg::ERR11, format!("for function {declr}")); diagnostics.set_err($token, crate::msg::ERR11, format!("for function {declr}"));
return Err(()); return Err(());
} }
@ -47,8 +66,8 @@ fn discover_functions<'a>(
declr.gen_uuid(); declr.gen_uuid();
// store new function and its declaration // store new function and its declaration
funcs.push(func); self.funcs.push(func);
declrs.push(declr); self.declrs.push(declr);
// create new empty function // create new empty function
declr = Declr::new(); declr = Declr::new();
@ -106,7 +125,7 @@ fn discover_functions<'a>(
Token::Type(typ, _) => { Token::Type(typ, _) => {
// check if we already have a result type // check if we already have a result type
if declr.result_typ.is_none() { 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 { if declr.results {
declr.result_typ = Some(*typ); declr.result_typ = Some(*typ);
continue; continue;
@ -181,7 +200,7 @@ fn discover_functions<'a>(
} }
Token::Assign(name, _, info) => { 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 // we dont want a double assignment
if declr.results { if declr.results {
diagnostics.set_err(&top, crate::msg::ERR17, ""); diagnostics.set_err(&top, crate::msg::ERR17, "");
@ -258,7 +277,7 @@ fn discover_functions<'a>(
} }
_ => { _ => {
diagnostics.set_err(&top, crate::msg::ERR23, ""); diagnostics.set_err(&top, crate::msg::ERR23, "");
return Err(()); return Err(()) ;
} }
} }
continue; continue;
@ -269,7 +288,7 @@ fn discover_functions<'a>(
Token::LineBreak(_) | Token::Terminator(_) => (), // valid whitespace Token::LineBreak(_) | Token::Terminator(_) => (), // valid whitespace
_ => { _ => {
diagnostics.set_err(&top, crate::msg::ERR22, ""); diagnostics.set_err(&top, crate::msg::ERR22, "");
return Err(()); return Err(()) ;
} }
} }
} }
@ -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. /// parse the functions raw content to expr for easy compilation using a brace-counter.
/// - ```{...}``` surround a block /// - ```{...}``` surround a block
/// - line breaks seperate expressions /// - line breaks seperate expressions
fn discover_exprs<'a>( fn discover_exprs(
functions: &mut Vec<Func<'a>>, &mut self,
_: &Vec<Declr<'a>>,
diagnostics: &mut data::Diagnostics, diagnostics: &mut data::Diagnostics,
) -> Result<(),()> { ) -> Result<(), ()> {
for func in self.funcs.iter_mut() {
if func.is_builtin {
continue;
}
for func in functions.iter_mut() {
let mut blocks = vec![Block::new()]; let mut blocks = vec![Block::new()];
let mut expr = VecDeque::new(); let mut expr = VecDeque::new();
@ -320,7 +342,7 @@ fn discover_exprs<'a>(
block.push_back(Expr::Term(expr)); block.push_back(Expr::Term(expr));
} else { } else {
diagnostics.set_err(&top, crate::msg::ERR41, ""); diagnostics.set_err(&top, crate::msg::ERR41, "");
return Err(()); return Err(()) ;
} }
expr = VecDeque::new(); expr = VecDeque::new();
blocks.push(Block::new()); blocks.push(Block::new());
@ -334,16 +356,16 @@ fn discover_exprs<'a>(
dst.push_back(Expr::Block(block)); dst.push_back(Expr::Block(block));
} else { } else {
diagnostics.set_err(&top, crate::msg::ERR41, ""); diagnostics.set_err(&top, crate::msg::ERR41, "");
return Err(()); return Err(()) ;
} }
} else { } else {
diagnostics.set_err(&top, crate::msg::ERR40, ""); diagnostics.set_err(&top, crate::msg::ERR40, "");
return Err(()); return Err(()) ;
} }
if blocks.is_empty() { if blocks.is_empty() {
diagnostics.set_err(&top, crate::msg::ERR41, ""); diagnostics.set_err(&top, crate::msg::ERR41, "");
return Err(()); return Err(()) ;
} }
continue; continue;
@ -361,7 +383,7 @@ fn discover_exprs<'a>(
block.push_back(Expr::Term(expr)); block.push_back(Expr::Term(expr));
} else { } else {
diagnostics.set_err(expr.back().unwrap(), crate::msg::ERR40, ""); diagnostics.set_err(expr.back().unwrap(), crate::msg::ERR40, "");
return Err(()); return Err(()) ;
} }
} }
@ -369,7 +391,8 @@ fn discover_exprs<'a>(
func.expr = Some(Expr::Block(block)); func.expr = Some(Expr::Block(block));
} }
} }
Ok(())
return Ok(())
} }
fn check_var_typ( fn check_var_typ(
@ -410,15 +433,16 @@ fn check_var_typ(
} }
} else { } else {
diagnostics.set_err(info, crate::msg::ERR52, ""); diagnostics.set_err(info, crate::msg::ERR52, "");
return Err(()); return Err(()) ;
} }
Ok(()) Ok(())
} }
fn process_keyword( fn process_keyword(
&mut self,
info: &DebugInfo, info: &DebugInfo,
keyword: Keyword, keyword: Keyword,
scope: &mut Scope,
operands: &mut Vec<Prim>, operands: &mut Vec<Prim>,
diagnostics: &mut data::Diagnostics, diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> { ) -> Result<(), ()> {
@ -430,7 +454,7 @@ fn process_keyword(
crate::msg::ERR53, crate::msg::ERR53,
format!("got {:?} values", operands.len()), format!("got {:?} values", operands.len()),
); );
return Err(()); return Err(()) ;
} }
if let Some(operand) = operands.pop() { if let Some(operand) = operands.pop() {
@ -438,13 +462,13 @@ fn process_keyword(
Prim::Bool => (), Prim::Bool => (),
_ => { _ => {
diagnostics.set_err(info, crate::msg::ERR53, format!("got {:?}", operand)); diagnostics.set_err(info, crate::msg::ERR53, format!("got {:?}", operand));
return Err(()); return Err(()) ;
} }
} }
} }
} }
Keyword::Return => { 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`"); diagnostics.set_err(info, crate::msg::ERR54, "perhaps use `yield`");
return Err(()); return Err(());
} }
@ -460,7 +484,7 @@ fn process_keyword(
} }
if let Some(operand) = operands.pop() { 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) { if !typ.is_equal(operand) {
diagnostics.set_err( diagnostics.set_err(
info, info,
@ -469,7 +493,7 @@ fn process_keyword(
); );
return Err(()); return Err(());
} }
scope.yields = scope.cond_count == 1; self.scope.yields = self.scope.cond_count == 1;
} else { } else {
diagnostics.set_err(info, crate::msg::ERR57, ""); diagnostics.set_err(info, crate::msg::ERR57, "");
return Err(()); return Err(());
@ -486,9 +510,8 @@ fn process_keyword(
} }
fn collapse_operation( fn collapse_operation(
&mut self,
operation: &mut Token, operation: &mut Token,
declrs: &Vec<Declr>,
scope: &mut Scope,
operands: &mut Vec<Prim>, operands: &mut Vec<Prim>,
diagnostics: &mut data::Diagnostics, diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> { ) -> Result<(), ()> {
@ -496,14 +519,14 @@ fn collapse_operation(
match operation { match operation {
Token::Operator(op, ref mut typehint, dbginf) => *typehint = Some(op.operate(operands, &dbginf, diagnostics)?), Token::Operator(op, ref mut typehint, dbginf) => *typehint = Some(op.operate(operands, &dbginf, diagnostics)?),
Token::Assign(name, ref mut typ, dbginf) => { Token::Assign(name, ref mut typ, dbginf) => {
check_var_typ(typ, operands, &dbginf, diagnostics)?; Self::check_var_typ(typ, operands, &dbginf, diagnostics)?;
scope.decl_var((*name).to_owned(), typ.clone()); self.scope.decl_var((*name).to_owned(), typ.clone());
} }
Token::Func(name, dbginf) => { Token::Func(name, dbginf) => {
call_func(name, declrs, operands, &dbginf, diagnostics)?; self.call_func(name, operands, &dbginf, diagnostics)?;
}, },
Token::Keyword(keyword, dbginf) => { 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( fn call_func(
&mut self,
name: &str, name: &str,
declrs: &Vec<Declr>,
operands: &mut Vec<Prim>, operands: &mut Vec<Prim>,
info: &DebugInfo, info: &DebugInfo,
diagnostics: &mut data::Diagnostics, diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> { ) -> Result<(), ()> {
// find the function in our function declarations by its name // 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 // check if declaration name matches the function name
if let Some(declr_name) = declr.name { if let Some(declr_name) = declr.name {
if declr_name != name { if declr_name != name {
@ -543,9 +566,8 @@ fn call_func(
// check parameter types // check parameter types
for (x, arg) in args.iter().enumerate() { for (x, arg) in args.iter().enumerate() {
// parameter are in reverse order on the stack // fetch next operand which is ontop of the stack
// so they are placed at the bottom let operand = operands.last().unwrap();
let operand = operands.first().unwrap();
// check types // check types
if !operand.is_equal(arg.1) { if !operand.is_equal(arg.1) {
diagnostics.set_err(info, crate::msg::ERR61, format!("expected {:?} got {:?} as {}th argument", arg, operand, x)); diagnostics.set_err(info, crate::msg::ERR61, format!("expected {:?} got {:?} as {}th argument", arg, operand, x));
@ -563,14 +585,14 @@ fn call_func(
} }
break; break;
} }
Ok(()) Ok(())
} }
/// parse a single term using a modified shunting yard /// parse a single term using a modified shunting yard
fn parse_term<'a>( fn parse_term(
&mut self,
term: &mut VecDeque<Token<'a>>, term: &mut VecDeque<Token<'a>>,
declrs: &Vec<Declr<'a>>,
scope: &mut Scope,
diagnostics: &mut data::Diagnostics, diagnostics: &mut data::Diagnostics,
) -> Result<(),()> { ) -> Result<(),()> {
@ -583,25 +605,25 @@ fn parse_term<'a>(
// resolve word to either a function, parameter or variable // resolve word to either a function, parameter or variable
Token::Word(text, dbginf) => { Token::Word(text, dbginf) => {
// test for function // 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)); op_stack.push(Token::Func(text, *dbginf));
continue; continue;
// test for function parameter // test for function parameter
} else if scope.is_arg(text) { } else if self.scope.is_arg(text, &self.declrs) {
value_stack.push(scope.get_arg_type(text)); value_stack.push(self.scope.get_arg_type(text, &self.declrs));
output.push_back(Token::Arg(text, *dbginf)); output.push_back(Token::Arg(text, *dbginf));
continue; continue;
// test for variable in scope // test for variable in scope
} else if scope.is_var(text).is_some() { } else if self.scope.is_var(text).is_some() {
value_stack.push(scope.get_var_type(text)); value_stack.push(self.scope.get_var_type(text));
output.push_back(Token::Var(text, *dbginf)); output.push_back(Token::Var(text, *dbginf));
continue; continue;
} }
// word was not reolved to anything // word was not reolved to anything
diagnostics.set_err(&token, crate::msg::ERR62, ""); diagnostics.set_err(&token, crate::msg::ERR62, "");
return Err(()); return Err(());
} }
Token::Bool(_, _) => { Token::Bool(_, _) => {
output.push_back(token); output.push_back(token);
@ -610,6 +632,10 @@ fn parse_term<'a>(
Token::Number(_, hint, _) => { Token::Number(_, hint, _) => {
output.push_back(token.clone()); output.push_back(token.clone());
value_stack.push(Prim::Num(*hint)) value_stack.push(Prim::Num(*hint))
},
Token::String(_, _) => {
output.push_back(token.clone());
value_stack.push(Prim::Str)
} }
Token::Assign(_, _, _) => { Token::Assign(_, _, _) => {
op_stack.push(token); op_stack.push(token);
@ -617,7 +643,7 @@ fn parse_term<'a>(
Token::Label(_, _) => output.push_back(token), Token::Label(_, _) => output.push_back(token),
Token::Keyword(key, _) => { Token::Keyword(key, _) => {
match key { match key {
Keyword::Unless => (), Keyword::While => output.push_back(Token::LoopStart),
_ => () _ => ()
} }
op_stack.push(token) op_stack.push(token)
@ -634,10 +660,8 @@ fn parse_term<'a>(
match &next { match &next {
Token::Func(_, _) => { Token::Func(_, _) => {
let mut token = op_stack.pop().unwrap(); let mut token = op_stack.pop().unwrap();
collapse_operation( self.collapse_operation(
&mut token, &mut token,
declrs,
scope,
&mut value_stack, &mut value_stack,
diagnostics, diagnostics,
)?; )?;
@ -650,10 +674,8 @@ fn parse_term<'a>(
} }
} }
_ => { _ => {
collapse_operation( self.collapse_operation(
&mut token, &mut token,
declrs,
scope,
&mut value_stack, &mut value_stack,
diagnostics, diagnostics,
)?; )?;
@ -662,11 +684,11 @@ fn parse_term<'a>(
} }
} }
diagnostics.set_err(&token, crate::msg::ERR64, ""); diagnostics.set_err(&token, crate::msg::ERR64, "");
return Err(()); return Err(());
} }
_ => { _ => {
diagnostics.set_err(&token, crate::msg::ERR65, ""); diagnostics.set_err(&token, crate::msg::ERR65, "");
return Err(()); return Err(());
} }
}, },
@ -678,10 +700,8 @@ fn parse_term<'a>(
let prec1 = op1.prec(); let prec1 = op1.prec();
if prec1 > prec0 || prec0 == prec1 && op.assoc() == Assoc::Left { if prec1 > prec0 || prec0 == prec1 && op.assoc() == Assoc::Left {
collapse_operation( self.collapse_operation(
&mut top, &mut top,
declrs,
scope,
&mut value_stack, &mut value_stack,
diagnostics, 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) output.push_back(token)
} }
} }
@ -720,18 +740,18 @@ fn parse_term<'a>(
return Err(()); return Err(());
} }
scope.expr_yield = value_stack.len() == 1; self.scope.expr_yield = value_stack.len() == 1;
if scope.expr_yield { if self.scope.expr_yield {
let yielded = value_stack.pop().unwrap(); 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( diagnostics.set_err(
&output[0], &output[0],
crate::msg::ERR59, crate::msg::ERR59,
format!( format!(
"expected {:?} got {:?}", "expected {:?} got {:?}",
scope.func_return_typ.unwrap(), self.declrs[self.scope.declr].result_typ.unwrap(),
yielded yielded
), ),
); );
@ -744,7 +764,7 @@ fn parse_term<'a>(
Ok(()) Ok(())
} }
fn is_func(declrs: &[Declr], text: &str) -> bool { fn is_func(&self, declrs: &[Declr], text: &str) -> bool {
for declr in declrs { for declr in declrs {
if declr.name.is_some() && declr.name.unwrap() == text { if declr.name.is_some() && declr.name.unwrap() == text {
return true; return true;
@ -753,51 +773,55 @@ fn is_func(declrs: &[Declr], text: &str) -> bool {
return false; return false;
} }
fn parse_block<'a>( fn parse_block(
&mut self,
block: &mut Block<'a>, block: &mut Block<'a>,
declrs: &Vec<Declr<'a>>,
scope: &mut Scope,
diagnostics: &mut data::Diagnostics, diagnostics: &mut data::Diagnostics,
) -> Result<(), ()> { ) -> Result<(), ()> {
scope.cond_count += 1; self.scope.cond_count += 1;
scope.alloc_scope(); self.scope.alloc_scope();
for expr in block.iter_mut() { for expr in block.iter_mut() {
match expr { match expr {
Expr::Block(block) => parse_block(block, declrs, scope, diagnostics)?, Expr::Block(block) => self.parse_block(block, diagnostics)?,
Expr::Term(term) => parse_term(term, declrs, scope, diagnostics)?, Expr::Term(term) => self.parse_term(term, diagnostics)?,
} }
} }
scope.pop_scope(); self.scope.pop_scope();
scope.cond_count -= 1; self.scope.cond_count -= 1;
Ok(()) Ok(())
} }
fn parse_exprs<'a>( fn parse_exprs(
funcs: &mut Vec<Func<'a>>, &mut self,
declrs: &Vec<Declr<'a>>,
diagnostics: &mut data::Diagnostics, diagnostics: &mut data::Diagnostics,
) -> Result<(),()> { ) -> Result<(),()> {
let mut scope = Scope::new();
for (x, func) in funcs.iter_mut().enumerate() { for x in 0..self.funcs.len() {
match func.expr.as_mut().expect("Function has no body") { 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) => { Expr::Block(block) => {
scope.args = declrs[x].args.as_ref(); block.clone()
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(());
}
} }
_ => { _ => {
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!(); 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(()) Ok(())
@ -806,16 +830,17 @@ fn parse_exprs<'a>(
/// reorder and organize a listing of instructions to a RPN based format: /// reorder and organize a listing of instructions to a RPN based format:
/// any program is made out of functions. /// 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. /// 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)?; self.discover_exprs(diagnostics)?;
parse_exprs(&mut funcs, &declrs, diagnostics)?; self.parse_exprs(diagnostics)?;
if settings.gen_erpn() { 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::DebugMsg;
use crate::token::MessageType::Error; use crate::token::MessageType::Error;
use crate::token::MessageType::Info; use crate::token::MessageType::Info;
//use crate::token::MessageType::Warning;
pub const ERR10: &DebugMsg = &DebugMsg { pub const ERR10: &DebugMsg = &DebugMsg {
typ: Error, typ: Error,

View File

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

View File

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

View File

@ -1,7 +1,13 @@
use std::io::Write; use std::io::Write;
fn print_to_file(file: &mut std::fs::File, prog: &crate::vmrt::Program) -> std::io::Result<()> { 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() { 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)?; writeln!(file, "\n{:#x}:", proc.0)?;
for instr in proc.1.code.iter() { 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(); 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() { 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: main:
Load Int 0 Load Int 0
Store Int x Store Int x
Loop Loop
Loopstart
Load Var x Load Var x
Load Int 4 Load Int 9
Add Int Gt Int
Store Int x While
Load Var x Load Var x
Load Int 16 Load Int 5
Lt Int NotEq Int
Unless Unless
Break Load Var x
Load Var x Load Int 1
Add Int
Store Int x
Continue
Load String ""
Load Var x
Cat Str
Call println
Load Var x
Load Int 1
Add Int
Store Int x
Break
Load Int 0
Yield Yield