This commit is contained in:
mb 2022-08-29 16:52:55 +03:00
commit 5c1cff92c6
15 changed files with 844 additions and 0 deletions

12
lorgn_runtime/Cargo.toml Normal file
View 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"

View 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
View 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()],
}));
}

View 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())
}
}

View 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),
}
}
}
}

View 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,
}
}
}

View 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,
}
}
}