lexer, some new keywords, full impl
This commit is contained in:
parent
34dd8ca486
commit
7d7782df0c
7 changed files with 869 additions and 296 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -2,6 +2,15 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "readformat"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b03f7fbd470aa8b3ad163c85cce8bccfc11cc9c44ef12da0a4eddd98bd307352"
|
||||
|
||||
[[package]]
|
||||
name = "spl"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"readformat",
|
||||
]
|
||||
|
|
|
@ -6,3 +6,4 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
readformat = "0.1"
|
||||
|
|
197
src/lexer.rs
Normal file
197
src/lexer.rs
Normal file
|
@ -0,0 +1,197 @@
|
|||
use crate::runtime::*;
|
||||
use readformat::*;
|
||||
|
||||
pub fn lex(input: String, filename: String) -> Words {
|
||||
let mut str_words = Vec::new();
|
||||
for line in input.split('\n') {
|
||||
str_words.append(&mut parse_line(line));
|
||||
}
|
||||
read_block(&str_words[..], false, &FrameInfo { file: filename }).1
|
||||
}
|
||||
|
||||
fn read_block(str_words: &[String], isfn: bool, origin: &FrameInfo) -> (Option<u32>, Words, usize) {
|
||||
let mut rem = None;
|
||||
if str_words[0] == "{" && isfn {
|
||||
let mut r = 0_u32;
|
||||
while str_words[r as usize + 1] != "|" {
|
||||
r += 1;
|
||||
}
|
||||
rem = Some(r);
|
||||
}
|
||||
let mut words = Vec::new();
|
||||
let mut i = 0;
|
||||
while i < str_words.len() {
|
||||
let word = str_words[i].to_owned();
|
||||
match word.as_str() {
|
||||
"def" => {
|
||||
words.push(Word::Key(Keyword::Def(str_words[i + 1].to_owned())));
|
||||
i += 1;
|
||||
}
|
||||
"func" => {
|
||||
if let Some(dat) = readf("func\0{}\0{", str_words[i..=i + 2].join("\0").as_str()) {
|
||||
let block = read_block(&str_words[i + 2..], true, &origin);
|
||||
i += 2 + block.2;
|
||||
words.push(Word::Key(Keyword::Func(
|
||||
dat[0].to_owned(),
|
||||
block.0.expect("LEXERR: Expected `{ <type> <...> |`."),
|
||||
block.1,
|
||||
)));
|
||||
}
|
||||
}
|
||||
"{" => {
|
||||
let block = read_block(&str_words[i..], true, &origin);
|
||||
i += block.2;
|
||||
words.push(Word::Const(Constant::Func(AFunc::new(Func {
|
||||
ret_count: block.0.expect("LEXERR: Expected `{ <type> <...> |`."),
|
||||
to_call: FuncImpl::SPL(block.1),
|
||||
origin: origin.to_owned(),
|
||||
}))))
|
||||
}
|
||||
"construct" => {
|
||||
let name = (&str_words[i + 1]).to_owned();
|
||||
assert_eq!(
|
||||
str_words[i + 2],
|
||||
"{",
|
||||
"LEXERR: Expected `construct <name> {{`, got `construct <name>`"
|
||||
);
|
||||
let mut fields = Vec::new();
|
||||
i += 2;
|
||||
while str_words[i] != ";" && str_words[i] != "}" {
|
||||
fields.push((&str_words[i]).to_owned());
|
||||
i += 1;
|
||||
}
|
||||
let mut methods = Vec::new();
|
||||
if str_words[i] == ";" {
|
||||
i += 1;
|
||||
while str_words[i] != "}" {
|
||||
let name = (&str_words[i]).to_owned();
|
||||
let block = read_block(&str_words[i + 1..], true, origin);
|
||||
i += 1 + block.2;
|
||||
methods.push((
|
||||
name,
|
||||
(
|
||||
block.0.expect("LEXERR: Expected `{ <type> <...> |`."),
|
||||
block.1,
|
||||
),
|
||||
));
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
words.push(Word::Key(Keyword::Construct(name, fields, methods)));
|
||||
}
|
||||
"include" => {
|
||||
if let Some(x) = readf(
|
||||
"include\0{}\0in\0{}",
|
||||
str_words[i..=i + 4].join("\0").as_str(),
|
||||
) {
|
||||
words.push(Word::Key(Keyword::Include(
|
||||
x[0].to_owned(),
|
||||
x[1].to_owned(),
|
||||
)))
|
||||
} else {
|
||||
panic!("LEXERR: Expected `include <typeA> in <typeB>`.");
|
||||
}
|
||||
}
|
||||
"while" => {
|
||||
let cond = read_block(&str_words[i + 1..], false, origin);
|
||||
i += 1 + cond.2;
|
||||
let blk = read_block(&str_words[i + 1..], false, origin);
|
||||
i += 1 + cond.2;
|
||||
words.push(Word::Key(Keyword::While(cond.1, blk.1)));
|
||||
}
|
||||
"if" => {
|
||||
let cond = read_block(&str_words[i + 1..], false, origin);
|
||||
i += 1 + cond.2;
|
||||
let blk = read_block(&str_words[i + 1..], false, origin);
|
||||
i += 1 + cond.2;
|
||||
words.push(Word::Key(Keyword::If(cond.1, blk.1)));
|
||||
}
|
||||
"with" => {
|
||||
let mut vars = Vec::new();
|
||||
i += 1;
|
||||
while &str_words[i] != ";" {
|
||||
vars.push((&str_words[i]).to_owned());
|
||||
i += 1;
|
||||
}
|
||||
words.push(Word::Key(Keyword::With(vars)));
|
||||
}
|
||||
"}" => {
|
||||
break;
|
||||
}
|
||||
mut x => {
|
||||
let mut ra = 0;
|
||||
while x.starts_with("&") {
|
||||
ra += 1;
|
||||
x = &x[1..];
|
||||
}
|
||||
if x.ends_with(";") {
|
||||
words.push(Word::Call(x[..x.len() - 1].to_owned(), true, ra));
|
||||
} else {
|
||||
words.push(Word::Call(x.to_owned(), false, ra));
|
||||
}
|
||||
for mut word in x.split(":").skip(1) {
|
||||
let mut ra = 0;
|
||||
while word.starts_with("&") {
|
||||
ra += 1;
|
||||
word = &word[1..];
|
||||
}
|
||||
if word.ends_with(";") {
|
||||
words.push(Word::ObjCall(word[..word.len() - 1].to_owned(), true, ra));
|
||||
} else {
|
||||
words.push(Word::ObjCall(word.to_owned(), false, ra));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
(rem, Words { words }, i)
|
||||
}
|
||||
|
||||
fn parse_line(line: &str) -> Vec<String> {
|
||||
let mut words = Vec::new();
|
||||
let mut in_string = false;
|
||||
let mut escaping = false;
|
||||
let mut s = String::new();
|
||||
for c in line.chars() {
|
||||
if in_string {
|
||||
if escaping {
|
||||
if c == '\\' {
|
||||
s += "\\";
|
||||
continue;
|
||||
}
|
||||
if c == 'n' {
|
||||
s += "\n";
|
||||
continue;
|
||||
}
|
||||
if c == 'r' {
|
||||
s += "\r";
|
||||
continue;
|
||||
}
|
||||
escaping = false;
|
||||
} else if c == '"' {
|
||||
in_string = false;
|
||||
escaping = false;
|
||||
continue;
|
||||
}
|
||||
if c == '\\' {
|
||||
escaping = true;
|
||||
}
|
||||
} else {
|
||||
if c == '"' {
|
||||
in_string = true;
|
||||
continue;
|
||||
}
|
||||
if c == ' ' {
|
||||
if s == "" {
|
||||
continue;
|
||||
}
|
||||
words.push(s);
|
||||
s = String::new();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
s += String::from(c).as_str();
|
||||
}
|
||||
words
|
||||
}
|
3
src/lib.rs
Normal file
3
src/lib.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub mod lexer;
|
||||
pub mod mutex;
|
||||
pub mod runtime;
|
332
src/main.rs
332
src/main.rs
|
@ -1,313 +1,53 @@
|
|||
use spl::runtime::*;
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
fmt::{Display, Formatter, Pointer, Debug},
|
||||
sync::{Arc, Mutex},
|
||||
io::{stdout, Write},
|
||||
sync::Arc,
|
||||
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")?;
|
||||
fn main() {
|
||||
let rt = Runtime::new();
|
||||
let mut stack = Stack::new();
|
||||
fn print(stack: &mut Stack) {
|
||||
let s = stack.pop();
|
||||
let s = s.lock();
|
||||
if let Constant::Str(ref s) = s.native {
|
||||
print!("{s}");
|
||||
stdout().lock().flush().unwrap();
|
||||
}
|
||||
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(),
|
||||
stack.define_func(
|
||||
"print".to_owned(),
|
||||
Arc::new(Func {
|
||||
ret_count: 0,
|
||||
to_call: FuncImpl::Native(print),
|
||||
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::Key(Keyword::Func(
|
||||
"println".to_owned(),
|
||||
0,
|
||||
Words {
|
||||
words: vec![
|
||||
Word::Call("print".to_owned(), true, 0),
|
||||
Word::Const(Constant::Str("\n".to_owned())),
|
||||
Word::Call("print".to_owned(), true, 0),
|
||||
],
|
||||
},
|
||||
)),
|
||||
Word::Key(Keyword::Def("helloworld".to_owned())),
|
||||
Word::Const(Constant::Str("Hello, World".to_owned())),
|
||||
Word::Key(Keyword::DUMP),
|
||||
Word::Call("=helloworld".to_owned(), false, 0),
|
||||
Word::Call("helloworld".to_owned(), false, 0),
|
||||
Word::Call("println".to_owned(), true, 0),
|
||||
],
|
||||
}
|
||||
.exec(&mut Stack::new());
|
||||
.exec(&mut stack);
|
||||
Runtime::reset();
|
||||
}
|
||||
|
|
22
src/mutex.rs
Normal file
22
src/mutex.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
use std::sync::{Mutex, MutexGuard};
|
||||
|
||||
pub struct Mut<T>(Mutex<T>);
|
||||
|
||||
impl<T> Mut<T> {
|
||||
pub fn new(obj: T) -> Mut<T> {
|
||||
Mut(Mutex::new(obj))
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> MutexGuard<T> {
|
||||
self.0.lock().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Mut<T>
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self(Mutex::new(self.0.lock().unwrap().clone()))
|
||||
}
|
||||
}
|
601
src/runtime.rs
Normal file
601
src/runtime.rs
Normal file
|
@ -0,0 +1,601 @@
|
|||
use crate::mutex::*;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
fmt::{Debug, Display, Formatter, Pointer},
|
||||
sync::Arc,
|
||||
vec,
|
||||
};
|
||||
|
||||
pub type AMObject = Arc<Mut<Object>>;
|
||||
pub type AMType = Arc<Mut<Type>>;
|
||||
pub type AFunc = Arc<Func>;
|
||||
|
||||
thread_local! {
|
||||
static RUNTIME: RefCell<Option<Runtime>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Runtime {
|
||||
next_type_id: u32,
|
||||
types_by_name: HashMap<String, AMType>,
|
||||
types_by_id: HashMap<u32, AMType>,
|
||||
}
|
||||
|
||||
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<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 make_type(&mut self, name: String, op: impl FnOnce(Type) -> Type) -> AMType {
|
||||
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(),
|
||||
})));
|
||||
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)]
|
||||
pub struct FrameInfo {
|
||||
pub file: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Frame {
|
||||
parent: Option<Arc<Frame>>,
|
||||
pub variables: Mut<HashMap<String, AMObject>>,
|
||||
pub functions: Mut<HashMap<String, AFunc>>,
|
||||
pub origin: FrameInfo,
|
||||
}
|
||||
|
||||
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().iter() {
|
||||
f.write_str(" ")?;
|
||||
f.write_str(&name)?;
|
||||
f.write_str(": ")?;
|
||||
object.lock().fmt(f)?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
fn root() -> Self {
|
||||
Frame {
|
||||
parent: None,
|
||||
variables: Mut::new(HashMap::new()),
|
||||
functions: Mut::new(HashMap::new()),
|
||||
origin: FrameInfo {
|
||||
file: "RUNTIME".to_owned(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(parent: Arc<Frame>, origin: FrameInfo) -> Self {
|
||||
Frame {
|
||||
parent: Some(parent),
|
||||
variables: Mut::new(HashMap::new()),
|
||||
functions: Mut::new(HashMap::new()),
|
||||
origin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Stack {
|
||||
frames: Vec<Arc<Frame>>,
|
||||
object_stack: Vec<AMObject>,
|
||||
}
|
||||
|
||||
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.as_ref().fmt(f)?;
|
||||
}
|
||||
f.write_str("Stack: \n")?;
|
||||
for object in &self.object_stack {
|
||||
f.write_str(" ")?;
|
||||
object.lock().fmt(f)?;
|
||||
f.write_str("\n")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
pub fn new() -> Self {
|
||||
Stack {
|
||||
frames: vec![Arc::new(Frame::root())],
|
||||
object_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn define_func(&mut self, name: String, func: AFunc) {
|
||||
self.frames
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.functions
|
||||
.lock()
|
||||
.insert(name, func);
|
||||
}
|
||||
|
||||
pub fn call(&mut self, func: &AFunc) {
|
||||
self.frames.push(Arc::new(Frame::new(
|
||||
self.frames.last().unwrap().clone(),
|
||||
func.origin.clone(),
|
||||
)));
|
||||
func.to_call.call(self);
|
||||
self.frames.pop().unwrap();
|
||||
}
|
||||
|
||||
pub fn get_func(&self, name: String) -> AFunc {
|
||||
let mut frame = self.frames.last().unwrap();
|
||||
loop {
|
||||
let functions = &frame.functions;
|
||||
if let Some(x) = functions.lock().get(&name) {
|
||||
return x.clone();
|
||||
}
|
||||
if let Some(ref x) = frame.parent {
|
||||
frame = x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn define_var(&mut self, name: String) {
|
||||
let frame = self.frames.last_mut().unwrap().clone();
|
||||
let tmpname = name.clone();
|
||||
frame.functions.lock().insert(
|
||||
name.clone(),
|
||||
Arc::new(Func {
|
||||
ret_count: 1,
|
||||
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
|
||||
stack.push(stack.get_var(tmpname.clone()))
|
||||
}))),
|
||||
origin: frame.origin.clone(),
|
||||
}),
|
||||
);
|
||||
let tmpname = name.clone();
|
||||
frame.functions.lock().insert(
|
||||
"=".to_owned() + &name,
|
||||
Arc::new(Func {
|
||||
ret_count: 0,
|
||||
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
|
||||
let v = stack.pop();
|
||||
stack.set_var(tmpname.clone(), v);
|
||||
}))),
|
||||
origin: frame.origin.clone(),
|
||||
}),
|
||||
);
|
||||
frame.variables.lock().insert(name, Constant::Null.spl());
|
||||
}
|
||||
|
||||
pub fn set_var(&self, name: String, obj: AMObject) {
|
||||
let mut frame = self.frames.last().unwrap();
|
||||
loop {
|
||||
if let Some(x) = frame.variables.lock().get_mut(&name) {
|
||||
*x = obj;
|
||||
break;
|
||||
}
|
||||
if let Some(ref x) = frame.parent {
|
||||
frame = x;
|
||||
} else {
|
||||
panic!("undefined var")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_var(&self, name: String) -> AMObject {
|
||||
let mut frame = self.frames.last().unwrap();
|
||||
loop {
|
||||
if let Some(x) = frame.variables.lock().get(&name) {
|
||||
return x.clone();
|
||||
}
|
||||
if let Some(ref x) = frame.parent {
|
||||
frame = x;
|
||||
} else {
|
||||
panic!("undefined var")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, obj: AMObject) {
|
||||
self.object_stack.push(obj)
|
||||
}
|
||||
|
||||
pub fn peek(&mut self) -> AMObject {
|
||||
self.object_stack
|
||||
.last()
|
||||
.cloned()
|
||||
.unwrap_or(Constant::Null.spl())
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> AMObject {
|
||||
self.object_stack.pop().unwrap_or(Constant::Null.spl())
|
||||
}
|
||||
|
||||
pub fn get_origin(&self) -> FrameInfo {
|
||||
self.frames.last().unwrap().origin.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Keyword {
|
||||
/// <none>
|
||||
///
|
||||
/// Dumps stack. Not available as actual keyword, therefore only obtainable through AST
|
||||
/// manipulation or modding. When using dyn variant, it must be enabled in the main function.
|
||||
/// equivalent to dyn-__dump
|
||||
/// example: func main { int | dyn-__dump-check "Hello, world!" dyn-__dump 0 }
|
||||
Dump,
|
||||
/// def <name>
|
||||
///
|
||||
/// Defines a variable.
|
||||
/// equivalent to <name> dyn-def
|
||||
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
|
||||
/// "<name>" dyn-construct; "<name>" "<field>" dyn-def-field { <rem> | <words> } "<name>"
|
||||
/// "<fn-name>" dyn-def-method
|
||||
Construct(String, Vec<String>, Vec<(String, (u32, Words))>),
|
||||
/// include <typeA> in <typeB>
|
||||
///
|
||||
/// Adds <typeA> as a parent type of <typeB>.
|
||||
/// equivalent to "<typeA>" "<typeB>" dyn-include
|
||||
Include(String, String),
|
||||
/// while <wordsA> { <wordsB> }
|
||||
///
|
||||
/// 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),
|
||||
/// if <wordsA> { <wordsB> }
|
||||
///
|
||||
/// If wordsA result in a truthy value being on the top of the stack, execute wordsB.
|
||||
/// equivalent to { int | <wordsA> } { | <wordsB> } dyn-if
|
||||
If(Words, Words),
|
||||
/// 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>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Constant {
|
||||
Null,
|
||||
Int(i32),
|
||||
Long(i64),
|
||||
Mega(i128),
|
||||
Func(AFunc),
|
||||
Str(String),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Word {
|
||||
Key(Keyword),
|
||||
Const(Constant),
|
||||
Call(String, bool, u32),
|
||||
ObjCall(String, bool, u32),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Words {
|
||||
pub words: Vec<Word>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum FuncImpl {
|
||||
Native(fn(&mut Stack)),
|
||||
NativeDyn(Arc<Box<dyn Fn(&mut Stack)>>),
|
||||
SPL(Words),
|
||||
}
|
||||
|
||||
impl FuncImpl {
|
||||
pub fn call(&self, stack: &mut Stack) {
|
||||
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: FrameInfo,
|
||||
}
|
||||
|
||||
impl Debug for Func {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&self.ret_count.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Type {
|
||||
name: String,
|
||||
id: u32,
|
||||
pub parents: Vec<AMType>,
|
||||
pub functions: HashMap<String, AFunc>,
|
||||
pub properties: Vec<String>,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
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() {
|
||||
if let Some(x) = t.lock().functions.get(&name) {
|
||||
return Some(x.clone());
|
||||
}
|
||||
q.append(&mut VecDeque::from(t.lock().parents.clone()));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Object {
|
||||
pub kind: AMType,
|
||||
pub property_map: HashMap<String, AMObject>,
|
||||
pub native: Constant,
|
||||
}
|
||||
|
||||
impl Display for Object {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&self.kind.lock().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: AMType, native: Constant) -> Object {
|
||||
Object {
|
||||
property_map: {
|
||||
let mut map = HashMap::new();
|
||||
for property in &kind.lock().properties {
|
||||
map.insert(property.clone(), Constant::Null.spl());
|
||||
}
|
||||
map
|
||||
},
|
||||
kind,
|
||||
native,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_truthy(&self) -> bool {
|
||||
match &self.native {
|
||||
Constant::Null => false,
|
||||
Constant::Int(x) => x > &0,
|
||||
Constant::Long(x) => x > &0,
|
||||
Constant::Mega(x) => x > &0,
|
||||
Constant::Func(_) => true,
|
||||
Constant::Str(x) => x == "",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Words {
|
||||
pub fn exec(&self, stack: &mut Stack) {
|
||||
for word in self.words.clone() {
|
||||
match word {
|
||||
Word::Key(x) => match x {
|
||||
Keyword::Dump => println!("{}", stack),
|
||||
Keyword::Def(x) => stack.define_var(x),
|
||||
Keyword::Func(name, rem, words) => stack.define_func(
|
||||
name,
|
||||
Arc::new(Func {
|
||||
ret_count: rem,
|
||||
to_call: FuncImpl::SPL(words),
|
||||
origin: stack.get_origin(),
|
||||
}),
|
||||
),
|
||||
Keyword::Construct(name, fields, methods) => {
|
||||
let origin = stack.get_origin();
|
||||
RUNTIME.with(move |rt| {
|
||||
rt.borrow_mut()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.make_type(name, move |mut t| {
|
||||
t.properties = fields;
|
||||
t.functions.extend(methods.into_iter().map(|(k, v)| {
|
||||
(
|
||||
k,
|
||||
Arc::new(Func {
|
||||
ret_count: v.0,
|
||||
to_call: FuncImpl::SPL(v.1),
|
||||
origin: origin.clone(),
|
||||
}),
|
||||
)
|
||||
}));
|
||||
t
|
||||
});
|
||||
})
|
||||
}
|
||||
Keyword::Include(ta, tb) => {
|
||||
RUNTIME.with(move |rt| {
|
||||
let mut rt = rt.borrow_mut();
|
||||
let rt = rt.as_mut().unwrap();
|
||||
// TODO: Handle properly
|
||||
rt.get_type_by_name(tb)
|
||||
.unwrap()
|
||||
.lock()
|
||||
.parents
|
||||
.push(rt.get_type_by_name(ta).unwrap())
|
||||
});
|
||||
}
|
||||
Keyword::While(cond, blk) => loop {
|
||||
cond.exec(stack);
|
||||
if !stack.pop().lock().is_truthy() {
|
||||
break;
|
||||
}
|
||||
blk.exec(stack);
|
||||
},
|
||||
Keyword::If(cond, blk) => {
|
||||
cond.exec(stack);
|
||||
if stack.pop().lock().is_truthy() {
|
||||
blk.exec(stack);
|
||||
}
|
||||
}
|
||||
Keyword::With(vars) => {
|
||||
for var in vars.into_iter().rev() {
|
||||
stack.define_var(var.clone());
|
||||
let obj = stack.pop();
|
||||
stack.set_var(var, obj);
|
||||
}
|
||||
}
|
||||
},
|
||||
Word::Const(x) => stack.push(x.clone().spl()),
|
||||
Word::Call(x, rem, ra) => {
|
||||
let f = stack.get_func(x);
|
||||
if ra != 0 {
|
||||
let mut f = Constant::Func(f);
|
||||
for _ in 1..ra {
|
||||
let ftmp = f;
|
||||
f = Constant::Func(AFunc::new(Func {
|
||||
ret_count: 1,
|
||||
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
|
||||
stack.push(ftmp.clone().spl());
|
||||
}))),
|
||||
origin: stack.get_origin(),
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
stack.call(&f);
|
||||
if rem {
|
||||
for _ in 0..f.ret_count {
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Word::ObjCall(x, rem, ra) => {
|
||||
let o = stack.peek();
|
||||
let o = o.lock();
|
||||
// TODO: raise error if not found
|
||||
let f = o.kind.lock();
|
||||
let f = f.functions.get(&x).unwrap();
|
||||
if ra != 0 {
|
||||
let mut f = Constant::Func(f.clone());
|
||||
for _ in 1..ra {
|
||||
let ftmp = f;
|
||||
f = Constant::Func(AFunc::new(Func {
|
||||
ret_count: 1,
|
||||
to_call: FuncImpl::NativeDyn(Arc::new(Box::new(move |stack| {
|
||||
stack.push(ftmp.clone().spl());
|
||||
}))),
|
||||
origin: stack.get_origin(),
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
stack.call(f);
|
||||
if rem {
|
||||
for _ in 0..f.ret_count {
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue