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