allow sasm file execution

This commit is contained in:
Daniella 2023-04-08 20:12:35 +02:00
parent cdcb27b91a
commit de7044cda5
Signed by: TudbuT
GPG key ID: 7D63D5634B7C417F
7 changed files with 241 additions and 10 deletions

View file

@ -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<Frame>) {
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<Frame>) {
("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),
];

View file

@ -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 {
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,
}))))
}
"<{" => {

View file

@ -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;

View file

@ -669,12 +669,12 @@ pub enum Keyword {
/// <none>
///
/// 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,
/// <none>
///

182
src/sasm.rs Normal file
View 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]),
}
}

View file

@ -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(())

8
test.sasm Normal file
View file

@ -0,0 +1,8 @@
func main 1
with args
const str HW
Hello, world!
end HW
call println
const mega 3
end