init
This commit is contained in:
commit
5c1cff92c6
15 changed files with 844 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
2
Cargo.toml
Normal file
2
Cargo.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[workspace]
|
||||||
|
members = ["lorgn_lang", "lorgn_runtime"]
|
9
README.md
Normal file
9
README.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# LORGN
|
||||||
|
|
||||||
|
Logic Organizer for Redaction in Graphical Notations
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
LORGN is a general purpose scripting language optimized for graphical programming.
|
9
lorgn_lang/Cargo.toml
Normal file
9
lorgn_lang/Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "lorgn_lang"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = { version = "1.0", features = ["derive"]}
|
74
lorgn_lang/src/ast.rs
Normal file
74
lorgn_lang/src/ast.rs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Path {
|
||||||
|
pub module: Name,
|
||||||
|
pub item: Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Name(pub String);
|
||||||
|
|
||||||
|
impl From<String> for Name {
|
||||||
|
fn from(input: String) -> Self {
|
||||||
|
Self(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Name> for String {
|
||||||
|
fn from(input: Name) -> Self {
|
||||||
|
let Name(result) = input;
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'s> From<&'s str> for Name {
|
||||||
|
fn from(input: &'s str) -> Self {
|
||||||
|
input.to_string().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Import {
|
||||||
|
pub module_name: Name,
|
||||||
|
pub items: Vec<Name>,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Export {
|
||||||
|
pub items: Vec<Name>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use expression::*;
|
||||||
|
mod expression;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct FnDef {
|
||||||
|
pub name: Name,
|
||||||
|
pub parameters: Vec<Name>,
|
||||||
|
pub expressions: Block,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum TopLevel {
|
||||||
|
Export(Export),
|
||||||
|
FnDef(FnDef),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TopLevel {
|
||||||
|
pub fn as_fndef(&self) -> Option<&FnDef> {
|
||||||
|
match self {
|
||||||
|
Self::FnDef(result) => Some(result),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn into_fndef(self) -> Option<FnDef> {
|
||||||
|
match self {
|
||||||
|
Self::FnDef(result) => Some(result),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Module {
|
||||||
|
pub items: Vec<TopLevel>,
|
||||||
|
}
|
135
lorgn_lang/src/ast/expression.rs
Normal file
135
lorgn_lang/src/ast/expression.rs
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::{Name, Path};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Block {
|
||||||
|
pub expressions: Vec<BExpr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Assignment {
|
||||||
|
pub variable_name: Name,
|
||||||
|
pub value: BExpr,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Invoke {
|
||||||
|
pub variable_name: Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum Litteral {
|
||||||
|
String(String),
|
||||||
|
Integer(i32),
|
||||||
|
Float(f32),
|
||||||
|
Bool(bool),
|
||||||
|
List(Vec<BExpr>),
|
||||||
|
Map(Vec<(Name, BExpr)>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for Litteral {
|
||||||
|
fn from(input: String) -> Self {
|
||||||
|
Self::String(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Litteral {
|
||||||
|
fn from(input: &str) -> Self {
|
||||||
|
Self::String(input.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i32> for Litteral {
|
||||||
|
fn from(input: i32) -> Self {
|
||||||
|
Self::Integer(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f32> for Litteral {
|
||||||
|
fn from(input: f32) -> Self {
|
||||||
|
Self::Float(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for Litteral {
|
||||||
|
fn from(bool: bool) -> Self {
|
||||||
|
Self::Bool(bool)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Vec<T>> for Litteral
|
||||||
|
where
|
||||||
|
T: Into<Litteral>,
|
||||||
|
{
|
||||||
|
fn from(input: Vec<T>) -> Self {
|
||||||
|
let list = input
|
||||||
|
.into_iter()
|
||||||
|
.map(|e| Box::new(Expr::Litteral(e.into())))
|
||||||
|
.collect();
|
||||||
|
Self::List(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S, T> From<Vec<(S, T)>> for Litteral
|
||||||
|
where
|
||||||
|
S: ToString,
|
||||||
|
T: Into<Litteral>,
|
||||||
|
{
|
||||||
|
fn from(input: Vec<(S, T)>) -> Self {
|
||||||
|
let list = input
|
||||||
|
.into_iter()
|
||||||
|
.map(|(n, e)| (n.to_string().into(), Box::new(Expr::Litteral(e.into()))))
|
||||||
|
.collect();
|
||||||
|
Self::Map(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct FnCall {
|
||||||
|
pub fn_path: Path,
|
||||||
|
pub arguments: Vec<BExpr>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Condition {
|
||||||
|
pub condition: BExpr,
|
||||||
|
pub true_case: BExpr,
|
||||||
|
pub false_case: BExpr,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Loop {
|
||||||
|
pub body: BExpr,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Return {
|
||||||
|
pub expression: BExpr,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct Break {
|
||||||
|
pub expression: BExpr,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub enum Expr {
|
||||||
|
Block(Block),
|
||||||
|
Assignment(Assignment),
|
||||||
|
Invoke(Invoke),
|
||||||
|
Litteral(Litteral),
|
||||||
|
FnCall(FnCall),
|
||||||
|
Condition(Condition),
|
||||||
|
Loop(Loop),
|
||||||
|
Return(Return),
|
||||||
|
Break(Break),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expr {
|
||||||
|
pub fn boxed(self) -> BExpr {
|
||||||
|
Box::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type BExpr = Box<Expr>;
|
2
lorgn_lang/src/lib.rs
Normal file
2
lorgn_lang/src/lib.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod ast;
|
||||||
|
pub mod typing;
|
6
lorgn_lang/src/typing.rs
Normal file
6
lorgn_lang/src/typing.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
pub enum Primitive {
|
||||||
|
String(String),
|
||||||
|
Integer(i32),
|
||||||
|
Float(f32),
|
||||||
|
Bool(bool),
|
||||||
|
}
|
12
lorgn_runtime/Cargo.toml
Normal file
12
lorgn_runtime/Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "lorgn_runtime"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
lorgn_lang = { path = "../lorgn_lang" }
|
||||||
|
gc = "0.4"
|
||||||
|
gc_derive = "0.4"
|
||||||
|
ron = "0.8"
|
91
lorgn_runtime/src/function.rs
Normal file
91
lorgn_runtime/src/function.rs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
use lorgn_lang::ast::{FnDef, Name, Path};
|
||||||
|
|
||||||
|
use crate::{runtime::Context, Value};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Imported {
|
||||||
|
_path: Path,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Native {
|
||||||
|
arg_count: usize,
|
||||||
|
handler: Box<dyn FnMut(Vec<Value>) -> Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Native {
|
||||||
|
pub fn run(&mut self, args: Vec<Value>) -> Value {
|
||||||
|
if self.arg_count != args.len() {
|
||||||
|
panic!("too few args")
|
||||||
|
}
|
||||||
|
(self.handler)(args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Native {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("<Native>").finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum FnImpl {
|
||||||
|
Imported(Imported),
|
||||||
|
Defined(FnDef),
|
||||||
|
Native(Native),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Function {
|
||||||
|
name: Name,
|
||||||
|
implem: FnImpl,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
pub fn new_defined(name: Name, definition: FnDef) -> Self {
|
||||||
|
let implem = FnImpl::Defined(definition);
|
||||||
|
Self { name, implem }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_imported(name: Name, module: Name) -> Self {
|
||||||
|
let implem = FnImpl::Imported(Imported {
|
||||||
|
_path: Path {
|
||||||
|
item: name.clone(),
|
||||||
|
module,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Self { name, implem }
|
||||||
|
}
|
||||||
|
pub fn new_native<const N: usize>(
|
||||||
|
name: Name,
|
||||||
|
mut caller: impl FnMut([Value; N]) -> Value + 'static,
|
||||||
|
) -> Self {
|
||||||
|
let handler = Box::new(move |values: Vec<Value>| {
|
||||||
|
let casted = values.try_into().unwrap();
|
||||||
|
(caller)(casted)
|
||||||
|
}) as Box<dyn FnMut(Vec<Value>) -> Value>;
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
implem: FnImpl::Native(Native {
|
||||||
|
arg_count: N,
|
||||||
|
handler,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call(&mut self, args: Vec<Value>, context: &mut Context) -> Value {
|
||||||
|
match &mut self.implem {
|
||||||
|
FnImpl::Defined(definition) => context.run_fun(definition, args),
|
||||||
|
FnImpl::Native(native) => native.run(args),
|
||||||
|
FnImpl::Imported(_imported) => {
|
||||||
|
todo!() // let mut res = context.find_function(&imported.path).unwrap();
|
||||||
|
// res.call(args, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &Name {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
}
|
31
lorgn_runtime/src/lib.rs
Normal file
31
lorgn_runtime/src/lib.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
mod module;
|
||||||
|
pub use module::Module;
|
||||||
|
|
||||||
|
mod function;
|
||||||
|
pub use function::Function;
|
||||||
|
|
||||||
|
mod runtime;
|
||||||
|
pub use runtime::Runtime;
|
||||||
|
|
||||||
|
mod value;
|
||||||
|
pub use value::Value;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_runtime() {
|
||||||
|
use lorgn_lang::ast::{Expr, FnCall, Path};
|
||||||
|
|
||||||
|
let mut runtime = Runtime::default();
|
||||||
|
let mut module = Module::new_empty("std");
|
||||||
|
module.push_native("print".into(), |[item]: [Value; 1]| {
|
||||||
|
println!("{item:?}");
|
||||||
|
Value::None
|
||||||
|
});
|
||||||
|
runtime.register(module);
|
||||||
|
runtime.evaluate(Expr::FnCall(FnCall {
|
||||||
|
fn_path: Path {
|
||||||
|
module: "std".into(),
|
||||||
|
item: "print".into(),
|
||||||
|
},
|
||||||
|
arguments: vec![Expr::Litteral("hello yorld".into()).boxed()],
|
||||||
|
}));
|
||||||
|
}
|
66
lorgn_runtime/src/module.rs
Normal file
66
lorgn_runtime/src/module.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
use std::{
|
||||||
|
cell::{RefCell, RefMut},
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
};
|
||||||
|
|
||||||
|
use lorgn_lang::ast::{self, Name, TopLevel};
|
||||||
|
|
||||||
|
use crate::{Function, Value};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Module {
|
||||||
|
name: Name,
|
||||||
|
functions: HashMap<Name, RefCell<Function>>,
|
||||||
|
_exports: HashSet<Name>, // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
pub fn new_empty(name: impl ToString) -> Self {
|
||||||
|
let name = name.to_string().into();
|
||||||
|
Self {
|
||||||
|
_exports: HashSet::new(),
|
||||||
|
functions: HashMap::new(),
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_ast(name: impl ToString, content: ast::Module) -> Self {
|
||||||
|
let name = name.to_string().into();
|
||||||
|
let mut functions = HashMap::new();
|
||||||
|
let mut exports = HashSet::new();
|
||||||
|
|
||||||
|
for item in content.items {
|
||||||
|
match item {
|
||||||
|
TopLevel::Export(export) => export.items.iter().for_each(|e| {
|
||||||
|
exports.insert(e.clone());
|
||||||
|
}),
|
||||||
|
TopLevel::FnDef(fndef) => {
|
||||||
|
let name = fndef.name.clone();
|
||||||
|
let fun = Function::new_defined(name.clone(), fndef);
|
||||||
|
functions.insert(name, RefCell::new(fun));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
functions,
|
||||||
|
_exports: exports,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn push_native<const N: usize>(
|
||||||
|
&mut self,
|
||||||
|
name: Name,
|
||||||
|
caller: impl FnMut([Value; N]) -> Value + 'static,
|
||||||
|
) {
|
||||||
|
let nat = Function::new_native(name.clone(), caller);
|
||||||
|
self.functions.insert(name, RefCell::new(nat));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &Name {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_function(&self, name: &Name) -> Option<RefMut<Function>> {
|
||||||
|
self.functions.get(name).map(|entry| entry.borrow_mut())
|
||||||
|
}
|
||||||
|
}
|
287
lorgn_runtime/src/runtime.rs
Normal file
287
lorgn_runtime/src/runtime.rs
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use lorgn_lang::ast::{Expr, Name};
|
||||||
|
|
||||||
|
use crate::{Module, Value};
|
||||||
|
|
||||||
|
pub struct Runtime {
|
||||||
|
modules: HashMap<Name, Module>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Runtime {
|
||||||
|
fn default() -> Self {
|
||||||
|
let modules = HashMap::new();
|
||||||
|
Self { modules }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Runtime {
|
||||||
|
pub fn register(&mut self, module: Module) {
|
||||||
|
self.modules.insert(module.name().clone(), module);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn evaluate(&mut self, expression: Expr) -> Value {
|
||||||
|
let mut context = self.context();
|
||||||
|
context.run_expr(&expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn context(&mut self) -> Context {
|
||||||
|
Context::new(&mut self.modules)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use eval_result::EvRes;
|
||||||
|
mod eval_result;
|
||||||
|
|
||||||
|
pub struct Scope {
|
||||||
|
bubble_variables: bool,
|
||||||
|
variables: HashMap<Name, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
pub fn new(bubble_variables: bool) -> Self {
|
||||||
|
let variables = HashMap::new();
|
||||||
|
Self {
|
||||||
|
bubble_variables,
|
||||||
|
variables,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with(variables: Vec<(Name, Value)>, bubble_variables: bool) -> Self {
|
||||||
|
let mut result = Self::new(bubble_variables);
|
||||||
|
for (name, value) in variables {
|
||||||
|
result.insert(name, value)
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, name: Name, value: Value) {
|
||||||
|
self.variables.insert(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, name: &Name) -> Option<&Value> {
|
||||||
|
self.variables.get(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self, name: &Name) -> Option<&mut Value> {
|
||||||
|
self.variables.get_mut(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use context::Context;
|
||||||
|
mod context {
|
||||||
|
use std::{cell::RefMut, collections::HashMap};
|
||||||
|
|
||||||
|
use lorgn_lang::ast::{
|
||||||
|
Assignment, Block, Break, Condition, Expr, FnCall, FnDef, Invoke, Litteral, Loop, Name,
|
||||||
|
Path, Return,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{Function, Module, Value};
|
||||||
|
|
||||||
|
use super::{EvRes, Scope};
|
||||||
|
|
||||||
|
pub struct Context<'r> {
|
||||||
|
modules: &'r HashMap<Name, Module>,
|
||||||
|
scopes: Vec<Scope>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'r> Context<'r> {
|
||||||
|
pub fn new(modules: &'r mut HashMap<Name, Module>) -> Self {
|
||||||
|
let scopes = vec![];
|
||||||
|
Self { modules, scopes }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_function(&self, path: &Path) -> Option<RefMut<Function>> {
|
||||||
|
self.modules
|
||||||
|
.get(&path.module)
|
||||||
|
.and_then(|m| m.get_function(&path.item))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_variable(&mut self, name: &Name) -> Option<&mut Value> {
|
||||||
|
for scope in self.scopes.iter_mut().rev() {
|
||||||
|
if !scope.bubble_variables {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
if let Some(result) = scope.variables.get_mut(name) {
|
||||||
|
return Some(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_fun(&mut self, fn_def: &FnDef, params: Vec<Value>) -> Value {
|
||||||
|
let variables = fn_def
|
||||||
|
.parameters
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.zip(params.into_iter())
|
||||||
|
.collect();
|
||||||
|
self.push_scope(Scope::new_with(variables, false));
|
||||||
|
let res = self.eval_block(&fn_def.expressions);
|
||||||
|
self.pop_scope();
|
||||||
|
match res {
|
||||||
|
EvRes::Value(res) => res,
|
||||||
|
EvRes::ReturnSC(res) => res,
|
||||||
|
EvRes::BreakSC(_) => panic!("break outside of loop"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_expr(&mut self, expr: &Expr) -> Value {
|
||||||
|
self.eval_expr(expr).into_value().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_scope(&mut self, scope: Scope) {
|
||||||
|
self.scopes.push(scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_scope(&mut self) {
|
||||||
|
self.scopes.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn top_scope(&mut self) -> Option<&mut Scope> {
|
||||||
|
self.scopes.last_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn top_index(&self) -> usize {
|
||||||
|
self.scopes.len() - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_expr(&mut self, expr: &Expr) -> EvRes {
|
||||||
|
match expr {
|
||||||
|
Expr::Block(block) => self.eval_block(block),
|
||||||
|
Expr::Assignment(assignment) => self.eval_assignment(assignment),
|
||||||
|
Expr::Invoke(invoke) => self.eval_invoke(invoke),
|
||||||
|
Expr::Litteral(litteral) => self.eval_litteral(litteral),
|
||||||
|
Expr::FnCall(fn_call) => self.eval_fn_call(fn_call),
|
||||||
|
Expr::Condition(condition) => self.eval_condition(condition),
|
||||||
|
Expr::Loop(loop_) => self.eval_loop(loop_),
|
||||||
|
Expr::Return(return_) => self.eval_return(return_),
|
||||||
|
Expr::Break(break_) => self.eval_break(break_),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_block(&mut self, block: &Block) -> EvRes {
|
||||||
|
let mut last = None;
|
||||||
|
for expr in &block.expressions {
|
||||||
|
let result = self.eval_expr(expr);
|
||||||
|
if let EvRes::Value(result) = result {
|
||||||
|
last = Some(result);
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let result = last.unwrap_or(Value::None);
|
||||||
|
EvRes::new_val(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_assignment(&mut self, assignment: &Assignment) -> EvRes {
|
||||||
|
let result = self.eval_expr(&assignment.value);
|
||||||
|
if let EvRes::Value(result) = result {
|
||||||
|
let name = assignment.variable_name.clone();
|
||||||
|
self.top_scope().unwrap().insert(name, result.clone());
|
||||||
|
EvRes::new_val(result)
|
||||||
|
} else {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_invoke(&mut self, invoke: &Invoke) -> EvRes {
|
||||||
|
let value = self.find_variable(&invoke.variable_name).unwrap().clone();
|
||||||
|
EvRes::new_val(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_litteral(&mut self, litteral: &Litteral) -> EvRes {
|
||||||
|
match litteral {
|
||||||
|
Litteral::String(str) => EvRes::Value(str.clone().into()),
|
||||||
|
Litteral::Integer(int) => EvRes::Value((*int).into()),
|
||||||
|
Litteral::Float(flt) => EvRes::Value((*flt).into()),
|
||||||
|
Litteral::Bool(bool) => EvRes::Value((*bool).into()),
|
||||||
|
Litteral::List(vec) => {
|
||||||
|
let mut results = vec![];
|
||||||
|
for expr in vec {
|
||||||
|
let result = self.eval_expr(expr);
|
||||||
|
if let EvRes::Value(result) = result {
|
||||||
|
results.push(result);
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EvRes::Value(results.into())
|
||||||
|
}
|
||||||
|
Litteral::Map(map) => {
|
||||||
|
let mut results = HashMap::new();
|
||||||
|
for (name, expr) in map {
|
||||||
|
let result = self.eval_expr(expr);
|
||||||
|
if let EvRes::Value(result) = result {
|
||||||
|
results.insert(name.clone(), result);
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EvRes::Value(results.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_fn_call(&mut self, fn_call: &FnCall) -> EvRes {
|
||||||
|
let mut args = vec![];
|
||||||
|
for arg in &fn_call.arguments {
|
||||||
|
let res = self.eval_expr(arg);
|
||||||
|
if res.is_short_circuit() {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
args.push(res.into_value().unwrap());
|
||||||
|
}
|
||||||
|
let path = &fn_call.fn_path;
|
||||||
|
let module = self.modules.get(&path.module).unwrap();
|
||||||
|
let mut function = module.get_function(&path.item).unwrap();
|
||||||
|
let res = function.call(args, self);
|
||||||
|
EvRes::Value(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_condition(&mut self, condition: &Condition) -> EvRes {
|
||||||
|
let cond = self.eval_expr(&condition.condition);
|
||||||
|
if cond.is_short_circuit() {
|
||||||
|
return cond;
|
||||||
|
}
|
||||||
|
let cond = cond.into_value().unwrap();
|
||||||
|
if cond.into_bool().unwrap() {
|
||||||
|
self.eval_expr(&condition.true_case)
|
||||||
|
} else {
|
||||||
|
self.eval_expr(&condition.false_case)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_loop(&mut self, loop_: &Loop) -> EvRes {
|
||||||
|
let body = &loop_.body;
|
||||||
|
let result = loop {
|
||||||
|
let res = self.eval_expr(body);
|
||||||
|
match res {
|
||||||
|
EvRes::ReturnSC(_) => return res,
|
||||||
|
EvRes::BreakSC(result) => break result,
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
EvRes::new_val(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_return(&mut self, return_: &Return) -> EvRes {
|
||||||
|
let result = self.eval_expr(&return_.expression);
|
||||||
|
match result {
|
||||||
|
EvRes::ReturnSC(_) => result,
|
||||||
|
EvRes::Value(v) => EvRes::ReturnSC(v),
|
||||||
|
EvRes::BreakSC(_) => panic!("break outside of loop"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_break(&mut self, break_: &Break) -> EvRes {
|
||||||
|
let result = self.eval_expr(&break_.expression);
|
||||||
|
match result {
|
||||||
|
EvRes::ReturnSC(_) => result,
|
||||||
|
EvRes::Value(v) => EvRes::BreakSC(v),
|
||||||
|
EvRes::BreakSC(v) => EvRes::BreakSC(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
lorgn_runtime/src/runtime/eval_result.rs
Normal file
28
lorgn_runtime/src/runtime/eval_result.rs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
use crate::Value;
|
||||||
|
|
||||||
|
// TODO: refactor into {res} | {sc {} | {}}
|
||||||
|
pub enum EvRes {
|
||||||
|
Value(Value),
|
||||||
|
ReturnSC(Value),
|
||||||
|
BreakSC(Value),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EvRes {
|
||||||
|
pub fn new_val(value: Value) -> Self {
|
||||||
|
Self::Value(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_short_circuit(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
EvRes::Value(_) => false,
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_value(self) -> Option<Value> {
|
||||||
|
match self {
|
||||||
|
Self::Value(val) => Some(val),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
90
lorgn_runtime/src/value.rs
Normal file
90
lorgn_runtime/src/value.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use gc::Gc;
|
||||||
|
use gc_derive::{Finalize, Trace};
|
||||||
|
use lorgn_lang::ast::Name;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Trace, Finalize)]
|
||||||
|
pub struct InnerObj(#[unsafe_ignore_trace] HashMap<Name, Value>);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Trace, Finalize)]
|
||||||
|
pub enum Value {
|
||||||
|
String(String),
|
||||||
|
Integer(i32),
|
||||||
|
Float(f32),
|
||||||
|
Bool(bool),
|
||||||
|
List(Gc<Vec<Value>>),
|
||||||
|
Object(Gc<InnerObj>),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
pub fn into_string(self) -> Option<String> {
|
||||||
|
match &self {
|
||||||
|
Self::String(str) => Some(str.clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn into_i32(self) -> Option<i32> {
|
||||||
|
match self {
|
||||||
|
Self::Integer(int) => Some(int),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn into_bool(self) -> Option<bool> {
|
||||||
|
match self {
|
||||||
|
Self::Bool(bool) => Some(bool),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for Value {
|
||||||
|
fn from(input: String) -> Self {
|
||||||
|
Self::String(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i32> for Value {
|
||||||
|
fn from(input: i32) -> Self {
|
||||||
|
Self::Integer(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<f32> for Value {
|
||||||
|
fn from(input: f32) -> Self {
|
||||||
|
Self::Float(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for Value {
|
||||||
|
fn from(input: bool) -> Self {
|
||||||
|
Self::Bool(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec<Value>> for Value {
|
||||||
|
fn from(input: Vec<Value>) -> Self {
|
||||||
|
let gc = Gc::new(input);
|
||||||
|
Self::List(gc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<HashMap<Name, Value>> for Value {
|
||||||
|
fn from(input: HashMap<Name, Value>) -> Self {
|
||||||
|
let gc = Gc::new(InnerObj(input));
|
||||||
|
Self::Object(gc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<Option<T>> for Value
|
||||||
|
where
|
||||||
|
T: Into<Value>,
|
||||||
|
{
|
||||||
|
fn from(input: Option<T>) -> Self {
|
||||||
|
match input {
|
||||||
|
Some(input) => input.into(),
|
||||||
|
None => Self::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue