diff --git a/src/dyn_fns.rs b/src/dyn_fns.rs new file mode 100644 index 0000000..e70816d --- /dev/null +++ b/src/dyn_fns.rs @@ -0,0 +1,297 @@ +use std::sync::Arc; + +use crate::{mutex::Mut, runtime::*, lexer}; + +pub fn dyn_dump(stack: &mut Stack) { + Words { + words: vec![Word::Key(Keyword::Dump)], + } + .exec(stack); +} + +pub fn dyn_def(stack: &mut Stack) { + if let Value::Str(s) = stack.pop().lock_ro().native.clone() { + Words { + words: vec![Word::Key(Keyword::Def(s))], + } + .exec(stack); + } else { + panic!("incorrect usage of dyn-def"); + } +} + +pub fn dyn_func(stack: &mut Stack) { + if let Value::Str(s) = stack.pop().lock_ro().native.clone() { + if let Value::Func(f) = stack.pop().lock_ro().native.clone() { + stack.define_func(s, f); + } else { + panic!("incorrect usage of dyn-func"); + } + } else { + panic!("incorrect usage of dyn-func"); + } +} + +pub fn dyn_construct(stack: &mut Stack) { + if let Value::Str(s) = stack.pop().lock_ro().native.clone() { + Words { + words: vec![Word::Key(Keyword::Construct(s, Vec::new(), Vec::new()))], + } + .exec(stack); + } else { + panic!("incorrect usage of dyn-construct"); + } +} + +pub fn dyn_def_field(stack: &mut Stack) { + if let Value::Str(s) = stack.pop().lock_ro().native.clone() { + if let Value::Str(name) = stack.pop().lock_ro().native.clone() { + runtime(|rt| { + rt.get_type_by_name(s) + .unwrap() + .lock() + .add_property(name, stack.get_frame()); + }); + } else { + panic!("incorrect usage of dyn-def-field"); + } + } else { + panic!("incorrect usage of dyn-def-field"); + } +} + +pub fn dyn_def_method(stack: &mut Stack) { + if let Value::Str(s) = stack.pop().lock_ro().native.clone() { + if let Value::Str(name) = stack.pop().lock_ro().native.clone() { + if let Value::Func(f) = stack.pop().lock_ro().native.clone() { + runtime(|rt| { + rt.get_type_by_name(s) + .unwrap() + .lock() + .functions + .insert(name, f); + }); + } else { + panic!("incorrect usage of dyn-def-method"); + } + } else { + panic!("incorrect usage of dyn-def-method"); + } + } else { + panic!("incorrect usage of dyn-def-method"); + } +} + +pub fn dyn_include(stack: &mut Stack) { + if let Value::Str(b) = stack.pop().lock_ro().native.clone() { + if let Value::Str(a) = stack.pop().lock_ro().native.clone() { + Words { + words: vec![Word::Key(Keyword::Include(a, b))], + } + .exec(stack); + } else { + panic!("incorrect usage of dyn-include"); + } + } else { + panic!("incorrect usage of dyn-include"); + } +} + +pub fn dyn_while(stack: &mut Stack) { + if let Value::Func(blk) = stack.pop().lock_ro().native.clone() { + if let Value::Func(cond) = stack.pop().lock_ro().native.clone() { + loop { + cond.to_call.call(stack); + if !stack.pop().lock_ro().is_truthy() { + break; + } + blk.to_call.call(stack); + } + } else { + panic!("incorrect usage of dyn-while"); + } + } else { + panic!("incorrect usage of dyn-while"); + } +} + +pub fn dyn_if(stack: &mut Stack) { + if let Value::Func(blk) = stack.pop().lock_ro().native.clone() { + if stack.pop().lock_ro().is_truthy() { + blk.to_call.call(stack); + } + } else { + panic!("incorrect usage of dyn-if"); + } +} + +pub fn dyn_call(stack: &mut Stack) { + if let Value::Str(mut s) = stack.pop().lock_ro().native.clone() { + let mut words = Vec::new(); + let mut ra = 0; + while s.starts_with("&") { + ra += 1; + s = s[1..].to_owned(); + } + if s.ends_with(";") { + words.push(Word::Call(s[..s.len() - 1].to_owned(), true, ra)); + } else { + words.push(Word::Call(s.to_owned(), false, ra)); + } + Words { words }.exec(stack); + } else { + panic!("incorrect usage of dyn-call"); + } +} + +pub fn dyn_objcall(stack: &mut Stack) { + if let Value::Str(mut s) = stack.pop().lock_ro().native.clone() { + let mut words = Vec::new(); + let mut ra = 0; + while s.starts_with("&") { + ra += 1; + s = s[1..].to_owned(); + } + if s.ends_with(";") { + words.push(Word::ObjCall(s[..s.len() - 1].to_owned(), true, ra)); + } else { + words.push(Word::ObjCall(s.to_owned(), false, ra)); + } + Words { words }.exec(stack); + } else { + panic!("incorrect usage of dyn-objcall"); + } +} + +pub fn dyn_all_types(stack: &mut Stack) { + runtime(|rt| { + stack.push( + Value::Array( + rt.get_types() + .into_iter() + .map(|x| Value::Str(x.lock_ro().get_name()).spl()) + .collect(), + ) + .spl(), + ); + }); +} + +pub fn dyn_read(stack: &mut Stack) { + if let Value::Str(s) = stack.pop().lock_ro().native.clone() { + stack.push(Value::Func(AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::SPL(lexer::lex(s, "dyn-read@".to_owned() + &stack.get_origin().file, stack.get_frame())), + origin: stack.get_frame(), + })).spl()); + } else { + panic!("incorrect usage of dyn-call"); + } +} + +pub fn register(r: &mut Stack, o: Arc) { + r.define_func( + "dyn-__dump".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(dyn_dump), + origin: o.clone(), + }), + ); + r.define_func( + "dyn-def".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(dyn_def), + origin: o.clone(), + }), + ); + r.define_func( + "dyn-func".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(dyn_func), + origin: o.clone(), + }), + ); + r.define_func( + "dyn-construct".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(dyn_construct), + origin: o.clone(), + }), + ); + r.define_func( + "dyn-def-field".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(dyn_def_field), + origin: o.clone(), + }), + ); + r.define_func( + "dyn-def-method".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(dyn_def_method), + origin: o.clone(), + }), + ); + r.define_func( + "dyn-include".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(dyn_include), + origin: o.clone(), + }), + ); + r.define_func( + "dyn-while".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(dyn_while), + origin: o.clone(), + }), + ); + r.define_func( + "dyn-if".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(dyn_if), + origin: o.clone(), + }), + ); + r.define_func( + "dyn-call".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(dyn_call), + origin: o.clone(), + }), + ); + r.define_func( + "dyn-objcall".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(dyn_objcall), + origin: o.clone(), + }), + ); + r.define_func( + "dyn-all-types".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(dyn_all_types), + origin: o.clone(), + }), + ); + r.define_func( + "dyn-read".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(dyn_read), + origin: o.clone(), + }), + ) +} diff --git a/src/lexer.rs b/src/lexer.rs index f1a285e..bb19d75 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -1,28 +1,32 @@ +use std::sync::Arc; + use crate::runtime::*; use readformat::*; -pub fn lex(input: String, filename: String) -> Words { +pub fn lex(input: String, filename: String, frame: Arc) -> Words { let mut str_words = Vec::new(); for line in input.split('\n') { str_words.append(&mut parse_line(line)); } - read_block(&str_words[..], false, &FrameInfo { file: filename }).1 + read_block( + &str_words[..], + false, + Arc::new(Frame::new_in(frame, filename)), + ) + .1 } -fn read_block(str_words: &[String], isfn: bool, origin: &FrameInfo) -> (Option, Words, usize) { +fn read_block(str_words: &[String], isfn: bool, origin: Arc) -> (Option, Words, usize) { let mut rem = None; let mut words = Vec::new(); let mut i = 0; - if str_words[0] == "{" { - if isfn { - let mut r = 0_u32; - while str_words[r as usize + 1] != "|" { - r += 1; - } - i += r as usize + 1; - rem = Some(r); + if str_words[0] == "{" && isfn { + let mut r = 0_u32; + while str_words[r as usize + 1] != "|" { + r += 1; } - i += 1; + i += r as usize + 2; + rem = Some(r); } while i < str_words.len() { let word = str_words[i].to_owned(); @@ -33,7 +37,11 @@ fn read_block(str_words: &[String], isfn: bool, origin: &FrameInfo) -> (Option { if let Some(dat) = readf("func\0{}\0{", str_words[i..=i + 2].join("\0").as_str()) { - let block = read_block(&str_words[i + 2..], true, &origin); + let block = read_block( + &str_words[i + 2..], + true, + Arc::new(Frame::new(origin.clone())), + ); i += 2 + block.2; words.push(Word::Key(Keyword::Func( dat[0].to_owned(), @@ -43,9 +51,9 @@ fn read_block(str_words: &[String], isfn: bool, origin: &FrameInfo) -> (Option { - let block = read_block(&str_words[i..], true, &origin); + let block = read_block(&str_words[i..], true, Arc::new(Frame::new(origin.clone()))); i += block.2; - words.push(Word::Const(Constant::Func(AFunc::new(Func { + words.push(Word::Const(Value::Func(AFunc::new(Func { ret_count: block.0.expect("LEXERR: Expected `{ <...> |`."), to_call: FuncImpl::SPL(block.1), origin: origin.to_owned(), @@ -59,17 +67,21 @@ fn read_block(str_words: &[String], isfn: bool, origin: &FrameInfo) -> (Option {{`, got `construct `" ); let mut fields = Vec::new(); - i += 2; + i += 3; while str_words[i] != ";" && str_words[i] != "}" { fields.push((&str_words[i]).to_owned()); i += 1; } let mut methods = Vec::new(); + let mut has_construct = false; if str_words[i] == ";" { i += 1; while str_words[i] != "}" { let name = (&str_words[i]).to_owned(); - let block = read_block(&str_words[i + 1..], true, origin); + if name == "construct" { + has_construct = true; + } + let block = read_block(&str_words[i + 1..], true, origin.clone()); i += 1 + block.2; methods.push(( name, @@ -81,12 +93,15 @@ fn read_block(str_words: &[String], isfn: bool, origin: &FrameInfo) -> (Option { if let Some(x) = readf( "include\0{}\0in\0{}", - str_words[i..=i + 4].join("\0").as_str(), + str_words[i..i + 4].join("\0").as_str(), ) { words.push(Word::Key(Keyword::Include( x[0].to_owned(), @@ -95,20 +110,19 @@ fn read_block(str_words: &[String], isfn: bool, origin: &FrameInfo) -> (Option in `."); } + i += 3; } "while" => { - let cond = read_block(&str_words[i + 1..], false, origin); - i += 1 + cond.2; - let blk = read_block(&str_words[i + 1..], false, origin); - i += 1 + cond.2; + let cond = read_block(&str_words[i + 2..], false, origin.clone()); + i += 2 + cond.2; + let blk = read_block(&str_words[i + 2..], false, origin.clone()); + i += 2 + blk.2; words.push(Word::Key(Keyword::While(cond.1, blk.1))); } "if" => { - let cond = read_block(&str_words[i + 1..], false, origin); - i += 1 + cond.2; - let blk = read_block(&str_words[i + 1..], false, origin); - i += 1 + cond.2; - words.push(Word::Key(Keyword::If(cond.1, blk.1))); + let blk = read_block(&str_words[i + 2..], false, origin.clone()); + i += 2 + blk.2; + words.push(Word::Key(Keyword::If(blk.1))); } "with" => { let mut vars = Vec::new(); @@ -123,24 +137,27 @@ fn read_block(str_words: &[String], isfn: bool, origin: &FrameInfo) -> (Option { - words.push(Word::Const(Constant::Str(x[1..].to_owned()))); + words.push(Word::Const(Value::Str(x[1..].to_owned()))); } x if x.chars().all(|c| c.is_numeric() || c == '_') && !x.starts_with("_") => { - words.push(Word::Const(Constant::Mega(x.parse().unwrap()))); + words.push(Word::Const(Value::Mega(x.parse().unwrap()))); } - x if x.chars().all(|c| c.is_numeric() || c == '.' || c == '_') && !x.starts_with("_") => { - words.push(Word::Const(Constant::Double(x.parse().unwrap()))); + x if x.chars().all(|c| c.is_numeric() || c == '.' || c == '_') + && !x.starts_with("_") => + { + words.push(Word::Const(Value::Double(x.parse().unwrap()))); } - mut x => { + x => { + let mut word = x.split(":").next().unwrap(); let mut ra = 0; - while x.starts_with("&") { + while word.starts_with("&") { ra += 1; - x = &x[1..]; + word = &word[1..]; } - if x.ends_with(";") { - words.push(Word::Call(x[..x.len() - 1].to_owned(), true, ra)); + if word.ends_with(";") { + words.push(Word::Call(word[..word.len() - 1].to_owned(), true, ra)); } else { - words.push(Word::Call(x.to_owned(), false, ra)); + words.push(Word::Call(word.to_owned(), false, ra)); } for mut word in x.split(":").skip(1) { let mut ra = 0; @@ -165,6 +182,7 @@ fn parse_line(line: &str) -> Vec { let mut words = Vec::new(); let mut in_string = false; let mut escaping = false; + let mut was_in_string = false; let mut s = String::new(); for c in line.chars() { if in_string { @@ -178,11 +196,15 @@ fn parse_line(line: &str) -> Vec { if c == 'r' { s += "\r"; } + if c == '"' { + s += "\""; + } escaping = false; continue; } else if c == '"' { in_string = false; escaping = false; + was_in_string = true; continue; } if c == '\\' { @@ -195,15 +217,24 @@ fn parse_line(line: &str) -> Vec { in_string = true; continue; } + if c == ';' && was_in_string { + s = String::new(); + continue; + } + if c == '(' || c == ')' { + continue; + } if c == ' ' { if s == "" { continue; } words.push(s); s = String::new(); + was_in_string = false; continue; } } + was_in_string = false; s += String::from(c).as_str(); } if s != "" { diff --git a/src/lib.rs b/src/lib.rs index 2876b4b..8e67ced 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +pub(crate) mod dyn_fns; pub mod lexer; pub mod mutex; pub mod runtime; +pub(crate) mod std_fns; diff --git a/src/main.rs b/src/main.rs index f449d7e..480ac27 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,32 +1,13 @@ use spl::{lexer::lex, runtime::*}; use std::{ - io::{stdout, Write}, - sync::Arc, + fs, vec, }; fn main() { let rt = Runtime::new(); let mut stack = Stack::new(); - fn print(stack: &mut Stack) { - let s = stack.pop(); - let s = s.lock(); - if let Constant::Str(ref s) = s.native { - print!("{s}"); - stdout().lock().flush().unwrap(); - } - } - stack.define_func( - "print".to_owned(), - Arc::new(Func { - ret_count: 0, - to_call: FuncImpl::Native(print), - origin: FrameInfo { - file: "RUNTIME".to_owned(), - }, - }), - ); rt.set(); Words { words: vec![ @@ -36,19 +17,25 @@ fn main() { Words { words: vec![ Word::Call("print".to_owned(), true, 0), - Word::Const(Constant::Str("\n".to_owned())), + Word::Const(Value::Str("\n".to_owned())), Word::Call("print".to_owned(), true, 0), ], }, )), Word::Key(Keyword::Def("helloworld".to_owned())), - Word::Const(Constant::Str("Hello, World".to_owned())), + Word::Const(Value::Str("Hello, World".to_owned())), Word::Call("=helloworld".to_owned(), false, 0), Word::Call("helloworld".to_owned(), false, 0), Word::Call("println".to_owned(), true, 0), ], } .exec(&mut stack); - lex("func println { | print \"\\n\" print } def helloworld \"Hello, World\" =helloworld helloworld println".to_owned(), "TEST".to_owned()).exec(&mut stack); + let words = lex( + fs::read_to_string("test.spl").unwrap(), + "test.spl".to_owned(), + stack.get_frame(), + ); + println!("{words:?}"); + words.exec(&mut stack); Runtime::reset(); } diff --git a/src/mutex.rs b/src/mutex.rs index 640caae..a2e33cc 100644 --- a/src/mutex.rs +++ b/src/mutex.rs @@ -1,14 +1,19 @@ -use std::sync::{Mutex, MutexGuard}; +use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; -pub struct Mut(Mutex); +#[derive(Debug)] +pub struct Mut(RwLock); impl Mut { pub fn new(obj: T) -> Mut { - Mut(Mutex::new(obj)) + Mut(RwLock::new(obj)) } - pub fn lock(&self) -> MutexGuard { - self.0.lock().unwrap() + pub fn lock_ro(&self) -> RwLockReadGuard { + self.0.read().unwrap() + } + + pub fn lock(&self) -> RwLockWriteGuard { + self.0.write().unwrap() } } @@ -17,6 +22,26 @@ where T: Clone, { fn clone(&self) -> Self { - Self(Mutex::new(self.0.lock().unwrap().clone())) + Self(RwLock::new(self.0.read().unwrap().clone())) + } +} + +impl PartialEq for Mut +where + T: PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + self.0.read().unwrap().eq(&other.0.read().unwrap()) + } +} + +impl Eq for Mut where T: Eq {} + +impl PartialOrd for Mut +where + T: PartialOrd, +{ + fn partial_cmp(&self, other: &Self) -> Option { + self.0.read().unwrap().partial_cmp(&other.0.read().unwrap()) } } diff --git a/src/runtime.rs b/src/runtime.rs index 9b08665..12902f5 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -1,10 +1,12 @@ -use crate::mutex::*; +use crate::{dyn_fns, mutex::*, std_fns}; +use core::panic; use std::collections::VecDeque; +use std::mem; use std::{ cell::RefCell, collections::HashMap, - fmt::{Debug, Display, Formatter, Pointer}, + fmt::{Debug, Display, Formatter}, sync::Arc, vec, }; @@ -17,6 +19,10 @@ thread_local! { static RUNTIME: RefCell> = RefCell::new(None); } +pub fn runtime(f: impl FnOnce(&mut Runtime) -> T) -> T { + RUNTIME.with(|rt| f(rt.borrow_mut().as_mut().unwrap())) +} + #[derive(Clone)] pub struct Runtime { next_type_id: u32, @@ -51,6 +57,10 @@ impl Runtime { self.types_by_id.get(&id).cloned() } + pub fn get_types(&self) -> Vec { + self.types_by_id.clone().into_values().collect() + } + pub fn make_type(&mut self, name: String, op: impl FnOnce(Type) -> Type) -> AMType { let t = Arc::new(Mut::new(op(Type { name: name.clone(), @@ -89,11 +99,11 @@ pub struct Frame { impl Display for Frame { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str("\nVars: \n")?; - for (name, object) in self.variables.lock().iter() { + for (name, object) in self.variables.lock_ro().iter() { f.write_str(" ")?; f.write_str(&name)?; f.write_str(": ")?; - object.lock().fmt(f)?; + std::fmt::Display::fmt(&object.lock_ro(), f)?; f.write_str("\n")?; } Ok(()) @@ -112,12 +122,21 @@ impl Frame { } } - pub fn new(parent: Arc, origin: FrameInfo) -> Self { + pub fn new(parent: Arc) -> Self { + Frame { + variables: Mut::new(HashMap::new()), + functions: Mut::new(HashMap::new()), + origin: parent.origin.clone(), + parent: Some(parent), + } + } + + pub fn new_in(parent: Arc, origin: String) -> Self { Frame { parent: Some(parent), variables: Mut::new(HashMap::new()), functions: Mut::new(HashMap::new()), - origin, + origin: FrameInfo { file: origin }, } } } @@ -139,7 +158,7 @@ impl Display for Stack { f.write_str("Stack: \n")?; for object in &self.object_stack { f.write_str(" ")?; - object.lock().fmt(f)?; + std::fmt::Display::fmt(&object.lock_ro(), f)?; f.write_str("\n")?; } Ok(()) @@ -148,10 +167,16 @@ impl Display for Stack { impl Stack { pub fn new() -> Self { - Stack { - frames: vec![Arc::new(Frame::root())], + let o = Arc::new(Frame::root()); + let mut r = Stack { + frames: vec![o.clone()], object_stack: Vec::new(), - } + }; + + dyn_fns::register(&mut r, o.clone()); + std_fns::register(&mut r, o.clone()); + + r } pub fn define_func(&mut self, name: String, func: AFunc) { @@ -164,10 +189,7 @@ impl Stack { } pub fn call(&mut self, func: &AFunc) { - self.frames.push(Arc::new(Frame::new( - self.frames.last().unwrap().clone(), - func.origin.clone(), - ))); + self.frames.push(Arc::new(Frame::new(func.origin.clone()))); func.to_call.call(self); self.frames.pop().unwrap(); } @@ -176,15 +198,19 @@ impl Stack { let mut frame = self.frames.last().unwrap(); loop { let functions = &frame.functions; - if let Some(x) = functions.lock().get(&name) { + if let Some(x) = functions.lock_ro().get(&name) { return x.clone(); } if let Some(ref x) = frame.parent { frame = x; + } else { + panic!("Function not found: {}", name) } } } + // TODO actually use the frame for the variable (can cause issues when using referenced + // functions) pub fn define_var(&mut self, name: String) { let frame = self.frames.last_mut().unwrap().clone(); let tmpname = name.clone(); @@ -195,7 +221,7 @@ impl Stack { to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| { stack.push(stack.get_var(tmpname.clone())) }))), - origin: frame.origin.clone(), + origin: frame.clone(), }), ); let tmpname = name.clone(); @@ -207,13 +233,13 @@ impl Stack { let v = stack.pop(); stack.set_var(tmpname.clone(), v); }))), - origin: frame.origin.clone(), + origin: frame.clone(), }), ); - frame.variables.lock().insert(name, Constant::Null.spl()); + frame.variables.lock().insert(name, Value::Null.spl()); } - pub fn set_var(&self, name: String, obj: AMObject) { + pub fn set_var(&mut self, name: String, obj: AMObject) { let mut frame = self.frames.last().unwrap(); loop { if let Some(x) = frame.variables.lock().get_mut(&name) { @@ -223,7 +249,8 @@ impl Stack { if let Some(ref x) = frame.parent { frame = x; } else { - panic!("undefined var") + dyn_fns::dyn_dump(self); + panic!("undefined var: {name}"); } } } @@ -231,7 +258,7 @@ impl Stack { pub fn get_var(&self, name: String) -> AMObject { let mut frame = self.frames.last().unwrap(); loop { - if let Some(x) = frame.variables.lock().get(&name) { + if let Some(x) = frame.variables.lock_ro().get(&name) { return x.clone(); } if let Some(ref x) = frame.parent { @@ -250,16 +277,20 @@ impl Stack { self.object_stack .last() .cloned() - .unwrap_or(Constant::Null.spl()) + .unwrap_or(Value::Null.spl()) } pub fn pop(&mut self) -> AMObject { - self.object_stack.pop().unwrap_or(Constant::Null.spl()) + self.object_stack.pop().unwrap_or(Value::Null.spl()) } pub fn get_origin(&self) -> FrameInfo { self.frames.last().unwrap().origin.clone() } + + pub fn get_frame(&self) -> Arc { + self.frames.last().unwrap().clone() + } } #[derive(Clone, Debug)] @@ -285,25 +316,25 @@ pub enum Keyword { /// /// Creates type /// equivalent to - /// "" dyn-construct; "" "" dyn-def-field { | } "" - /// "" dyn-def-method + /// "" dyn-construct; "" "" dyn-def-field { | } "" + /// "" dyn-def-method Construct(String, Vec, Vec<(String, (u32, Words))>), /// include in /// /// Adds as a parent type of . /// equivalent to "" "" dyn-include Include(String, String), - /// while { } + /// while { } { } /// /// If wordsA result in a truthy value being on the top of the stack, execute wordsB, and /// repeat. /// equivalent to { int | } { | } dyn-while While(Words, Words), - /// if { } + /// if { } /// /// If wordsA result in a truthy value being on the top of the stack, execute wordsB. - /// equivalent to { int | } { | } dyn-if - If(Words, Words), + /// equivalent to { | } dyn-if + If(Words), /// with <...> ; /// /// Defines variables in reverse order. @@ -312,8 +343,8 @@ pub enum Keyword { With(Vec), } -#[derive(Clone, Debug)] -pub enum Constant { +#[derive(Clone, Debug, PartialEq)] +pub enum Value { Null, Int(i32), Long(i64), @@ -321,13 +352,23 @@ pub enum Constant { Float(f32), Double(f64), Func(AFunc), + Array(Vec), Str(String), } +impl PartialOrd for Value { + fn partial_cmp(&self, other: &Self) -> Option { + match (self, other) { + (Value::Mega(a), Value::Mega(b)) => a.partial_cmp(b), + _ => panic!(), + } + } +} + #[derive(Clone, Debug)] pub enum Word { Key(Keyword), - Const(Constant), + Const(Value), Call(String, bool, u32), ObjCall(String, bool, u32), } @@ -358,7 +399,13 @@ impl FuncImpl { pub struct Func { pub ret_count: u32, pub to_call: FuncImpl, - pub origin: FrameInfo, + pub origin: Arc, +} + +impl PartialEq for Func { + fn eq(&self, _other: &Self) -> bool { + false + } } impl Debug for Func { @@ -368,7 +415,7 @@ impl Debug for Func { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Type { name: String, id: u32, @@ -377,39 +424,99 @@ pub struct Type { pub properties: Vec, } +impl PartialEq for Type { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} + impl Type { + pub fn get_name(&self) -> String { + self.name.clone() + } + + pub fn get_id(&self) -> u32 { + self.id + } + pub fn get_fn(&self, name: String) -> Option { if let Some(x) = self.functions.get(&name) { return Some(x.clone()); } let mut q = VecDeque::from(self.parents.clone()); while let Some(t) = q.pop_front() { - if let Some(x) = t.lock().functions.get(&name) { + if let Some(x) = t.lock_ro().functions.get(&name) { return Some(x.clone()); } - q.append(&mut VecDeque::from(t.lock().parents.clone())); + q.append(&mut VecDeque::from(t.lock_ro().parents.clone())); } None } + + pub fn add_property(&mut self, name: String, origin: Arc) { + let tmpname = name.clone(); + self.functions.insert( + name.clone(), + Arc::new(Func { + ret_count: 1, + to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| { + let o = stack.pop(); + stack.push(o.lock_ro().property_map.get(&tmpname).unwrap().clone()); + }))), + origin: origin.clone(), + }), + ); + let tmpname = name.clone(); + self.functions.insert( + "=".to_owned() + &name, + Arc::new(Func { + ret_count: 0, + to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| { + let o = stack.pop(); + let v = stack.pop(); + o.lock().property_map.insert(tmpname.clone(), v); + }))), + origin, + }), + ); + self.properties.push(name); + } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Object { pub kind: AMType, pub property_map: HashMap, - pub native: Constant, + pub native: Value, +} + +impl PartialEq for Object { + fn eq(&self, other: &Self) -> bool { + self.kind == other.kind + && self.property_map == other.property_map + && self.native == other.native + } +} + +impl PartialOrd for Object { + fn partial_cmp(&self, other: &Self) -> Option { + if self.kind != other.kind { + panic!(); + } + self.native.partial_cmp(&other.native) + } } impl Display for Object { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.kind.lock().name)?; + f.write_str(&self.kind.lock_ro().name)?; f.write_str("(")?; self.native.fmt(f)?; f.write_str(") { ")?; for (k, v) in &self.property_map { f.write_str(&k)?; f.write_str(": ")?; - v.fmt(f)?; + std::fmt::Display::fmt(&v.lock_ro(), f)?; } f.write_str(" }")?; Ok(()) @@ -417,12 +524,12 @@ impl Display for Object { } impl Object { - pub fn new(kind: AMType, native: Constant) -> Object { + pub fn new(kind: AMType, native: Value) -> Object { Object { property_map: { let mut map = HashMap::new(); - for property in &kind.lock().properties { - map.insert(property.clone(), Constant::Null.spl()); + for property in &kind.lock_ro().properties { + map.insert(property.clone(), Value::Null.spl()); } map }, @@ -433,34 +540,35 @@ impl Object { pub fn is_truthy(&self) -> bool { match &self.native { - Constant::Null => false, - Constant::Int(x) => x > &0, - Constant::Long(x) => x > &0, - Constant::Mega(x) => x > &0, - Constant::Float(_) => true, - Constant::Double(_) => true, - Constant::Func(_) => true, - Constant::Str(x) => x == "", + Value::Null => false, + Value::Int(x) => x > &0, + Value::Long(x) => x > &0, + Value::Mega(x) => x > &0, + Value::Float(_) => true, + Value::Double(_) => true, + Value::Func(_) => true, + Value::Array(_) => true, + Value::Str(x) => x == "", } } } -impl From for Object { - fn from(value: Constant) -> Self { +impl From for Object { + fn from(value: Value) -> Self { Object::new( RUNTIME.with(|x| { let x = x.borrow(); let x = x.as_ref().unwrap(); match value { - Constant::Null => x.get_type_by_id(0), - Constant::Int(_) => x.get_type_by_id(1), - Constant::Long(_) => x.get_type_by_id(2), - Constant::Mega(_) => x.get_type_by_id(3), - Constant::Float(_) => x.get_type_by_id(4), - Constant::Double(_) => x.get_type_by_id(5), - Constant::Func(_) => x.get_type_by_id(6), - // array is 7 - Constant::Str(_) => x.get_type_by_id(8), + Value::Null => x.get_type_by_id(0), + Value::Int(_) => x.get_type_by_id(1), + Value::Long(_) => x.get_type_by_id(2), + Value::Mega(_) => x.get_type_by_id(3), + Value::Float(_) => x.get_type_by_id(4), + Value::Double(_) => x.get_type_by_id(5), + Value::Func(_) => x.get_type_by_id(6), + Value::Array(_) => x.get_type_by_id(7), + Value::Str(_) => x.get_type_by_id(8), } .expect("runtime uninitialized: default types not set.") }), @@ -494,30 +602,44 @@ impl Words { Arc::new(Func { ret_count: rem, to_call: FuncImpl::SPL(words), - origin: stack.get_origin(), + origin: stack.get_frame(), }), ), Keyword::Construct(name, fields, methods) => { - let origin = stack.get_origin(); - RUNTIME.with(move |rt| { - rt.borrow_mut() - .as_mut() - .unwrap() - .make_type(name, move |mut t| { - t.properties = fields; - t.functions.extend(methods.into_iter().map(|(k, v)| { - ( - k, - Arc::new(Func { - ret_count: v.0, - to_call: FuncImpl::SPL(v.1), - origin: origin.clone(), - }), + let origin = stack.get_frame(); + stack.define_var(name.clone()); + stack.set_var( + name.clone(), + Value::Str( + RUNTIME + .with(move |rt| { + rt.borrow_mut().as_mut().unwrap().make_type( + name, + move |mut t| { + for field in fields { + t.add_property(field, origin.clone()); + } + t.functions.extend(methods.into_iter().map( + |(k, v)| { + ( + k, + Arc::new(Func { + ret_count: v.0, + to_call: FuncImpl::SPL(v.1), + origin: origin.clone(), + }), + ) + }, + )); + t + }, ) - })); - t - }); - }) + }) + .lock_ro() + .get_name(), + ) + .spl(), + ); } Keyword::Include(ta, tb) => { RUNTIME.with(move |rt| { @@ -533,14 +655,13 @@ impl Words { } Keyword::While(cond, blk) => loop { cond.exec(stack); - if !stack.pop().lock().is_truthy() { + if !stack.pop().lock_ro().is_truthy() { break; } blk.exec(stack); }, - Keyword::If(cond, blk) => { - cond.exec(stack); - if stack.pop().lock().is_truthy() { + Keyword::If(blk) => { + if stack.pop().lock_ro().is_truthy() { blk.exec(stack); } } @@ -556,15 +677,15 @@ impl Words { Word::Call(x, rem, ra) => { let f = stack.get_func(x); if ra != 0 { - let mut f = Constant::Func(f); + let mut f = Value::Func(f); for _ in 1..ra { let ftmp = f; - f = Constant::Func(AFunc::new(Func { + f = Value::Func(AFunc::new(Func { ret_count: 1, to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| { stack.push(ftmp.clone().spl()); }))), - origin: stack.get_origin(), + origin: stack.get_frame(), })); } } else { @@ -578,24 +699,26 @@ impl Words { } Word::ObjCall(x, rem, ra) => { let o = stack.peek(); - let o = o.lock(); + let o = o.lock_ro(); // TODO: raise error if not found - let f = o.kind.lock(); - let f = f.functions.get(&x).unwrap(); + let f0 = o.kind.lock_ro(); + let f = f0.functions.get(&x).unwrap_or_else(|| panic!("objcall not possible. {} {:?} {}", o.kind.lock_ro().name, o.native, x)).clone(); + mem::drop(f0); + mem::drop(o); if ra != 0 { - let mut f = Constant::Func(f.clone()); + let mut f = Value::Func(f.clone()); for _ in 1..ra { let ftmp = f; - f = Constant::Func(AFunc::new(Func { + f = Value::Func(AFunc::new(Func { ret_count: 1, to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| { stack.push(ftmp.clone().spl()); }))), - origin: stack.get_origin(), + origin: stack.get_frame(), })); } } else { - stack.call(f); + stack.call(&f); if rem { for _ in 0..f.ret_count { stack.pop(); diff --git a/src/std_fns.rs b/src/std_fns.rs new file mode 100644 index 0000000..5f39618 --- /dev/null +++ b/src/std_fns.rs @@ -0,0 +1,506 @@ +use core::panic; +use std::{ + io::{stdout, Write}, + mem, + sync::Arc, +}; + +use crate::{mutex::Mut, runtime::*}; + +pub fn print(stack: &mut Stack) { + if let Value::Str(s) = stack.pop().lock_ro().native.clone() { + print!("{s}"); + stdout().lock().flush().unwrap(); + } else { + panic!("incorrect usage of print"); + } +} + +pub fn clone(stack: &mut Stack) { + let o = stack.pop(); + stack.push(Arc::new(Mut::new(o.lock_ro().clone()))); +} + +pub fn dup(stack: &mut Stack) { + let o = stack.peek(); + stack.push(o); +} + +pub fn pop(stack: &mut Stack) { + stack.pop(); +} + +pub fn swap(stack: &mut Stack) { + let a = stack.pop(); + let b = stack.pop(); + stack.push(a); + stack.push(b); +} + +pub fn settype(stack: &mut Stack) { + if let Value::Str(s) = stack.pop().lock_ro().native.clone() { + let o = stack.pop(); + let kind = runtime(|rt| rt.get_type_by_name(s).unwrap()); + let mut obj = o.lock(); + for property in &kind.lock_ro().properties { + obj.property_map.insert(property.clone(), Value::Null.spl()); + } + obj.kind = kind; + mem::drop(obj); + stack.push(o); + } else { + panic!("incorrect usage of settype"); + } +} + +pub fn gettype(stack: &mut Stack) { + let o = stack.pop(); + stack.push(Value::Str(o.lock_ro().kind.lock_ro().get_name()).spl()); +} + +pub fn array_new(stack: &mut Stack) { + if let Value::Mega(i) = stack.pop().lock_ro().native.clone() { + stack.push(Value::Array(vec![Value::Null.spl(); i as usize]).spl()); + } else { + panic!("incorrect usage of anew"); + } +} + +pub fn array_len(stack: &mut Stack) { + if let Value::Array(ref a) = stack.pop().lock_ro().native { + stack.push(Value::Mega(a.len() as i128).spl()); + } else { + panic!("incorrect usage of array-len"); + } +} + +pub fn array_get(stack: &mut Stack) { + if let Value::Array(ref a) = stack.pop().lock_ro().native { + if let Value::Mega(i) = stack.pop().lock_ro().native.clone() { + stack.push(a[i as usize].clone()); + } else { + panic!("incorrect usage of array-get"); + } + } else { + panic!("incorrect usage of array-get"); + } +} + +pub fn array_set(stack: &mut Stack) { + if let Value::Array(ref mut a) = stack.pop().lock().native { + if let Value::Mega(i) = stack.pop().lock_ro().native.clone() { + let o = stack.pop(); + a[i as usize] = o; + } else { + panic!("incorrect usage of array-set"); + } + } else { + panic!("incorrect usage of array-set"); + } +} + +pub fn eq(stack: &mut Stack) { + let b = stack.pop(); + let a = stack.pop(); + stack.push(Value::Int(if a == b { 1 } else { 0 }).spl()) +} + +pub fn lt(stack: &mut Stack) { + let b = stack.pop(); + let a = stack.pop(); + stack.push(Value::Int(if a < b { 1 } else { 0 }).spl()) +} + +pub fn gt(stack: &mut Stack) { + let b = stack.pop(); + let a = stack.pop(); + stack.push(Value::Int(if a > b { 1 } else { 0 }).spl()) +} + +pub fn not(stack: &mut Stack) { + let o = stack.pop(); + stack.push(Value::Int(if o.lock_ro().is_truthy() { 0 } else { 1 }).spl()) +} + +pub fn plus(stack: &mut Stack) { + let a = stack.pop().lock_ro().native.clone(); + let b = stack.pop().lock_ro().native.clone(); + stack.push( + match (a, b) { + (Value::Mega(a), Value::Mega(b)) => Value::Mega(a + b), + _ => panic!(), + } + .spl(), + ); +} + +pub fn minus(stack: &mut Stack) { + let a = stack.pop().lock_ro().native.clone(); + let b = stack.pop().lock_ro().native.clone(); + stack.push( + match (a, b) { + (Value::Mega(a), Value::Mega(b)) => Value::Mega(a - b), + _ => panic!(), + } + .spl(), + ); +} + +pub fn slash(stack: &mut Stack) { + let a = stack.pop().lock_ro().native.clone(); + let b = stack.pop().lock_ro().native.clone(); + stack.push( + match (a, b) { + (Value::Mega(a), Value::Mega(b)) => Value::Mega(a / b), + _ => panic!(), + } + .spl(), + ); +} + +pub fn star(stack: &mut Stack) { + let a = stack.pop().lock_ro().native.clone(); + let b = stack.pop().lock_ro().native.clone(); + stack.push( + match (a, b) { + (Value::Mega(a), Value::Mega(b)) => Value::Mega(a * b), + _ => panic!(), + } + .spl(), + ); +} + +pub fn to_int(stack: &mut Stack) { + let o = stack.pop().lock_ro().native.clone(); + stack.push(Value::Int(match o { + Value::Null => panic!("incompatible: null - int"), + Value::Int(x) => x, + Value::Long(x) => x as i32, + Value::Mega(x) => x as i32, + Value::Float(x) => x as i32, + Value::Double(x) => x as i32, + Value::Func(_) => panic!("incompatible: func - int"), + Value::Array(_) => panic!("incompatible: array - int"), + Value::Str(x) => x.parse().expect("invalid int"), + }).spl()) +} + +pub fn to_long(stack: &mut Stack) { + let o = stack.pop().lock_ro().native.clone(); + stack.push(Value::Long(match o { + Value::Null => panic!("incompatible: null - long"), + Value::Int(x) => x as i64, + Value::Long(x) => x as i64, + Value::Mega(x) => x as i64, + Value::Float(x) => x as i64, + Value::Double(x) => x as i64, + Value::Func(_) => panic!("incompatible: func - long"), + Value::Array(_) => panic!("incompatible: array - long"), + Value::Str(x) => x.parse().expect("invalid long"), + }).spl()) +} + +pub fn to_mega(stack: &mut Stack) { + let o = stack.pop().lock_ro().native.clone(); + stack.push(Value::Mega(match o { + Value::Null => panic!("incompatible: null - mega"), + Value::Int(x) => x as i128, + Value::Long(x) => x as i128, + Value::Mega(x) => x as i128, + Value::Float(x) => x as i128, + Value::Double(x) => x as i128, + Value::Func(_) => panic!("incompatible: func - mega"), + Value::Array(_) => panic!("incompatible: array - mega"), + Value::Str(x) => x.parse().expect("invalid mega"), + }).spl()) +} + +pub fn to_float(stack: &mut Stack) { + let o = stack.pop().lock_ro().native.clone(); + stack.push(Value::Float(match o { + Value::Null => panic!("incompatible: null - float"), + Value::Int(x) => x as f32, + Value::Long(x) => x as f32, + Value::Mega(x) => x as f32, + Value::Float(x) => x as f32, + Value::Double(x) => x as f32, + Value::Func(_) => panic!("incompatible: func - float"), + Value::Array(_) => panic!("incompatible: array - float"), + Value::Str(x) => x.parse().expect("invalid float"), + }).spl()) +} + +pub fn to_double(stack: &mut Stack) { + let o = stack.pop().lock_ro().native.clone(); + stack.push(Value::Double(match o { + Value::Null => panic!("incompatible: null - double"), + Value::Int(x) => x as f64, + Value::Long(x) => x as f64, + Value::Mega(x) => x as f64, + Value::Float(x) => x as f64, + Value::Double(x) => x as f64, + Value::Func(_) => panic!("incompatible: func - double"), + Value::Array(_) => panic!("incompatible: array - double"), + Value::Str(x) => x.parse().expect("invalid double"), + }).spl()) +} + +pub fn to_array(stack: &mut Stack) { + let o = stack.pop().lock_ro().native.clone(); + stack.push(Value::Array(match o { + Value::Null => panic!("incompatible: null - array"), + Value::Int(_) => panic!("incompatible: int - array"), + Value::Long(_) => panic!("incompatible: long - array"), + Value::Mega(_) => panic!("incompatible: mega - array"), + Value::Float(_) => panic!("incompatible: float - array"), + Value::Double(_) => panic!("incompatible: double - array"), + Value::Func(_) => panic!("incompatible: func - array"), + Value::Array(x) => x, + Value::Str(x) => x.chars().map(|x| Value::Int(x as u32 as i32).spl()).collect(), + }).spl()) +} + +pub fn to_str(stack: &mut Stack) { + let o = stack.pop().lock_ro().native.clone(); + stack.push(Value::Str(match o { + Value::Null => panic!("incompatible: null - str"), + Value::Int(x) => x.to_string(), + Value::Long(x) => x.to_string(), + Value::Mega(x) => x.to_string(), + Value::Float(x) => x.to_string(), + Value::Double(x) => x.to_string(), + Value::Func(_) => panic!("incompatible: func - str"), + Value::Array(x) => String::from_iter(x.into_iter().map(|x| match &x.lock_ro().native { + Value::Int(x) => char::from_u32(*x as u32).expect("invalid Unicode Char: {x}"), + _ => panic!("incompatible: !int - __str_element") + })), + Value::Str(x) => x, + }).spl()) +} + +pub fn call(stack: &mut Stack) { + if let Value::Func(ref a) = stack.pop().lock_ro().native { + stack.call(a); + } else { + panic!("incorrect usage of call"); + } +} + +pub fn register(r: &mut Stack, o: Arc) { + r.define_func( + "pop".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(pop), + origin: o.clone(), + }), + ); + r.define_func( + "dup".to_owned(), + AFunc::new(Func { + ret_count: 2, + to_call: FuncImpl::Native(dup), + origin: o.clone(), + }), + ); + r.define_func( + "clone".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(clone), + origin: o.clone(), + }), + ); + r.define_func( + "swap".to_owned(), + AFunc::new(Func { + ret_count: 2, + to_call: FuncImpl::Native(swap), + origin: o.clone(), + }), + ); + r.define_func( + "print".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(print), + origin: o.clone(), + }), + ); + r.define_func( + "call".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(call), + origin: o.clone(), + }), + ); + r.define_func( + "gettype".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(gettype), + origin: o.clone(), + }), + ); + r.define_func( + "settype".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(settype), + origin: o.clone(), + }), + ); + r.define_func( + "anew".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(array_new), + origin: o.clone(), + }), + ); + r.define_func( + "array-len".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(array_len), + origin: o.clone(), + }), + ); + r.define_func( + "array-get".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(array_get), + origin: o.clone(), + }), + ); + r.define_func( + "array-set".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(array_set), + origin: o.clone(), + }), + ); + r.define_func( + "eq".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(eq), + origin: o.clone(), + }), + ); + r.define_func( + "lt".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(lt), + origin: o.clone(), + }), + ); + r.define_func( + "gt".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(gt), + origin: o.clone(), + }), + ); + r.define_func( + "not".to_owned(), + AFunc::new(Func { + ret_count: 0, + to_call: FuncImpl::Native(not), + origin: o.clone(), + }), + ); + r.define_func( + "+".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(plus), + origin: o.clone(), + }), + ); + r.define_func( + "-".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(minus), + origin: o.clone(), + }), + ); + r.define_func( + "/".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(slash), + origin: o.clone(), + }), + ); + r.define_func( + "*".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(star), + origin: o.clone(), + }), + ); + r.define_func( + "_int".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(to_int), + origin: o.clone(), + }), + ); + r.define_func( + "_long".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(to_long), + origin: o.clone(), + }), + ); + r.define_func( + "_mega".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(to_mega), + origin: o.clone(), + }), + ); + r.define_func( + "_float".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(to_float), + origin: o.clone(), + }), + ); + r.define_func( + "_double".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(to_double), + origin: o.clone(), + }), + ); + r.define_func( + "_array".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(to_array), + origin: o.clone(), + }), + ); + r.define_func( + "_str".to_owned(), + AFunc::new(Func { + ret_count: 1, + to_call: FuncImpl::Native(to_str), + origin: o.clone(), + }), + ); +} diff --git a/test.spl b/test.spl new file mode 100644 index 0000000..67f1a7f --- /dev/null +++ b/test.spl @@ -0,0 +1,100 @@ + +def null + +func println { | + print "\n" print +} + +{ int | array-get } "get" "array" dyn-def-method +{ int | array-len } "len" "array" dyn-def-method +{ | array-set } "set" "array" dyn-def-method +{ | with this ; + def len this:len =len + def i 0 =i + while { i len lt } { + i this:get + i 1 + =i + } +} "to-stack" "array" dyn-def-method + +{ any | with type ; + null clone type settype "construct" dyn-objcall +} "new" "str" dyn-def-method + + +construct ChangingArray { + array + ; + construct { this | with array this ; + array this:=array + this + } + push { | with item this ; + [ this:array:to-stack item ] this:=array + } +} +construct ShrinkingArray_trait { + ; + pop { any | with this ; + [ this:array:to-stack pop ] this:=array + } +} + +include ShrinkingArray_trait in ChangingArray + +"ChangingArray now has push and pop."; + +construct shadow { } + +"Copy array"; +func acopy { array | with arr1 arr2 idx1 idx2 len ; + + def i 0 =i + while { i len lt } { + (( i idx1 + ) arr1:get) (i idx2 +) arr2:set + i 1 + =i + } + + arr2 +} + +func aadd { array | with arr1 arr2 ; + + def newarr arr1:len arr2:len + anew =newarr + + arr1 newarr 0 0 arr1:len acopy =newarr + arr2 newarr 0 arr1:len arr2:len acopy =newarr + + newarr +} + +func [ { shadow | + "array" "shadow" settype +} + +func ] { array | + "create an array containing everything on stack until the arrayshadow"; + def array 0 anew =array + def array2 + while { dup [ eq not } { + 1 anew =array2 + 0 array2:set + array2 array aadd =array + } + pop array +} + +def thing 1 anew =thing + +"hi" 0 thing:set + +def thing2 thing ChangingArray:new =thing2 + +"world" thing2:push + +def thing3 thing2:array =thing3 + +0 thing3:get println +1 thing3:get println + +"\"heya\" println" dyn-read call