2023-02-19 19:34:25 +01:00
|
|
|
use crate::{
|
|
|
|
dyn_fns,
|
|
|
|
mutex::*,
|
2023-02-25 15:02:31 +01:00
|
|
|
std_fns, stdlib,
|
|
|
|
stream::{self, *},
|
2023-02-19 19:34:25 +01:00
|
|
|
};
|
2023-02-17 22:47:45 +01:00
|
|
|
|
2023-02-18 18:43:05 +01:00
|
|
|
use core::panic;
|
2023-02-25 12:41:02 +01:00
|
|
|
use std::collections::VecDeque;
|
|
|
|
use std::sync::{RwLockReadGuard, RwLockWriteGuard};
|
2023-02-17 22:47:45 +01:00
|
|
|
use std::{
|
|
|
|
cell::RefCell,
|
|
|
|
collections::HashMap,
|
2023-02-18 18:43:05 +01:00
|
|
|
fmt::{Debug, Display, Formatter},
|
2023-02-17 22:47:45 +01:00
|
|
|
sync::Arc,
|
|
|
|
vec,
|
|
|
|
};
|
2023-02-25 11:37:07 +01:00
|
|
|
use std::{env::var, mem, path::Path};
|
2023-02-17 22:47:45 +01:00
|
|
|
|
|
|
|
pub type AMObject = Arc<Mut<Object>>;
|
|
|
|
pub type AMType = Arc<Mut<Type>>;
|
|
|
|
pub type AFunc = Arc<Func>;
|
2023-02-19 02:03:06 +01:00
|
|
|
pub type OError = Result<(), Error>;
|
2023-02-17 22:47:45 +01:00
|
|
|
|
|
|
|
thread_local! {
|
2023-02-19 04:57:32 +01:00
|
|
|
static RUNTIME: RefCell<Option<Arc<Mut<Runtime>>>> = RefCell::new(None);
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// Obtains a reference to the runtime.
|
2023-02-25 11:37:07 +01:00
|
|
|
pub fn runtime<T>(f: impl FnOnce(RwLockReadGuard<Runtime>) -> T) -> T {
|
|
|
|
RUNTIME.with(|rt| {
|
|
|
|
f(rt.borrow_mut()
|
|
|
|
.as_mut()
|
|
|
|
.expect("no runtime (use .set())")
|
|
|
|
.lock_ro())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// Obtains a mutable reference to the runtime.
|
2023-02-25 11:37:07 +01:00
|
|
|
pub fn runtime_mut<T>(f: impl FnOnce(RwLockWriteGuard<Runtime>) -> T) -> T {
|
2023-02-19 04:57:32 +01:00
|
|
|
RUNTIME.with(|rt| {
|
|
|
|
f(rt.borrow_mut()
|
|
|
|
.as_mut()
|
|
|
|
.expect("no runtime (use .set())")
|
|
|
|
.lock())
|
|
|
|
})
|
2023-02-18 18:43:05 +01:00
|
|
|
}
|
|
|
|
|
2023-03-06 14:56:49 +01:00
|
|
|
pub fn get_type(name: &str) -> Option<AMType> {
|
|
|
|
runtime(|rt| rt.get_type_by_name(name))
|
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// An SPL runtime.
|
|
|
|
///
|
|
|
|
/// This holds:
|
|
|
|
/// - types
|
|
|
|
/// - type refs
|
|
|
|
/// - streams
|
2023-02-17 22:47:45 +01:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Runtime {
|
|
|
|
next_type_id: u32,
|
|
|
|
types_by_name: HashMap<String, AMType>,
|
|
|
|
types_by_id: HashMap<u32, AMType>,
|
2023-02-19 19:34:25 +01:00
|
|
|
next_stream_id: u128,
|
|
|
|
streams: HashMap<u128, Arc<Mut<Stream>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for Runtime {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
f.debug_struct("Runtime")
|
|
|
|
.field("next_type_id", &self.next_type_id)
|
|
|
|
.field("types_by_name", &self.types_by_name)
|
|
|
|
.field("types_by_id", &self.types_by_id)
|
|
|
|
.field("next_stream_id", &self.next_stream_id)
|
|
|
|
.finish()
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-19 02:14:01 +01:00
|
|
|
impl Default for Runtime {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-17 22:47:45 +01:00
|
|
|
impl Runtime {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
let mut rt = Runtime {
|
|
|
|
next_type_id: 0,
|
|
|
|
types_by_name: HashMap::new(),
|
|
|
|
types_by_id: HashMap::new(),
|
2023-02-19 19:34:25 +01:00
|
|
|
next_stream_id: 0,
|
|
|
|
streams: HashMap::new(),
|
2023-02-17 22:47:45 +01:00
|
|
|
};
|
2023-02-19 02:14:01 +01:00
|
|
|
let _ = rt.make_type("null".to_owned(), Ok); // infallible
|
|
|
|
let _ = rt.make_type("int".to_owned(), Ok); // infallible
|
|
|
|
let _ = rt.make_type("long".to_owned(), Ok); // infallible
|
|
|
|
let _ = rt.make_type("mega".to_owned(), Ok); // infallible
|
|
|
|
let _ = rt.make_type("float".to_owned(), Ok); // infallible
|
|
|
|
let _ = rt.make_type("double".to_owned(), Ok); // infallible
|
|
|
|
let _ = rt.make_type("func".to_owned(), Ok); // infallible
|
|
|
|
let _ = rt.make_type("array".to_owned(), Ok); // infallible
|
|
|
|
let _ = rt.make_type("str".to_owned(), Ok); // infallible
|
2023-02-17 22:47:45 +01:00
|
|
|
rt
|
|
|
|
}
|
|
|
|
|
2023-03-06 14:56:49 +01:00
|
|
|
pub fn get_type_by_name(&self, name: &str) -> Option<AMType> {
|
|
|
|
self.types_by_name.get(name).cloned()
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_type_by_id(&self, id: u32) -> Option<AMType> {
|
|
|
|
self.types_by_id.get(&id).cloned()
|
|
|
|
}
|
|
|
|
|
2023-02-18 18:43:05 +01:00
|
|
|
pub fn get_types(&self) -> Vec<AMType> {
|
|
|
|
self.types_by_id.clone().into_values().collect()
|
|
|
|
}
|
|
|
|
|
2023-02-19 04:57:32 +01:00
|
|
|
pub fn make_type(
|
|
|
|
&mut self,
|
|
|
|
name: String,
|
|
|
|
op: impl FnOnce(Type) -> Result<Type, Error>,
|
|
|
|
) -> Result<AMType, Error> {
|
2023-02-17 22:47:45 +01:00
|
|
|
let t = Arc::new(Mut::new(op(Type {
|
|
|
|
name: name.clone(),
|
|
|
|
id: (self.next_type_id, self.next_type_id += 1).0,
|
|
|
|
parents: Vec::new(),
|
|
|
|
functions: HashMap::new(),
|
|
|
|
properties: Vec::new(),
|
2023-02-19 02:03:06 +01:00
|
|
|
})?));
|
2023-02-17 22:47:45 +01:00
|
|
|
self.types_by_id.insert(self.next_type_id - 1, t.clone());
|
|
|
|
self.types_by_name.insert(name, t.clone());
|
2023-02-19 02:03:06 +01:00
|
|
|
Ok(t)
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-19 19:34:25 +01:00
|
|
|
pub fn register_stream(&mut self, stream: Stream) -> (u128, Arc<Mut<Stream>>) {
|
|
|
|
let id = (self.next_stream_id, self.next_stream_id += 1).0;
|
|
|
|
self.streams.insert(id, Arc::new(Mut::new(stream)));
|
|
|
|
(id, self.streams.get(&id).unwrap().clone())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_stream(&self, id: u128) -> Option<Arc<Mut<Stream>>> {
|
|
|
|
self.streams.get(&id).cloned()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn destroy_stream(&mut self, id: u128) {
|
|
|
|
self.streams.remove(&id);
|
|
|
|
}
|
|
|
|
|
2023-02-17 22:47:45 +01:00
|
|
|
pub fn reset() {
|
|
|
|
RUNTIME.with(|x| *x.borrow_mut() = None);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// Anything that can be .set() and result in the runtime being set.
|
|
|
|
/// Implemented for Arc<Mut<Runtime>> and Runtime.
|
2023-02-19 04:57:32 +01:00
|
|
|
pub trait SetRuntime {
|
|
|
|
fn set(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SetRuntime for Runtime {
|
|
|
|
fn set(self) {
|
|
|
|
Arc::new(Mut::new(self)).set()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SetRuntime for Arc<Mut<Runtime>> {
|
|
|
|
fn set(self) {
|
|
|
|
RUNTIME.with(move |x| *x.borrow_mut() = Some(self));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// A frame's location in SPL code.
|
2023-03-06 14:56:49 +01:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
2023-02-17 22:47:45 +01:00
|
|
|
pub struct FrameInfo {
|
|
|
|
pub file: String,
|
2023-02-19 04:57:32 +01:00
|
|
|
pub function: String,
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// An SPL stack frame.
|
|
|
|
///
|
|
|
|
/// This holds:
|
|
|
|
/// - its parent
|
|
|
|
/// - variables
|
|
|
|
/// - functions
|
|
|
|
/// - its origin ([FrameInfo])
|
|
|
|
/// - whether all functions in it should be made global.
|
2023-02-19 19:34:25 +01:00
|
|
|
#[derive(Clone, Debug)]
|
2023-02-17 22:47:45 +01:00
|
|
|
pub struct Frame {
|
|
|
|
parent: Option<Arc<Frame>>,
|
|
|
|
pub variables: Mut<HashMap<String, AMObject>>,
|
|
|
|
pub functions: Mut<HashMap<String, AFunc>>,
|
|
|
|
pub origin: FrameInfo,
|
2023-02-19 19:34:25 +01:00
|
|
|
pub redirect_to_base: bool,
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for Frame {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
f.write_str("\nVars: \n")?;
|
2023-02-18 18:43:05 +01:00
|
|
|
for (name, object) in self.variables.lock_ro().iter() {
|
2023-02-17 22:47:45 +01:00
|
|
|
f.write_str(" ")?;
|
2023-02-19 02:14:01 +01:00
|
|
|
f.write_str(name)?;
|
2023-02-17 22:47:45 +01:00
|
|
|
f.write_str(": ")?;
|
2023-02-18 18:43:05 +01:00
|
|
|
std::fmt::Display::fmt(&object.lock_ro(), f)?;
|
2023-02-17 22:47:45 +01:00
|
|
|
f.write_str("\n")?;
|
|
|
|
}
|
2023-02-25 11:37:07 +01:00
|
|
|
f.write_str("\nFuncs: \n")?;
|
|
|
|
for (name, ..) in self.functions.lock_ro().iter() {
|
|
|
|
f.write_str(" ")?;
|
|
|
|
f.write_str(name)?;
|
|
|
|
f.write_str("\n")?;
|
|
|
|
}
|
|
|
|
f.write_str("\n\n")?;
|
2023-02-17 22:47:45 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Frame {
|
2023-02-19 04:57:32 +01:00
|
|
|
pub fn dummy() -> Self {
|
|
|
|
Frame {
|
|
|
|
parent: None,
|
|
|
|
variables: Mut::new(HashMap::new()),
|
|
|
|
functions: Mut::new(HashMap::new()),
|
|
|
|
origin: FrameInfo {
|
|
|
|
file: "\0".to_owned(),
|
|
|
|
function: "\0".to_owned(),
|
|
|
|
},
|
2023-02-19 19:34:25 +01:00
|
|
|
redirect_to_base: false,
|
2023-02-19 04:57:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn root() -> Self {
|
2023-02-17 22:47:45 +01:00
|
|
|
Frame {
|
|
|
|
parent: None,
|
|
|
|
variables: Mut::new(HashMap::new()),
|
|
|
|
functions: Mut::new(HashMap::new()),
|
|
|
|
origin: FrameInfo {
|
2023-02-25 15:02:31 +01:00
|
|
|
file: "std.spl".to_owned(),
|
2023-02-19 04:57:32 +01:00
|
|
|
function: "root".to_owned(),
|
2023-02-17 22:47:45 +01:00
|
|
|
},
|
2023-02-19 19:34:25 +01:00
|
|
|
redirect_to_base: false,
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-19 04:57:32 +01:00
|
|
|
pub fn root_in(info: FrameInfo) -> Self {
|
|
|
|
Frame {
|
|
|
|
parent: None,
|
|
|
|
variables: Mut::new(HashMap::new()),
|
|
|
|
functions: Mut::new(HashMap::new()),
|
|
|
|
origin: info,
|
2023-02-19 19:34:25 +01:00
|
|
|
redirect_to_base: false,
|
2023-02-19 04:57:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new(parent: Arc<Frame>, function: String) -> Self {
|
2023-02-18 18:43:05 +01:00
|
|
|
Frame {
|
|
|
|
variables: Mut::new(HashMap::new()),
|
|
|
|
functions: Mut::new(HashMap::new()),
|
2023-02-19 04:57:32 +01:00
|
|
|
origin: FrameInfo {
|
|
|
|
function,
|
|
|
|
..parent.origin.clone()
|
|
|
|
},
|
2023-02-18 18:43:05 +01:00
|
|
|
parent: Some(parent),
|
2023-02-19 19:34:25 +01:00
|
|
|
redirect_to_base: false,
|
2023-02-18 18:43:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-19 19:34:25 +01:00
|
|
|
pub fn new_in(
|
|
|
|
parent: Arc<Frame>,
|
|
|
|
origin: String,
|
|
|
|
function: String,
|
|
|
|
redirect_to_parent: bool,
|
|
|
|
) -> Self {
|
2023-02-17 22:47:45 +01:00
|
|
|
Frame {
|
|
|
|
parent: Some(parent),
|
|
|
|
variables: Mut::new(HashMap::new()),
|
|
|
|
functions: Mut::new(HashMap::new()),
|
2023-02-19 04:57:32 +01:00
|
|
|
origin: FrameInfo {
|
|
|
|
file: origin,
|
|
|
|
function,
|
|
|
|
},
|
2023-02-19 19:34:25 +01:00
|
|
|
redirect_to_base: redirect_to_parent,
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
}
|
2023-02-19 02:03:06 +01:00
|
|
|
|
|
|
|
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 {
|
2023-03-06 14:56:49 +01:00
|
|
|
return Err(stack.error(ErrorKind::VariableNotFound(name)));
|
2023-02-19 02:03:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
2023-03-06 14:56:49 +01:00
|
|
|
return Err(stack.error(ErrorKind::VariableNotFound(name)));
|
2023-02-19 02:03:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-19 04:57:32 +01:00
|
|
|
|
|
|
|
pub fn path(&self) -> Vec<FrameInfo> {
|
|
|
|
let mut r = Vec::new();
|
|
|
|
let mut frame = self;
|
|
|
|
loop {
|
|
|
|
r.insert(0, frame.origin.clone());
|
|
|
|
|
|
|
|
if let Some(ref parent) = frame.parent {
|
|
|
|
frame = parent;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r
|
|
|
|
}
|
|
|
|
|
2023-02-19 19:34:25 +01:00
|
|
|
pub fn readable_path(&self) -> String {
|
|
|
|
let mut item = String::new();
|
|
|
|
let path = self.path();
|
|
|
|
let mut file = "\0".to_owned();
|
|
|
|
for element in path {
|
|
|
|
if element.file != file {
|
|
|
|
item += " | in ";
|
|
|
|
item += &element.file;
|
|
|
|
item += ":";
|
|
|
|
file = element.file;
|
|
|
|
}
|
|
|
|
item += " ";
|
|
|
|
item += &element.function;
|
|
|
|
}
|
|
|
|
item
|
|
|
|
}
|
|
|
|
|
2023-02-19 04:57:32 +01:00
|
|
|
pub fn is_dummy(&self) -> bool {
|
|
|
|
self.parent.is_none() && self.origin.file == "\0" && self.origin.function == "\0"
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// An SPL stack.
|
|
|
|
///
|
|
|
|
/// This holds:
|
|
|
|
/// - a stack of frames
|
|
|
|
/// - the main stack of objects
|
|
|
|
/// - a return accumultor: how many blocks to return directly from
|
2023-02-19 19:34:25 +01:00
|
|
|
#[derive(Clone, Debug)]
|
2023-02-17 22:47:45 +01:00
|
|
|
pub struct Stack {
|
|
|
|
frames: Vec<Arc<Frame>>,
|
|
|
|
object_stack: Vec<AMObject>,
|
2023-04-07 22:03:36 +02:00
|
|
|
objcall_stack: Vec<AMObject>,
|
2023-03-06 03:45:16 +01:00
|
|
|
files: Vec<String>,
|
2023-02-19 19:34:25 +01:00
|
|
|
pub return_accumultor: u32,
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for Stack {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
for frame in &self.frames {
|
2023-02-19 19:34:25 +01:00
|
|
|
f.write_str("Frame:")?;
|
|
|
|
f.write_str(&frame.readable_path())?;
|
|
|
|
f.write_str("\n")?;
|
|
|
|
std::fmt::Display::fmt(&frame.as_ref(), f)?;
|
2023-02-17 22:47:45 +01:00
|
|
|
f.write_str("\n\n")?;
|
|
|
|
}
|
|
|
|
f.write_str("Stack: \n")?;
|
|
|
|
for object in &self.object_stack {
|
|
|
|
f.write_str(" ")?;
|
2023-02-18 18:43:05 +01:00
|
|
|
std::fmt::Display::fmt(&object.lock_ro(), f)?;
|
2023-02-17 22:47:45 +01:00
|
|
|
f.write_str("\n")?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-19 02:14:01 +01:00
|
|
|
impl Default for Stack {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-17 22:47:45 +01:00
|
|
|
impl Stack {
|
|
|
|
pub fn new() -> Self {
|
2023-02-18 18:43:05 +01:00
|
|
|
let o = Arc::new(Frame::root());
|
|
|
|
let mut r = Stack {
|
|
|
|
frames: vec![o.clone()],
|
2023-02-17 22:47:45 +01:00
|
|
|
object_stack: Vec::new(),
|
2023-04-07 22:03:36 +02:00
|
|
|
objcall_stack: Vec::new(),
|
2023-03-06 03:45:16 +01:00
|
|
|
files: Vec::new(),
|
2023-02-19 19:34:25 +01:00
|
|
|
return_accumultor: 0,
|
2023-02-18 18:43:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
dyn_fns::register(&mut r, o.clone());
|
2023-02-19 19:34:25 +01:00
|
|
|
std_fns::register(&mut r, o.clone());
|
|
|
|
stream::register(&mut r, o);
|
2023-02-18 18:43:05 +01:00
|
|
|
|
|
|
|
r
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-19 04:57:32 +01:00
|
|
|
pub fn new_in(frame_info: FrameInfo) -> Self {
|
|
|
|
let o = Arc::new(Frame::root_in(frame_info));
|
|
|
|
let mut r = Stack {
|
|
|
|
frames: vec![o.clone()],
|
|
|
|
object_stack: Vec::new(),
|
2023-04-07 22:03:36 +02:00
|
|
|
objcall_stack: Vec::new(),
|
2023-03-06 03:45:16 +01:00
|
|
|
files: Vec::new(),
|
2023-02-19 19:34:25 +01:00
|
|
|
return_accumultor: 0,
|
2023-02-19 04:57:32 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
dyn_fns::register(&mut r, o.clone());
|
2023-02-19 19:34:25 +01:00
|
|
|
std_fns::register(&mut r, o.clone());
|
|
|
|
stream::register(&mut r, o);
|
2023-02-19 04:57:32 +01:00
|
|
|
|
|
|
|
r
|
|
|
|
}
|
|
|
|
|
2023-02-17 22:47:45 +01:00
|
|
|
pub fn define_func(&mut self, name: String, func: AFunc) {
|
2023-02-19 19:34:25 +01:00
|
|
|
let mut frame = self.frames.last().unwrap().clone();
|
|
|
|
if frame.redirect_to_base {
|
|
|
|
frame = self.frames.first().unwrap().clone();
|
|
|
|
}
|
|
|
|
frame.functions.lock().insert(name, func);
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-19 02:03:06 +01:00
|
|
|
pub fn call(&mut self, func: &AFunc) -> OError {
|
2023-02-19 19:34:25 +01:00
|
|
|
let f = if let Some(ref cname) = func.fname {
|
|
|
|
Frame::new_in(
|
|
|
|
func.origin.clone(),
|
|
|
|
cname.clone(),
|
|
|
|
func.name.clone(),
|
2023-02-25 15:02:31 +01:00
|
|
|
func.run_as_base,
|
2023-02-19 19:34:25 +01:00
|
|
|
)
|
|
|
|
} else {
|
|
|
|
Frame::new(func.origin.clone(), func.name.clone())
|
|
|
|
};
|
2023-02-18 20:05:24 +01:00
|
|
|
self.frames.push(Arc::new(f));
|
2023-02-25 11:37:07 +01:00
|
|
|
let r = func.to_call.call(self);
|
2023-02-17 22:47:45 +01:00
|
|
|
self.frames.pop().unwrap();
|
2023-02-25 11:37:07 +01:00
|
|
|
r
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-19 02:03:06 +01:00
|
|
|
pub fn get_func(&self, name: String) -> Result<AFunc, Error> {
|
2023-02-17 22:47:45 +01:00
|
|
|
let mut frame = self.frames.last().unwrap();
|
|
|
|
loop {
|
|
|
|
let functions = &frame.functions;
|
2023-02-18 18:43:05 +01:00
|
|
|
if let Some(x) = functions.lock_ro().get(&name) {
|
2023-02-19 02:03:06 +01:00
|
|
|
return Ok(x.clone());
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
if let Some(ref x) = frame.parent {
|
|
|
|
frame = x;
|
2023-02-18 18:43:05 +01:00
|
|
|
} else {
|
2023-03-06 14:56:49 +01:00
|
|
|
return Err(self.error(ErrorKind::FuncNotFound(name)));
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn define_var(&mut self, name: String) {
|
2023-02-19 19:34:25 +01:00
|
|
|
let mut frame = self.frames.last().unwrap().clone();
|
|
|
|
if frame.redirect_to_base {
|
|
|
|
frame = self.frames.first().unwrap().clone();
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
let tmpname = name.clone();
|
2023-02-19 02:03:06 +01:00
|
|
|
let tmpframe = frame.clone();
|
2023-02-17 22:47:45 +01:00
|
|
|
frame.functions.lock().insert(
|
|
|
|
name.clone(),
|
|
|
|
Arc::new(Func {
|
|
|
|
ret_count: 1,
|
2023-02-19 02:03:06 +01:00
|
|
|
origin: frame.clone(),
|
2023-02-17 22:47:45 +01:00
|
|
|
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
|
2023-02-19 02:14:01 +01:00
|
|
|
stack.push(tmpframe.get_var(tmpname.clone(), stack)?);
|
2023-02-19 02:03:06 +01:00
|
|
|
Ok(())
|
2023-02-17 22:47:45 +01:00
|
|
|
}))),
|
2023-02-25 15:02:31 +01:00
|
|
|
run_as_base: false,
|
2023-02-19 04:57:32 +01:00
|
|
|
fname: Some("RUNTIME".to_owned()),
|
|
|
|
name: name.clone(),
|
2023-02-17 22:47:45 +01:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
let tmpname = name.clone();
|
2023-02-19 02:03:06 +01:00
|
|
|
let tmpframe = frame.clone();
|
2023-02-19 02:14:01 +01:00
|
|
|
frame.functions.lock().insert(
|
2023-02-17 22:47:45 +01:00
|
|
|
"=".to_owned() + &name,
|
|
|
|
Arc::new(Func {
|
|
|
|
ret_count: 0,
|
2023-02-19 02:03:06 +01:00
|
|
|
origin: frame.clone(),
|
2023-02-17 22:47:45 +01:00
|
|
|
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
|
|
|
|
let v = stack.pop();
|
2023-02-19 02:14:01 +01:00
|
|
|
tmpframe.set_var(tmpname.clone(), v, stack)
|
2023-02-17 22:47:45 +01:00
|
|
|
}))),
|
2023-02-25 15:02:31 +01:00
|
|
|
run_as_base: false,
|
2023-02-19 04:57:32 +01:00
|
|
|
fname: Some("RUNTIME".to_owned()),
|
|
|
|
name: "=".to_owned() + &name,
|
2023-02-17 22:47:45 +01:00
|
|
|
}),
|
|
|
|
);
|
2023-02-18 18:43:05 +01:00
|
|
|
frame.variables.lock().insert(name, Value::Null.spl());
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-19 19:34:25 +01:00
|
|
|
pub fn pop_until(&mut self, obj: AMObject) -> Vec<AMObject> {
|
|
|
|
let Some((idx, ..)) = self.object_stack.iter().enumerate().rfind(|o| *o.1.lock_ro() == *obj.lock_ro()) else {
|
|
|
|
return Vec::new()
|
|
|
|
};
|
|
|
|
let items = self.object_stack[idx + 1..].to_vec();
|
|
|
|
self.object_stack = self.object_stack[0..idx].to_vec();
|
|
|
|
items
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.object_stack.len()
|
|
|
|
}
|
|
|
|
|
2023-02-19 02:03:06 +01:00
|
|
|
pub fn set_var(&self, name: String, obj: AMObject) -> OError {
|
|
|
|
self.get_frame().set_var(name, obj, self)
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-19 02:03:06 +01:00
|
|
|
pub fn get_var(&self, name: String) -> Result<AMObject, Error> {
|
|
|
|
self.get_frame().get_var(name, self)
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn push(&mut self, obj: AMObject) {
|
|
|
|
self.object_stack.push(obj)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn peek(&mut self) -> AMObject {
|
|
|
|
self.object_stack
|
|
|
|
.last()
|
|
|
|
.cloned()
|
2023-02-18 18:43:05 +01:00
|
|
|
.unwrap_or(Value::Null.spl())
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn pop(&mut self) -> AMObject {
|
2023-02-18 18:43:05 +01:00
|
|
|
self.object_stack.pop().unwrap_or(Value::Null.spl())
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_origin(&self) -> FrameInfo {
|
|
|
|
self.frames.last().unwrap().origin.clone()
|
|
|
|
}
|
2023-02-18 18:43:05 +01:00
|
|
|
|
|
|
|
pub fn get_frame(&self) -> Arc<Frame> {
|
|
|
|
self.frames.last().unwrap().clone()
|
|
|
|
}
|
2023-02-19 02:03:06 +01:00
|
|
|
|
|
|
|
pub fn err<T>(&self, kind: ErrorKind) -> Result<T, Error> {
|
|
|
|
Err(Error {
|
|
|
|
kind,
|
|
|
|
stack: self.trace(),
|
2023-03-06 14:56:49 +01:00
|
|
|
mr_stack: self.mr_trace(),
|
2023-02-19 02:03:06 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn error(&self, kind: ErrorKind) -> Error {
|
|
|
|
Error {
|
|
|
|
kind,
|
|
|
|
stack: self.trace(),
|
2023-03-06 14:56:49 +01:00
|
|
|
mr_stack: self.mr_trace(),
|
2023-02-19 02:03:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-19 04:57:32 +01:00
|
|
|
pub fn mr_trace(&self) -> Vec<Vec<FrameInfo>> {
|
|
|
|
self.frames.iter().map(|frame| frame.path()).collect()
|
|
|
|
}
|
|
|
|
|
2023-02-19 02:03:06 +01:00
|
|
|
pub fn trace(&self) -> Vec<String> {
|
2023-02-19 04:57:32 +01:00
|
|
|
self.frames
|
|
|
|
.iter()
|
2023-02-19 19:34:25 +01:00
|
|
|
.map(|frame| frame.readable_path())
|
2023-02-19 04:57:32 +01:00
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn peek_frame(&self, index: usize) -> Arc<Frame> {
|
2023-02-19 04:58:17 +01:00
|
|
|
self.frames
|
|
|
|
.get(self.frames.len() - index - 1)
|
|
|
|
.unwrap()
|
|
|
|
.clone()
|
2023-02-19 04:57:32 +01:00
|
|
|
}
|
|
|
|
|
2023-02-19 19:34:25 +01:00
|
|
|
/// # Safety
|
|
|
|
/// This function is not technically unsafe. It is marked this way to indicate that it
|
|
|
|
/// can cause unstable runtime states and panics. However, memory safety is still guaranteed.
|
2023-02-19 04:57:32 +01:00
|
|
|
pub unsafe fn pop_frame(&mut self, index: usize) -> Arc<Frame> {
|
|
|
|
self.frames.remove(self.frames.len() - index - 1)
|
|
|
|
}
|
|
|
|
|
2023-02-19 19:34:25 +01:00
|
|
|
/// # Safety
|
|
|
|
/// This function is not technically unsafe. It is marked this way to indicate that it
|
|
|
|
/// can cause unstable runtime states and panics. However, memory safety is still guaranteed.
|
2023-02-19 04:57:32 +01:00
|
|
|
pub unsafe fn push_frame(&mut self, frame: Arc<Frame>) {
|
|
|
|
self.frames.push(frame);
|
2023-02-19 02:03:06 +01:00
|
|
|
}
|
2023-03-06 03:45:16 +01:00
|
|
|
|
|
|
|
pub(crate) fn include_file(&mut self, s: &String) -> bool {
|
|
|
|
if self.files.contains(s) {
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
self.files.push(s.to_owned());
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// An SPL keyword. Used to deviate from normal linear code structure.
|
|
|
|
///
|
|
|
|
/// This is different from a [Word], which are any SPL code.
|
2023-02-18 01:53:48 +01:00
|
|
|
#[derive(Clone, Debug)]
|
2023-02-17 22:47:45 +01:00
|
|
|
pub enum Keyword {
|
|
|
|
/// <none>
|
|
|
|
///
|
|
|
|
/// Dumps stack. Not available as actual keyword, therefore only obtainable through AST
|
2023-02-25 11:37:07 +01:00
|
|
|
/// manipulation, a dyn call, or modding.
|
2023-02-17 22:47:45 +01:00
|
|
|
/// equivalent to dyn-__dump
|
2023-02-25 11:37:07 +01:00
|
|
|
/// example: func main { int | "Hello, world!" dyn-__dump pop 0 }
|
2023-02-17 22:47:45 +01:00
|
|
|
Dump,
|
|
|
|
/// def <name>
|
|
|
|
///
|
|
|
|
/// Defines a variable.
|
2023-03-06 14:56:49 +01:00
|
|
|
/// equivalent to "<name>" dyn-def
|
2023-02-17 22:47:45 +01:00
|
|
|
Def(String),
|
|
|
|
/// func <name> { <rem> | <words> }
|
|
|
|
///
|
|
|
|
/// Defines function <name> with <rem> return size
|
|
|
|
/// equivalent to { <rem> | <words> } "<name>" dyn-func
|
|
|
|
Func(String, u32, Words),
|
|
|
|
/// construct <name> { <field> <...> ; <fn-name> { <rem> | <words> } <...> }
|
|
|
|
///
|
|
|
|
/// Creates type <name>
|
|
|
|
/// equivalent to
|
2023-02-18 18:43:05 +01:00
|
|
|
/// "<name>" dyn-construct; "<field>" "<name>" dyn-def-field { <rem> | <words> } "<fn-name>"
|
|
|
|
/// "<name>" dyn-def-method
|
2023-03-06 03:45:16 +01:00
|
|
|
Construct(String, Vec<String>, Vec<(String, (u32, Words))>, bool),
|
2023-02-17 22:47:45 +01:00
|
|
|
/// include <typeA> in <typeB>
|
|
|
|
///
|
|
|
|
/// Adds <typeA> as a parent type of <typeB>.
|
|
|
|
/// equivalent to "<typeA>" "<typeB>" dyn-include
|
|
|
|
Include(String, String),
|
2023-03-06 14:56:49 +01:00
|
|
|
/// use <path>:<item>
|
|
|
|
///
|
|
|
|
/// equivalent to "<path>:<item>" dyn-use
|
|
|
|
Use(String),
|
2023-02-18 18:43:05 +01:00
|
|
|
/// while { <wordsA> } { <wordsB> }
|
2023-02-17 22:47:45 +01:00
|
|
|
///
|
|
|
|
/// If wordsA result in a truthy value being on the top of the stack, execute wordsB, and
|
|
|
|
/// repeat.
|
|
|
|
/// equivalent to { int | <wordsA> } { | <wordsB> } dyn-while
|
|
|
|
While(Words, Words),
|
2023-02-18 18:43:05 +01:00
|
|
|
/// if { <wordsB> }
|
2023-02-17 22:47:45 +01:00
|
|
|
///
|
|
|
|
/// If wordsA result in a truthy value being on the top of the stack, execute wordsB.
|
2023-02-18 18:43:05 +01:00
|
|
|
/// equivalent to { | <wordsB> } dyn-if
|
|
|
|
If(Words),
|
2023-02-17 22:47:45 +01:00
|
|
|
/// with <item> <...> ;
|
|
|
|
///
|
|
|
|
/// Defines variables in reverse order.
|
|
|
|
/// equivalent to def <...> =<...> def <item> =<item>
|
|
|
|
/// or "<...>" dyn-def "=<...>" dyn-call "<item>" dyn-def "=<item>" dyn-call
|
|
|
|
With(Vec<String>),
|
2023-03-06 14:56:49 +01:00
|
|
|
/// catch [<type> <...>] { <code> } with { <wordsOnCatch> }
|
|
|
|
///
|
|
|
|
/// Catches errors that happen within <code>, running <wordsOnCatch> when an error is
|
|
|
|
/// encountered and the error is of <type> (or, if no type is specified, any error).
|
|
|
|
/// equivalent to \[ ["<type>" <...>] \] { | <code> } { | <wordsOnCatch> } dyn-catch
|
|
|
|
Catch(Vec<String>, Words, Words),
|
2023-04-07 22:03:36 +02:00
|
|
|
/// <none>
|
|
|
|
///
|
|
|
|
/// Used by `object:method <{ arg1 arg2 }` syntax. Generates as:
|
2023-04-08 20:12:35 +02:00
|
|
|
/// - call object
|
|
|
|
/// - objpush
|
|
|
|
/// - call arg1
|
|
|
|
/// - call arg2
|
|
|
|
/// - objpop
|
|
|
|
/// - objcall method
|
2023-04-07 22:03:36 +02:00
|
|
|
ObjPush,
|
|
|
|
/// <none>
|
|
|
|
///
|
|
|
|
/// see [Keyword::ObjPush]
|
|
|
|
ObjPop,
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// Any SPL value that is not a construct.
|
|
|
|
///
|
|
|
|
/// Holds its rust representation.
|
2023-02-18 18:43:05 +01:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
pub enum Value {
|
2023-02-17 22:47:45 +01:00
|
|
|
Null,
|
|
|
|
Int(i32),
|
|
|
|
Long(i64),
|
|
|
|
Mega(i128),
|
2023-02-18 01:53:48 +01:00
|
|
|
Float(f32),
|
|
|
|
Double(f64),
|
2023-02-17 22:47:45 +01:00
|
|
|
Func(AFunc),
|
2023-02-18 18:43:05 +01:00
|
|
|
Array(Vec<AMObject>),
|
2023-02-17 22:47:45 +01:00
|
|
|
Str(String),
|
|
|
|
}
|
|
|
|
|
2023-02-19 04:57:32 +01:00
|
|
|
impl Value {
|
|
|
|
fn ensure_init(self, stack: &Stack) -> Self {
|
|
|
|
match self {
|
|
|
|
Value::Func(x) if x.origin.is_dummy() => Value::Func(AFunc::new(Func {
|
|
|
|
origin: stack.get_frame(),
|
|
|
|
..x.as_ref().clone()
|
|
|
|
})),
|
|
|
|
x => x,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn try_mega_to_int(self) -> Value {
|
|
|
|
if let Value::Mega(x) = self {
|
|
|
|
Value::Int(x as i32)
|
|
|
|
} else {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-18 18:43:05 +01:00
|
|
|
impl PartialOrd for Value {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
|
|
match (self, other) {
|
|
|
|
(Value::Mega(a), Value::Mega(b)) => a.partial_cmp(b),
|
|
|
|
_ => panic!(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// The smallest fragment of SPL code.
|
2023-02-18 01:53:48 +01:00
|
|
|
#[derive(Clone, Debug)]
|
2023-02-17 22:47:45 +01:00
|
|
|
pub enum Word {
|
2023-02-25 15:02:31 +01:00
|
|
|
/// A keyword, used to deviate from normal code structure.
|
2023-02-17 22:47:45 +01:00
|
|
|
Key(Keyword),
|
2023-02-25 15:02:31 +01:00
|
|
|
/// A constant to push to the stack when encountered.
|
2023-02-18 18:43:05 +01:00
|
|
|
Const(Value),
|
2023-02-25 15:02:31 +01:00
|
|
|
/// A function call.
|
2023-02-17 22:47:45 +01:00
|
|
|
Call(String, bool, u32),
|
2023-02-25 15:02:31 +01:00
|
|
|
/// A method call.
|
2023-02-17 22:47:45 +01:00
|
|
|
ObjCall(String, bool, u32),
|
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// A collection of executable words.
|
2023-02-18 01:53:48 +01:00
|
|
|
#[derive(Clone, Debug)]
|
2023-02-17 22:47:45 +01:00
|
|
|
pub struct Words {
|
|
|
|
pub words: Vec<Word>,
|
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
impl Words {
|
|
|
|
pub fn new(words: Vec<Word>) -> Self {
|
|
|
|
Words { words }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Any kind of SPL-executable code.
|
2023-02-17 22:47:45 +01:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub enum FuncImpl {
|
2023-02-19 02:03:06 +01:00
|
|
|
Native(fn(&mut Stack) -> OError),
|
|
|
|
NativeDyn(Arc<Box<dyn Fn(&mut Stack) -> OError>>),
|
2023-02-17 22:47:45 +01:00
|
|
|
SPL(Words),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FuncImpl {
|
2023-02-19 02:03:06 +01:00
|
|
|
pub fn call(&self, stack: &mut Stack) -> OError {
|
2023-02-17 22:47:45 +01:00
|
|
|
match self {
|
|
|
|
FuncImpl::Native(x) => x(stack),
|
|
|
|
FuncImpl::NativeDyn(x) => x(stack),
|
|
|
|
FuncImpl::SPL(x) => x.exec(stack),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// Any kind of SPL-executable code with metadata surrounding it.
|
|
|
|
///
|
|
|
|
/// This holds:
|
|
|
|
/// - the amount of values returned when called
|
|
|
|
/// - the actual executable code ([FuncImpl])
|
|
|
|
/// - the frame that defined it
|
|
|
|
/// - the name of the file it was defined in, if this is different form the definition frame
|
|
|
|
/// - the name of the function.
|
|
|
|
/// - wether it should be run as the root layer (= wether functions it defines should be made
|
|
|
|
/// global)
|
2023-02-17 22:47:45 +01:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Func {
|
|
|
|
pub ret_count: u32,
|
|
|
|
pub to_call: FuncImpl,
|
2023-02-18 18:43:05 +01:00
|
|
|
pub origin: Arc<Frame>,
|
2023-02-19 04:57:32 +01:00
|
|
|
pub fname: Option<String>,
|
|
|
|
pub name: String,
|
2023-02-25 15:02:31 +01:00
|
|
|
pub run_as_base: bool,
|
2023-02-18 18:43:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for Func {
|
|
|
|
fn eq(&self, _other: &Self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for Func {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
f.write_str(&self.ret_count.to_string())?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// Any SPL type.
|
|
|
|
///
|
|
|
|
/// This holds:
|
|
|
|
/// - the name
|
|
|
|
/// - the numeric ID
|
|
|
|
/// - its parent types
|
|
|
|
/// - its methods
|
|
|
|
/// - its fields
|
2023-02-18 18:43:05 +01:00
|
|
|
#[derive(Clone, Debug)]
|
2023-02-17 22:47:45 +01:00
|
|
|
pub struct Type {
|
|
|
|
name: String,
|
|
|
|
id: u32,
|
|
|
|
pub parents: Vec<AMType>,
|
|
|
|
pub functions: HashMap<String, AFunc>,
|
|
|
|
pub properties: Vec<String>,
|
|
|
|
}
|
|
|
|
|
2023-02-18 18:43:05 +01:00
|
|
|
impl PartialEq for Type {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.id == other.id
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-17 22:47:45 +01:00
|
|
|
impl Type {
|
2023-02-18 18:43:05 +01:00
|
|
|
pub fn get_name(&self) -> String {
|
|
|
|
self.name.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_id(&self) -> u32 {
|
|
|
|
self.id
|
|
|
|
}
|
|
|
|
|
2023-02-17 22:47:45 +01:00
|
|
|
pub fn get_fn(&self, name: String) -> Option<AFunc> {
|
|
|
|
if let Some(x) = self.functions.get(&name) {
|
|
|
|
return Some(x.clone());
|
|
|
|
}
|
|
|
|
let mut q = VecDeque::from(self.parents.clone());
|
|
|
|
while let Some(t) = q.pop_front() {
|
2023-02-18 18:43:05 +01:00
|
|
|
if let Some(x) = t.lock_ro().functions.get(&name) {
|
2023-02-17 22:47:45 +01:00
|
|
|
return Some(x.clone());
|
|
|
|
}
|
2023-02-18 18:43:05 +01:00
|
|
|
q.append(&mut VecDeque::from(t.lock_ro().parents.clone()));
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
2023-02-18 18:43:05 +01:00
|
|
|
|
2023-02-19 19:34:25 +01:00
|
|
|
pub fn write_into(&self, object: &mut Object) {
|
|
|
|
let mut to_apply = self.properties.clone();
|
|
|
|
let mut q = VecDeque::from(self.parents.clone());
|
|
|
|
while let Some(t) = q.pop_front() {
|
|
|
|
to_apply.append(&mut t.lock_ro().properties.clone());
|
|
|
|
q.append(&mut VecDeque::from(t.lock_ro().parents.clone()));
|
|
|
|
}
|
|
|
|
for property in to_apply.into_iter().rev() {
|
2023-04-07 22:03:36 +02:00
|
|
|
object
|
|
|
|
.property_map
|
|
|
|
.entry(property)
|
|
|
|
.or_insert_with(|| Value::Null.spl());
|
2023-02-19 19:34:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-19 02:03:06 +01:00
|
|
|
pub fn add_property(&mut self, name: String, origin: Arc<Frame>) -> OError {
|
2023-02-18 18:43:05 +01:00
|
|
|
let tmpname = name.clone();
|
|
|
|
self.functions.insert(
|
|
|
|
name.clone(),
|
|
|
|
Arc::new(Func {
|
|
|
|
ret_count: 1,
|
|
|
|
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
|
|
|
|
let o = stack.pop();
|
2023-02-19 02:03:06 +01:00
|
|
|
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(())
|
2023-02-18 18:43:05 +01:00
|
|
|
}))),
|
|
|
|
origin: origin.clone(),
|
2023-02-25 15:02:31 +01:00
|
|
|
run_as_base: false,
|
2023-02-19 04:57:32 +01:00
|
|
|
fname: Some("RUNTIME".to_owned()),
|
|
|
|
name: name.clone(),
|
2023-02-18 18:43:05 +01:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
let tmpname = name.clone();
|
|
|
|
self.functions.insert(
|
|
|
|
"=".to_owned() + &name,
|
|
|
|
Arc::new(Func {
|
|
|
|
ret_count: 0,
|
|
|
|
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
|
|
|
|
let o = stack.pop();
|
|
|
|
let v = stack.pop();
|
|
|
|
o.lock().property_map.insert(tmpname.clone(), v);
|
2023-02-19 02:03:06 +01:00
|
|
|
Ok(())
|
2023-02-18 18:43:05 +01:00
|
|
|
}))),
|
|
|
|
origin,
|
2023-02-25 15:02:31 +01:00
|
|
|
run_as_base: false,
|
2023-02-19 04:57:32 +01:00
|
|
|
fname: Some("RUNTIME".to_owned()),
|
|
|
|
name: "=".to_owned() + &name,
|
2023-02-18 18:43:05 +01:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
self.properties.push(name);
|
2023-02-19 02:03:06 +01:00
|
|
|
Ok(())
|
2023-02-18 18:43:05 +01:00
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// Any kind of SPL object, no matter if it is a construct or not.
|
|
|
|
///
|
|
|
|
/// This holds:
|
|
|
|
/// - the type of the object
|
|
|
|
/// - the fields mandated by the type
|
|
|
|
/// - the native value ([Value]), null for constructs unless set manually.
|
2023-02-18 18:43:05 +01:00
|
|
|
#[derive(Clone, Debug)]
|
2023-02-17 22:47:45 +01:00
|
|
|
pub struct Object {
|
|
|
|
pub kind: AMType,
|
|
|
|
pub property_map: HashMap<String, AMObject>,
|
2023-02-18 18:43:05 +01:00
|
|
|
pub native: Value,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for Object {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.kind == other.kind
|
|
|
|
&& self.property_map == other.property_map
|
|
|
|
&& self.native == other.native
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialOrd for Object {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
|
|
if self.kind != other.kind {
|
2023-02-25 11:37:07 +01:00
|
|
|
return None;
|
2023-02-18 18:43:05 +01:00
|
|
|
}
|
|
|
|
self.native.partial_cmp(&other.native)
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-02-19 04:57:32 +01:00
|
|
|
impl Eq for Object {}
|
|
|
|
|
2023-02-17 22:47:45 +01:00
|
|
|
impl Display for Object {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
2023-02-18 18:43:05 +01:00
|
|
|
f.write_str(&self.kind.lock_ro().name)?;
|
2023-02-17 22:47:45 +01:00
|
|
|
f.write_str("(")?;
|
|
|
|
self.native.fmt(f)?;
|
2023-02-19 19:34:25 +01:00
|
|
|
f.write_str(") {")?;
|
2023-02-17 22:47:45 +01:00
|
|
|
for (k, v) in &self.property_map {
|
2023-02-19 19:34:25 +01:00
|
|
|
f.write_str(" ")?;
|
2023-02-19 02:14:01 +01:00
|
|
|
f.write_str(k)?;
|
2023-02-17 22:47:45 +01:00
|
|
|
f.write_str(": ")?;
|
2023-02-18 18:43:05 +01:00
|
|
|
std::fmt::Display::fmt(&v.lock_ro(), f)?;
|
2023-02-19 19:34:25 +01:00
|
|
|
f.write_str(",")?;
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
f.write_str(" }")?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Object {
|
2023-02-18 18:43:05 +01:00
|
|
|
pub fn new(kind: AMType, native: Value) -> Object {
|
2023-02-19 19:34:25 +01:00
|
|
|
let mut r = Object {
|
|
|
|
property_map: HashMap::new(),
|
|
|
|
kind: kind.clone(),
|
2023-02-17 22:47:45 +01:00
|
|
|
native,
|
2023-02-19 19:34:25 +01:00
|
|
|
};
|
|
|
|
kind.lock_ro().write_into(&mut r);
|
|
|
|
r
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_truthy(&self) -> bool {
|
|
|
|
match &self.native {
|
2023-02-19 19:34:25 +01:00
|
|
|
Value::Null => self.kind.lock_ro().id != 0,
|
2023-02-18 18:43:05 +01:00
|
|
|
Value::Int(x) => x > &0,
|
|
|
|
Value::Long(x) => x > &0,
|
|
|
|
Value::Mega(x) => x > &0,
|
|
|
|
Value::Float(_) => true,
|
|
|
|
Value::Double(_) => true,
|
|
|
|
Value::Func(_) => true,
|
|
|
|
Value::Array(_) => true,
|
2023-02-19 19:34:25 +01:00
|
|
|
Value::Str(x) => !x.is_empty(),
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
}
|
2023-03-06 03:45:16 +01:00
|
|
|
|
|
|
|
pub fn field(&self, name: &str, stack: &mut Stack) -> Result<AMObject, Error> {
|
|
|
|
Ok(self
|
|
|
|
.property_map
|
|
|
|
.get(name)
|
|
|
|
.ok_or_else(|| {
|
|
|
|
stack.error(ErrorKind::PropertyNotFound(
|
|
|
|
self.kind.lock_ro().name.to_owned(),
|
|
|
|
name.to_owned(),
|
|
|
|
))
|
|
|
|
})?
|
|
|
|
.clone())
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
|
2023-03-06 14:56:49 +01:00
|
|
|
impl From<String> for Object {
|
|
|
|
fn from(value: String) -> Self {
|
|
|
|
Value::Str(value).into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<FrameInfo> for Object {
|
|
|
|
fn from(value: FrameInfo) -> Self {
|
|
|
|
let mut obj = Object::new(
|
|
|
|
get_type("FrameInfo").expect("FrameInfo type must exist"),
|
|
|
|
Value::Null,
|
|
|
|
);
|
|
|
|
obj.property_map.insert("file".to_owned(), value.file.spl());
|
|
|
|
obj.property_map
|
|
|
|
.insert("function".to_owned(), value.function.spl());
|
|
|
|
obj
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> From<Vec<T>> for Object
|
|
|
|
where
|
|
|
|
T: Into<Object>,
|
|
|
|
{
|
|
|
|
fn from(value: Vec<T>) -> Self {
|
|
|
|
Value::Array(value.into_iter().map(|x| x.spl()).collect()).into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-18 18:43:05 +01:00
|
|
|
impl From<Value> for Object {
|
|
|
|
fn from(value: Value) -> Self {
|
2023-02-17 22:47:45 +01:00
|
|
|
Object::new(
|
2023-02-19 04:57:32 +01:00
|
|
|
runtime(|x| {
|
2023-02-17 22:47:45 +01:00
|
|
|
match value {
|
2023-02-18 18:43:05 +01:00
|
|
|
Value::Null => x.get_type_by_id(0),
|
|
|
|
Value::Int(_) => x.get_type_by_id(1),
|
|
|
|
Value::Long(_) => x.get_type_by_id(2),
|
|
|
|
Value::Mega(_) => x.get_type_by_id(3),
|
|
|
|
Value::Float(_) => x.get_type_by_id(4),
|
|
|
|
Value::Double(_) => x.get_type_by_id(5),
|
|
|
|
Value::Func(_) => x.get_type_by_id(6),
|
|
|
|
Value::Array(_) => x.get_type_by_id(7),
|
|
|
|
Value::Str(_) => x.get_type_by_id(8),
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
.expect("runtime uninitialized: default types not set.")
|
|
|
|
}),
|
|
|
|
value,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// Trait for converting things to SPL Objects.
|
2023-02-17 22:47:45 +01:00
|
|
|
pub trait SPL {
|
|
|
|
fn spl(self) -> AMObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> SPL for T
|
|
|
|
where
|
|
|
|
T: Into<Object>,
|
|
|
|
{
|
|
|
|
fn spl(self) -> AMObject {
|
|
|
|
Arc::new(Mut::new(self.into()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// Finds a file in the SPL_PATH, or returns the internal [stdlib] version of it.
|
2023-02-25 13:58:17 +01:00
|
|
|
pub fn find_in_splpath(path: &str) -> Result<String, String> {
|
2023-02-25 11:37:07 +01:00
|
|
|
if Path::new(path).exists() {
|
2023-02-25 13:58:17 +01:00
|
|
|
return Ok(path.to_owned());
|
2023-02-25 11:37:07 +01:00
|
|
|
}
|
|
|
|
let s = var("SPL_PATH").unwrap_or("/usr/lib/spl".to_owned()) + "/" + path;
|
|
|
|
if Path::new(&s).exists() {
|
2023-02-25 13:58:17 +01:00
|
|
|
Ok(s)
|
2023-02-25 11:37:07 +01:00
|
|
|
} else {
|
2023-02-25 13:58:17 +01:00
|
|
|
match path {
|
|
|
|
"std.spl" => Err(stdlib::STD.to_owned()),
|
2023-03-06 15:21:02 +01:00
|
|
|
"net.spl" => Err(stdlib::NET.to_owned()),
|
2023-02-25 13:58:17 +01:00
|
|
|
"iter.spl" => Err(stdlib::ITER.to_owned()),
|
2023-03-06 15:21:02 +01:00
|
|
|
"http.spl" => Err(stdlib::HTTP.to_owned()),
|
2023-02-25 13:58:17 +01:00
|
|
|
"stream.spl" => Err(stdlib::STREAM.to_owned()),
|
|
|
|
_ => Ok(path.to_owned()),
|
|
|
|
}
|
2023-02-25 11:37:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-17 22:47:45 +01:00
|
|
|
impl Words {
|
2023-02-25 15:02:31 +01:00
|
|
|
/// Executes the words. This does *not* create a new frame on the stack. Use [Stack::call] to
|
|
|
|
/// call and create a new frame.
|
2023-02-19 02:03:06 +01:00
|
|
|
pub fn exec(&self, stack: &mut Stack) -> OError {
|
2023-02-17 22:47:45 +01:00
|
|
|
for word in self.words.clone() {
|
|
|
|
match word {
|
|
|
|
Word::Key(x) => match x {
|
2023-02-19 02:14:01 +01:00
|
|
|
Keyword::Dump => println!("{stack}"),
|
2023-02-17 22:47:45 +01:00
|
|
|
Keyword::Def(x) => stack.define_var(x),
|
|
|
|
Keyword::Func(name, rem, words) => stack.define_func(
|
2023-02-19 04:57:32 +01:00
|
|
|
name.clone(),
|
2023-02-17 22:47:45 +01:00
|
|
|
Arc::new(Func {
|
|
|
|
ret_count: rem,
|
|
|
|
to_call: FuncImpl::SPL(words),
|
2023-02-18 18:43:05 +01:00
|
|
|
origin: stack.get_frame(),
|
2023-02-25 15:02:31 +01:00
|
|
|
run_as_base: false,
|
2023-02-19 04:57:32 +01:00
|
|
|
fname: None,
|
|
|
|
name,
|
2023-02-17 22:47:45 +01:00
|
|
|
}),
|
|
|
|
),
|
2023-03-06 03:45:16 +01:00
|
|
|
Keyword::Construct(name, fields, methods, is_namespace) => {
|
2023-02-18 18:43:05 +01:00
|
|
|
let origin = stack.get_frame();
|
2023-03-06 03:45:16 +01:00
|
|
|
if !name.contains(':') {
|
|
|
|
stack.define_var(name.clone());
|
|
|
|
}
|
|
|
|
let t = runtime_mut(|mut rt| {
|
|
|
|
rt.make_type(name.clone(), |mut t| {
|
|
|
|
for field in fields {
|
|
|
|
t.add_property(field, origin.clone())?;
|
|
|
|
}
|
|
|
|
t.functions.extend(methods.into_iter().map(|(k, v)| {
|
|
|
|
(
|
|
|
|
k.clone(),
|
|
|
|
Arc::new(Func {
|
|
|
|
ret_count: v.0,
|
|
|
|
to_call: FuncImpl::SPL(v.1),
|
|
|
|
origin: origin.clone(),
|
|
|
|
run_as_base: false,
|
|
|
|
fname: None,
|
|
|
|
name: name.clone() + ":" + &k,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
}));
|
|
|
|
Ok(t)
|
|
|
|
})
|
|
|
|
})?;
|
|
|
|
|
|
|
|
let to_set: Object = if is_namespace {
|
|
|
|
let mut obj: Object = Value::Null.into();
|
|
|
|
obj.kind = t.clone();
|
|
|
|
t.lock_ro().write_into(&mut obj);
|
|
|
|
obj
|
|
|
|
} else {
|
|
|
|
Value::Str(t.lock_ro().get_name()).into()
|
|
|
|
};
|
|
|
|
if name.contains(':') {
|
|
|
|
let Some((a, mut name)) = name.split_once(':') else { unreachable!() };
|
|
|
|
let mut f = stack.get_var(a.to_owned())?;
|
|
|
|
while let Some((a, b)) = name.split_once(':') {
|
|
|
|
name = b;
|
|
|
|
let o = f.lock_ro();
|
|
|
|
let nf = o.field(a, stack)?;
|
|
|
|
mem::drop(o);
|
|
|
|
f = nf;
|
|
|
|
}
|
|
|
|
*f.lock_ro().field(name, stack)?.lock() = to_set;
|
|
|
|
} else {
|
|
|
|
stack.set_var(name.clone(), to_set.spl())?;
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
Keyword::Include(ta, tb) => {
|
2023-02-19 02:03:06 +01:00
|
|
|
let rstack = &stack;
|
2023-02-19 04:57:32 +01:00
|
|
|
runtime(move |rt| {
|
2023-03-06 14:56:49 +01:00
|
|
|
rt.get_type_by_name(&tb)
|
2023-02-19 19:34:25 +01:00
|
|
|
.ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(tb)))?
|
2023-02-19 04:57:32 +01:00
|
|
|
.lock()
|
|
|
|
.parents
|
|
|
|
.push(
|
2023-03-06 14:56:49 +01:00
|
|
|
rt.get_type_by_name(&ta)
|
2023-02-19 19:34:25 +01:00
|
|
|
.ok_or_else(|| rstack.error(ErrorKind::TypeNotFound(ta)))?,
|
2023-02-19 04:57:32 +01:00
|
|
|
);
|
|
|
|
Ok(())
|
2023-02-19 02:03:06 +01:00
|
|
|
})?;
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
2023-03-06 14:56:49 +01:00
|
|
|
Keyword::Use(item) => {
|
|
|
|
if let Some((a, mut name)) = item.split_once(':') {
|
|
|
|
let mut f = stack.get_var(a.to_owned())?;
|
|
|
|
while let Some((a, b)) = name.split_once(':') {
|
|
|
|
name = b;
|
|
|
|
let o = f.lock_ro();
|
|
|
|
let nf = o.field(a, stack)?;
|
|
|
|
mem::drop(o);
|
|
|
|
f = nf;
|
|
|
|
}
|
|
|
|
stack.define_var(name.to_owned());
|
|
|
|
let o = f.lock_ro().field(name, stack)?.clone();
|
|
|
|
stack.set_var(name.to_owned(), o)?;
|
|
|
|
}
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
Keyword::While(cond, blk) => loop {
|
2023-02-19 02:03:06 +01:00
|
|
|
cond.exec(stack)?;
|
2023-02-18 18:43:05 +01:00
|
|
|
if !stack.pop().lock_ro().is_truthy() {
|
2023-02-17 22:47:45 +01:00
|
|
|
break;
|
|
|
|
}
|
2023-02-19 02:03:06 +01:00
|
|
|
blk.exec(stack)?;
|
2023-02-19 19:34:25 +01:00
|
|
|
if stack.return_accumultor > 0 {
|
2023-03-06 14:56:49 +01:00
|
|
|
stack.return_accumultor -= 1;
|
2023-02-19 19:34:25 +01:00
|
|
|
break;
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
},
|
2023-02-18 18:43:05 +01:00
|
|
|
Keyword::If(blk) => {
|
|
|
|
if stack.pop().lock_ro().is_truthy() {
|
2023-02-19 02:03:06 +01:00
|
|
|
blk.exec(stack)?;
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
}
|
2023-03-06 14:56:49 +01:00
|
|
|
Keyword::Catch(types, blk, ctch) => {
|
|
|
|
if let Err(e) = blk.exec(stack) {
|
|
|
|
if types.is_empty() || types.contains(&e.kind.to_string()) {
|
|
|
|
stack.push(e.spl());
|
|
|
|
ctch.exec(stack)?;
|
|
|
|
} else {
|
|
|
|
return Err(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
Keyword::With(vars) => {
|
|
|
|
for var in vars.into_iter().rev() {
|
|
|
|
stack.define_var(var.clone());
|
|
|
|
let obj = stack.pop();
|
2023-02-19 02:03:06 +01:00
|
|
|
stack.set_var(var, obj)?;
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
}
|
2023-04-07 22:03:36 +02:00
|
|
|
Keyword::ObjPush => {
|
|
|
|
let o = stack.pop();
|
|
|
|
stack.objcall_stack.push(o);
|
|
|
|
}
|
|
|
|
Keyword::ObjPop => {
|
|
|
|
let o = stack
|
|
|
|
.objcall_stack
|
|
|
|
.pop()
|
|
|
|
.expect("invalid word generation. objpop without objpush!");
|
|
|
|
stack.push(o);
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
},
|
2023-02-19 19:34:25 +01:00
|
|
|
Word::Const(x) => {
|
|
|
|
if option_env!("SPLDEBUG").is_some() {
|
|
|
|
println!("CNST({}) {x:?}", stack.len());
|
|
|
|
}
|
|
|
|
stack.push(x.clone().ensure_init(stack).spl())
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
Word::Call(x, rem, ra) => {
|
2023-02-19 19:34:25 +01:00
|
|
|
if option_env!("SPLDEBUG").is_some() {
|
|
|
|
println!("CALL({}) {x}", stack.len());
|
|
|
|
}
|
2023-02-19 04:57:32 +01:00
|
|
|
let f = stack.get_func(x.clone())?;
|
2023-02-17 22:47:45 +01:00
|
|
|
if ra != 0 {
|
2023-02-18 18:43:05 +01:00
|
|
|
let mut f = Value::Func(f);
|
2023-02-19 04:57:32 +01:00
|
|
|
for n in 1..ra {
|
|
|
|
let mut s = String::new();
|
|
|
|
for _ in 0..n {
|
|
|
|
s += "&";
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
let ftmp = f;
|
2023-02-18 18:43:05 +01:00
|
|
|
f = Value::Func(AFunc::new(Func {
|
2023-02-17 22:47:45 +01:00
|
|
|
ret_count: 1,
|
|
|
|
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
|
|
|
|
stack.push(ftmp.clone().spl());
|
2023-02-19 02:03:06 +01:00
|
|
|
Ok(())
|
2023-02-17 22:47:45 +01:00
|
|
|
}))),
|
2023-02-18 18:43:05 +01:00
|
|
|
origin: stack.get_frame(),
|
2023-02-25 15:02:31 +01:00
|
|
|
run_as_base: false,
|
2023-02-19 04:57:32 +01:00
|
|
|
fname: None,
|
|
|
|
name: s + &x,
|
2023-02-17 22:47:45 +01:00
|
|
|
}));
|
|
|
|
}
|
2023-02-19 04:57:32 +01:00
|
|
|
stack.push(f.spl());
|
2023-02-17 22:47:45 +01:00
|
|
|
} else {
|
2023-02-19 02:03:06 +01:00
|
|
|
stack.call(&f)?;
|
2023-02-17 22:47:45 +01:00
|
|
|
if rem {
|
|
|
|
for _ in 0..f.ret_count {
|
|
|
|
stack.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Word::ObjCall(x, rem, ra) => {
|
|
|
|
let o = stack.peek();
|
2023-02-18 18:43:05 +01:00
|
|
|
let o = o.lock_ro();
|
|
|
|
let f0 = o.kind.lock_ro();
|
2023-02-18 18:45:15 +01:00
|
|
|
let f = f0
|
2023-02-19 19:34:25 +01:00
|
|
|
.get_fn(x.clone())
|
2023-03-06 14:56:49 +01:00
|
|
|
.ok_or_else(|| {
|
|
|
|
stack.error(ErrorKind::MethodNotFound(f0.name.clone(), x.clone()))
|
2023-02-19 02:03:06 +01:00
|
|
|
})?
|
2023-02-18 18:45:15 +01:00
|
|
|
.clone();
|
2023-02-19 19:34:25 +01:00
|
|
|
if option_env!("SPLDEBUG").is_some() {
|
|
|
|
println!("CALL({}) {}:{x}", stack.len(), &o.kind.lock_ro().name);
|
|
|
|
}
|
2023-02-18 18:43:05 +01:00
|
|
|
mem::drop(f0);
|
|
|
|
mem::drop(o);
|
2023-02-17 22:47:45 +01:00
|
|
|
if ra != 0 {
|
2023-02-18 18:43:05 +01:00
|
|
|
let mut f = Value::Func(f.clone());
|
2023-02-19 04:57:32 +01:00
|
|
|
for n in 1..ra {
|
|
|
|
let mut s = String::new();
|
|
|
|
for _ in 0..n {
|
|
|
|
s += "&";
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
let ftmp = f;
|
2023-02-18 18:43:05 +01:00
|
|
|
f = Value::Func(AFunc::new(Func {
|
2023-02-17 22:47:45 +01:00
|
|
|
ret_count: 1,
|
|
|
|
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
|
|
|
|
stack.push(ftmp.clone().spl());
|
2023-02-19 02:03:06 +01:00
|
|
|
Ok(())
|
2023-02-17 22:47:45 +01:00
|
|
|
}))),
|
2023-02-18 18:43:05 +01:00
|
|
|
origin: stack.get_frame(),
|
2023-02-25 15:02:31 +01:00
|
|
|
run_as_base: false,
|
2023-02-19 04:57:32 +01:00
|
|
|
fname: None,
|
|
|
|
name: s + &x,
|
2023-02-17 22:47:45 +01:00
|
|
|
}));
|
|
|
|
}
|
2023-02-19 19:34:25 +01:00
|
|
|
stack.pop();
|
2023-02-19 04:57:32 +01:00
|
|
|
stack.push(f.spl())
|
2023-02-17 22:47:45 +01:00
|
|
|
} else {
|
2023-02-19 02:03:06 +01:00
|
|
|
stack.call(&f)?;
|
2023-02-17 22:47:45 +01:00
|
|
|
if rem {
|
|
|
|
for _ in 0..f.ret_count {
|
|
|
|
stack.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-19 19:34:25 +01:00
|
|
|
if stack.return_accumultor > 0 {
|
|
|
|
stack.return_accumultor -= 1;
|
|
|
|
return Ok(());
|
|
|
|
}
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
2023-02-19 02:03:06 +01:00
|
|
|
Ok(())
|
2023-02-17 22:47:45 +01:00
|
|
|
}
|
|
|
|
}
|
2023-02-19 02:03:06 +01:00
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// Any error SPL can handle and throw.
|
2023-02-19 02:03:06 +01:00
|
|
|
#[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),
|
2023-02-19 04:57:32 +01:00
|
|
|
IO(String),
|
|
|
|
Custom(String),
|
|
|
|
CustomObject(AMObject),
|
2023-02-19 02:03:06 +01:00
|
|
|
}
|
|
|
|
|
2023-03-06 14:56:49 +01:00
|
|
|
impl Display for ErrorKind {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
match self {
|
|
|
|
ErrorKind::Parse(_, _) => f.write_str("Parse"),
|
|
|
|
ErrorKind::InvalidCall(_) => f.write_str("InvalidCall"),
|
|
|
|
ErrorKind::InvalidType(_, _) => f.write_str("InvalidType"),
|
|
|
|
ErrorKind::VariableNotFound(_) => f.write_str("VariableNotFound"),
|
|
|
|
ErrorKind::FuncNotFound(_) => f.write_str("FuncNotFound"),
|
|
|
|
ErrorKind::MethodNotFound(_, _) => f.write_str("MethodNotFound"),
|
|
|
|
ErrorKind::PropertyNotFound(_, _) => f.write_str("PropertyNotFound"),
|
|
|
|
ErrorKind::TypeNotFound(_) => f.write_str("TypeNotFound"),
|
|
|
|
ErrorKind::LexError(_) => f.write_str("LexError"),
|
|
|
|
ErrorKind::IO(_) => f.write_str("IO"),
|
|
|
|
ErrorKind::Custom(_) => f.write_str("Custom"),
|
|
|
|
ErrorKind::CustomObject(_) => f.write_str("CustomObject"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-25 15:02:31 +01:00
|
|
|
/// Wrapper for ErrorKind with the stack trace.
|
2023-02-19 19:34:25 +01:00
|
|
|
#[derive(PartialEq, Eq)]
|
2023-02-19 02:03:06 +01:00
|
|
|
pub struct Error {
|
|
|
|
pub kind: ErrorKind,
|
|
|
|
pub stack: Vec<String>,
|
2023-03-06 14:56:49 +01:00
|
|
|
pub mr_stack: Vec<Vec<FrameInfo>>,
|
2023-02-19 02:03:06 +01:00
|
|
|
}
|
2023-02-19 19:34:25 +01:00
|
|
|
|
|
|
|
impl Debug for Error {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
2023-02-25 11:37:07 +01:00
|
|
|
f.write_str("\n\nSPL PANIC DUE TO UNCAUGHT ERROR:\n")?;
|
|
|
|
f.write_str(format!("Error: {:?}", self.kind).as_str())?;
|
|
|
|
f.write_str("\n")?;
|
|
|
|
f.write_str(self.stack.join("\n").as_str())?;
|
|
|
|
f.write_str("\n\n")?;
|
|
|
|
Ok(())
|
2023-02-19 19:34:25 +01:00
|
|
|
}
|
|
|
|
}
|
2023-03-06 14:56:49 +01:00
|
|
|
|
|
|
|
impl From<Error> for Object {
|
|
|
|
fn from(value: Error) -> Self {
|
|
|
|
let mut obj = Object::new(
|
|
|
|
get_type("error").expect("error type must exist"),
|
|
|
|
Value::Null,
|
|
|
|
);
|
|
|
|
obj.property_map
|
|
|
|
.insert("kind".to_owned(), value.kind.to_string().spl());
|
|
|
|
obj.property_map
|
|
|
|
.insert("message".to_owned(), format!("{:?}", value.kind).spl());
|
|
|
|
if let ErrorKind::CustomObject(ref o) = value.kind {
|
|
|
|
obj.property_map.insert("object".to_owned(), o.clone());
|
|
|
|
}
|
|
|
|
if let ErrorKind::Custom(ref s) = value.kind {
|
|
|
|
obj.property_map
|
|
|
|
.insert("message".to_owned(), s.clone().spl());
|
|
|
|
}
|
|
|
|
obj.property_map
|
|
|
|
.insert("trace".to_owned(), value.stack.spl());
|
|
|
|
obj.property_map
|
|
|
|
.insert("mr-trace".to_owned(), value.mr_stack.spl());
|
|
|
|
obj
|
|
|
|
}
|
|
|
|
}
|