use crate::{
dyn_fns,
mutex::*,
std_fns, stdlib,
stream::{self, *},
};
use core::panic;
use std::{
cell::RefCell,
collections::HashMap,
fmt::{Debug, Display, Formatter},
sync::Arc,
vec,
};
use std::{
collections::LinkedList,
sync::{RwLockReadGuard, RwLockWriteGuard},
};
use std::{collections::VecDeque, process::Child};
use std::{env::var, mem, path::Path};
pub type AMObject = Arc<Mut<Object>>;
pub type AMType = Arc<Mut<Type>>;
pub type AFunc = Arc<Func>;
pub type OError = Result<(), Error>;
thread_local! {
static RUNTIME: RefCell<Option<Arc<Mut<Runtime>>>> = RefCell::new(None);
}
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())
})
}
pub fn runtime_mut<T>(f: impl FnOnce(RwLockWriteGuard<Runtime>) -> T) -> T {
RUNTIME.with(|rt| {
f(rt.borrow_mut()
.as_mut()
.expect("no runtime (use .set())")
.lock())
})
}
pub fn fork_runtime() -> Arc<Mut<Runtime>> {
RUNTIME.with(|rt| {
rt.borrow_mut()
.as_mut()
.expect("no runtime (use .set)")
.clone()
})
}
pub fn get_type(name: &str) -> Option<AMType> {
runtime(|rt| rt.get_type_by_name(name))
}
#[derive(Clone)]
pub struct Runtime {
next_type_id: u32,
types_by_name: HashMap<String, AMType>,
types_by_id: HashMap<u32, AMType>,
next_stream_id: u128,
streams: HashMap<u128, Arc<Mut<Stream>>>,
server_streams: HashMap<u128, Arc<Mut<ServerStream>>>,
pub embedded_files: HashMap<&'static str, &'static str>,
pub native_functions: HashMap<&'static str, (u32, FuncImpl)>,
children: Arc<Mut<Vec<Child>>>,
}
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()
}
}
impl Default for Runtime {
fn default() -> Self {
Self::new()
}
}
impl Runtime {
pub fn new() -> Self {
let mut rt = Runtime {
next_type_id: 0,
types_by_name: HashMap::new(),
types_by_id: HashMap::new(),
next_stream_id: 0,
streams: HashMap::new(),
server_streams: HashMap::new(),
embedded_files: HashMap::new(),
native_functions: HashMap::new(),
children: Arc::new(Mut::new(Vec::new())),
};
let _ = rt.make_type("null".to_owned(), Ok); let _ = rt.make_type("int".to_owned(), Ok); let _ = rt.make_type("long".to_owned(), Ok); let _ = rt.make_type("mega".to_owned(), Ok); let _ = rt.make_type("float".to_owned(), Ok); let _ = rt.make_type("double".to_owned(), Ok); let _ = rt.make_type("func".to_owned(), Ok); let _ = rt.make_type("array".to_owned(), Ok); let _ = rt.make_type("str".to_owned(), Ok); let _ = rt.make_type("bytearray".to_owned(), Ok); stdlib::register(&mut rt);
rt
}
pub fn get_type_by_name(&self, name: &str) -> Option<AMType> {
self.types_by_name.get(name).cloned()
}
pub fn get_type_by_id(&self, id: u32) -> Option<AMType> {
self.types_by_id.get(&id).cloned()
}
pub fn get_types(&self) -> Vec<AMType> {
self.types_by_id.clone().into_values().collect()
}
pub fn make_type(
&mut self,
name: String,
op: impl FnOnce(Type) -> Result<Type, Error>,
) -> Result<AMType, Error> {
let t = 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(),
conditions: None,
})?;
let t = Arc::new(Mut::new(t));
self.types_by_id.insert(self.next_type_id - 1, t.clone());
self.types_by_name.insert(name, t.clone());
self.propagate_extensions(t.clone());
Ok(t)
}
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);
}
pub fn register_server_stream(
&mut self,
stream: ServerStream,
) -> (u128, Arc<Mut<ServerStream>>) {
let id = (self.next_stream_id, self.next_stream_id += 1).0;
self.server_streams.insert(id, Arc::new(Mut::new(stream)));
(id, self.server_streams.get(&id).unwrap().clone())
}
pub fn get_server_stream(&self, id: u128) -> Option<Arc<Mut<ServerStream>>> {
self.server_streams.get(&id).cloned()
}
pub fn destroy_server_stream(&mut self, id: u128) {
self.server_streams.remove(&id);
}
pub fn load_native_function(&self, name: &str) -> &(u32, FuncImpl) {
self.native_functions.get(name).unwrap_or_else(|| {
panic!(
"It seems the native function {name} was not compiled into this program. Stopping."
)
})
}
pub fn child(&self, child: Child) {
let mut children = self.children.lock();
children.retain_mut(|x| x.try_wait().is_err());
children.push(child);
}
pub fn propagate_extensions(&self, ty: Arc<Mut<Type>>) {
let mut next = LinkedList::new();
next.push_back(ty);
while let Some(ty) = next.pop_front() {
{
let mut ty = ty.lock();
let all_appliers = ty.all_appliers(self);
for applier in all_appliers {
ty.parents.push(applier);
}
}
{
let all_applying = ty.lock_ro().all_applying(self);
for applying in all_applying {
applying.lock().parents.push(ty.clone());
next.push_back(applying);
}
}
}
}
pub fn reset() {
RUNTIME.with(|x| *x.borrow_mut() = None);
}
}
pub trait SetRuntime {
fn set(self);
}
impl SetRuntime for Runtime {
fn set(self) {
Arc::new(Mut::new(self)).set()
}
}
impl SetRuntime for Arc<Mut<Runtime>> {
fn set(self) {
RUNTIME.with(move |x| *x.borrow_mut() = Some(self));
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FrameInfo {
pub file: String,
pub function: String,
}
#[derive(Clone, Debug)]
pub struct Frame {
parent: Option<Arc<Frame>>,
pub variables: Mut<HashMap<String, AMObject>>,
pub functions: Mut<HashMap<String, AFunc>>,
pub origin: FrameInfo,
pub redirect_to_base: bool,
}
impl Display for Frame {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("\nVars: \n")?;
for (name, object) in self.variables.lock_ro().iter() {
f.write_str(" ")?;
f.write_str(name)?;
f.write_str(": ")?;
std::fmt::Display::fmt(&object.lock_ro(), f)?;
f.write_str("\n")?;
}
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")?;
Ok(())
}
}
impl Frame {
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(),
},
redirect_to_base: false,
}
}
pub fn root() -> Self {
Frame {
parent: None,
variables: Mut::new(HashMap::new()),
functions: Mut::new(HashMap::new()),
origin: FrameInfo {
file: "std.spl".to_owned(),
function: "root".to_owned(),
},
redirect_to_base: false,
}
}
pub fn root_in(info: FrameInfo) -> Self {
Frame {
parent: None,
variables: Mut::new(HashMap::new()),
functions: Mut::new(HashMap::new()),
origin: info,
redirect_to_base: false,
}
}
pub fn new(parent: Arc<Frame>, function: String) -> Self {
Frame {
variables: Mut::new(HashMap::new()),
functions: Mut::new(HashMap::new()),
origin: FrameInfo {
function,
..parent.origin.clone()
},
parent: Some(parent),
redirect_to_base: false,
}
}
pub fn new_in(
parent: Arc<Frame>,
origin: String,
function: String,
redirect_to_parent: bool,
) -> Self {
Frame {
parent: Some(parent),
variables: Mut::new(HashMap::new()),
functions: Mut::new(HashMap::new()),
origin: FrameInfo {
file: origin,
function,
},
redirect_to_base: redirect_to_parent,
}
}
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(stack.error(ErrorKind::VariableNotFound(name)));
}
}
}
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(stack.error(ErrorKind::VariableNotFound(name)));
}
}
}
pub fn path(&self) -> Vec<FrameInfo> {
let mut r = Vec::new();
let mut frame = self;
loop {
r.insert(0, frame.origin.clone());
if let Some(ref parent) = frame.parent {
frame = parent;
} else {
break;
}
}
r
}
pub fn 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
}
pub fn is_dummy(&self) -> bool {
self.parent.is_none() && self.origin.file == "\0" && self.origin.function == "\0"
}
}
#[derive(Clone, Debug)]
pub struct Stack {
frames: Vec<Arc<Frame>>,
object_stack: Vec<AMObject>,
objcall_stack: Vec<AMObject>,
files: Vec<String>,
pub return_accumultor: u32,
}
impl Display for Stack {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
for frame in &self.frames {
f.write_str("Frame:")?;
f.write_str(&frame.readable_path())?;
f.write_str("\n")?;
std::fmt::Display::fmt(&frame.as_ref(), f)?;
f.write_str("\n\n")?;
}
f.write_str("Stack: \n")?;
for object in &self.object_stack {
f.write_str(" ")?;
std::fmt::Display::fmt(&object.lock_ro(), f)?;
f.write_str("\n")?;
}
Ok(())
}
}
impl Default for Stack {
fn default() -> Self {
Self::new()
}
}
impl Stack {
pub fn new() -> Self {
let o = Arc::new(Frame::root());
let mut r = Stack {
frames: vec![o.clone()],
object_stack: Vec::new(),
objcall_stack: Vec::new(),
files: Vec::new(),
return_accumultor: 0,
};
dyn_fns::register(&mut r, o.clone());
std_fns::register(&mut r, o.clone());
stream::register(&mut r, o);
r
}
pub fn new_in(frame_info: FrameInfo) -> Self {
let o = Arc::new(Frame::root_in(frame_info));
let mut r = Stack {
frames: vec![o.clone()],
object_stack: Vec::new(),
objcall_stack: Vec::new(),
files: Vec::new(),
return_accumultor: 0,
};
dyn_fns::register(&mut r, o.clone());
std_fns::register(&mut r, o.clone());
stream::register(&mut r, o);
r
}
pub fn define_func(&mut self, name: String, func: AFunc) {
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);
}
pub fn call(&mut self, func: &AFunc) -> OError {
if func.origin.is_dummy() {
return self.fast_call(func);
}
let f = if let Some(ref cname) = func.fname {
Frame::new_in(
func.origin.clone(),
cname.clone(),
func.name.clone(),
func.run_as_base,
)
} else {
Frame::new(func.origin.clone(), func.name.clone())
};
self.frames.push(Arc::new(f));
let r = func.to_call.call(self);
self.frames.pop().unwrap();
r
}
pub fn fast_call(&mut self, func: &AFunc) -> OError {
let r = func.to_call.call(self);
r
}
pub fn get_func(&self, name: String) -> Result<AFunc, Error> {
let mut frame = self.frames.last().unwrap();
loop {
let functions = &frame.functions;
if let Some(x) = functions.lock_ro().get(&name) {
return Ok(x.clone());
}
if let Some(ref x) = frame.parent {
frame = x;
} else {
return Err(self.error(ErrorKind::FuncNotFound(name)));
}
}
}
pub fn define_var(&mut self, name: String) {
let mut frame = self.frames.last().unwrap().clone();
if frame.redirect_to_base {
frame = self.frames.first().unwrap().clone();
}
let tmpname = name.clone();
frame.functions.lock().insert(
name.clone(),
Arc::new(Func {
ret_count: 1,
origin: Arc::new(Frame::dummy()),
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
stack.push(stack.get_var(tmpname.clone())?);
Ok(())
}))),
run_as_base: false,
fname: Some("RUNTIME".to_owned()),
name: name.clone(),
}),
);
let tmpname = name.clone();
frame.functions.lock().insert(
"=".to_owned() + &name,
Arc::new(Func {
ret_count: 0,
origin: Arc::new(Frame::dummy()),
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
let v = stack.pop();
stack.set_var(tmpname.clone(), v)
}))),
run_as_base: false,
fname: Some("RUNTIME".to_owned()),
name: "=".to_owned() + &name,
}),
);
frame.variables.lock().insert(name, Value::Null.spl());
}
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()
}
pub fn set_var(&self, name: String, obj: AMObject) -> OError {
if let Err(x) = self.get_frame().set_var(name.clone(), obj.clone(), self) {
for i in 1..self.frames.len() {
if self
.peek_frame(i)
.set_var(name.clone(), obj.clone(), self)
.is_ok()
{
return Ok(());
}
}
return Err(x);
}
Ok(())
}
pub fn get_var(&self, name: String) -> Result<AMObject, Error> {
match self.get_frame().get_var(name.clone(), self) {
Err(x) => {
for i in 1..self.frames.len() {
if let Ok(x) = self.peek_frame(i).get_var(name.clone(), self) {
return Ok(x);
}
}
Err(x)
}
Ok(x) => Ok(x),
}
}
pub fn push(&mut self, obj: AMObject) {
self.object_stack.push(obj)
}
pub fn peek(&mut self) -> AMObject {
self.object_stack
.last()
.cloned()
.unwrap_or(Value::Null.spl())
}
pub fn pop(&mut self) -> AMObject {
self.object_stack.pop().unwrap_or(Value::Null.spl())
}
pub fn get_origin(&self) -> FrameInfo {
self.frames.last().unwrap().origin.clone()
}
pub fn get_frame(&self) -> Arc<Frame> {
self.frames.last().unwrap().clone()
}
pub fn err<T>(&self, kind: ErrorKind) -> Result<T, Error> {
Err(Error {
kind,
stack: self.trace(),
mr_stack: self.mr_trace(),
})
}
pub fn error(&self, kind: ErrorKind) -> Error {
Error {
kind,
stack: self.trace(),
mr_stack: self.mr_trace(),
}
}
pub fn mr_trace(&self) -> Vec<Vec<FrameInfo>> {
self.frames.iter().map(|frame| frame.path()).collect()
}
pub fn trace(&self) -> Vec<String> {
self.frames
.iter()
.map(|frame| frame.readable_path())
.collect()
}
pub fn peek_frame(&self, index: usize) -> Arc<Frame> {
self.frames
.get(self.frames.len() - index - 1)
.unwrap()
.clone()
}
pub unsafe fn pop_frame(&mut self, index: usize) -> Arc<Frame> {
self.frames.remove(self.frames.len() - index - 1)
}
pub unsafe fn push_frame(&mut self, frame: Arc<Frame>) {
self.frames.push(frame);
}
pub(crate) fn include_file(&mut self, s: &String) -> bool {
if self.files.contains(s) {
false
} else {
self.files.push(s.to_owned());
true
}
}
}
#[derive(Clone, Debug)]
pub enum FuncImplType {
Rust,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConstructKind {
Thing,
Namespace,
Extension(Vec<String>),
}
#[derive(Clone, Debug)]
pub enum Keyword {
Dump,
InlineCallable,
InlineStart,
InlineEnd,
Def(String),
Func(String, u32, Words),
Construct(
String,
Vec<String>,
Vec<(String, (u32, Words))>,
ConstructKind,
),
Include(String, String),
Use(String),
While(Words, Words),
If(Words),
With(Vec<String>),
Catch(Vec<String>, Words, Words),
ObjPush,
ObjPop,
FuncOf(String, String, FuncImplType),
}
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Null,
Int(i32),
Long(i64),
Mega(i128),
Float(f32),
Double(f64),
Func(AFunc),
Array(Vec<AMObject>),
ByteArray(Vec<u8>),
Str(String),
}
impl Value {
fn ensure_init(self, stack: &Stack) -> Self {
match self {
Value::Func(x) if x.origin.is_dummy() => Value::Func(AFunc::new(Func {
origin: stack.get_frame(),
..x.as_ref().clone()
})),
x => x,
}
}
pub fn try_mega_to_int(self) -> Value {
if let Value::Mega(x) = self {
Value::Int(x as i32)
} else {
self
}
}
}
impl PartialOrd for Value {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match (self, other) {
(Value::Mega(a), Value::Mega(b)) => a.partial_cmp(b),
(Value::Long(a), Value::Long(b)) => a.partial_cmp(b),
(Value::Int(a), Value::Int(b)) => a.partial_cmp(b),
(Value::Double(a), Value::Double(b)) => a.partial_cmp(b),
(Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
_ => panic!(),
}
}
}
#[derive(Clone, Debug)]
pub enum Word {
Key(Keyword),
Const(Value),
Call(String, bool, u32),
ObjCall(String, bool, u32),
}
#[derive(Clone, Debug)]
pub struct Words {
pub words: Vec<Word>,
}
impl Words {
pub fn new(words: Vec<Word>) -> Self {
Words { words }
}
}
#[derive(Clone)]
pub enum FuncImpl {
Native(fn(&mut Stack) -> OError),
NativeDyn(Arc<Box<dyn (Fn(&mut Stack) -> OError) + Send + Sync>>),
SPL(Words),
}
impl FuncImpl {
pub fn call(&self, stack: &mut Stack) -> OError {
match self {
FuncImpl::Native(x) => x(stack),
FuncImpl::NativeDyn(x) => x(stack),
FuncImpl::SPL(x) => x.exec(stack),
}
}
}
#[derive(Clone)]
pub struct Func {
pub ret_count: u32,
pub to_call: FuncImpl,
pub origin: Arc<Frame>,
pub fname: Option<String>,
pub name: String,
pub run_as_base: bool,
}
impl PartialEq for Func {
fn eq(&self, _other: &Self) -> bool {
false
}
}
impl Debug for Func {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.ret_count.to_string())?;
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct Type {
name: String,
id: u32,
pub parents: Vec<AMType>,
pub functions: HashMap<String, AFunc>,
pub properties: Vec<String>,
pub conditions: Option<Vec<String>>,
}
impl PartialEq for Type {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Type {
pub fn get_name(&self) -> String {
self.name.clone()
}
pub fn get_id(&self) -> u32 {
self.id
}
pub fn get_fn(&self, name: &str) -> 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() {
if let Some(x) = t.lock_ro().functions.get(name) {
return Some(x.clone());
}
q.append(&mut VecDeque::from(t.lock_ro().parents.clone()));
}
None
}
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() {
object
.property_map
.entry(property)
.or_insert_with(|| Value::Null.spl());
}
}
pub fn add_property(&mut self, name: String, origin: Arc<Frame>) -> OError {
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();
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(),
run_as_base: false,
fname: Some("RUNTIME".to_owned()),
name: name.clone(),
}),
);
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);
Ok(())
}))),
origin,
run_as_base: false,
fname: Some("RUNTIME".to_owned()),
name: "=".to_owned() + &name,
}),
);
self.properties.push(name);
Ok(())
}
fn applies(&self, ty: &Type) -> bool {
if ty.id == self.id {
return false;
}
if ty.parents.iter().any(|x| x.lock_ro().id == self.id) {
return false;
}
if let Some(ref conditions) = self.conditions {
for cond in conditions {
if ty.get_fn(cond).is_none() {
return false;
}
}
true
} else {
false
}
}
fn all_applying(&self, rt: &Runtime) -> Vec<Arc<Mut<Type>>> {
let mut r = Vec::new();
if let Some(_) = self.conditions {
for (id, other) in rt.types_by_id.iter() {
if *id == self.id {
continue;
}
let o = other.lock_ro();
if self.applies(&o) {
drop(o);
r.push(other.clone());
} else {
drop(o);
}
}
}
r
}
fn all_appliers(&self, rt: &Runtime) -> Vec<Arc<Mut<Type>>> {
let mut r = Vec::new();
for (id, other) in rt.types_by_id.iter() {
if *id == self.id {
continue;
}
let o = other.lock_ro();
if o.applies(self) {
drop(o);
r.push(other.clone());
} else {
drop(o);
}
}
r
}
}
#[derive(Clone, Debug)]
pub struct Object {
pub kind: AMType,
pub property_map: HashMap<String, AMObject>,
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 {
return None;
}
self.native.partial_cmp(&other.native)
}
}
impl Eq for Object {}
impl Display for Object {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.kind.lock_ro().name)?;
f.write_str("(")?;
self.native.fmt(f)?;
f.write_str(") {")?;
for (k, v) in &self.property_map {
f.write_str(" ")?;
f.write_str(k)?;
f.write_str(": ")?;
std::fmt::Display::fmt(&v.lock_ro(), f)?;
f.write_str(",")?;
}
f.write_str(" }")?;
Ok(())
}
}
impl Object {
pub fn new(kind: AMType, native: Value) -> Object {
let mut r = Object {
property_map: HashMap::new(),
kind: kind.clone(),
native,
};
kind.lock_ro().write_into(&mut r);
r
}
pub fn is_truthy(&self) -> bool {
match &self.native {
Value::Null => self.kind.lock_ro().id != 0,
Value::Int(x) => *x > 0,
Value::Long(x) => *x > 0,
Value::Mega(x) => *x > 0,
Value::Float(x) => x.is_finite(),
Value::Double(x) => x.is_finite(),
Value::Func(_) => true,
Value::Array(_) => true,
Value::Str(x) => !x.is_empty(),
Value::ByteArray(_) => true,
}
}
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())
}
}
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()
}
}
impl From<Value> for Object {
fn from(value: Value) -> Self {
Object::new(
runtime(|x| {
match value {
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),
Value::ByteArray(_) => x.get_type_by_id(9),
}
.expect("runtime uninitialized: default types not set.")
}),
value,
)
}
}
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()))
}
}
macro_rules! impl_to_object {
($kind:ident, $type:ty) => {
impl From<$type> for Object {
fn from(value: $type) -> Object {
Value::$kind(value).into()
}
}
};
}
impl_to_object!(Int, i32);
impl_to_object!(Long, i64);
impl_to_object!(Mega, i128);
impl_to_object!(Float, f32);
impl_to_object!(Double, f64);
pub fn find_in_splpath(path: &str) -> Result<String, String> {
if Path::new(path).exists() {
return Ok(path.to_owned());
}
let s = var("SPL_PATH").unwrap_or("/usr/lib/spl".to_owned()) + "/" + path;
if Path::new(&s).exists() {
Ok(s)
} else {
runtime(|x| {
for (&p, &data) in &x.embedded_files {
if path == p {
return Err(data.to_owned());
}
}
Ok(path.to_owned()) })
}
}
impl Words {
pub fn exec(&self, stack: &mut Stack) -> OError {
let mut inline_calls = false;
for word in self.words.iter() {
match word {
Word::Key(x) => match x {
Keyword::Dump => println!("{stack}"),
Keyword::InlineCallable => {
let Value::Func(f) = stack.pop().lock_ro().native.clone() else {
return Err(
stack.error(ErrorKind::InvalidCall("inline-callable".to_owned()))
);
};
stack.fast_call(&f)?;
}
Keyword::InlineStart => {
inline_calls = true;
}
Keyword::InlineEnd => {
inline_calls = false;
}
Keyword::Def(x) => stack.define_var(x.to_owned()),
Keyword::Func(name, rem, words) => stack.define_func(
name.clone(),
Arc::new(Func {
ret_count: *rem,
to_call: FuncImpl::SPL(words.to_owned()),
origin: stack.get_frame(),
run_as_base: false,
fname: None,
name: name.to_owned(),
}),
),
Keyword::Construct(name, fields, methods, kind) => {
let origin = stack.get_frame();
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.to_owned(), 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.to_owned()),
origin: origin.clone(),
run_as_base: false,
fname: None,
name: name.clone() + ":" + &k,
}),
)
}));
if let ConstructKind::Extension(cond) = kind {
t.conditions = Some(cond.clone());
}
Ok(t)
})
})?;
let to_set: Object = if *kind == ConstructKind::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())?;
}
}
Keyword::Include(ta, tb) => {
let rstack = &stack;
runtime(move |rt| {
rt.get_type_by_name(&tb)
.ok_or_else(|| {
rstack.error(ErrorKind::TypeNotFound(tb.to_owned()))
})?
.lock()
.parents
.push(rt.get_type_by_name(&ta).ok_or_else(|| {
rstack.error(ErrorKind::TypeNotFound(ta.to_owned()))
})?);
Ok(())
})?;
}
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)?;
}
}
Keyword::While(cond, blk) => loop {
cond.exec(stack)?;
if !stack.pop().lock_ro().is_truthy() {
break;
}
blk.exec(stack)?;
if stack.return_accumultor > 0 {
stack.return_accumultor -= 1;
break;
}
},
Keyword::If(blk) => {
if stack.pop().lock_ro().is_truthy() {
blk.exec(stack)?;
}
}
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);
}
}
}
Keyword::With(vars) => {
for var in vars.into_iter().rev() {
stack.define_var(var.clone());
let obj = stack.pop();
stack.set_var(var.to_owned(), obj)?;
}
}
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);
}
Keyword::FuncOf(name, _, _) => runtime(|x| {
let f = x.load_native_function(&name);
stack.define_func(
name.to_owned(),
Arc::new(Func {
ret_count: f.0,
to_call: f.1.clone(),
origin: stack.get_frame(),
run_as_base: false,
fname: None,
name: name.to_owned(),
}),
)
}),
},
Word::Const(x) => {
if option_env!("SPLDEBUG").is_some() {
println!("CNST({}) {x:?}", stack.len());
}
stack.push(x.clone().ensure_init(stack).spl())
}
Word::Call(x, rem, ra) => {
let ra = *ra;
if option_env!("SPLDEBUG").is_some() {
println!("CALL({}) {x}", stack.len());
}
let f = stack.get_func(x.clone())?;
if ra != 0 {
let mut f = Value::Func(f);
for n in 1..ra {
let mut s = String::new();
for _ in 0..n {
s += "&";
}
let ftmp = f;
f = Value::Func(AFunc::new(Func {
ret_count: 1,
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
stack.push(ftmp.clone().spl());
Ok(())
}))),
origin: stack.get_frame(),
run_as_base: false,
fname: None,
name: s + &x,
}));
}
stack.push(f.spl());
} else {
if inline_calls {
stack.fast_call(&f)?;
} else {
stack.call(&f)?;
}
if *rem {
for _ in 0..f.ret_count {
stack.pop();
}
}
}
}
Word::ObjCall(x, rem, ra) => {
let ra = *ra;
let o = stack.peek();
let o = o.lock_ro();
let f0 = o.kind.lock_ro();
let f = f0
.get_fn(&x)
.ok_or_else(|| {
stack.error(ErrorKind::MethodNotFound(f0.name.clone(), x.clone()))
})?
.clone();
if option_env!("SPLDEBUG").is_some() {
println!("CALL({}) {}:{x}", stack.len(), &o.kind.lock_ro().name);
}
mem::drop(f0);
mem::drop(o);
if ra != 0 {
let mut f = Value::Func(f.clone());
for n in 1..ra {
let mut s = String::new();
for _ in 0..n {
s += "&";
}
let ftmp = f;
f = Value::Func(AFunc::new(Func {
ret_count: 1,
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
stack.push(ftmp.clone().spl());
Ok(())
}))),
origin: stack.get_frame(),
run_as_base: false,
fname: None,
name: s + &x,
}));
}
stack.pop();
stack.push(f.spl())
} else {
if inline_calls {
stack.fast_call(&f)?;
} else {
stack.call(&f)?;
}
if *rem {
for _ in 0..f.ret_count {
stack.pop();
}
}
}
}
}
if stack.return_accumultor > 0 {
stack.return_accumultor -= 1;
return Ok(());
}
}
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),
IO(String),
Custom(String),
CustomObject(AMObject),
}
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"),
}
}
}
#[derive(PartialEq, Eq)]
pub struct Error {
pub kind: ErrorKind,
pub stack: Vec<String>,
pub mr_stack: Vec<Vec<FrameInfo>>,
}
impl Debug for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
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(())
}
}
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
}
}