more std functions, some fixes
This commit is contained in:
parent
b0e2697c8c
commit
2ce44f2b55
8 changed files with 1233 additions and 162 deletions
297
src/dyn_fns.rs
Normal file
297
src/dyn_fns.rs
Normal file
|
@ -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<Frame>) {
|
||||
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(),
|
||||
}),
|
||||
)
|
||||
}
|
97
src/lexer.rs
97
src/lexer.rs
|
@ -1,29 +1,33 @@
|
|||
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<Frame>) -> 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<u32>, Words, usize) {
|
||||
fn read_block(str_words: &[String], isfn: bool, origin: Arc<Frame>) -> (Option<u32>, Words, usize) {
|
||||
let mut rem = None;
|
||||
let mut words = Vec::new();
|
||||
let mut i = 0;
|
||||
if str_words[0] == "{" {
|
||||
if isfn {
|
||||
if str_words[0] == "{" && isfn {
|
||||
let mut r = 0_u32;
|
||||
while str_words[r as usize + 1] != "|" {
|
||||
r += 1;
|
||||
}
|
||||
i += r as usize + 1;
|
||||
i += r as usize + 2;
|
||||
rem = Some(r);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
while i < str_words.len() {
|
||||
let word = str_words[i].to_owned();
|
||||
match word.as_str() {
|
||||
|
@ -33,7 +37,11 @@ fn read_block(str_words: &[String], isfn: bool, origin: &FrameInfo) -> (Option<u
|
|||
}
|
||||
"func" => {
|
||||
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<u
|
|||
}
|
||||
}
|
||||
"{" => {
|
||||
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 `{ <type> <...> |`."),
|
||||
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<u
|
|||
"LEXERR: Expected `construct <name> {{`, got `construct <name>`"
|
||||
);
|
||||
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<u
|
|||
i += 1;
|
||||
}
|
||||
}
|
||||
if !has_construct {
|
||||
methods.push(("construct".to_string(), (1, Words { words: vec![] })));
|
||||
}
|
||||
words.push(Word::Key(Keyword::Construct(name, fields, methods)));
|
||||
}
|
||||
"include" => {
|
||||
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<u
|
|||
} else {
|
||||
panic!("LEXERR: Expected `include <typeA> in <typeB>`.");
|
||||
}
|
||||
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<u
|
|||
break;
|
||||
}
|
||||
x if x.starts_with("\"") => {
|
||||
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<String> {
|
|||
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<String> {
|
|||
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<String> {
|
|||
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 != "" {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
pub(crate) mod dyn_fns;
|
||||
pub mod lexer;
|
||||
pub mod mutex;
|
||||
pub mod runtime;
|
||||
pub(crate) mod std_fns;
|
||||
|
|
33
src/main.rs
33
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();
|
||||
}
|
||||
|
|
37
src/mutex.rs
37
src/mutex.rs
|
@ -1,14 +1,19 @@
|
|||
use std::sync::{Mutex, MutexGuard};
|
||||
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
||||
pub struct Mut<T>(Mutex<T>);
|
||||
#[derive(Debug)]
|
||||
pub struct Mut<T>(RwLock<T>);
|
||||
|
||||
impl<T> Mut<T> {
|
||||
pub fn new(obj: T) -> Mut<T> {
|
||||
Mut(Mutex::new(obj))
|
||||
Mut(RwLock::new(obj))
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> MutexGuard<T> {
|
||||
self.0.lock().unwrap()
|
||||
pub fn lock_ro(&self) -> RwLockReadGuard<T> {
|
||||
self.0.read().unwrap()
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> RwLockWriteGuard<T> {
|
||||
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<T> PartialEq for Mut<T>
|
||||
where
|
||||
T: PartialEq,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.read().unwrap().eq(&other.0.read().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Eq for Mut<T> where T: Eq {}
|
||||
|
||||
impl<T> PartialOrd for Mut<T>
|
||||
where
|
||||
T: PartialOrd,
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
self.0.read().unwrap().partial_cmp(&other.0.read().unwrap())
|
||||
}
|
||||
}
|
||||
|
|
297
src/runtime.rs
297
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<Option<Runtime>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
pub fn runtime<T>(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<AMType> {
|
||||
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<Frame>, origin: FrameInfo) -> Self {
|
||||
pub fn new(parent: Arc<Frame>) -> 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<Frame>, 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<Frame> {
|
||||
self.frames.last().unwrap().clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -285,25 +316,25 @@ pub enum Keyword {
|
|||
///
|
||||
/// Creates type <name>
|
||||
/// equivalent to
|
||||
/// "<name>" dyn-construct; "<name>" "<field>" dyn-def-field { <rem> | <words> } "<name>"
|
||||
/// "<fn-name>" dyn-def-method
|
||||
/// "<name>" dyn-construct; "<field>" "<name>" dyn-def-field { <rem> | <words> } "<fn-name>"
|
||||
/// "<name>" dyn-def-method
|
||||
Construct(String, Vec<String>, Vec<(String, (u32, Words))>),
|
||||
/// include <typeA> in <typeB>
|
||||
///
|
||||
/// Adds <typeA> as a parent type of <typeB>.
|
||||
/// equivalent to "<typeA>" "<typeB>" dyn-include
|
||||
Include(String, String),
|
||||
/// while <wordsA> { <wordsB> }
|
||||
/// while { <wordsA> } { <wordsB> }
|
||||
///
|
||||
/// If wordsA result in a truthy value being on the top of the stack, execute wordsB, and
|
||||
/// repeat.
|
||||
/// equivalent to { int | <wordsA> } { | <wordsB> } dyn-while
|
||||
While(Words, Words),
|
||||
/// if <wordsA> { <wordsB> }
|
||||
/// if { <wordsB> }
|
||||
///
|
||||
/// If wordsA result in a truthy value being on the top of the stack, execute wordsB.
|
||||
/// equivalent to { int | <wordsA> } { | <wordsB> } dyn-if
|
||||
If(Words, Words),
|
||||
/// equivalent to { | <wordsB> } dyn-if
|
||||
If(Words),
|
||||
/// with <item> <...> ;
|
||||
///
|
||||
/// Defines variables in reverse order.
|
||||
|
@ -312,8 +343,8 @@ pub enum Keyword {
|
|||
With(Vec<String>),
|
||||
}
|
||||
|
||||
#[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<AMObject>),
|
||||
Str(String),
|
||||
}
|
||||
|
||||
impl PartialOrd for Value {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
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<Frame>,
|
||||
}
|
||||
|
||||
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<String>,
|
||||
}
|
||||
|
||||
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<AFunc> {
|
||||
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<Frame>) {
|
||||
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<String, AMObject>,
|
||||
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<std::cmp::Ordering> {
|
||||
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<Constant> for Object {
|
||||
fn from(value: Constant) -> Self {
|
||||
impl From<Value> 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,18 +602,25 @@ 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)| {
|
||||
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 {
|
||||
|
@ -514,10 +629,17 @@ impl Words {
|
|||
origin: origin.clone(),
|
||||
}),
|
||||
)
|
||||
}));
|
||||
},
|
||||
));
|
||||
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();
|
||||
|
|
506
src/std_fns.rs
Normal file
506
src/std_fns.rs
Normal file
|
@ -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<Frame>) {
|
||||
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(),
|
||||
}),
|
||||
);
|
||||
}
|
100
test.spl
Normal file
100
test.spl
Normal file
|
@ -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
|
Loading…
Add table
Reference in a new issue