allow sasm file execution
This commit is contained in:
parent
cdcb27b91a
commit
de7044cda5
7 changed files with 241 additions and 10 deletions
|
@ -1,5 +1,6 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::sasm::sasm_read;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use crate::{lexer, runtime::*};
|
use crate::{lexer, runtime::*};
|
||||||
|
|
||||||
|
@ -248,6 +249,39 @@ pub fn dyn_readf(stack: &mut Stack) -> OError {
|
||||||
Ok(())
|
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 {
|
pub fn dyn_catch(stack: &mut Stack) -> OError {
|
||||||
require_on_stack!(ctch, Func, stack, "dyn-catch");
|
require_on_stack!(ctch, Func, stack, "dyn-catch");
|
||||||
require_on_stack!(blk, 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<Frame>) {
|
pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
||||||
type Fn = fn(&mut Stack) -> OError;
|
type Fn = fn(&mut Stack) -> OError;
|
||||||
let fns: [(&str, Fn, u32); 17] = [
|
let fns: [(&str, Fn, u32); 19] = [
|
||||||
("dyn-__dump", dyn_dump, 0),
|
("dyn-__dump", dyn_dump, 0),
|
||||||
("dyn-def", dyn_def, 0),
|
("dyn-def", dyn_def, 0),
|
||||||
("dyn-func", dyn_func, 0),
|
("dyn-func", dyn_func, 0),
|
||||||
|
@ -296,6 +330,8 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
|
||||||
("dyn-all-types", dyn_all_types, 1),
|
("dyn-all-types", dyn_all_types, 1),
|
||||||
("dyn-read", dyn_read, 1),
|
("dyn-read", dyn_read, 1),
|
||||||
("dyn-readf", dyn_readf, 1),
|
("dyn-readf", dyn_readf, 1),
|
||||||
|
("dyn-sasm", dyn_sasm, 1),
|
||||||
|
("dyn-sasmf", dyn_sasmf, 1),
|
||||||
("dyn-catch", dyn_catch, 0),
|
("dyn-catch", dyn_catch, 0),
|
||||||
("dyn-use", dyn_use, 0),
|
("dyn-use", dyn_use, 0),
|
||||||
];
|
];
|
||||||
|
|
|
@ -60,10 +60,10 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, u
|
||||||
words.push(Word::Const(Value::Func(AFunc::new(Func {
|
words.push(Word::Const(Value::Func(AFunc::new(Func {
|
||||||
ret_count: block.0.ok_or(LexerError::FunctionBlockExpected)?,
|
ret_count: block.0.ok_or(LexerError::FunctionBlockExpected)?,
|
||||||
to_call: FuncImpl::SPL(block.1),
|
to_call: FuncImpl::SPL(block.1),
|
||||||
run_as_base: false,
|
|
||||||
origin: Arc::new(Frame::dummy()),
|
origin: Arc::new(Frame::dummy()),
|
||||||
fname: None,
|
fname: None,
|
||||||
name: "dyn".to_owned(),
|
name: "dyn".to_owned(),
|
||||||
|
run_as_base: false,
|
||||||
}))))
|
}))))
|
||||||
}
|
}
|
||||||
"<{" => {
|
"<{" => {
|
||||||
|
|
|
@ -30,6 +30,7 @@ pub mod dyn_fns;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
|
pub mod sasm;
|
||||||
pub mod std_fns;
|
pub mod std_fns;
|
||||||
pub mod stdlib;
|
pub mod stdlib;
|
||||||
pub mod stream;
|
pub mod stream;
|
||||||
|
|
|
@ -669,12 +669,12 @@ pub enum Keyword {
|
||||||
/// <none>
|
/// <none>
|
||||||
///
|
///
|
||||||
/// Used by `object:method <{ arg1 arg2 }` syntax. Generates as:
|
/// Used by `object:method <{ arg1 arg2 }` syntax. Generates as:
|
||||||
/// - CALL object
|
/// - call object
|
||||||
/// - OBJPUSH
|
/// - objpush
|
||||||
/// - CALL arg1
|
/// - call arg1
|
||||||
/// - CALL arg2
|
/// - call arg2
|
||||||
/// - OBJPOP
|
/// - objpop
|
||||||
/// - OBJCALL method
|
/// - objcall method
|
||||||
ObjPush,
|
ObjPush,
|
||||||
/// <none>
|
/// <none>
|
||||||
///
|
///
|
||||||
|
|
182
src/sasm.rs
Normal file
182
src/sasm.rs
Normal file
|
@ -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<Item = &'a str>) -> 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<Word>, lines: &mut impl Iterator<Item = &'a str>) {
|
||||||
|
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]),
|
||||||
|
}
|
||||||
|
}
|
|
@ -638,7 +638,7 @@ pub fn import(stack: &mut Stack) -> OError {
|
||||||
.to_string_lossy())
|
.to_string_lossy())
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
) {
|
) {
|
||||||
stack.push(Value::Str(s).spl());
|
stack.push(Value::Str(s.clone()).spl());
|
||||||
dup(stack)?;
|
dup(stack)?;
|
||||||
read_file(stack).or_else(|x| {
|
read_file(stack).or_else(|x| {
|
||||||
if let Some(fallback) = fallback {
|
if let Some(fallback) = fallback {
|
||||||
|
@ -648,7 +648,11 @@ pub fn import(stack: &mut Stack) -> OError {
|
||||||
Err(x)
|
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)?;
|
call(stack)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
8
test.sasm
Normal file
8
test.sasm
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
func main 1
|
||||||
|
with args
|
||||||
|
const str HW
|
||||||
|
Hello, world!
|
||||||
|
end HW
|
||||||
|
call println
|
||||||
|
const mega 3
|
||||||
|
end
|
Loading…
Add table
Reference in a new issue