more std functions, some fixes

This commit is contained in:
Daniella / Tove 2023-02-18 18:43:05 +01:00
parent b0e2697c8c
commit 2ce44f2b55
Signed by: TudbuT
GPG key ID: 7D63D5634B7C417F
8 changed files with 1233 additions and 162 deletions

297
src/dyn_fns.rs Normal file
View 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(),
}),
)
}

View file

@ -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<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 {
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<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 != "" {

View file

@ -1,3 +1,5 @@
pub(crate) mod dyn_fns;
pub mod lexer;
pub mod mutex;
pub mod runtime;
pub(crate) mod std_fns;

View file

@ -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();
}

View file

@ -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())
}
}

View file

@ -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,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();

506
src/std_fns.rs Normal file
View 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
View 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