improve speed, add time.spl, improve isbpl.spl, add inlining support

This commit is contained in:
Daniella / Tove 2024-09-09 14:37:56 +02:00
parent 6d78b276d4
commit a1f5941c1a
11 changed files with 230 additions and 32 deletions

61
benchmark.spl Normal file
View file

@ -0,0 +1,61 @@
"#time.spl" import
func main { mega | with args ;
def begin
def end
"[-] spl benchmark v0.1.0" println
"[0] benchmarking while loop with variable 0..100000" println
"==> bgin at " print unixms dup =begin println
def i 0 =i
while { i 100000 lt } {
i ++ =i
}
"==> done at " print unixms dup =end println
"==> in " print end begin - println
"[1] benchmarking foreach on 100000" println
"==> bgin at " print unixms dup =begin println
{ | pop } 100000 :foreach
"==> done at " print unixms dup =end println
"==> in " print end begin - println
"[2] benchmarking fast foreach on 100000" println
"==> bgin at " print unixms dup =begin println
{ | pop } 100000 :fforeach
"==> done at " print unixms dup =end println
"==> in " print end begin - println
"[3] benchmarking foreach on Range 100000..200000" println
"==> bgin at " print unixms dup =begin println
100000 200000 Range:new
:iter
:foreach <{ | with i ; }>
"==> done at " print unixms dup =end println
"==> in " print end begin - println
"[4] benchmarking manual multiply of 100000 x 5" println
"==> bgin at " print unixms dup =begin println
def i 0 =i
def n 0 =n
while { i 100000 lt } {
i ++ =i
n 5 + =n
}
" -> n = " print n println
"==> done at " print unixms dup =end println
"==> in " print end begin - println
"[5] benchmarking 10000 array adds" println
"==> bgin at " print unixms dup =begin println
def i 0 =i
def arr 0 anew =arr
while { i 10000 lt } {
i awrap arr aadd =arr
i ++ =i
}
"==> done at " print unixms dup =end println
"==> in " print end begin - println
0
}

View file

@ -1,3 +1,4 @@
"#time.spl" import
native engage-compatibility-mode
func # { pop }
func puts { print }
@ -5,6 +6,8 @@ func fcall { call }
func strconcat { concat }
func aget { swap :get }
func stoi { _mega }
func stol { _mega }
func _int { _mega }
func itos { _str }
def argv'pre-isbplmod &argv =argv'pre-isbplmod
func argv {
@ -13,6 +16,17 @@ func argv {
args nargs 2 0 nargs:len acopy
nargs
}
func eputs {
print
}
func isbplmod'import-transform { with s ;
"spl: [compat] transforming import " s concat println
s:_char "#" :_char eq if {
"#nop.spl" =s
}
"spl: [compat] transformed to " s concat println
s
}
func inc {
"isbpl.spl: ISBPL code tried to call inc, an untranslatable function" println
pop
@ -21,3 +35,8 @@ func dec {
"isbpl.spl: ISBPL code tried to call inc, an untranslatable function" println
pop
}
func getms {
0 time
}
func main { }

View file

@ -11,10 +11,11 @@ construct _Iter {
arr
}
foreach { | with callable this ;
def itm
while { this:next dup =itm null eq not } {
itm callable call
!!-
while { !!- this:next dup null eq not } {
!!- callable call
}
pop
}
collect { array | with this ;
[ { any | } this:foreach ]

View file

@ -3,7 +3,7 @@ mod compat;
use std::{mem, sync::Arc};
use crate::runtime::*;
use compat::match_compat;
use compat::{match_compat, transform_compat};
use readformat::*;
#[derive(Debug, PartialEq, Eq)]
@ -57,7 +57,11 @@ fn read_block_dyn(
rem = Some(r as u32);
}
while i < str_words.len() {
let word = str_words[i].to_owned();
let word = if !compat {
str_words[i].to_owned()
} else {
transform_compat(&str_words[i])
};
if compat && match_compat(word.to_owned(), str_words, &mut words, &mut i) {
continue;
}
@ -236,6 +240,15 @@ fn read_block_dyn(
}
words.push(Word::Key(Keyword::With(vars)));
}
"inline-callable" => {
words.push(Word::Key(Keyword::InlineCallable));
}
"!!-" => {
words.push(Word::Key(Keyword::InlineStart));
}
"-!!" => {
words.push(Word::Key(Keyword::InlineEnd));
}
x if x == endword => {
break;
}

View file

@ -1,5 +1,12 @@
use crate::Word;
pub(crate) fn transform_compat(word: &str) -> String {
match word {
"try" => "catch".to_owned(),
_ => word.to_owned(),
}
}
pub(crate) fn match_compat(
word: String,
str_words: &[String],
@ -15,6 +22,7 @@ pub(crate) fn match_compat(
true
}
"dec" => {
eprintln!("spl: [compat] transforming dec call");
eprintln!("spl: [compat] transforming dec call");
words.push(Word::Call("--".to_owned(), false, 0));
words.push(Word::Call("=".to_owned() + &str_words[*i - 1], false, 0));
@ -22,8 +30,9 @@ pub(crate) fn match_compat(
true
}
"include" => {
// TODO: translate some stdlib components?
words.push(Word::Call("isbplmod'import-transform".to_owned(), false, 0));
words.push(Word::Call("import".to_owned(), false, 0));
*i += 1;
true
}
_ => false,

View file

@ -470,6 +470,11 @@ impl Stack {
r
}
pub fn fast_call(&mut self, func: &AFunc) -> OError {
let r = func.to_call.call(self);
r
}
pub fn get_func(&self, name: String) -> Result<AFunc, Error> {
let mut frame = self.frames.last().unwrap();
loop {
@ -649,6 +654,21 @@ pub enum Keyword {
/// equivalent to dyn-__dump
/// example: func main { int | "Hello, world!" dyn-__dump pop 0 }
Dump,
/// inline-call
///
/// Inlines a callable into the current function
/// equivalent to call
InlineCallable,
/// !!-
///
/// Makes future calls inline, not adding a new stack frame
/// no equivalent
InlineStart,
/// -!!
///
/// Stops making calls inline
/// no equivalent
InlineEnd,
/// def <name>
///
/// Defines a variable.
@ -1144,20 +1164,35 @@ impl Words {
/// Executes the words. This does *not* create a new frame on the stack. Use [Stack::call] to
/// call and create a new frame.
pub fn exec(&self, stack: &mut Stack) -> OError {
for word in self.words.clone() {
let mut inline_calls = false;
for word in self.words.iter() {
match word {
Word::Key(x) => match x {
Keyword::Dump => println!("{stack}"),
Keyword::Def(x) => stack.define_var(x),
Keyword::InlineCallable => {
let Value::Func(f) = stack.pop().lock_ro().native.clone() else {
return Err(
stack.error(ErrorKind::InvalidCall("inline-callable".to_owned()))
);
};
stack.fast_call(&f)?;
}
Keyword::InlineStart => {
inline_calls = true;
}
Keyword::InlineEnd => {
inline_calls = false;
}
Keyword::Def(x) => stack.define_var(x.to_owned()),
Keyword::Func(name, rem, words) => stack.define_func(
name.clone(),
Arc::new(Func {
ret_count: rem,
to_call: FuncImpl::SPL(words),
ret_count: *rem,
to_call: FuncImpl::SPL(words.to_owned()),
origin: stack.get_frame(),
run_as_base: false,
fname: None,
name,
name: name.to_owned(),
}),
),
Keyword::Construct(name, fields, methods, is_namespace) => {
@ -1168,14 +1203,14 @@ impl Words {
let t = runtime_mut(|mut rt| {
rt.make_type(name.clone(), |mut t| {
for field in fields {
t.add_property(field, origin.clone())?;
t.add_property(field.to_owned(), origin.clone())?;
}
t.functions.extend(methods.into_iter().map(|(k, v)| {
(
k.clone(),
Arc::new(Func {
ret_count: v.0,
to_call: FuncImpl::SPL(v.1),
to_call: FuncImpl::SPL(v.1.to_owned()),
origin: origin.clone(),
run_as_base: false,
fname: None,
@ -1187,7 +1222,7 @@ impl Words {
})
})?;
let to_set: Object = if is_namespace {
let to_set: Object = if *is_namespace {
let mut obj: Object = Value::Null.into();
obj.kind = t.clone();
t.lock_ro().write_into(&mut obj);
@ -1216,13 +1251,14 @@ impl Words {
let rstack = &stack;
runtime(move |rt| {
rt.get_type_by_name(&tb)
.ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(tb)))?
.ok_or_else(|| {
rstack.error(ErrorKind::TypeNotFound(tb.to_owned()))
})?
.lock()
.parents
.push(
rt.get_type_by_name(&ta)
.ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(ta)))?,
);
.push(rt.get_type_by_name(&ta).ok_or_else(|| {
rstack.error(ErrorKind::TypeNotFound(ta.to_owned()))
})?);
Ok(())
})?;
}
@ -1271,7 +1307,7 @@ impl Words {
for var in vars.into_iter().rev() {
stack.define_var(var.clone());
let obj = stack.pop();
stack.set_var(var, obj)?;
stack.set_var(var.to_owned(), obj)?;
}
}
Keyword::ObjPush => {
@ -1295,7 +1331,7 @@ impl Words {
origin: stack.get_frame(),
run_as_base: false,
fname: None,
name,
name: name.to_owned(),
}),
)
}),
@ -1307,6 +1343,7 @@ impl Words {
stack.push(x.clone().ensure_init(stack).spl())
}
Word::Call(x, rem, ra) => {
let ra = *ra;
if option_env!("SPLDEBUG").is_some() {
println!("CALL({}) {x}", stack.len());
}
@ -1332,9 +1369,13 @@ impl Words {
}));
}
stack.push(f.spl());
} else {
if inline_calls {
stack.fast_call(&f)?;
} else {
stack.call(&f)?;
if rem {
}
if *rem {
for _ in 0..f.ret_count {
stack.pop();
}
@ -1342,6 +1383,7 @@ impl Words {
}
}
Word::ObjCall(x, rem, ra) => {
let ra = *ra;
let o = stack.peek();
let o = o.lock_ro();
let f0 = o.kind.lock_ro();
@ -1378,9 +1420,13 @@ impl Words {
}
stack.pop();
stack.push(f.spl())
} else {
if inline_calls {
stack.fast_call(&f)?;
} else {
stack.call(&f)?;
if rem {
}
if *rem {
for _ in 0..f.ret_count {
stack.pop();
}

View file

@ -24,6 +24,9 @@ fn sasm_parse<'a>(line: &str, words: &mut Vec<Word>, lines: &mut impl Iterator<I
let line: Vec<_> = line.split(" ").collect();
match line[0] {
"dump" => words.push(Word::Key(Keyword::Dump)),
"inline-callable" => words.push(Word::Key(Keyword::InlineCallable)),
"inline-start" => words.push(Word::Key(Keyword::InlineStart)),
"inline-end" => words.push(Word::Key(Keyword::InlineEnd)),
"def" => words.push(Word::Key(Keyword::Def(line[1].to_owned()))),
"func" => words.push(Word::Key(Keyword::Func(
line[1].to_owned(),
@ -223,6 +226,9 @@ fn sasm_write_func(words: Words) -> String {
Keyword::Dump => {
output += "dump\n";
}
Keyword::InlineCallable => output += "inline-callable\n",
Keyword::InlineStart => output += "inline-start\n",
Keyword::InlineEnd => output += "inline-end\n",
Keyword::Def(x) => {
output += "def ";
output += &x;

View file

@ -8,6 +8,7 @@ use std::{
process::{self, Stdio},
sync::Arc,
thread,
time::{Duration, SystemTime},
};
use crate::{dyn_fns, mutex::Mut, runtime::*, sasm::sasm_write, *};
@ -51,6 +52,13 @@ pub fn dup(stack: &mut Stack) -> OError {
Ok(())
}
pub fn dup2(stack: &mut Stack) -> OError {
let o = stack.peek();
stack.push(o.clone());
stack.push(o);
Ok(())
}
pub fn pop(stack: &mut Stack) -> OError {
stack.pop();
Ok(())
@ -854,11 +862,27 @@ pub fn fork(stack: &mut Stack) -> OError {
Ok(())
}
pub fn time(stack: &mut Stack) -> OError {
require_on_stack!(sleep_ms, Mega, stack, "time");
if sleep_ms != 0 {
thread::sleep(Duration::from_millis(sleep_ms as u64));
}
stack.push(
(SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_millis() as i128)
.spl(),
);
Ok(())
}
pub fn register(r: &mut Stack, o: Arc<Frame>) {
type Fn = fn(&mut Stack) -> OError;
let fns: [(&str, Fn, u32); 54] = [
let fns: [(&str, Fn, u32); 56] = [
("pop", pop, 0),
("dup", dup, 2),
("dup2", dup2, 3),
("clone", clone, 1),
("swap", swap, 2),
("mswap", mswap, 2),
@ -911,6 +935,7 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
("write-sasm", write_sasm, 1),
("write-file-sasm", write_file_sasm, 1),
("fork", fork, 0),
("time", time, 0),
];
for f in fns {
r.define_func(

View file

@ -11,6 +11,8 @@ pub const ASSEMBLE: &str = include_str!("../assemble.spl");
pub const ISBPL: &str = include_str!("../isbpl.spl");
pub const REPL: &str = include_str!("../repl.spl");
pub const PURE: &str = include_str!("../pure.spl");
pub const TIME: &str = include_str!("../time.spl");
pub const NOP: &str = "";
pub fn register(runtime: &mut Runtime) {
multicall! {
@ -25,5 +27,7 @@ pub fn register(runtime: &mut Runtime) {
insert("isbpl.spl", ISBPL);
insert("repl.spl", REPL);
insert("pure.spl", PURE);
insert("time.spl", TIME);
insert("nop.spl", NOP);
}
}

20
std.spl
View file

@ -12,7 +12,7 @@ func print { |
}
func println { |
"\n" concat print
!!- _str "\n" concat print
}
construct error {
@ -96,7 +96,10 @@ construct _mega-ext {
mswap { .. | mswap }
foreach { | with callable this ;
def i 0 =i
while { i this lt } { i callable call i ++ =i }
while { !!- i this lt } { !!- i callable call i 1 + =i }
}
fforeach { | with callable this ;
0 while { !!- dup2 this lt } { !!- callable inline-callable 1 + }
}
} include _mega-ext in mega
@ -368,16 +371,21 @@ construct Range {
}
construct RangeIter {
range
upper step
idx
;
construct { this | with range this ;
range this:=range
0 this:=idx
range:lower this:=idx
range:upper this:=upper
range:step this:=step
this
}
next { mega | with this ;
this:idx dup ++ this:=idx this:range:item
!!-
this:idx dup this:step + this:=idx
dup this:upper lt not if {
pop null
}
}
}

6
time.spl Normal file
View file

@ -0,0 +1,6 @@
func unixms { mega |
0 time
}
func sleep { mega | time }