Initial commit
This commit is contained in:
commit
34dd8ca486
4 changed files with 329 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "spl"
|
||||
version = "0.1.0"
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "spl"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
313
src/main.rs
Normal file
313
src/main.rs
Normal file
|
@ -0,0 +1,313 @@
|
|||
use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
fmt::{Display, Formatter, Pointer, Debug},
|
||||
sync::{Arc, Mutex},
|
||||
vec,
|
||||
};
|
||||
|
||||
thread_local! {
|
||||
static RUNTIME: RefCell<Option<Runtime>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Runtime {
|
||||
next_type_id: u32,
|
||||
types_by_name: HashMap<String, Arc<Type>>,
|
||||
types_by_id: HashMap<u32, Arc<Type>>,
|
||||
}
|
||||
|
||||
impl Runtime {
|
||||
pub fn new() -> Self {
|
||||
let mut rt = Runtime {
|
||||
next_type_id: 0,
|
||||
types_by_name: HashMap::new(),
|
||||
types_by_id: HashMap::new(),
|
||||
};
|
||||
rt.make_type("null".to_owned(), |t|t);
|
||||
rt.make_type("int".to_owned(), |t|t);
|
||||
rt.make_type("long".to_owned(), |t|t);
|
||||
rt.make_type("mega".to_owned(), |t|t);
|
||||
rt.make_type("func".to_owned(), |t|t);
|
||||
rt.make_type("array".to_owned(), |t|t);
|
||||
rt.make_type("str".to_owned(), |t|t);
|
||||
rt
|
||||
}
|
||||
|
||||
pub fn get_type_by_name(&self, name: String) -> Option<Arc<Type>> {
|
||||
self.types_by_name.get(&name).cloned()
|
||||
}
|
||||
|
||||
pub fn get_type_by_id(&self, id: u32) -> Option<Arc<Type>> {
|
||||
self.types_by_id.get(&id).cloned()
|
||||
}
|
||||
|
||||
pub fn make_type(&mut self, name: String, op: impl FnOnce(Type) -> Type) -> Arc<Type> {
|
||||
let t = Arc::new(op(Type {
|
||||
name: name.clone(),
|
||||
id: (self.next_type_id, self.next_type_id += 1).0,
|
||||
functions: HashMap::new(),
|
||||
properties: Vec::new(),
|
||||
}));
|
||||
self.types_by_id.insert(self.next_type_id - 1, t.clone());
|
||||
self.types_by_name.insert(name, t.clone());
|
||||
t
|
||||
}
|
||||
|
||||
pub fn set(self) {
|
||||
RUNTIME.with(move |x| *x.borrow_mut() = Some(self));
|
||||
}
|
||||
|
||||
pub fn reset() {
|
||||
RUNTIME.with(|x| *x.borrow_mut() = None);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct FrameInfo {
|
||||
file: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Frame {
|
||||
parent: Option<Arc<Frame>>,
|
||||
object_stack: Vec<Arc<Mutex<Object>>>,
|
||||
variables: HashMap<String, Arc<Mutex<Object>>>,
|
||||
origin: FrameInfo,
|
||||
}
|
||||
|
||||
impl Display for Frame {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("Stack: \n")?;
|
||||
for object in &self.object_stack {
|
||||
f.write_str(" ")?;
|
||||
object.lock().unwrap().fmt(f)?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
f.write_str("\nVars: \n")?;
|
||||
for (name, object) in &self.variables {
|
||||
f.write_str(" ")?;
|
||||
f.write_str(&name)?;
|
||||
f.write_str(": ")?;
|
||||
object.lock().unwrap().fmt(f)?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
fn root() -> Self {
|
||||
Frame {
|
||||
parent: None,
|
||||
object_stack: Vec::new(),
|
||||
variables: HashMap::new(),
|
||||
origin: FrameInfo {
|
||||
file: "RUNTIME".to_owned(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(parent: Arc<Frame>, origin: FrameInfo) -> Self {
|
||||
Frame {
|
||||
parent: Some(parent),
|
||||
object_stack: Vec::new(),
|
||||
variables: HashMap::new(),
|
||||
origin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Stack {
|
||||
frames: Vec<Frame>,
|
||||
}
|
||||
|
||||
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.origin.file)?;
|
||||
f.write_str("\n\n")?;
|
||||
frame.fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
pub fn new() -> Self {
|
||||
Stack {
|
||||
frames: vec![Frame::root()],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, obj: Arc<Mutex<Object>>) {
|
||||
self.frames
|
||||
.last_mut()
|
||||
.expect("program end reached but stack still being used")
|
||||
.object_stack
|
||||
.push(obj)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Keyword {
|
||||
DUMP,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum Constant {
|
||||
Int(i32),
|
||||
Long(i64),
|
||||
Mega(i128),
|
||||
Str(String),
|
||||
Func(Func),
|
||||
Null,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Word {
|
||||
Key(Keyword),
|
||||
Const(Constant),
|
||||
GetPointer(String),
|
||||
ObjGetPointer(String),
|
||||
Call(String),
|
||||
ObjCall(String),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Words {
|
||||
words: Vec<Word>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum FuncImpl {
|
||||
NATIVE(fn(&mut Stack)),
|
||||
SPL(Words),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Func {
|
||||
arg_count: u32,
|
||||
to_call: FuncImpl,
|
||||
}
|
||||
|
||||
impl Debug for Func {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&self.arg_count.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Type {
|
||||
name: String,
|
||||
id: u32,
|
||||
functions: HashMap<String, Func>,
|
||||
properties: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Object {
|
||||
kind: Arc<Type>,
|
||||
property_map: HashMap<String, Arc<Mutex<Object>>>,
|
||||
native: Constant,
|
||||
}
|
||||
|
||||
impl Display for Object {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&self.kind.name)?;
|
||||
f.write_str("(")?;
|
||||
self.native.fmt(f)?;
|
||||
f.write_str(") { ")?;
|
||||
for (k, v) in &self.property_map {
|
||||
f.write_str(&k)?;
|
||||
f.write_str(": ")?;
|
||||
v.fmt(f)?;
|
||||
}
|
||||
f.write_str(" }")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Object {
|
||||
pub fn new(kind: Arc<Type>, native: Constant) -> Object {
|
||||
Object {
|
||||
property_map: {
|
||||
let mut map = HashMap::new();
|
||||
for property in &kind.properties {
|
||||
map.insert(property.clone(), Constant::Null.spl());
|
||||
}
|
||||
map
|
||||
},
|
||||
kind,
|
||||
native,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Constant> for Object {
|
||||
fn from(value: Constant) -> Self {
|
||||
Object::new(
|
||||
RUNTIME.with(|x| {
|
||||
let x = x.borrow();
|
||||
let x = x.as_ref().unwrap();
|
||||
match value {
|
||||
Constant::Null => x.get_type_by_id(0),
|
||||
Constant::Int(_) => x.get_type_by_id(1),
|
||||
Constant::Long(_) => x.get_type_by_id(2),
|
||||
Constant::Mega(_) => x.get_type_by_id(3),
|
||||
Constant::Func(_) => x.get_type_by_id(4),
|
||||
// array is 5
|
||||
Constant::Str(_) => x.get_type_by_id(6),
|
||||
}
|
||||
.expect("runtime uninitialized: default types not set.")
|
||||
}),
|
||||
value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
trait SPL {
|
||||
fn spl(self) -> Arc<Mutex<Object>>;
|
||||
}
|
||||
|
||||
impl<T> SPL for T
|
||||
where
|
||||
T: Into<Object>,
|
||||
{
|
||||
fn spl(self) -> Arc<Mutex<Object>> {
|
||||
Arc::new(Mutex::new(self.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Words {
|
||||
pub fn exec(&self, stack: &mut Stack) {
|
||||
for word in &self.words {
|
||||
match word {
|
||||
Word::Key(x) => match x {
|
||||
Keyword::DUMP => println!("{}", stack),
|
||||
},
|
||||
Word::Const(x) => stack.push(x.clone().spl()),
|
||||
Word::GetPointer(_) => todo!(),
|
||||
Word::ObjGetPointer(_) => todo!(),
|
||||
Word::Call(_) => todo!(),
|
||||
Word::ObjCall(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let rt = Runtime::new();
|
||||
rt.set();
|
||||
Words {
|
||||
words: vec![
|
||||
Word::Const(Constant::Str("Hello, World".to_owned())),
|
||||
Word::Key(Keyword::DUMP),
|
||||
],
|
||||
}
|
||||
.exec(&mut Stack::new());
|
||||
Runtime::reset();
|
||||
}
|
Loading…
Add table
Reference in a new issue