diff --git a/assemble.spl b/assemble.spl new file mode 100644 index 0000000..9c17c9e --- /dev/null +++ b/assemble.spl @@ -0,0 +1,5 @@ + +func main { mega | with args ; + 2 args:get write-file-sasm println + 0 +} diff --git a/echo.spl b/echo.spl new file mode 100644 index 0000000..b9b661e --- /dev/null +++ b/echo.spl @@ -0,0 +1,9 @@ +func main { mega | with args ; + 2 args:iter:skip =args + { | with item ; + item print + " " print + } args:foreach + "\n" print + 0 exit +} diff --git a/src/lexer.rs b/src/lexer.rs index aecc6ba..b5f1208 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -62,6 +62,7 @@ fn read_block(str_words: &[String], isfn: bool) -> Result<(Option, Words, u return Err(LexerError::FunctionBlockExpected); } } + // lambda "{" => { let block = read_block(&str_words[i..], true)?; i += block.2; diff --git a/src/sasm.rs b/src/sasm.rs index 3bbc7b9..a62b977 100644 --- a/src/sasm.rs +++ b/src/sasm.rs @@ -1,6 +1,6 @@ -use std::sync::Arc; +use std::{sync::Arc, time::SystemTime}; -use crate::{Frame, Func, FuncImpl, Keyword, Value, Word, Words}; +use crate::{Frame, Func, FuncImpl, FuncImplType, Keyword, Value, Word, Words}; /// Reads sasm, the text representation of an SPL AST. pub fn sasm_read(s: String) -> Words { @@ -62,7 +62,7 @@ fn sasm_parse<'a>(line: &str, words: &mut Vec, lines: &mut impl Iterator false, - Some(x) => (|x| x == "namespace")(x), + Some(x) => x == "namespace", }, ))) } @@ -86,6 +86,33 @@ fn sasm_parse<'a>(line: &str, words: &mut Vec, lines: &mut impl Iterator words.push(Word::Key(Keyword::ObjPush)), "objpop" => words.push(Word::Key(Keyword::ObjPop)), + "func_of_Rust" => { + // output += &format!( + // "func_of_{kind:?} {name} {t}\0\0{}\0\0end {t}\n", + // content.replace("\0", "\0\x01").replace("\n", "\0\0") + // ); + let name = line[1]; + 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::Key(Keyword::FuncOf( + name.to_owned(), + s, + FuncImplType::Rust, + ))); + } // main words "const" => match line[1] { "str" => { @@ -181,3 +208,172 @@ fn sasm_parse<'a>(line: &str, words: &mut Vec, lines: &mut impl Iterator panic!("invalid sasm instruction: {}", line[0]), } } + +pub fn sasm_write(words: Words) -> String { + sasm_write_func(words) + .replace("\0\0", "\n") + .replace("\0\x01", "\0") +} + +fn sasm_write_func(words: Words) -> String { + let mut output = String::new(); + for word in words.words { + match word { + Word::Key(word) => match word { + Keyword::Dump => { + output += "dump\n"; + } + Keyword::Def(x) => { + output += "def "; + output += &x; + output += "\n"; + } + Keyword::Func(name, returns, text) => { + output += &format!("func {name} {returns}\n\t"); + let text = sasm_write_func(text).replace("\n", "\n\t"); + let text = text.trim_end(); + output += &text; + output += "\nend\n"; + } + Keyword::Construct(name, vars, methods, is_namespace) => { + output += &format!("construct {name} "); + for var in vars { + output += &var; + output += " "; + } + output += ";"; + for method in &methods { + output += " "; + output += &method.0; + output += " "; + output += &method.1 .0.to_string(); + } + if is_namespace { + output += " ; namespace"; + } + output += "\n"; + for method in methods { + output += "\t"; + output += &sasm_write_func(method.1 .1) + .replace("\n", "\n\t") + .trim_end(); + output += "\nend\n"; + } + } + Keyword::Include(type_to_include, t) => { + output += &format!("include {type_to_include} {t}\n"); + } + Keyword::Use(path) => output += &format!("use {path}\n"), + Keyword::While(cond, blk) => { + output += "while\n\t"; + output += &sasm_write_func(cond).replace("\n", "\n\t").trim_end(); + output += "\nend\n\t"; + output += &sasm_write_func(blk).replace("\n", "\n\t").trim_end(); + output += "\nend\n"; + } + Keyword::If(blk) => { + output += "if\n\t"; + output += &sasm_write_func(blk).replace("\n", "\n\t").trim_end(); + output += "\nend\n"; + } + Keyword::With(items) => { + output += "with"; + for item in items { + output += " "; + output += &item; + } + output += "\n"; + } + Keyword::Catch(kinds, blk, ctch) => { + output += "catch"; + for kind in kinds { + output += " "; + output += &kind; + } + output += "\n\t"; + output += &sasm_write_func(blk).replace("\n", "\n\t").trim_end(); + output += "\nend\n\t"; + output += &sasm_write_func(ctch).replace("\n", "\n\t").trim_end(); + output += "\nend\n"; + } + Keyword::ObjPush => output += "objpush\n", + Keyword::ObjPop => output += "objpop\n", + Keyword::FuncOf(name, content, kind) => { + fn time() -> String { + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_micros() + .to_string() + } + let mut t = time(); + while content.contains(&t) { + t = time(); + } + output += &format!( + "func_of_{kind:?} {name} {t}\0\0{}\0\0end {t}\n", + content.replace("\0", "\0\x01").replace("\n", "\0\0") + ); + } + }, + Word::Const(item) => match item { + Value::Null => output += "const null\n", + Value::Int(x) => output += &format!("const int {x}\n"), + Value::Long(x) => output += &format!("const long {x}\n"), + Value::Mega(x) => output += &format!("const mega {x}\n"), + Value::Float(x) => output += &format!("const float {x}\n"), + Value::Double(x) => output += &format!("const double {x}\n"), + Value::Func(x) => { + let text = match &x.to_call { + FuncImpl::Native(_) => panic!("sasm can't write native function"), + FuncImpl::NativeDyn(_) => panic!("sasm can't write native function"), + FuncImpl::SPL(x) => sasm_write_func(x.clone()).replace("\n", "\n\t"), + }; + let text = text.trim_end(); + output += &format!("const func {}\n\t{}\nend\n", x.ret_count, text); + } + Value::Array(_) => panic!("sasm can't write arrays"), + Value::Str(text) => { + fn time() -> String { + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_micros() + .to_string() + } + let mut t = time(); + while text.contains(&t) { + t = time(); + } + output += &format!( + "const str {t}\0\0{}\0\0end {t}\n", + text.replace("\0", "\0\x01").replace("\n", "\0\0") + ); + } + }, + Word::Call(name, rem, ra) => { + output += "call "; + output += &name; + if rem { + output += " pop"; + } + for _ in 0..ra { + output += " ref"; + } + output += "\n"; + } + Word::ObjCall(name, rem, ra) => { + output += "objcall "; + output += &name; + if rem { + output += " pop"; + } + for _ in 0..ra { + output += " ref"; + } + output += "\n"; + } + } + } + output +} diff --git a/src/std_fns.rs b/src/std_fns.rs index 088c85f..d001e5e 100644 --- a/src/std_fns.rs +++ b/src/std_fns.rs @@ -9,7 +9,7 @@ use std::{ sync::Arc, }; -use crate::{dyn_fns, mutex::Mut, runtime::*, *}; +use crate::{dyn_fns, mutex::Mut, runtime::*, sasm::sasm_write, *}; #[macro_export] macro_rules! type_err { @@ -803,9 +803,37 @@ pub fn throw(stack: &mut Stack) -> OError { stack.err(ErrorKind::CustomObject(obj)) } +pub fn write_sasm(stack: &mut Stack) -> OError { + require_on_stack!(code, Str, stack, "write-sasm"); + stack.push( + Value::Str( + lexer::lex(code) + .map(|x| sasm_write(x)) + .map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?, + ) + .spl(), + ); + Ok(()) +} + +pub fn write_file_sasm(stack: &mut Stack) -> OError { + require_on_stack!(file, Str, stack, "write-file-sasm"); + stack.push( + Value::Str( + lexer::lex( + fs::read_to_string(file).map_err(|x| stack.error(ErrorKind::IO(x.to_string())))?, + ) + .map(|x| sasm_write(x)) + .map_err(|x| stack.error(ErrorKind::LexError(format!("{x:?}"))))?, + ) + .spl(), + ); + Ok(()) +} + pub fn register(r: &mut Stack, o: Arc) { type Fn = fn(&mut Stack) -> OError; - let fns: [(&str, Fn, u32); 51] = [ + let fns: [(&str, Fn, u32); 53] = [ ("pop", pop, 0), ("dup", dup, 2), ("clone", clone, 1), @@ -857,6 +885,8 @@ pub fn register(r: &mut Stack, o: Arc) { ("bytes-to-str", bytes_to_str, 1), ("acopy", acopy, 1), ("throw", throw, 0), + ("write-sasm", write_sasm, 1), + ("write-file-sasm", write_file_sasm, 1), ]; for f in fns { r.define_func( diff --git a/std.spl b/std.spl index 5d11e69..6778f4a 100644 --- a/std.spl +++ b/std.spl @@ -133,6 +133,31 @@ construct _array-ext { } } include _array-ext in array +construct _func-ext { + args + ; + call { | with this ; + this:args null eq if { + 0 anew this:=args + } + this:args:to-stack this call + } + add-args { this | with args this ; + this:args null eq if { + 0 anew this:=args + } + [ this:args:to-stack args:to-stack ] this:=args + this + } + add-arg { this | with arg this ; + this:args null eq if { + 0 anew this:=args + } + [ this:args:to-stack arg ] this:=args + this + } +} include _func-ext in func + "#iter.spl" import construct List {