improve speed, add time.spl, improve isbpl.spl, add inlining support
This commit is contained in:
parent
6d78b276d4
commit
a1f5941c1a
11 changed files with 230 additions and 32 deletions
61
benchmark.spl
Normal file
61
benchmark.spl
Normal 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
|
||||
}
|
19
isbpl.spl
19
isbpl.spl
|
@ -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 { }
|
||||
|
|
7
iter.spl
7
iter.spl
|
@ -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 ]
|
||||
|
|
17
src/lexer.rs
17
src/lexer.rs
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
@ -1333,8 +1370,12 @@ impl Words {
|
|||
}
|
||||
stack.push(f.spl());
|
||||
} else {
|
||||
stack.call(&f)?;
|
||||
if rem {
|
||||
if inline_calls {
|
||||
stack.fast_call(&f)?;
|
||||
} else {
|
||||
stack.call(&f)?;
|
||||
}
|
||||
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();
|
||||
|
@ -1379,8 +1421,12 @@ impl Words {
|
|||
stack.pop();
|
||||
stack.push(f.spl())
|
||||
} else {
|
||||
stack.call(&f)?;
|
||||
if rem {
|
||||
if inline_calls {
|
||||
stack.fast_call(&f)?;
|
||||
} else {
|
||||
stack.call(&f)?;
|
||||
}
|
||||
if *rem {
|
||||
for _ in 0..f.ret_count {
|
||||
stack.pop();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
20
std.spl
|
@ -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
6
time.spl
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
func unixms { mega |
|
||||
0 time
|
||||
}
|
||||
|
||||
func sleep { mega | time }
|
Loading…
Add table
Reference in a new issue