errors, stack traces

This commit is contained in:
Daniella / Tove 2023-02-19 04:57:32 +01:00
parent 07264a5f67
commit 901a5cb734
Signed by: TudbuT
GPG key ID: 7D63D5634B7C417F
6 changed files with 407 additions and 286 deletions

View file

@ -188,24 +188,19 @@ pub fn dyn_all_types(stack: &mut Stack) -> OError {
pub fn dyn_read(stack: &mut Stack) -> OError {
let Value::Str(s) = stack.pop().lock_ro().native.clone() else {
return stack.err(ErrorKind::InvalidCall("dyn-call".to_owned()))
return stack.err(ErrorKind::InvalidCall("dyn-read".to_owned()))
};
let origin = stack.peek_frame(1);
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(),
)
.map_err(|x| Error {
to_call: FuncImpl::SPL(lexer::lex(s).map_err(|x| Error {
kind: ErrorKind::LexError(format!("{x:?}")),
stack: stack.trace(),
})?,
),
origin: stack.get_frame(),
cname: None,
})?),
origin,
fname: None,
name: "(dyn-read)".to_owned(),
}))
.spl(),
);
@ -214,25 +209,25 @@ pub fn dyn_read(stack: &mut Stack) -> OError {
pub fn dyn_readf(stack: &mut Stack) -> OError {
let (
Value::Str(n),
Value::Str(s),
Value::Str(n),
) = (
stack.pop().lock_ro().native.clone(),
stack.pop().lock_ro().native.clone(),
) else {
return stack.err(ErrorKind::InvalidCall("dyn-call".to_owned()))
return stack.err(ErrorKind::InvalidCall("dyn-readf".to_owned()))
};
let origin = stack.peek_frame(1);
stack.push(
Value::Func(AFunc::new(Func {
ret_count: 0,
to_call: FuncImpl::SPL(lexer::lex(s, n.clone(), stack.get_frame()).map_err(|x| {
Error {
to_call: FuncImpl::SPL(lexer::lex(s).map_err(|x| Error {
kind: ErrorKind::LexError(format!("{x:?}")),
stack: stack.trace(),
}
})?),
origin: stack.get_frame(),
cname: Some(n),
origin,
fname: Some(n),
name: "(dyn-read)".to_owned(),
}))
.spl(),
);
@ -264,7 +259,8 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
ret_count: f.2,
to_call: FuncImpl::Native(f.1),
origin: o.clone(),
cname: None,
fname: None,
name: f.0.to_owned(),
}),
);
}

View file

@ -4,26 +4,23 @@ use crate::runtime::*;
use readformat::*;
#[derive(Debug, PartialEq, Eq)]
pub enum LexerError {}
pub enum LexerError {
FunctionBlockExpected,
WrongFunctionDeclaration,
InvalidInclude,
InvalidConstructBlock,
InvalidNumber(String),
}
pub fn lex(input: String, filename: String, frame: Arc<Frame>) -> Result<Words, LexerError> {
pub fn lex(input: String) -> Result<Words, LexerError> {
let mut str_words = Vec::new();
for line in input.split('\n') {
str_words.append(&mut parse_line(line));
}
Ok(read_block(
&str_words[..],
false,
Arc::new(Frame::new_in(frame, filename)),
)?
.1)
Ok(read_block(&str_words[..], false)?.1)
}
fn read_block(
str_words: &[String],
isfn: bool,
origin: Arc<Frame>,
) -> Result<(Option<u32>, Words, usize), LexerError> {
fn read_block(str_words: &[String], isfn: bool) -> Result<(Option<u32>, Words, usize), LexerError> {
let mut rem = None;
let mut words = Vec::new();
let mut i = 0;
@ -43,38 +40,32 @@ fn read_block(
i += 1;
}
"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,
Arc::new(Frame::new(origin.clone())),
)?;
if let Some(dat) = readf1("func\0{}\0{", str_words[i..=i + 2].join("\0").as_str()) {
let block = read_block(&str_words[i + 2..], true)?;
i += 2 + block.2;
words.push(Word::Key(Keyword::Func(
dat[0].to_owned(),
block.0.expect("LEXERR: Expected `{ <type> <...> |`."),
dat.to_owned(),
block.0.ok_or(LexerError::FunctionBlockExpected)?,
block.1,
)));
}
}
"{" => {
let block =
read_block(&str_words[i..], true, Arc::new(Frame::new(origin.clone())))?;
let block = read_block(&str_words[i..], true)?;
i += block.2;
words.push(Word::Const(Value::Func(AFunc::new(Func {
ret_count: block.0.expect("LEXERR: Expected `{ <type> <...> |`."),
ret_count: block.0.ok_or(LexerError::FunctionBlockExpected)?,
to_call: FuncImpl::SPL(block.1),
origin: origin.to_owned(),
cname: None,
origin: Arc::new(Frame::dummy()),
fname: None,
name: "dyn".to_owned(),
}))))
}
"construct" => {
let name = str_words[i + 1].to_owned();
assert_eq!(
str_words[i + 2],
"{",
"LEXERR: Expected `construct <name> {{`, got `construct <name>`"
);
if str_words[i + 2] != "{" {
return Err(LexerError::InvalidConstructBlock);
}
let mut fields = Vec::new();
i += 3;
while str_words[i] != ";" && str_words[i] != "}" {
@ -90,14 +81,11 @@ fn read_block(
if name == "construct" {
has_construct = true;
}
let block = read_block(&str_words[i + 1..], true, origin.clone())?;
let block = read_block(&str_words[i + 1..], true)?;
i += 1 + block.2;
methods.push((
name,
(
block.0.expect("LEXERR: Expected `{ <type> <...> |`."),
block.1,
),
(block.0.ok_or(LexerError::FunctionBlockExpected)?, block.1),
));
i += 1;
}
@ -117,19 +105,19 @@ fn read_block(
x[1].to_owned(),
)))
} else {
panic!("LEXERR: Expected `include <typeA> in <typeB>`.");
return Err(LexerError::InvalidInclude);
}
i += 3;
}
"while" => {
let cond = read_block(&str_words[i + 2..], false, origin.clone())?;
let cond = read_block(&str_words[i + 2..], false)?;
i += 2 + cond.2;
let blk = read_block(&str_words[i + 2..], false, origin.clone())?;
let blk = read_block(&str_words[i + 2..], false)?;
i += 2 + blk.2;
words.push(Word::Key(Keyword::While(cond.1, blk.1)));
}
"if" => {
let blk = read_block(&str_words[i + 2..], false, origin.clone())?;
let blk = read_block(&str_words[i + 2..], false)?;
i += 2 + blk.2;
words.push(Word::Key(Keyword::If(blk.1)));
}
@ -149,15 +137,24 @@ fn read_block(
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(Value::Mega(x.parse().unwrap())));
words.push(Word::Const(Value::Mega(
x.parse()
.map_err(|_| LexerError::InvalidNumber(x.to_owned()))?,
)));
}
x if x.chars().all(|c| c.is_numeric() || c == '.' || c == '_')
&& !x.starts_with('_') =>
{
words.push(Word::Const(Value::Double(x.parse().unwrap())));
words.push(Word::Const(Value::Double(
x.parse()
.map_err(|_| LexerError::InvalidNumber(x.to_owned()))?,
)));
}
x => {
let mut word = x.split(':').next().unwrap();
let mut word = x
.split(':')
.next()
.expect("unreachable (empty words are filtered by the parser)");
let mut ra = 0;
while word.starts_with('&') {
ra += 1;

View file

@ -1,41 +1,43 @@
use spl::{lexer::lex, runtime::*};
use std::{fs, vec};
use std::{fs, env::args};
fn main() -> OError {
let rt = Runtime::new();
let mut stack = Stack::new();
rt.set();
Words {
words: vec![
Word::Key(Keyword::Func(
"println".to_owned(),
0,
Words {
words: vec![
Word::Call("print".to_owned(), true, 0),
Word::Const(Value::Str("\n".to_owned())),
Word::Call("print".to_owned(), true, 0),
],
},
)),
Word::Key(Keyword::Def("helloworld".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),
],
let mut stack = Stack::new_in(FrameInfo {
file: "std.spl".to_owned(),
function: "root".to_owned(),
});
fn argv(stack: &mut Stack) -> OError {
stack.push(Value::Array(args().into_iter().map(|x| Value::Str(x).spl()).collect()).spl());
Ok(())
}
.exec(&mut stack)?;
let words = lex(
fs::read_to_string("test.spl").unwrap(),
"test.spl".to_owned(),
stack.get_frame(),
).map_err(|x| Error {
fn read_file(stack: &mut Stack) -> OError {
let Value::Str(s) = stack.pop().lock_ro().native.clone() else {
return stack.err(ErrorKind::InvalidCall("read_file".to_owned()))
};
stack.push(Value::Str(fs::read_to_string(s).map_err(|x| stack.error(ErrorKind::IO(format!("{x:?}"))))?).spl());
Ok(())
}
stack.define_func("argv".to_owned(), AFunc::new(Func {
ret_count: 1,
to_call: FuncImpl::Native(argv),
origin: stack.get_frame(),
fname: None,
name: "argv".to_owned(),
}));
stack.define_func("read-file".to_owned(), AFunc::new(Func {
ret_count: 1,
to_call: FuncImpl::Native(read_file),
origin: stack.get_frame(),
fname: None,
name: "read-file".to_owned(),
}));
let words = lex(fs::read_to_string("std.spl").unwrap()).map_err(|x| Error {
kind: ErrorKind::LexError(format!("{x:?}")),
stack: Vec::new(),
})?;
println!("{words:#?}");
words.exec(&mut stack)?;
Runtime::reset();
Ok(())

View file

@ -3,6 +3,7 @@ use crate::{dyn_fns, mutex::*, std_fns};
use core::panic;
use std::collections::VecDeque;
use std::mem;
use std::sync::RwLockWriteGuard;
use std::{
cell::RefCell,
collections::HashMap,
@ -17,11 +18,16 @@ pub type AFunc = Arc<Func>;
pub type OError = Result<(), Error>;
thread_local! {
static RUNTIME: RefCell<Option<Runtime>> = RefCell::new(None);
static RUNTIME: RefCell<Option<Arc<Mut<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()))
pub fn runtime<T>(f: impl FnOnce(RwLockWriteGuard<Runtime>) -> T) -> T {
RUNTIME.with(|rt| {
f(rt.borrow_mut()
.as_mut()
.expect("no runtime (use .set())")
.lock())
})
}
#[derive(Clone)]
@ -68,7 +74,11 @@ impl Runtime {
self.types_by_id.clone().into_values().collect()
}
pub fn make_type(&mut self, name: String, op: impl FnOnce(Type) -> Result<Type, Error>) -> Result<AMType, Error> {
pub fn make_type(
&mut self,
name: String,
op: impl FnOnce(Type) -> Result<Type, Error>,
) -> Result<AMType, Error> {
let t = Arc::new(Mut::new(op(Type {
name: name.clone(),
id: (self.next_type_id, self.next_type_id += 1).0,
@ -81,18 +91,31 @@ impl Runtime {
Ok(t)
}
pub fn set(self) {
RUNTIME.with(move |x| *x.borrow_mut() = Some(self));
}
pub fn reset() {
RUNTIME.with(|x| *x.borrow_mut() = None);
}
}
pub trait SetRuntime {
fn set(self);
}
impl SetRuntime for Runtime {
fn set(self) {
Arc::new(Mut::new(self)).set()
}
}
impl SetRuntime for Arc<Mut<Runtime>> {
fn set(self) {
RUNTIME.with(move |x| *x.borrow_mut() = Some(self));
}
}
#[derive(Clone)]
pub struct FrameInfo {
pub file: String,
pub function: String,
}
#[derive(Clone)]
@ -118,32 +141,60 @@ impl Display for Frame {
}
impl Frame {
fn root() -> Self {
pub fn dummy() -> Self {
Frame {
parent: None,
variables: Mut::new(HashMap::new()),
functions: Mut::new(HashMap::new()),
origin: FrameInfo {
file: "\0".to_owned(),
function: "\0".to_owned(),
},
}
}
pub fn root() -> Self {
Frame {
parent: None,
variables: Mut::new(HashMap::new()),
functions: Mut::new(HashMap::new()),
origin: FrameInfo {
file: "RUNTIME".to_owned(),
function: "root".to_owned(),
},
}
}
pub fn new(parent: Arc<Frame>) -> Self {
pub fn root_in(info: FrameInfo) -> Self {
Frame {
parent: None,
variables: Mut::new(HashMap::new()),
functions: Mut::new(HashMap::new()),
origin: info,
}
}
pub fn new(parent: Arc<Frame>, function: String) -> Self {
Frame {
variables: Mut::new(HashMap::new()),
functions: Mut::new(HashMap::new()),
origin: parent.origin.clone(),
origin: FrameInfo {
function,
..parent.origin.clone()
},
parent: Some(parent),
}
}
pub fn new_in(parent: Arc<Frame>, origin: String) -> Self {
pub fn new_in(parent: Arc<Frame>, origin: String, function: String) -> Self {
Frame {
parent: Some(parent),
variables: Mut::new(HashMap::new()),
functions: Mut::new(HashMap::new()),
origin: FrameInfo { file: origin },
origin: FrameInfo {
file: origin,
function,
},
}
}
@ -181,6 +232,25 @@ impl Frame {
}
}
}
pub fn path(&self) -> Vec<FrameInfo> {
let mut r = Vec::new();
let mut frame = self;
loop {
r.insert(0, frame.origin.clone());
if let Some(ref parent) = frame.parent {
frame = parent;
} else {
break;
}
}
r
}
pub fn is_dummy(&self) -> bool {
self.parent.is_none() && self.origin.file == "\0" && self.origin.function == "\0"
}
}
#[derive(Clone)]
@ -227,6 +297,19 @@ impl Stack {
r
}
pub fn new_in(frame_info: FrameInfo) -> Self {
let o = Arc::new(Frame::root_in(frame_info));
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);
r
}
pub fn define_func(&mut self, name: String, func: AFunc) {
self.frames
.last_mut()
@ -237,8 +320,8 @@ impl Stack {
}
pub fn call(&mut self, func: &AFunc) -> OError {
let mut f = Frame::new(func.origin.clone());
if let Some(ref cname) = func.cname {
let mut f = Frame::new(func.origin.clone(), func.name.clone());
if let Some(ref cname) = func.fname {
f.origin.file = cname.clone();
}
self.frames.push(Arc::new(f));
@ -278,7 +361,8 @@ impl Stack {
stack.push(tmpframe.get_var(tmpname.clone(), stack)?);
Ok(())
}))),
cname: Some("RUNTIME".to_owned()),
fname: Some("RUNTIME".to_owned()),
name: name.clone(),
}),
);
let tmpname = name.clone();
@ -292,7 +376,8 @@ impl Stack {
let v = stack.pop();
tmpframe.set_var(tmpname.clone(), v, stack)
}))),
cname: Some("RUNTIME".to_owned()),
fname: Some("RUNTIME".to_owned()),
name: "=".to_owned() + &name,
}),
);
frame.variables.lock().insert(name, Value::Null.spl());
@ -343,8 +428,42 @@ impl Stack {
}
}
pub fn mr_trace(&self) -> Vec<Vec<FrameInfo>> {
self.frames.iter().map(|frame| frame.path()).collect()
}
pub fn trace(&self) -> Vec<String> {
todo!()
self.frames
.iter()
.map(|frame| {
let mut item = String::new();
let path = frame.path();
let mut file = "\0".to_owned();
for element in path {
if element.file != file {
item += " | in ";
item += &element.file;
item += ":";
file = element.file;
}
item += " ";
item += &element.function;
}
item
})
.collect()
}
pub fn peek_frame(&self, index: usize) -> Arc<Frame> {
self.frames.get(self.frames.len() - index - 1).unwrap().clone()
}
pub unsafe fn pop_frame(&mut self, index: usize) -> Arc<Frame> {
self.frames.remove(self.frames.len() - index - 1)
}
pub unsafe fn push_frame(&mut self, frame: Arc<Frame>) {
self.frames.push(frame);
}
}
@ -411,6 +530,26 @@ pub enum Value {
Str(String),
}
impl Value {
fn ensure_init(self, stack: &Stack) -> Self {
match self {
Value::Func(x) if x.origin.is_dummy() => Value::Func(AFunc::new(Func {
origin: stack.get_frame(),
..x.as_ref().clone()
})),
x => x,
}
}
pub fn try_mega_to_int(self) -> Value {
if let Value::Mega(x) = self {
Value::Int(x as i32)
} else {
self
}
}
}
impl PartialOrd for Value {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match (self, other) {
@ -456,7 +595,8 @@ pub struct Func {
pub ret_count: u32,
pub to_call: FuncImpl,
pub origin: Arc<Frame>,
pub cname: Option<String>,
pub fname: Option<String>,
pub name: String,
}
impl PartialEq for Func {
@ -533,7 +673,8 @@ impl Type {
Ok(())
}))),
origin: origin.clone(),
cname: Some("RUNTIME".to_owned()),
fname: Some("RUNTIME".to_owned()),
name: name.clone(),
}),
);
let tmpname = name.clone();
@ -548,7 +689,8 @@ impl Type {
Ok(())
}))),
origin,
cname: Some("RUNTIME".to_owned()),
fname: Some("RUNTIME".to_owned()),
name: "=".to_owned() + &name,
}),
);
self.properties.push(name);
@ -580,6 +722,8 @@ impl PartialOrd for Object {
}
}
impl Eq for Object {}
impl Display for Object {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.kind.lock_ro().name)?;
@ -629,9 +773,7 @@ impl Object {
impl From<Value> for Object {
fn from(value: Value) -> Self {
Object::new(
RUNTIME.with(|x| {
let x = x.borrow();
let x = x.as_ref().expect("no runtime (use .set())");
runtime(|x| {
match value {
Value::Null => x.get_type_by_id(0),
Value::Int(_) => x.get_type_by_id(1),
@ -671,12 +813,13 @@ impl Words {
Keyword::Dump => println!("{stack}"),
Keyword::Def(x) => stack.define_var(x),
Keyword::Func(name, rem, words) => stack.define_func(
name,
name.clone(),
Arc::new(Func {
ret_count: rem,
to_call: FuncImpl::SPL(words),
origin: stack.get_frame(),
cname: None,
fname: None,
name,
}),
),
Keyword::Construct(name, fields, methods) => {
@ -685,30 +828,25 @@ impl Words {
stack.set_var(
name.clone(),
Value::Str(
RUNTIME
.with(move |rt| {
rt.borrow_mut().as_mut().expect("no runtime (use .set)").make_type(
name,
move |mut t| {
runtime(move |mut rt| {
rt.make_type(name.clone(), move |mut t| {
for field in fields {
t.add_property(field, origin.clone())?;
}
t.functions.extend(methods.into_iter().map(
|(k, v)| {
t.functions.extend(methods.into_iter().map(|(k, v)| {
(
k,
k.clone(),
Arc::new(Func {
ret_count: v.0,
to_call: FuncImpl::SPL(v.1),
origin: origin.clone(),
cname: None,
fname: None,
name: name.clone() + ":" + &k,
}),
)
},
));
}));
Ok(t)
},
)
})
})?
.lock_ro()
.get_name(),
@ -718,16 +856,16 @@ impl Words {
}
Keyword::Include(ta, tb) => {
let rstack = &stack;
RUNTIME.with(move |rt| {
let mut rt = rt.borrow_mut();
let rt = rt.as_mut().expect("no runtime (use .set())");
runtime(move |rt| {
rt.get_type_by_name(tb.clone())
.ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(tb.clone())))?
.lock()
.parents
.push(rt.get_type_by_name(ta).ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(tb)))?);
Ok(
())
.push(
rt.get_type_by_name(ta)
.ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(tb)))?,
);
Ok(())
})?;
}
Keyword::While(cond, blk) => loop {
@ -750,12 +888,16 @@ impl Words {
}
}
},
Word::Const(x) => stack.push(x.clone().spl()),
Word::Const(x) => stack.push(x.clone().ensure_init(stack).spl()),
Word::Call(x, rem, ra) => {
let f = stack.get_func(x)?;
let f = stack.get_func(x.clone())?;
if ra != 0 {
let mut f = Value::Func(f);
for _ in 1..ra {
for n in 1..ra {
let mut s = String::new();
for _ in 0..n {
s += "&";
}
let ftmp = f;
f = Value::Func(AFunc::new(Func {
ret_count: 1,
@ -764,9 +906,11 @@ impl Words {
Ok(())
}))),
origin: stack.get_frame(),
cname: None,
fname: None,
name: s + &x,
}));
}
stack.push(f.spl());
} else {
stack.call(&f)?;
if rem {
@ -784,7 +928,7 @@ impl Words {
.functions
.get(&x)
.ok_or_else(|| Error {
kind: ErrorKind::MethodNotFound(f0.name.clone(), x),
kind: ErrorKind::MethodNotFound(f0.name.clone(), x.clone()),
stack: stack.trace(),
})?
.clone();
@ -792,7 +936,11 @@ impl Words {
mem::drop(o);
if ra != 0 {
let mut f = Value::Func(f.clone());
for _ in 1..ra {
for n in 1..ra {
let mut s = String::new();
for _ in 0..n {
s += "&";
}
let ftmp = f;
f = Value::Func(AFunc::new(Func {
ret_count: 1,
@ -801,9 +949,11 @@ impl Words {
Ok(())
}))),
origin: stack.get_frame(),
cname: None,
fname: None,
name: s + &x,
}));
}
stack.push(f.spl())
} else {
stack.call(&f)?;
if rem {
@ -830,6 +980,9 @@ pub enum ErrorKind {
PropertyNotFound(String, String),
TypeNotFound(String),
LexError(String),
IO(String),
Custom(String),
CustomObject(AMObject),
}
#[derive(Debug, PartialEq, Eq)]

View file

@ -365,22 +365,75 @@ pub fn call(stack: &mut Stack) -> OError {
stack.call(&a)
}
pub fn trace(stack: &mut Stack) -> OError {
let trace = stack.trace();
stack.push(Value::Array(trace.into_iter().map(|x| Value::Str(x).spl()).collect()).spl());
Ok(())
}
pub fn mr_trace(stack: &mut Stack) -> OError {
let trace = stack.mr_trace();
let kind = runtime(|rt| rt.get_type_by_name("TraceElement".to_owned()))
.ok_or_else(|| stack.error(ErrorKind::TypeNotFound("TraceElement".to_owned())))?;
stack.push(
Value::Array(
trace
.into_iter()
.map(|x| {
Value::Array(
x.into_iter()
.map(|x| {
let item = Value::Null.spl();
let mut obj = item.lock();
for property in &kind.lock_ro().properties {
obj.property_map.insert(property.clone(), Value::Null.spl());
}
obj.kind = kind.clone();
obj.property_map
.insert("file".to_owned(), Value::Str(x.file).spl());
obj.property_map
.insert("function".to_owned(), Value::Str(x.function).spl());
mem::drop(obj);
item
})
.collect(),
)
.spl()
})
.collect(),
)
.spl(),
);
Ok(())
}
pub fn exit(stack: &mut Stack) -> OError {
let Value::Int(a) = stack.pop().lock_ro().native.clone() else {
let Value::Int(a) = stack.pop().lock_ro().native.clone().try_mega_to_int() else {
return stack.err(ErrorKind::InvalidCall("exit".to_owned()))
};
process::exit(a)
}
pub fn exec(stack: &mut Stack) -> OError {
let Value::Func(a) = stack.pop().lock_ro().native.clone() else {
return stack.err(ErrorKind::InvalidCall("exec".to_owned()))
};
unsafe {
let f = stack.pop_frame(0);
a.to_call.call(stack)?;
stack.push_frame(f);
}
Ok(())
}
pub fn register(r: &mut Stack, o: Arc<Frame>) {
type Fn = fn(&mut Stack) -> OError;
let fns: [(&str, Fn, u32); 28] = [
let fns: [(&str, Fn, u32); 31] = [
("pop", pop, 0),
("dup", dup, 2),
("clone", clone, 1),
("swap", swap, 2),
("print", print, 0),
("call", call, 0),
("gettype", gettype, 1),
("settype", settype, 1),
("anew", array_new, 1),
@ -402,7 +455,11 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
("_double", to_double, 1),
("_array", to_array, 1),
("_str", to_str, 1),
("call", call, 0),
("trace", trace, 1),
("mr-trace", mr_trace, 1),
("exit", exit, 0),
("exec", exec, 0),
];
for f in fns {
r.define_func(
@ -411,7 +468,8 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
ret_count: f.2,
to_call: FuncImpl::Native(f.1),
origin: o.clone(),
cname: None,
fname: None,
name: f.0.to_owned(),
}),
);
}

125
test.spl
View file

@ -1,107 +1,5 @@
def null
func println { |
print "\n" print
}
{ int | array-get } "get" "array" dyn-def-method
{ int | array-len } "len" "array" dyn-def-method
{ any | 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
{ | with callable this ;
def i 0 =i
while { i this:len lt } { i this:get callable call i ++ =i }
} "foreach" "array" 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
}
func ++ { mega |
1 +
}
{ | with type ;
"registering on " print type println
{ self | } "unwrap" type dyn-def-method
} dyn-all-types:foreach
{ | with this ;
"ERR: null cannot be unwrapped." println
1 _int exit
} "unwrap" "null" dyn-def-method
func main { int | with args ;
def thing
1 anew =thing
@ -117,6 +15,23 @@ def thing3 thing2:unwrap:array =thing3
0 thing3:unwrap:get println
1 thing3:unwrap:get println
"\"heya1\" println" dyn-read call
def thingy
"heya1" =thingy
"thingy println" dyn-read call
{ | "heya2" println } call
"heya2" =thingy
{ |
thingy println
{ |
{ | with it ;
it println
} trace:foreach
} call
} call
100
}
{ | with it ;
it println
} trace:foreach