basic error propagation

This commit is contained in:
Daniella / Tove 2023-02-19 02:03:06 +01:00
parent 7b5ba3fbf7
commit d2d533642a
Signed by: TudbuT
GPG key ID: 7D63D5634B7C417F
6 changed files with 639 additions and 447 deletions

View file

@ -2,223 +2,245 @@ use std::sync::Arc;
use crate::{lexer, runtime::*}; use crate::{lexer, runtime::*};
pub fn dyn_dump(stack: &mut Stack) { pub fn dyn_dump(stack: &mut Stack) -> OError {
Words { Words {
words: vec![Word::Key(Keyword::Dump)], words: vec![Word::Key(Keyword::Dump)],
} }
.exec(stack); .exec(stack)
} }
pub fn dyn_def(stack: &mut Stack) { pub fn dyn_def(stack: &mut Stack) -> OError {
if let Value::Str(s) = stack.pop().lock_ro().native.clone() { let Value::Str(s) = stack.pop().lock_ro().native.clone() else {
Words { return stack.err(ErrorKind::InvalidCall("dyn-def".to_owned()))
words: vec![Word::Key(Keyword::Def(s))], };
} Words {
.exec(stack); words: vec![Word::Key(Keyword::Def(s))],
} else {
panic!("incorrect usage of dyn-def");
} }
.exec(stack)?;
Ok(())
} }
pub fn dyn_func(stack: &mut Stack) { pub fn dyn_func(stack: &mut Stack) -> OError {
if let Value::Str(s) = stack.pop().lock_ro().native.clone() { let (
if let Value::Func(f) = stack.pop().lock_ro().native.clone() { Value::Str(s),
stack.define_func(s, f); Value::Func(f),
} else { ) = (
panic!("incorrect usage of dyn-func"); stack.pop().lock_ro().native.clone(),
} stack.pop().lock_ro().native.clone(),
} else { ) else {
panic!("incorrect usage of dyn-func"); return stack.err(ErrorKind::InvalidCall("dyn-func".to_owned()))
};
stack.define_func(s, f);
Ok(())
}
pub fn dyn_construct(stack: &mut Stack) -> OError {
let Value::Str(s) = stack.pop().lock_ro().native.clone() else {
return stack.err(ErrorKind::InvalidCall("dyn-construct".to_owned()))
};
Words {
words: vec![Word::Key(Keyword::Construct(s, Vec::new(), Vec::new()))],
} }
.exec(stack)?;
Ok(())
} }
pub fn dyn_construct(stack: &mut Stack) { pub fn dyn_def_field(stack: &mut Stack) -> OError {
if let Value::Str(s) = stack.pop().lock_ro().native.clone() { let (
Words { Value::Str(s),
words: vec![Word::Key(Keyword::Construct(s, Vec::new(), Vec::new()))], Value::Str(name),
} ) = (
.exec(stack); stack.pop().lock_ro().native.clone(),
} else { stack.pop().lock_ro().native.clone(),
panic!("incorrect usage of dyn-construct"); ) else {
return stack.err(ErrorKind::InvalidCall("dyn-def-field".to_owned()))
};
runtime(|rt| rt.get_type_by_name(s.to_owned()))
.ok_or_else(|| Error {
kind: ErrorKind::TypeNotFound(s),
stack: stack.trace(),
})?
.lock()
.add_property(name, stack.get_frame())?;
Ok(())
}
pub fn dyn_def_method(stack: &mut Stack) -> OError {
let (
Value::Str(s),
Value::Str(name),
Value::Func(f),
) = (
stack.pop().lock_ro().native.clone(),
stack.pop().lock_ro().native.clone(),
stack.pop().lock_ro().native.clone(),
) else {
return stack.err(ErrorKind::InvalidCall("dyn-def-method".to_owned()))
};
runtime(|rt| rt.get_type_by_name(s.to_owned()))
.ok_or_else(|| Error {
kind: ErrorKind::TypeNotFound(s),
stack: stack.trace(),
})?
.lock()
.functions
.insert(name, f);
Ok(())
}
pub fn dyn_include(stack: &mut Stack) -> OError {
let (
Value::Str(b),
Value::Str(a),
) = (
stack.pop().lock_ro().native.clone(),
stack.pop().lock_ro().native.clone(),
) else {
return stack.err(ErrorKind::InvalidCall("dyn-include".to_owned()))
};
Words {
words: vec![Word::Key(Keyword::Include(a, b))],
} }
.exec(stack)?;
Ok(())
} }
pub fn dyn_def_field(stack: &mut Stack) { pub fn dyn_while(stack: &mut Stack) -> OError {
if let Value::Str(s) = stack.pop().lock_ro().native.clone() { let (
if let Value::Str(name) = stack.pop().lock_ro().native.clone() { Value::Func(blk),
runtime(|rt| { Value::Func(cond),
rt.get_type_by_name(s) ) = (
.unwrap() stack.pop().lock_ro().native.clone(),
.lock() stack.pop().lock_ro().native.clone(),
.add_property(name, stack.get_frame()); ) else {
}); return stack.err(ErrorKind::InvalidCall("dyn-while".to_owned()))
} else { };
panic!("incorrect usage of dyn-def-field"); loop {
cond.to_call.call(stack)?;
if !stack.pop().lock_ro().is_truthy() {
break;
} }
} else { blk.to_call.call(stack)?;
panic!("incorrect usage of dyn-def-field");
} }
Ok(())
} }
pub fn dyn_def_method(stack: &mut Stack) { pub fn dyn_if(stack: &mut Stack) -> OError {
if let Value::Str(s) = stack.pop().lock_ro().native.clone() { let Value::Func(blk) = stack.pop().lock_ro().native.clone() else {
if let Value::Str(name) = stack.pop().lock_ro().native.clone() { return stack.err(ErrorKind::InvalidCall("dyn-if".to_owned()))
if let Value::Func(f) = stack.pop().lock_ro().native.clone() { };
runtime(|rt| { if stack.pop().lock_ro().is_truthy() {
rt.get_type_by_name(s) blk.to_call.call(stack)?;
.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");
} }
Ok(())
} }
pub fn dyn_include(stack: &mut Stack) { pub fn dyn_call(stack: &mut Stack) -> OError {
if let Value::Str(b) = stack.pop().lock_ro().native.clone() { let Value::Str(mut s) = stack.pop().lock_ro().native.clone() else {
if let Value::Str(a) = stack.pop().lock_ro().native.clone() { return stack.err(ErrorKind::InvalidCall("dyn-call".to_owned()))
Words { };
words: vec![Word::Key(Keyword::Include(a, b))], let mut words = Vec::new();
} let mut ra = 0;
.exec(stack); while s.starts_with("&") {
} else { ra += 1;
panic!("incorrect usage of dyn-include"); s = s[1..].to_owned();
}
} else {
panic!("incorrect usage of dyn-include");
} }
} if s.ends_with(";") {
words.push(Word::Call(s[..s.len() - 1].to_owned(), true, ra));
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 { } else {
panic!("incorrect usage of dyn-while"); words.push(Word::Call(s.to_owned(), false, ra));
} }
Words { words }.exec(stack)?;
Ok(())
} }
pub fn dyn_if(stack: &mut Stack) { pub fn dyn_objcall(stack: &mut Stack) -> OError {
if let Value::Func(blk) = stack.pop().lock_ro().native.clone() { let Value::Str(mut s) = stack.pop().lock_ro().native.clone() else {
if stack.pop().lock_ro().is_truthy() { return stack.err(ErrorKind::InvalidCall("dyn-objcall".to_owned()))
blk.to_call.call(stack); };
} 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 { } else {
panic!("incorrect usage of dyn-if"); words.push(Word::ObjCall(s.to_owned(), false, ra));
} }
Words { words }.exec(stack)?;
Ok(())
} }
pub fn dyn_call(stack: &mut Stack) { pub fn dyn_all_types(stack: &mut Stack) -> OError {
if let Value::Str(mut s) = stack.pop().lock_ro().native.clone() { stack.push(
let mut words = Vec::new(); Value::Array(
let mut ra = 0; runtime(|rt| rt.get_types())
while s.starts_with("&") { .into_iter()
ra += 1; .map(|x| Value::Str(x.lock_ro().get_name()).spl())
s = s[1..].to_owned(); .collect(),
} )
if s.ends_with(";") { .spl(),
words.push(Word::Call(s[..s.len() - 1].to_owned(), true, ra)); );
} else { Ok(())
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) { pub fn dyn_read(stack: &mut Stack) -> OError {
if let Value::Str(mut s) = stack.pop().lock_ro().native.clone() { let Value::Str(s) = stack.pop().lock_ro().native.clone() else {
let mut words = Vec::new(); return stack.err(ErrorKind::InvalidCall("dyn-call".to_owned()))
let mut ra = 0; };
while s.starts_with("&") { stack.push(
ra += 1; Value::Func(AFunc::new(Func {
s = s[1..].to_owned(); ret_count: 0,
} to_call: FuncImpl::SPL(
if s.ends_with(";") { lexer::lex(
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, s,
"dyn-read@".to_owned() + &stack.get_origin().file, "dyn-read@".to_owned() + &stack.get_origin().file,
stack.get_frame(), stack.get_frame(),
)), )
origin: stack.get_frame(), .map_err(|x| Error {
cname: None, kind: ErrorKind::LexError(format!("{x:?}")),
})) stack: stack.trace(),
.spl(), })?,
); ),
} else { origin: stack.get_frame(),
panic!("incorrect usage of dyn-call"); cname: None,
} }))
.spl(),
);
Ok(())
} }
pub fn dyn_readf(stack: &mut Stack) { pub fn dyn_readf(stack: &mut Stack) -> OError {
if let Value::Str(n) = stack.pop().lock_ro().native.clone() { let (
if let Value::Str(s) = stack.pop().lock_ro().native.clone() { Value::Str(n),
stack.push( Value::Str(s),
Value::Func(AFunc::new(Func { ) = (
ret_count: 0, stack.pop().lock_ro().native.clone(),
to_call: FuncImpl::SPL(lexer::lex(s, n.clone(), stack.get_frame())), stack.pop().lock_ro().native.clone(),
origin: stack.get_frame(), ) else {
cname: Some(n), return stack.err(ErrorKind::InvalidCall("dyn-call".to_owned()))
})) };
.spl(), stack.push(
); Value::Func(AFunc::new(Func {
} else { ret_count: 0,
panic!("incorrect usage of dyn-call"); to_call: FuncImpl::SPL(lexer::lex(s, n.clone(), stack.get_frame()).map_err(|x| {
} Error {
} else { kind: ErrorKind::LexError(format!("{x:?}")),
panic!("incorrect usage of dyn-call"); stack: stack.trace(),
} }
})?),
origin: stack.get_frame(),
cname: Some(n),
}))
.spl(),
);
Ok(())
} }
pub fn register(r: &mut Stack, o: Arc<Frame>) { pub fn register(r: &mut Stack, o: Arc<Frame>) {
let fns: [(&str, fn(&mut Stack), u32); 14] = [ let fns: [(&str, fn(&mut Stack) -> OError, u32); 14] = [
("dyn-__dump", dyn_dump, 0), ("dyn-__dump", dyn_dump, 0),
("dyn-def", dyn_def, 0), ("dyn-def", dyn_def, 0),
("dyn-func", dyn_func, 0), ("dyn-func", dyn_func, 0),
@ -235,11 +257,14 @@ pub fn register(r: &mut Stack, o: Arc<Frame>) {
("dyn-readf", dyn_readf, 1), ("dyn-readf", dyn_readf, 1),
]; ];
for f in fns { for f in fns {
r.define_func(f.0.to_owned(), AFunc::new(Func { r.define_func(
ret_count: f.2, f.0.to_owned(),
to_call: FuncImpl::Native(f.1), AFunc::new(Func {
origin: o.clone(), ret_count: f.2,
cname: None, to_call: FuncImpl::Native(f.1),
})); origin: o.clone(),
cname: None,
}),
);
} }
} }

View file

@ -3,20 +3,27 @@ use std::sync::Arc;
use crate::runtime::*; use crate::runtime::*;
use readformat::*; use readformat::*;
pub fn lex(input: String, filename: String, frame: Arc<Frame>) -> Words { #[derive(Debug, PartialEq, Eq)]
pub enum LexerError {}
pub fn lex(input: String, filename: String, frame: Arc<Frame>) -> 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));
} }
read_block( Ok(read_block(
&str_words[..], &str_words[..],
false, false,
Arc::new(Frame::new_in(frame, filename)), Arc::new(Frame::new_in(frame, filename)),
) )?
.1 .1)
} }
fn read_block(str_words: &[String], isfn: bool, origin: Arc<Frame>) -> (Option<u32>, Words, usize) { fn read_block(
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;
@ -41,7 +48,7 @@ fn read_block(str_words: &[String], isfn: bool, origin: Arc<Frame>) -> (Option<u
&str_words[i + 2..], &str_words[i + 2..],
true, true,
Arc::new(Frame::new(origin.clone())), 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[0].to_owned(),
@ -51,7 +58,8 @@ fn read_block(str_words: &[String], isfn: bool, origin: Arc<Frame>) -> (Option<u
} }
} }
"{" => { "{" => {
let block = read_block(&str_words[i..], true, Arc::new(Frame::new(origin.clone()))); let block =
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.expect("LEXERR: Expected `{ <type> <...> |`."),
@ -82,7 +90,7 @@ fn read_block(str_words: &[String], isfn: bool, origin: Arc<Frame>) -> (Option<u
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, origin.clone())?;
i += 1 + block.2; i += 1 + block.2;
methods.push(( methods.push((
name, name,
@ -114,14 +122,14 @@ fn read_block(str_words: &[String], isfn: bool, origin: Arc<Frame>) -> (Option<u
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, origin.clone())?;
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, origin.clone())?;
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, origin.clone())?;
i += 2 + blk.2; i += 2 + blk.2;
words.push(Word::Key(Keyword::If(blk.1))); words.push(Word::Key(Keyword::If(blk.1)));
} }
@ -176,7 +184,7 @@ fn read_block(str_words: &[String], isfn: bool, origin: Arc<Frame>) -> (Option<u
} }
i += 1; i += 1;
} }
(rem, Words { words }, i) Ok((rem, Words { words }, i))
} }
fn parse_line(line: &str) -> Vec<String> { fn parse_line(line: &str) -> Vec<String> {

View file

@ -2,7 +2,7 @@ use spl::{lexer::lex, runtime::*};
use std::{fs, vec}; use std::{fs, vec};
fn main() { fn main() -> OError {
let rt = Runtime::new(); let rt = Runtime::new();
let mut stack = Stack::new(); let mut stack = Stack::new();
rt.set(); rt.set();
@ -26,13 +26,17 @@ fn main() {
Word::Call("println".to_owned(), true, 0), Word::Call("println".to_owned(), true, 0),
], ],
} }
.exec(&mut stack); .exec(&mut stack)?;
let words = lex( let words = lex(
fs::read_to_string("test.spl").unwrap(), fs::read_to_string("test.spl").unwrap(),
"test.spl".to_owned(), "test.spl".to_owned(),
stack.get_frame(), stack.get_frame(),
); ).map_err(|x| Error {
println!("{words:?}"); kind: ErrorKind::LexError(format!("{x:?}")),
words.exec(&mut stack); stack: Vec::new(),
})?;
println!("{words:#?}");
words.exec(&mut stack)?;
Runtime::reset(); Runtime::reset();
Ok(())
} }

View file

@ -14,6 +14,7 @@ use std::{
pub type AMObject = Arc<Mut<Object>>; pub type AMObject = Arc<Mut<Object>>;
pub type AMType = Arc<Mut<Type>>; pub type AMType = Arc<Mut<Type>>;
pub type AFunc = Arc<Func>; pub type AFunc = Arc<Func>;
pub type OError = Result<(), Error>;
thread_local! { thread_local! {
static RUNTIME: RefCell<Option<Runtime>> = RefCell::new(None); static RUNTIME: RefCell<Option<Runtime>> = RefCell::new(None);
@ -37,15 +38,15 @@ impl Runtime {
types_by_name: HashMap::new(), types_by_name: HashMap::new(),
types_by_id: HashMap::new(), types_by_id: HashMap::new(),
}; };
rt.make_type("null".to_owned(), |t| t); let _ = rt.make_type("null".to_owned(), |t| Ok(t)); // infallible
rt.make_type("int".to_owned(), |t| t); let _ = rt.make_type("int".to_owned(), |t| Ok(t)); // infallible
rt.make_type("long".to_owned(), |t| t); let _ = rt.make_type("long".to_owned(), |t| Ok(t)); // infallible
rt.make_type("mega".to_owned(), |t| t); let _ = rt.make_type("mega".to_owned(), |t| Ok(t)); // infallible
rt.make_type("float".to_owned(), |t| t); let _ = rt.make_type("float".to_owned(), |t| Ok(t)); // infallible
rt.make_type("double".to_owned(), |t| t); let _ = rt.make_type("double".to_owned(), |t| Ok(t)); // infallible
rt.make_type("func".to_owned(), |t| t); let _ = rt.make_type("func".to_owned(), |t| Ok(t)); // infallible
rt.make_type("array".to_owned(), |t| t); let _ = rt.make_type("array".to_owned(), |t| Ok(t)); // infallible
rt.make_type("str".to_owned(), |t| t); let _ = rt.make_type("str".to_owned(), |t| Ok(t)); // infallible
rt rt
} }
@ -61,17 +62,17 @@ 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) -> Type) -> AMType { 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,
parents: Vec::new(), parents: Vec::new(),
functions: HashMap::new(), functions: HashMap::new(),
properties: Vec::new(), properties: Vec::new(),
}))); })?));
self.types_by_id.insert(self.next_type_id - 1, t.clone()); self.types_by_id.insert(self.next_type_id - 1, t.clone());
self.types_by_name.insert(name, t.clone()); self.types_by_name.insert(name, t.clone());
t Ok(t)
} }
pub fn set(self) { pub fn set(self) {
@ -139,6 +140,41 @@ impl Frame {
origin: FrameInfo { file: origin }, origin: FrameInfo { file: origin },
} }
} }
pub fn set_var(&self, name: String, obj: AMObject, stack: &Stack) -> OError {
let mut frame = self;
loop {
if let Some(x) = frame.variables.lock().get_mut(&name) {
*x = obj;
return Ok(());
}
if let Some(ref x) = frame.parent {
frame = x;
} else {
return Err(Error {
kind: ErrorKind::VariableNotFound(name),
stack: stack.trace(),
});
}
}
}
pub fn get_var(&self, name: String, stack: &Stack) -> Result<AMObject, Error> {
let mut frame = self;
loop {
if let Some(x) = frame.variables.lock_ro().get(&name) {
return Ok(x.clone());
}
if let Some(ref x) = frame.parent {
frame = x;
} else {
return Err(Error {
kind: ErrorKind::VariableNotFound(name),
stack: stack.trace(),
});
}
}
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -188,91 +224,74 @@ impl Stack {
.insert(name, func); .insert(name, func);
} }
pub fn call(&mut self, func: &AFunc) { pub fn call(&mut self, func: &AFunc) -> OError {
let mut f = Frame::new(func.origin.clone()); let mut f = Frame::new(func.origin.clone());
if let Some(ref cname) = func.cname { if let Some(ref cname) = func.cname {
f.origin.file = cname.clone(); f.origin.file = cname.clone();
} }
self.frames.push(Arc::new(f)); self.frames.push(Arc::new(f));
func.to_call.call(self); func.to_call.call(self)?;
self.frames.pop().unwrap(); self.frames.pop().unwrap();
Ok(())
} }
pub fn get_func(&self, name: String) -> AFunc { pub fn get_func(&self, name: String) -> Result<AFunc, Error> {
let mut frame = self.frames.last().unwrap(); let mut frame = self.frames.last().unwrap();
loop { loop {
let functions = &frame.functions; let functions = &frame.functions;
if let Some(x) = functions.lock_ro().get(&name) { if let Some(x) = functions.lock_ro().get(&name) {
return x.clone(); return Ok(x.clone());
} }
if let Some(ref x) = frame.parent { if let Some(ref x) = frame.parent {
frame = x; frame = x;
} else { } else {
panic!("Function not found: {}", name) return Err(Error {
kind: ErrorKind::FuncNotFound(name),
stack: self.trace(),
});
} }
} }
} }
// TODO actually use the frame for the variable (can cause issues when using referenced
// functions)
pub fn define_var(&mut self, name: String) { pub fn define_var(&mut self, name: String) {
let frame = self.frames.last_mut().unwrap().clone(); let frame = self.frames.last_mut().unwrap().clone();
let tmpname = name.clone(); let tmpname = name.clone();
let tmpframe = frame.clone();
frame.functions.lock().insert( frame.functions.lock().insert(
name.clone(), name.clone(),
Arc::new(Func { Arc::new(Func {
ret_count: 1, ret_count: 1,
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
stack.push(stack.get_var(tmpname.clone()))
}))),
origin: frame.clone(), origin: frame.clone(),
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
stack.push(tmpframe.get_var(tmpname.clone(), &stack)?);
Ok(())
}))),
cname: Some("RUNTIME".to_owned()), cname: Some("RUNTIME".to_owned()),
}), }),
); );
let tmpname = name.clone(); let tmpname = name.clone();
frame.functions.lock().insert( let tmpframe = frame.clone();
frame.clone().functions.lock().insert(
"=".to_owned() + &name, "=".to_owned() + &name,
Arc::new(Func { Arc::new(Func {
ret_count: 0, ret_count: 0,
origin: frame.clone(),
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| { to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
let v = stack.pop(); let v = stack.pop();
stack.set_var(tmpname.clone(), v); tmpframe.set_var(tmpname.clone(), v, &stack)
}))), }))),
origin: frame.clone(),
cname: Some("RUNTIME".to_owned()), cname: Some("RUNTIME".to_owned()),
}), }),
); );
frame.variables.lock().insert(name, Value::Null.spl()); frame.variables.lock().insert(name, Value::Null.spl());
} }
pub fn set_var(&mut self, name: String, obj: AMObject) { pub fn set_var(&self, name: String, obj: AMObject) -> OError {
let mut frame = self.frames.last().unwrap(); self.get_frame().set_var(name, obj, self)
loop {
if let Some(x) = frame.variables.lock().get_mut(&name) {
*x = obj;
break;
}
if let Some(ref x) = frame.parent {
frame = x;
} else {
dyn_fns::dyn_dump(self);
panic!("undefined var: {name}");
}
}
} }
pub fn get_var(&self, name: String) -> AMObject { pub fn get_var(&self, name: String) -> Result<AMObject, Error> {
let mut frame = self.frames.last().unwrap(); self.get_frame().get_var(name, self)
loop {
if let Some(x) = frame.variables.lock_ro().get(&name) {
return x.clone();
}
if let Some(ref x) = frame.parent {
frame = x;
} else {
panic!("undefined var")
}
}
} }
pub fn push(&mut self, obj: AMObject) { pub fn push(&mut self, obj: AMObject) {
@ -297,6 +316,24 @@ impl Stack {
pub fn get_frame(&self) -> Arc<Frame> { pub fn get_frame(&self) -> Arc<Frame> {
self.frames.last().unwrap().clone() self.frames.last().unwrap().clone()
} }
pub fn err<T>(&self, kind: ErrorKind) -> Result<T, Error> {
Err(Error {
kind,
stack: self.trace(),
})
}
pub fn error(&self, kind: ErrorKind) -> Error {
Error {
kind,
stack: self.trace(),
}
}
pub fn trace(&self) -> Vec<String> {
todo!()
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -386,13 +423,13 @@ pub struct Words {
#[derive(Clone)] #[derive(Clone)]
pub enum FuncImpl { pub enum FuncImpl {
Native(fn(&mut Stack)), Native(fn(&mut Stack) -> OError),
NativeDyn(Arc<Box<dyn Fn(&mut Stack)>>), NativeDyn(Arc<Box<dyn Fn(&mut Stack) -> OError>>),
SPL(Words), SPL(Words),
} }
impl FuncImpl { impl FuncImpl {
pub fn call(&self, stack: &mut Stack) { pub fn call(&self, stack: &mut Stack) -> OError {
match self { match self {
FuncImpl::Native(x) => x(stack), FuncImpl::Native(x) => x(stack),
FuncImpl::NativeDyn(x) => x(stack), FuncImpl::NativeDyn(x) => x(stack),
@ -460,7 +497,7 @@ impl Type {
None None
} }
pub fn add_property(&mut self, name: String, origin: Arc<Frame>) { pub fn add_property(&mut self, name: String, origin: Arc<Frame>) -> OError {
let tmpname = name.clone(); let tmpname = name.clone();
self.functions.insert( self.functions.insert(
name.clone(), name.clone(),
@ -468,7 +505,19 @@ impl Type {
ret_count: 1, ret_count: 1,
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| { to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
let o = stack.pop(); let o = stack.pop();
stack.push(o.lock_ro().property_map.get(&tmpname).unwrap().clone()); let o = o.lock_ro();
stack.push(
o.property_map
.get(&tmpname)
.ok_or_else(|| {
stack.error(ErrorKind::PropertyNotFound(
o.kind.lock_ro().name.clone(),
tmpname.clone(),
))
})?
.clone(),
);
Ok(())
}))), }))),
origin: origin.clone(), origin: origin.clone(),
cname: Some("RUNTIME".to_owned()), cname: Some("RUNTIME".to_owned()),
@ -483,12 +532,14 @@ impl Type {
let o = stack.pop(); let o = stack.pop();
let v = stack.pop(); let v = stack.pop();
o.lock().property_map.insert(tmpname.clone(), v); o.lock().property_map.insert(tmpname.clone(), v);
Ok(())
}))), }))),
origin, origin,
cname: Some("RUNTIME".to_owned()), cname: Some("RUNTIME".to_owned()),
}), }),
); );
self.properties.push(name); self.properties.push(name);
Ok(())
} }
} }
@ -567,7 +618,7 @@ impl From<Value> for Object {
Object::new( Object::new(
RUNTIME.with(|x| { RUNTIME.with(|x| {
let x = x.borrow(); let x = x.borrow();
let x = x.as_ref().unwrap(); 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),
@ -600,7 +651,7 @@ where
} }
impl Words { impl Words {
pub fn exec(&self, stack: &mut Stack) { pub fn exec(&self, stack: &mut Stack) -> OError {
for word in self.words.clone() { for word in self.words.clone() {
match word { match word {
Word::Key(x) => match x { Word::Key(x) => match x {
@ -623,11 +674,11 @@ impl Words {
Value::Str( Value::Str(
RUNTIME RUNTIME
.with(move |rt| { .with(move |rt| {
rt.borrow_mut().as_mut().unwrap().make_type( rt.borrow_mut().as_mut().expect("no runtime (use .set)").make_type(
name, name,
move |mut t| { 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)| {
@ -642,51 +693,52 @@ impl Words {
) )
}, },
)); ));
t Ok(t)
}, },
) )
}) })?
.lock_ro() .lock_ro()
.get_name(), .get_name(),
) )
.spl(), .spl(),
); )?;
} }
Keyword::Include(ta, tb) => { Keyword::Include(ta, tb) => {
let rstack = &stack;
RUNTIME.with(move |rt| { RUNTIME.with(move |rt| {
let mut rt = rt.borrow_mut(); let mut rt = rt.borrow_mut();
let rt = rt.as_mut().unwrap(); let rt = rt.as_mut().expect("no runtime (use .set())");
// TODO: Handle properly Ok(
rt.get_type_by_name(tb) rt.get_type_by_name(tb.clone())
.unwrap() .ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(tb.clone())))?
.lock() .lock()
.parents .parents
.push(rt.get_type_by_name(ta).unwrap()) .push(rt.get_type_by_name(ta).ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(tb)))?))
}); })?;
} }
Keyword::While(cond, blk) => loop { Keyword::While(cond, blk) => loop {
cond.exec(stack); cond.exec(stack)?;
if !stack.pop().lock_ro().is_truthy() { if !stack.pop().lock_ro().is_truthy() {
break; break;
} }
blk.exec(stack); blk.exec(stack)?;
}, },
Keyword::If(blk) => { Keyword::If(blk) => {
if stack.pop().lock_ro().is_truthy() { if stack.pop().lock_ro().is_truthy() {
blk.exec(stack); blk.exec(stack)?;
} }
} }
Keyword::With(vars) => { Keyword::With(vars) => {
for var in vars.into_iter().rev() { for var in vars.into_iter().rev() {
stack.define_var(var.clone()); stack.define_var(var.clone());
let obj = stack.pop(); let obj = stack.pop();
stack.set_var(var, obj); stack.set_var(var, obj)?;
} }
} }
}, },
Word::Const(x) => stack.push(x.clone().spl()), Word::Const(x) => stack.push(x.clone().spl()),
Word::Call(x, rem, ra) => { Word::Call(x, rem, ra) => {
let f = stack.get_func(x); let f = stack.get_func(x)?;
if ra != 0 { if ra != 0 {
let mut f = Value::Func(f); let mut f = Value::Func(f);
for _ in 1..ra { for _ in 1..ra {
@ -695,13 +747,14 @@ impl Words {
ret_count: 1, ret_count: 1,
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| { to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
stack.push(ftmp.clone().spl()); stack.push(ftmp.clone().spl());
Ok(())
}))), }))),
origin: stack.get_frame(), origin: stack.get_frame(),
cname: None, cname: None,
})); }));
} }
} else { } else {
stack.call(&f); stack.call(&f)?;
if rem { if rem {
for _ in 0..f.ret_count { for _ in 0..f.ret_count {
stack.pop(); stack.pop();
@ -712,19 +765,14 @@ impl Words {
Word::ObjCall(x, rem, ra) => { Word::ObjCall(x, rem, ra) => {
let o = stack.peek(); let o = stack.peek();
let o = o.lock_ro(); let o = o.lock_ro();
// TODO: raise error if not found
let f0 = o.kind.lock_ro(); let f0 = o.kind.lock_ro();
let f = f0 let f = f0
.functions .functions
.get(&x) .get(&x)
.unwrap_or_else(|| { .ok_or_else(|| Error {
panic!( kind: ErrorKind::MethodNotFound(f0.name.clone(), x),
"objcall not possible. {} {:?} {}", stack: stack.trace(),
o.kind.lock_ro().name, })?
o.native,
x
)
})
.clone(); .clone();
mem::drop(f0); mem::drop(f0);
mem::drop(o); mem::drop(o);
@ -736,13 +784,14 @@ impl Words {
ret_count: 1, ret_count: 1,
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| { to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
stack.push(ftmp.clone().spl()); stack.push(ftmp.clone().spl());
Ok(())
}))), }))),
origin: stack.get_frame(), origin: stack.get_frame(),
cname: None, cname: None,
})); }));
} }
} else { } else {
stack.call(&f); stack.call(&f)?;
if rem { if rem {
for _ in 0..f.ret_count { for _ in 0..f.ret_count {
stack.pop(); stack.pop();
@ -752,5 +801,25 @@ impl Words {
} }
} }
} }
Ok(())
} }
} }
#[derive(Debug, PartialEq, Eq)]
pub enum ErrorKind {
Parse(String, String),
InvalidCall(String),
InvalidType(String, String),
VariableNotFound(String),
FuncNotFound(String),
MethodNotFound(String, String),
PropertyNotFound(String, String),
TypeNotFound(String),
LexError(String),
}
#[derive(Debug, PartialEq, Eq)]
pub struct Error {
pub kind: ErrorKind,
pub stack: Vec<String>,
}

View file

@ -1,276 +1,312 @@
use core::panic;
use std::{ use std::{
io::{stdout, Write}, io::{stdout, Write},
mem, mem, process,
sync::Arc, sync::Arc,
}; };
use crate::{mutex::Mut, runtime::*}; use crate::{mutex::Mut, runtime::*};
pub fn print(stack: &mut Stack) { macro_rules! type_err {
if let Value::Str(s) = stack.pop().lock_ro().native.clone() { ($stack:expr, $a:expr, $b:expr) => {
print!("{s}"); $stack.err(ErrorKind::InvalidType($a.to_owned(), $b.to_owned()))?
stdout().lock().flush().unwrap(); };
} else {
panic!("incorrect usage of print");
}
} }
pub fn clone(stack: &mut Stack) { pub fn print(stack: &mut Stack) -> OError {
let Value::Str(s) = stack.pop().lock_ro().native.clone() else {
return stack.err(ErrorKind::InvalidCall("print".to_owned()))
};
print!("{s}");
stdout().lock().flush().unwrap();
Ok(())
}
pub fn clone(stack: &mut Stack) -> OError {
let o = stack.pop(); let o = stack.pop();
stack.push(Arc::new(Mut::new(o.lock_ro().clone()))); stack.push(Arc::new(Mut::new(o.lock_ro().clone())));
Ok(())
} }
pub fn dup(stack: &mut Stack) { pub fn dup(stack: &mut Stack) -> OError {
let o = stack.peek(); let o = stack.peek();
stack.push(o); stack.push(o);
Ok(())
} }
pub fn pop(stack: &mut Stack) { pub fn pop(stack: &mut Stack) -> OError {
stack.pop(); stack.pop();
Ok(())
} }
pub fn swap(stack: &mut Stack) { pub fn swap(stack: &mut Stack) -> OError {
let a = stack.pop(); let a = stack.pop();
let b = stack.pop(); let b = stack.pop();
stack.push(a); stack.push(a);
stack.push(b); stack.push(b);
Ok(())
} }
pub fn settype(stack: &mut Stack) { pub fn settype(stack: &mut Stack) -> OError {
if let Value::Str(s) = stack.pop().lock_ro().native.clone() { let Value::Str(s) = stack.pop().lock_ro().native.clone() else {
let o = stack.pop(); return stack.err(ErrorKind::InvalidCall("settype".to_owned()))
let kind = runtime(|rt| rt.get_type_by_name(s).unwrap()); };
let mut obj = o.lock(); let o = stack.pop();
for property in &kind.lock_ro().properties { let kind = runtime(|rt| rt.get_type_by_name(s.clone()))
obj.property_map.insert(property.clone(), Value::Null.spl()); .ok_or_else(|| stack.error(ErrorKind::TypeNotFound(s)))?;
} let mut obj = o.lock();
obj.kind = kind; for property in &kind.lock_ro().properties {
mem::drop(obj); obj.property_map.insert(property.clone(), Value::Null.spl());
stack.push(o);
} else {
panic!("incorrect usage of settype");
} }
obj.kind = kind;
mem::drop(obj);
stack.push(o);
Ok(())
} }
pub fn gettype(stack: &mut Stack) { pub fn gettype(stack: &mut Stack) -> OError {
let o = stack.pop(); let o = stack.pop();
stack.push(Value::Str(o.lock_ro().kind.lock_ro().get_name()).spl()); stack.push(Value::Str(o.lock_ro().kind.lock_ro().get_name()).spl());
Ok(())
} }
pub fn array_new(stack: &mut Stack) { pub fn array_new(stack: &mut Stack) -> OError {
if let Value::Mega(i) = stack.pop().lock_ro().native.clone() { let Value::Mega(i) = stack.pop().lock_ro().native.clone() else {
stack.push(Value::Array(vec![Value::Null.spl(); i as usize]).spl()); return stack.err(ErrorKind::InvalidCall("anew".to_owned()))
} else { };
panic!("incorrect usage of anew"); stack.push(Value::Array(vec![Value::Null.spl(); i as usize]).spl());
} Ok(())
} }
pub fn array_len(stack: &mut Stack) { pub fn array_len(stack: &mut Stack) -> OError {
if let Value::Array(ref a) = stack.pop().lock_ro().native { let binding = stack.pop();
stack.push(Value::Mega(a.len() as i128).spl()); let Value::Array(ref a) = binding.lock_ro().native else {
} else { return stack.err(ErrorKind::InvalidCall("array-len".to_owned()))
panic!("incorrect usage of array-len"); };
} stack.push(Value::Mega(a.len() as i128).spl());
Ok(())
} }
pub fn array_get(stack: &mut Stack) { pub fn array_get(stack: &mut Stack) -> OError {
if let Value::Array(ref a) = stack.pop().lock_ro().native { let binding = stack.pop();
if let Value::Mega(i) = stack.pop().lock_ro().native.clone() { let Value::Array(ref a) = binding.lock_ro().native else {
stack.push(a[i as usize].clone()); return stack.err(ErrorKind::InvalidCall("array-get".to_owned()))
} else { };
panic!("incorrect usage of array-get"); let Value::Mega(i) = stack.pop().lock_ro().native.clone() else {
} return stack.err(ErrorKind::InvalidCall("array-get".to_owned()))
} else { };
panic!("incorrect usage of array-get"); stack.push(a[i as usize].clone());
} Ok(())
} }
pub fn array_set(stack: &mut Stack) { pub fn array_set(stack: &mut Stack) -> OError {
if let Value::Array(ref mut a) = stack.pop().lock().native { let binding = stack.pop();
if let Value::Mega(i) = stack.pop().lock_ro().native.clone() { let Value::Array(ref mut a) = binding.lock().native else {
let o = stack.pop(); return stack.err(ErrorKind::InvalidCall("array-set".to_owned()))
a[i as usize] = o; };
} else { let Value::Mega(i) = stack.pop().lock_ro().native.clone() else {
panic!("incorrect usage of array-set"); return stack.err(ErrorKind::InvalidCall("array-set".to_owned()))
} };
} 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(); let o = stack.pop();
stack.push(Value::Int(if o.lock_ro().is_truthy() { 0 } else { 1 }).spl()) stack.push(a[i as usize].clone());
a[i as usize] = o;
Ok(())
} }
pub fn plus(stack: &mut Stack) { pub fn eq(stack: &mut Stack) -> OError {
let b = stack.pop();
let a = stack.pop();
stack.push(Value::Int(if a == b { 1 } else { 0 }).spl());
Ok(())
}
pub fn lt(stack: &mut Stack) -> OError {
let b = stack.pop();
let a = stack.pop();
stack.push(Value::Int(if a < b { 1 } else { 0 }).spl());
Ok(())
}
pub fn gt(stack: &mut Stack) -> OError {
let b = stack.pop();
let a = stack.pop();
stack.push(Value::Int(if a > b { 1 } else { 0 }).spl());
Ok(())
}
pub fn not(stack: &mut Stack) -> OError {
let o = stack.pop();
stack.push(Value::Int(if o.lock_ro().is_truthy() { 0 } else { 1 }).spl());
Ok(())
}
pub fn plus(stack: &mut Stack) -> OError {
let a = stack.pop().lock_ro().native.clone(); let a = stack.pop().lock_ro().native.clone();
let b = stack.pop().lock_ro().native.clone(); let b = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
match (a, b) { match (a, b) {
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a + b), (Value::Mega(a), Value::Mega(b)) => Value::Mega(a + b),
_ => panic!(), _ => todo!(),
} }
.spl(), .spl(),
); );
Ok(())
} }
pub fn minus(stack: &mut Stack) { pub fn minus(stack: &mut Stack) -> OError {
let a = stack.pop().lock_ro().native.clone(); let a = stack.pop().lock_ro().native.clone();
let b = stack.pop().lock_ro().native.clone(); let b = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
match (a, b) { match (a, b) {
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a - b), (Value::Mega(a), Value::Mega(b)) => Value::Mega(a - b),
_ => panic!(), _ => todo!(),
} }
.spl(), .spl(),
); );
Ok(())
} }
pub fn slash(stack: &mut Stack) { pub fn slash(stack: &mut Stack) -> OError {
let a = stack.pop().lock_ro().native.clone(); let a = stack.pop().lock_ro().native.clone();
let b = stack.pop().lock_ro().native.clone(); let b = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
match (a, b) { match (a, b) {
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a / b), (Value::Mega(a), Value::Mega(b)) => Value::Mega(a / b),
_ => panic!(), _ => todo!(),
} }
.spl(), .spl(),
); );
Ok(())
} }
pub fn star(stack: &mut Stack) { pub fn star(stack: &mut Stack) -> OError {
let a = stack.pop().lock_ro().native.clone(); let a = stack.pop().lock_ro().native.clone();
let b = stack.pop().lock_ro().native.clone(); let b = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
match (a, b) { match (a, b) {
(Value::Mega(a), Value::Mega(b)) => Value::Mega(a * b), (Value::Mega(a), Value::Mega(b)) => Value::Mega(a * b),
_ => panic!(), _ => todo!(),
} }
.spl(), .spl(),
); );
Ok(())
} }
pub fn to_int(stack: &mut Stack) { pub fn to_int(stack: &mut Stack) -> OError {
let o = stack.pop().lock_ro().native.clone(); let o = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
Value::Int(match o { Value::Int(match o {
Value::Null => panic!("incompatible: null - int"), Value::Null => type_err!(stack, "null", "int"),
Value::Int(x) => x, Value::Int(x) => x,
Value::Long(x) => x as i32, Value::Long(x) => x as i32,
Value::Mega(x) => x as i32, Value::Mega(x) => x as i32,
Value::Float(x) => x as i32, Value::Float(x) => x as i32,
Value::Double(x) => x as i32, Value::Double(x) => x as i32,
Value::Func(_) => panic!("incompatible: func - int"), Value::Func(_) => type_err!(stack, "func", "int"),
Value::Array(_) => panic!("incompatible: array - int"), Value::Array(_) => type_err!(stack, "array", "int"),
Value::Str(x) => x.parse().expect("invalid int"), Value::Str(x) => x
.parse()
.map_err(|_| stack.error(ErrorKind::Parse(x, "int".to_owned())))?,
}) })
.spl(), .spl(),
) );
Ok(())
} }
pub fn to_long(stack: &mut Stack) { pub fn to_long(stack: &mut Stack) -> OError {
let o = stack.pop().lock_ro().native.clone(); let o = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
Value::Long(match o { Value::Long(match o {
Value::Null => panic!("incompatible: null - long"), Value::Null => type_err!(stack, "null", "long"),
Value::Int(x) => x as i64, Value::Int(x) => x as i64,
Value::Long(x) => x as i64, Value::Long(x) => x as i64,
Value::Mega(x) => x as i64, Value::Mega(x) => x as i64,
Value::Float(x) => x as i64, Value::Float(x) => x as i64,
Value::Double(x) => x as i64, Value::Double(x) => x as i64,
Value::Func(_) => panic!("incompatible: func - long"), Value::Func(_) => type_err!(stack, "func", "long"),
Value::Array(_) => panic!("incompatible: array - long"), Value::Array(_) => type_err!(stack, "array", "long"),
Value::Str(x) => x.parse().expect("invalid long"), Value::Str(x) => x
.parse()
.map_err(|_| stack.error(ErrorKind::Parse(x, "long".to_owned())))?,
}) })
.spl(), .spl(),
) );
Ok(())
} }
pub fn to_mega(stack: &mut Stack) { pub fn to_mega(stack: &mut Stack) -> OError {
let o = stack.pop().lock_ro().native.clone(); let o = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
Value::Mega(match o { Value::Mega(match o {
Value::Null => panic!("incompatible: null - mega"), Value::Null => type_err!(stack, "null", "mega"),
Value::Int(x) => x as i128, Value::Int(x) => x as i128,
Value::Long(x) => x as i128, Value::Long(x) => x as i128,
Value::Mega(x) => x as i128, Value::Mega(x) => x as i128,
Value::Float(x) => x as i128, Value::Float(x) => x as i128,
Value::Double(x) => x as i128, Value::Double(x) => x as i128,
Value::Func(_) => panic!("incompatible: func - mega"), Value::Func(_) => type_err!(stack, "func", "mega"),
Value::Array(_) => panic!("incompatible: array - mega"), Value::Array(_) => type_err!(stack, "array", "mega"),
Value::Str(x) => x.parse().expect("invalid mega"), Value::Str(x) => x
.parse()
.map_err(|_| stack.error(ErrorKind::Parse(x, "mega".to_owned())))?,
}) })
.spl(), .spl(),
) );
Ok(())
} }
pub fn to_float(stack: &mut Stack) { pub fn to_float(stack: &mut Stack) -> OError {
let o = stack.pop().lock_ro().native.clone(); let o = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
Value::Float(match o { Value::Float(match o {
Value::Null => panic!("incompatible: null - float"), Value::Null => type_err!(stack, "null", "float"),
Value::Int(x) => x as f32, Value::Int(x) => x as f32,
Value::Long(x) => x as f32, Value::Long(x) => x as f32,
Value::Mega(x) => x as f32, Value::Mega(x) => x as f32,
Value::Float(x) => x as f32, Value::Float(x) => x as f32,
Value::Double(x) => x as f32, Value::Double(x) => x as f32,
Value::Func(_) => panic!("incompatible: func - float"), Value::Func(_) => type_err!(stack, "func", "float"),
Value::Array(_) => panic!("incompatible: array - float"), Value::Array(_) => type_err!(stack, "array", "float"),
Value::Str(x) => x.parse().expect("invalid float"), Value::Str(x) => x
.parse()
.map_err(|_| stack.error(ErrorKind::Parse(x, "float".to_owned())))?,
}) })
.spl(), .spl(),
) );
Ok(())
} }
pub fn to_double(stack: &mut Stack) { pub fn to_double(stack: &mut Stack) -> OError {
let o = stack.pop().lock_ro().native.clone(); let o = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
Value::Double(match o { Value::Double(match o {
Value::Null => panic!("incompatible: null - double"), Value::Null => type_err!(stack, "null", "double"),
Value::Int(x) => x as f64, Value::Int(x) => x as f64,
Value::Long(x) => x as f64, Value::Long(x) => x as f64,
Value::Mega(x) => x as f64, Value::Mega(x) => x as f64,
Value::Float(x) => x as f64, Value::Float(x) => x as f64,
Value::Double(x) => x as f64, Value::Double(x) => x as f64,
Value::Func(_) => panic!("incompatible: func - double"), Value::Func(_) => type_err!(stack, "func", "double"),
Value::Array(_) => panic!("incompatible: array - double"), Value::Array(_) => type_err!(stack, "array", "double"),
Value::Str(x) => x.parse().expect("invalid double"), Value::Str(x) => x
.parse()
.map_err(|_| stack.error(ErrorKind::Parse(x, "double".to_owned())))?,
}) })
.spl(), .spl(),
) );
Ok(())
} }
pub fn to_array(stack: &mut Stack) { pub fn to_array(stack: &mut Stack) -> OError {
let o = stack.pop().lock_ro().native.clone(); let o = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
Value::Array(match o { Value::Array(match o {
Value::Null => panic!("incompatible: null - array"), Value::Null => type_err!(stack, "null", "array"),
Value::Int(_) => panic!("incompatible: int - array"), Value::Int(_) => type_err!(stack, "int", "array"),
Value::Long(_) => panic!("incompatible: long - array"), Value::Long(_) => type_err!(stack, "long", "array"),
Value::Mega(_) => panic!("incompatible: mega - array"), Value::Mega(_) => type_err!(stack, "mega", "array"),
Value::Float(_) => panic!("incompatible: float - array"), Value::Float(_) => type_err!(stack, "float", "array"),
Value::Double(_) => panic!("incompatible: double - array"), Value::Double(_) => type_err!(stack, "double", "array"),
Value::Func(_) => panic!("incompatible: func - array"), Value::Func(_) => type_err!(stack, "func", "array"),
Value::Array(x) => x, Value::Array(x) => x,
Value::Str(x) => x Value::Str(x) => x
.chars() .chars()
@ -278,42 +314,66 @@ pub fn to_array(stack: &mut Stack) {
.collect(), .collect(),
}) })
.spl(), .spl(),
) );
Ok(())
} }
pub fn to_str(stack: &mut Stack) { pub fn to_str(stack: &mut Stack) -> OError {
let o = stack.pop().lock_ro().native.clone(); let o = stack.pop().lock_ro().native.clone();
stack.push( stack.push(
Value::Str(match o { Value::Str(match o {
Value::Null => panic!("incompatible: null - str"), Value::Null => type_err!(stack, "null", "str"),
Value::Int(x) => x.to_string(), Value::Int(x) => x.to_string(),
Value::Long(x) => x.to_string(), Value::Long(x) => x.to_string(),
Value::Mega(x) => x.to_string(), Value::Mega(x) => x.to_string(),
Value::Float(x) => x.to_string(), Value::Float(x) => x.to_string(),
Value::Double(x) => x.to_string(), Value::Double(x) => x.to_string(),
Value::Func(_) => panic!("incompatible: func - str"), Value::Func(_) => type_err!(stack, "func", "str"),
Value::Array(x) => { Value::Array(x) => {
String::from_iter(x.into_iter().map(|x| match &x.lock_ro().native { let iter: Vec<_> = x
Value::Int(x) => char::from_u32(*x as u32).expect("invalid Unicode Char: {x}"), .into_iter()
_ => panic!("incompatible: !int - __str_element"), .map(|x| match &x.lock_ro().native {
})) Value::Int(x) => char::from_u32(*x as u32).ok_or_else(|| {
stack.error(ErrorKind::InvalidType(
format!("int-{x}"),
"__str-element".to_owned(),
))
}),
_ => stack.err(ErrorKind::InvalidType(
"int".to_owned(),
"__str-element".to_owned(),
)),
})
.collect();
let mut fixed = String::with_capacity(iter.len());
for item in iter {
fixed.push(item?);
}
fixed
} }
Value::Str(x) => x, Value::Str(x) => x,
}) })
.spl(), .spl(),
) );
Ok(())
} }
pub fn call(stack: &mut Stack) { pub fn call(stack: &mut Stack) -> OError {
if let Value::Func(ref a) = stack.pop().lock_ro().native { let Value::Func(a) = stack.pop().lock_ro().native.clone() else {
stack.call(a); return stack.err(ErrorKind::InvalidCall("call".to_owned()))
} else { };
panic!("incorrect usage of call"); stack.call(&a)
} }
pub fn exit(stack: &mut Stack) -> OError {
let Value::Int(a) = stack.pop().lock_ro().native.clone() else {
return stack.err(ErrorKind::InvalidCall("exit".to_owned()))
};
process::exit(a)
} }
pub fn register(r: &mut Stack, o: Arc<Frame>) { pub fn register(r: &mut Stack, o: Arc<Frame>) {
let fns: [(&str, fn(&mut Stack), u32); 27] = [ let fns: [(&str, fn(&mut Stack) -> OError, u32); 28] = [
("pop", pop, 0), ("pop", pop, 0),
("dup", dup, 2), ("dup", dup, 2),
("clone", clone, 1), ("clone", clone, 1),
@ -341,13 +401,17 @@ 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),
("exit", exit, 0),
]; ];
for f in fns { for f in fns {
r.define_func(f.0.to_owned(), AFunc::new(Func { r.define_func(
ret_count: f.2, f.0.to_owned(),
to_call: FuncImpl::Native(f.1), AFunc::new(Func {
origin: o.clone(), ret_count: f.2,
cname: None, to_call: FuncImpl::Native(f.1),
})); origin: o.clone(),
cname: None,
}),
);
} }
} }

View file

@ -7,7 +7,7 @@ func println { |
{ int | array-get } "get" "array" dyn-def-method { int | array-get } "get" "array" dyn-def-method
{ int | array-len } "len" "array" dyn-def-method { int | array-len } "len" "array" dyn-def-method
{ | array-set } "set" "array" dyn-def-method { any | array-set } "set" "array" dyn-def-method
{ | with this ; { | with this ;
def len this:len =len def len this:len =len
def i 0 =i def i 0 =i
@ -21,6 +21,10 @@ func println { |
null clone type settype "construct" dyn-objcall null clone type settype "construct" dyn-objcall
} "new" "str" dyn-def-method } "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 { construct ChangingArray {
array array
@ -51,7 +55,7 @@ func acopy { array | with arr1 arr2 idx1 idx2 len ;
def i 0 =i def i 0 =i
while { i len lt } { while { i len lt } {
(( i idx1 + ) arr1:get) (i idx2 +) arr2:set (( i idx1 + ) arr1:get) (i idx2 +) arr2:set;
i 1 + =i i 1 + =i
} }
@ -62,7 +66,7 @@ func aadd { array | with arr1 arr2 ;
def newarr arr1:len arr2:len + anew =newarr def newarr arr1:len arr2:len + anew =newarr
arr1 newarr 0 0 arr1:len acopy =newarr arr1 newarr 0 0 arr1:len acopy =newarr
arr2 newarr 0 arr1:len arr2:len acopy =newarr arr2 newarr 0 arr1:len arr2:len acopy =newarr
newarr newarr
@ -78,23 +82,41 @@ func ] { array |
def array2 def array2
while { dup [ eq not } { while { dup [ eq not } {
1 anew =array2 1 anew =array2
0 array2:set 0 array2:set;
array2 array aadd =array array2 array aadd =array
} }
pop array pop array
} }
def thing 1 anew =thing func ++ { mega |
1 +
}
"hi" 0 thing:set { | 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 thing2 thing ChangingArray:new =thing2
"world" thing2:push def thing
def thing3 thing2:array =thing3 1 anew =thing
0 thing3:get println "hi" 0 thing:unwrap:set;
1 thing3:get println
"\"heya\" println" dyn-read call 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