diff --git a/src/dyn_fns.rs b/src/dyn_fns.rs index 35d0c43..5a041c1 100644 --- a/src/dyn_fns.rs +++ b/src/dyn_fns.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use crate::sasm::sasm_read; use crate::*; use crate::{lexer, runtime::*}; @@ -248,6 +249,39 @@ pub fn dyn_readf(stack: &mut Stack) -> OError { Ok(()) } +pub fn dyn_sasm(stack: &mut Stack) -> OError { + require_on_stack!(sasm, Str, stack, "dyn-sasm"); + stack.push( + Value::Func(AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::SPL(sasm_read(sasm)), + origin: stack.get_frame(), + fname: None, + name: "(dyn-read)".to_owned(), + run_as_base: false, + })) + .spl(), + ); + Ok(()) +} + +pub fn dyn_sasmf(stack: &mut Stack) -> OError { + require_on_stack!(sasm, Str, stack, "dyn-sasmf"); + require_on_stack!(n, Str, stack, "dyn-sasmf"); + stack.push( + Value::Func(AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::SPL(sasm_read(sasm)), + origin: stack.get_frame(), + fname: Some(n), + name: "root".to_owned(), + run_as_base: true, + })) + .spl(), + ); + Ok(()) +} + pub fn dyn_catch(stack: &mut Stack) -> OError { require_on_stack!(ctch, Func, stack, "dyn-catch"); require_on_stack!(blk, Func, stack, "dyn-catch"); @@ -280,7 +314,7 @@ pub(crate) fn wrap(f: fn(&mut Stack) -> OError) -> impl Fn(&mut Stack) -> OError pub fn register(r: &mut Stack, o: Arc) { type Fn = fn(&mut Stack) -> OError; - let fns: [(&str, Fn, u32); 17] = [ + let fns: [(&str, Fn, u32); 19] = [ ("dyn-__dump", dyn_dump, 0), ("dyn-def", dyn_def, 0), ("dyn-func", dyn_func, 0), @@ -296,6 +330,8 @@ pub fn register(r: &mut Stack, o: Arc) { ("dyn-all-types", dyn_all_types, 1), ("dyn-read", dyn_read, 1), ("dyn-readf", dyn_readf, 1), + ("dyn-sasm", dyn_sasm, 1), + ("dyn-sasmf", dyn_sasmf, 1), ("dyn-catch", dyn_catch, 0), ("dyn-use", dyn_use, 0), ]; diff --git a/src/lexer.rs b/src/lexer.rs index 2633fd1..9e87a6b 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -60,10 +60,10 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option, Words, u words.push(Word::Const(Value::Func(AFunc::new(Func { ret_count: block.0.ok_or(LexerError::FunctionBlockExpected)?, to_call: FuncImpl::SPL(block.1), - run_as_base: false, origin: Arc::new(Frame::dummy()), fname: None, name: "dyn".to_owned(), + run_as_base: false, })))) } "<{" => { diff --git a/src/lib.rs b/src/lib.rs index 54a26b8..9679a97 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ pub mod dyn_fns; pub mod lexer; pub mod mutex; pub mod runtime; +pub mod sasm; pub mod std_fns; pub mod stdlib; pub mod stream; diff --git a/src/runtime.rs b/src/runtime.rs index 07b06ae..cb5049e 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -669,12 +669,12 @@ pub enum Keyword { /// /// /// Used by `object:method <{ arg1 arg2 }` syntax. Generates as: - /// - CALL object - /// - OBJPUSH - /// - CALL arg1 - /// - CALL arg2 - /// - OBJPOP - /// - OBJCALL method + /// - call object + /// - objpush + /// - call arg1 + /// - call arg2 + /// - objpop + /// - objcall method ObjPush, /// /// diff --git a/src/sasm.rs b/src/sasm.rs new file mode 100644 index 0000000..430c67f --- /dev/null +++ b/src/sasm.rs @@ -0,0 +1,182 @@ +use std::sync::Arc; + +use crate::{Frame, Func, FuncImpl, Keyword, Value, Word, Words}; + +/// Reads sasm, the text representation of an SPL AST. +pub fn sasm_read(s: String) -> Words { + let mut lines = s.split("\n"); + sasm_read_func(&mut lines) +} + +pub fn sasm_read_func<'a>(lines: &mut impl Iterator) -> Words { + let mut words = Vec::new(); + while let Some(line) = lines.next() { + if line == "end" { + break; + } + sasm_parse(line, &mut words, lines); + } + Words::new(words) +} + +fn sasm_parse<'a>(line: &str, words: &mut Vec, lines: &mut impl Iterator) { + let line: Vec<_> = line.trim_start().split(" ").collect(); + match line[0] { + "dump" => words.push(Word::Key(Keyword::Dump)), + "def" => words.push(Word::Key(Keyword::Def(line[1].to_owned()))), + "func" => words.push(Word::Key(Keyword::Func( + line[1].to_owned(), + line[2].parse().expect("invalid sasm func: func ... NAN"), + sasm_read_func(lines), + ))), + "construct" => { + let name = line[1].to_owned(); + let mut fields = Vec::new(); + let mut methods = Vec::new(); + let mut iter = line.into_iter().skip(2); + for word in &mut iter { + if word == ";" { + break; + } + fields.push(word.to_owned()); + } + while let Some(word) = iter.next() { + if word == ";" { + break; + } + methods.push(( + word.to_owned(), + ( + iter.next() + .map(|x| x.parse().ok()) + .flatten() + .expect("invalid sasm construct: construct .... ; ... NAN ...."), + sasm_read_func(lines), + ), + )); + } + words.push(Word::Key(Keyword::Construct( + name, + fields, + methods, + match iter.next() { + None => false, + Some(x) => (|x| x == "namespace")(x), + }, + ))) + } + "include" => words.push(Word::Key(Keyword::Include( + line[1].to_owned(), + line[2].to_owned(), + ))), + "use" => words.push(Word::Key(Keyword::Use(line[1].to_owned()))), + "while" => words.push(Word::Key(Keyword::While( + sasm_read_func(lines), + sasm_read_func(lines), + ))), + "if" => words.push(Word::Key(Keyword::If(sasm_read_func(lines)))), + "with" => words.push(Word::Key(Keyword::With( + line.into_iter().skip(1).map(ToOwned::to_owned).collect(), + ))), + "catch" => words.push(Word::Key(Keyword::Catch( + line.into_iter().skip(1).map(ToOwned::to_owned).collect(), + sasm_read_func(lines), + sasm_read_func(lines), + ))), + "objpush" => words.push(Word::Key(Keyword::ObjPush)), + "objpop" => words.push(Word::Key(Keyword::ObjPop)), + // main words + "const" => match line[1] { + "str" => { + let marker = line[2]; + let mut s = String::new(); + let mut line; + while ( + line = lines.next().expect("sasm string without end marker"), + line, + ) + .1 + != "end ".to_owned() + marker + { + s = s + line + "\n"; + } + if let Some(l) = s.strip_suffix("\n") { + s = l.to_owned(); + } + words.push(Word::Const(Value::Str(s))); + } + "int" => { + words.push(Word::Const(Value::Int( + line[2].parse().expect("invalid sasm const: const int NAN"), + ))); + } + "long" => { + words.push(Word::Const(Value::Long( + line[2].parse().expect("invalid sasm const: const long NAN"), + ))); + } + "mega" => { + words.push(Word::Const(Value::Mega( + line[2].parse().expect("invalid sasm const: const mega NAN"), + ))); + } + "float" => { + words.push(Word::Const(Value::Float( + line[2] + .parse() + .expect("invalid sasm const: const float NAN"), + ))); + } + "double" => { + words.push(Word::Const(Value::Double( + line[2] + .parse() + .expect("invalid sasm const: const double NAN"), + ))); + } + "func" => words.push(Word::Const(Value::Func(Arc::new(Func { + ret_count: line[2].parse().expect("invalid sasm const: const fun NAN"), + to_call: FuncImpl::SPL(sasm_read_func(lines)), + origin: Arc::new(Frame::dummy()), + fname: None, + name: "dyn".to_owned(), + run_as_base: false, + })))), + "null" => words.push(Word::Const(Value::Null)), + "array" => panic!("invalid sasm const: array - not all Values can be consts!"), + _ => panic!("invalid sasm const: {}", line[1]), + }, + "call" => { + let name = line[1].to_owned(); + let mut rem = false; + let mut ra = 0; + for word in line.into_iter().skip(2) { + if word == "pop" { + rem = true; + } else if word == "ref" { + ra += 1; + } else { + panic!("invalid sasm call: words after name must be either `pop` or `ref`"); + } + } + words.push(Word::Call(name, rem, ra)); + } + "objcall" => { + let name = line[1].to_owned(); + let mut rem = false; + let mut ra = 0; + for word in line.into_iter().skip(2) { + if word == "pop" { + rem = true; + } else if word == "ref" { + ra += 1; + } else { + panic!("invalid sasm objcall: words after name must be either `pop` or `ref`"); + } + } + words.push(Word::ObjCall(name, rem, ra)); + } + "" => {} + _ => panic!("invalid sasm instruction: {}", line[0]), + } +} diff --git a/src/std_fns.rs b/src/std_fns.rs index 8835ad9..980151b 100644 --- a/src/std_fns.rs +++ b/src/std_fns.rs @@ -638,7 +638,7 @@ pub fn import(stack: &mut Stack) -> OError { .to_string_lossy()) .to_owned(), ) { - stack.push(Value::Str(s).spl()); + stack.push(Value::Str(s.clone()).spl()); dup(stack)?; read_file(stack).or_else(|x| { if let Some(fallback) = fallback { @@ -648,7 +648,11 @@ pub fn import(stack: &mut Stack) -> OError { Err(x) } })?; - dyn_fns::wrap(dyn_fns::dyn_readf)(stack)?; + dyn_fns::wrap(if s.ends_with(".sasm") { + dyn_fns::dyn_sasmf + } else { + dyn_fns::dyn_readf + })(stack)?; call(stack)?; } Ok(()) diff --git a/test.sasm b/test.sasm new file mode 100644 index 0000000..212985a --- /dev/null +++ b/test.sasm @@ -0,0 +1,8 @@ +func main 1 + with args + const str HW +Hello, world! +end HW + call println + const mega 3 +end