finished yard
This commit is contained in:
parent
ba0d6837f3
commit
a506f51f71
53
prog.vsasm
53
prog.vsasm
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
49
src/main.rs
49
src/main.rs
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
118
src/token/mod.rs
118
src/token/mod.rs
|
@ -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()));
|
||||
|
|
165
src/vmrt/mod.rs
165
src/vmrt/mod.rs
|
@ -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()?);
|
||||
}
|
||||
|
||||
|
|
|
@ -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!();
|
||||
}
|
||||
}
|
||||
|
|
49
test.erpn
49
test.erpn
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue