basic error propagation
This commit is contained in:
parent
7b5ba3fbf7
commit
d2d533642a
6 changed files with 639 additions and 447 deletions
391
src/dyn_fns.rs
391
src/dyn_fns.rs
|
@ -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,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
32
src/lexer.rs
32
src/lexer.rs
|
@ -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> {
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
239
src/runtime.rs
239
src/runtime.rs
|
@ -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>,
|
||||||
|
}
|
||||||
|
|
364
src/std_fns.rs
364
src/std_fns.rs
|
@ -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,
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
46
test.spl
46
test.spl
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue