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

View file

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

View file

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

View file

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

View file

@ -365,22 +365,75 @@ pub fn call(stack: &mut Stack) -> OError {
stack.call(&a) 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 { 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())) return stack.err(ErrorKind::InvalidCall("exit".to_owned()))
}; };
process::exit(a) 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>) { pub fn register(r: &mut Stack, o: Arc<Frame>) {
type Fn = fn(&mut Stack) -> OError; type Fn = fn(&mut Stack) -> OError;
let fns: [(&str, Fn, u32); 28] = [ let fns: [(&str, Fn, u32); 31] = [
("pop", pop, 0), ("pop", pop, 0),
("dup", dup, 2), ("dup", dup, 2),
("clone", clone, 1), ("clone", clone, 1),
("swap", swap, 2), ("swap", swap, 2),
("print", print, 0), ("print", print, 0),
("call", call, 0),
("gettype", gettype, 1), ("gettype", gettype, 1),
("settype", settype, 1), ("settype", settype, 1),
("anew", array_new, 1), ("anew", array_new, 1),
@ -402,7 +455,11 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
("_double", to_double, 1), ("_double", to_double, 1),
("_array", to_array, 1), ("_array", to_array, 1),
("_str", to_str, 1), ("_str", to_str, 1),
("call", call, 0),
("trace", trace, 1),
("mr-trace", mr_trace, 1),
("exit", exit, 0), ("exit", exit, 0),
("exec", exec, 0),
]; ];
for f in fns { for f in fns {
r.define_func( r.define_func(
@ -411,7 +468,8 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
ret_count: f.2, ret_count: f.2,
to_call: FuncImpl::Native(f.1), to_call: FuncImpl::Native(f.1),
origin: o.clone(), origin: o.clone(),
cname: None, fname: None,
name: f.0.to_owned(),
}), }),
); );
} }

151
test.spl
View file

@ -1,122 +1,37 @@
def null func main { int | with args ;
def thing
func println { | 1 anew =thing
print "\n" print
"hi" 0 thing:unwrap:set;
def thing2 thing:unwrap ChangingArray:new =thing2
"world" thing2:unwrap:push
def thing3 thing2:unwrap:array =thing3
0 thing3:unwrap:get println
1 thing3:unwrap:get println
def thingy
"heya1" =thingy
"thingy println" dyn-read call
"heya2" =thingy
{ |
thingy println
{ |
{ | with it ;
it println
} trace:foreach
} call
} call
100
} }
{ int | array-get } "get" "array" dyn-def-method { | with it ;
{ int | array-len } "len" "array" dyn-def-method it println
{ any | array-set } "set" "array" dyn-def-method } trace:foreach
{ | 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
def thing
1 anew =thing
"hi" 0 thing:unwrap:set;
def thing2 thing:unwrap ChangingArray:new =thing2
"world" thing2:unwrap:push
def thing3 thing2:unwrap:array =thing3
0 thing3:unwrap:get println
1 thing3:unwrap:get println
"\"heya1\" println" dyn-read call
{ | "heya2" println } call