errors, stack traces
This commit is contained in:
parent
07264a5f67
commit
901a5cb734
6 changed files with 407 additions and 286 deletions
|
@ -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(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
83
src/lexer.rs
83
src/lexer.rs
|
@ -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;
|
||||
|
|
58
src/main.rs
58
src/main.rs
|
@ -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(())
|
||||
|
|
257
src/runtime.rs
257
src/runtime.rs
|
@ -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)]
|
||||
|
|
|
@ -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(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
|
151
test.spl
151
test.spl
|
@ -1,122 +1,37 @@
|
|||
|
||||
def null
|
||||
func main { int | with args ;
|
||||
def thing
|
||||
|
||||
func println { |
|
||||
print "\n" print
|
||||
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
|
||||
|
||||
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
|
||||
{ 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
|
||||
|
||||
|
||||
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
|
||||
{ | with it ;
|
||||
it println
|
||||
} trace:foreach
|
||||
|
|
Loading…
Add table
Reference in a new issue