finished yard
This commit is contained in:
parent
ba0d6837f3
commit
a506f51f71
53
prog.vsasm
53
prog.vsasm
|
@ -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
|
||||||
|
|
|
@ -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 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 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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 function name
|
||||||
|
write!(&mut file, "{}:\n", parser.declrs[x].name.unwrap()).unwrap();
|
||||||
|
|
||||||
|
if !func.is_builtin {
|
||||||
// write down function body
|
// write down function body
|
||||||
write_expr(&mut file, &mut indent, func.expr.as_ref().unwrap());
|
write_expr(&mut file, &mut indent, func.expr.as_ref().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
writeln!(&mut file).unwrap();
|
writeln!(&mut file).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
49
src/main.rs
49
src/main.rs
|
@ -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,33 +26,20 @@ 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;
|
let mut diagnostics = Diagnostics::new(&settings, code);
|
||||||
|
|
||||||
loop {
|
if let Ok(mut tokens) = tokenize(code, &mut diagnostics) {
|
||||||
x = x + 4
|
let specs = crate::direct::resolve_directives(&mut tokens);
|
||||||
|
|
||||||
unless x < 16 {
|
let mut parser = Parser::new(&specs);
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
yield x;
|
if let Ok((funcs, declrs, builtin)) = parser.parse(&mut tokens, &mut diagnostics, &settings) {
|
||||||
}
|
if let Ok(prog) = vmrt::compile(&funcs, &declrs, builtin, &settings) {
|
||||||
";
|
|
||||||
|
|
||||||
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(exit_code) = vmrt::execute(&prog) {
|
if let Ok(exit_code) = vmrt::execute(&prog) {
|
||||||
crate::message(MessageType::Info, format!("Program exited with {}", exit_code));
|
crate::message(MessageType::Info, format!("Program exited with {}", exit_code));
|
||||||
}
|
}
|
||||||
|
@ -56,4 +48,15 @@ main() = int {
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", diagnostics);
|
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::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,
|
||||||
|
|
|
@ -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,7 +48,7 @@ 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,
|
||||||
|
@ -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, "");
|
||||||
|
@ -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 functions.iter_mut() {
|
for func in self.funcs.iter_mut() {
|
||||||
|
if func.is_builtin {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let mut blocks = vec![Block::new()];
|
let mut blocks = vec![Block::new()];
|
||||||
|
|
||||||
let mut expr = VecDeque::new();
|
let mut expr = VecDeque::new();
|
||||||
|
@ -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(
|
||||||
|
@ -412,13 +435,14 @@ fn check_var_typ(
|
||||||
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<(), ()> {
|
||||||
|
@ -444,7 +468,7 @@ fn process_keyword(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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,19 +605,19 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
)?;
|
)?;
|
||||||
|
@ -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 {
|
||||||
Expr::Block(block) => {
|
continue;
|
||||||
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(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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!();
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -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,
|
||||||
|
|
118
src/token/mod.rs
118
src/token/mod.rs
|
@ -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,11 +167,12 @@ 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()));
|
||||||
|
|
165
src/vmrt/mod.rs
165
src/vmrt/mod.rs
|
@ -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,9 +443,24 @@ 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) => {
|
||||||
|
@ -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,13 +501,24 @@ 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() {
|
||||||
|
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 code = vec![];
|
||||||
let mut ct = Compiletime::default();
|
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));
|
.insert(declrs[x].uuid(), create_proc(&declrs[x], code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if settings.gen_vsasm() {
|
if settings.gen_vsasm() {
|
||||||
output::dump_program(&prog);
|
output::dump_program(&prog);
|
||||||
}
|
}
|
||||||
|
@ -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()?);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
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:
|
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
|
||||||
|
Gt Int
|
||||||
|
While
|
||||||
|
Load Var x
|
||||||
|
Load Int 5
|
||||||
|
NotEq Int
|
||||||
|
Unless
|
||||||
|
Load Var x
|
||||||
|
Load Int 1
|
||||||
Add Int
|
Add Int
|
||||||
Store Int x
|
Store Int x
|
||||||
|
Continue
|
||||||
|
Load String ""
|
||||||
Load Var x
|
Load Var x
|
||||||
Load Int 16
|
Cat Str
|
||||||
Lt Int
|
Call println
|
||||||
Unless
|
Load Var x
|
||||||
|
Load Int 1
|
||||||
|
Add Int
|
||||||
|
Store Int x
|
||||||
Break
|
Break
|
||||||
Load Var x
|
Load Int 0
|
||||||
Yield
|
Yield
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue