add start of eval impl
This commit is contained in:
parent
e6d013c716
commit
054993a6ed
4 changed files with 291 additions and 13 deletions
194
src/lib/eval/mod.rs
Normal file
194
src/lib/eval/mod.rs
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
use std::{
|
||||||
|
array,
|
||||||
|
borrow::{Borrow, BorrowMut},
|
||||||
|
collections::{HashMap, VecDeque},
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::parse::ast;
|
||||||
|
|
||||||
|
pub fn eval(program: &ast::Program) {
|
||||||
|
let mut realm = Realm::default();
|
||||||
|
realm.eval_block(&program.body);
|
||||||
|
|
||||||
|
for stat in &program.body.statements {
|
||||||
|
realm.eval_statement(stat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Realm {
|
||||||
|
scope: Scope<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Scope<'p> {
|
||||||
|
parent: Option<Box<&'p mut Scope<'p>>>,
|
||||||
|
locals: HashMap<ast::Name, Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p> Scope<'p> {
|
||||||
|
fn child<'c: 'p>(&'c mut self) -> Scope<'c> {
|
||||||
|
Scope {
|
||||||
|
parent: Some(Box::new(self)),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_name(&mut self, name: &ast::Name) -> Option<&mut Value> {
|
||||||
|
let own = self.locals.get_mut(name);
|
||||||
|
own.or_else(|| self.parent.as_mut().map(|p| p.find_name(name)).flatten())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set(&mut self, name: ast::Name, value: Value) {
|
||||||
|
self.locals.insert(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, name: &ast::Name, mut value: Value) -> bool {
|
||||||
|
let mut found = self.locals.get_mut(name);
|
||||||
|
if found.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
found.insert(&mut value);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Realm {
|
||||||
|
fn eval_block(&mut self, block: &ast::Body) -> RealmResult<Option<Value>> {
|
||||||
|
for stat in &block.statements {
|
||||||
|
self.eval_statement(stat)?;
|
||||||
|
}
|
||||||
|
let result = block.last_expr.as_ref().map(|e| self.eval_expr(&e.0));
|
||||||
|
match result {
|
||||||
|
Some(Result::Err(error)) => Err(error),
|
||||||
|
Some(Result::Ok(result)) => Ok(Some(result)),
|
||||||
|
None => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_statement(&mut self, stat: &ast::Statement) -> RealmResult<()> {
|
||||||
|
match stat {
|
||||||
|
ast::Statement::Definition(def) => self.eval_def(def),
|
||||||
|
ast::Statement::Assign(assign) => self.eval_assign(&assign),
|
||||||
|
ast::Statement::Expression(expr) => Ok(drop(self.eval_expr(&expr))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_def(&mut self, def: &ast::Definition) -> RealmResult<()> {
|
||||||
|
let value = self.eval_expr(&def.value)?;
|
||||||
|
|
||||||
|
fn rec(scope: &mut Scope, pattern: &ast::Pattern, value: &Value) -> RealmResult<()> {
|
||||||
|
match pattern {
|
||||||
|
ast::Pattern::Name(name) => scope.set(name.clone(), value.clone()),
|
||||||
|
ast::Pattern::TuplDestr(tup) => {
|
||||||
|
let Value::Array(arr) = value else {
|
||||||
|
Err(RealmError::IllegalAccess)?
|
||||||
|
};
|
||||||
|
if arr.len() != tup.fields.len() {
|
||||||
|
Err(RealmError::IllegalAccess)?
|
||||||
|
}
|
||||||
|
for (pattern, value) in tup.fields.iter().zip(arr.iter()) {
|
||||||
|
rec(scope, pattern, value)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::Pattern::ArrDestr(arr_pat) => {
|
||||||
|
let Value::Array(arr) = value else {
|
||||||
|
Err(RealmError::IllegalAccess)?
|
||||||
|
};
|
||||||
|
let expected_len = arr_pat.item_bef.len() + arr_pat.item_aft.len();
|
||||||
|
let fold_len = arr.len() - expected_len;
|
||||||
|
if arr.len() < expected_len {
|
||||||
|
Err(RealmError::IllegalAccess)?
|
||||||
|
}
|
||||||
|
let mut values = arr.iter();
|
||||||
|
for (pattern, value) in arr_pat.item_bef.iter().zip(&mut values) {
|
||||||
|
rec(scope, pattern, value)?
|
||||||
|
}
|
||||||
|
if let Some(fold) = &arr_pat.item_fold {
|
||||||
|
let value = (&mut values).take(fold_len).cloned().collect();
|
||||||
|
let value = Value::new_array(value);
|
||||||
|
rec(scope, fold, &value)?
|
||||||
|
}
|
||||||
|
for (pattern, value) in arr_pat.item_aft.iter().zip(values) {
|
||||||
|
rec(scope, pattern, value)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::Pattern::ObjDestr(obj_pat) => {
|
||||||
|
let Value::Obj(obj) = value else {
|
||||||
|
Err(RealmError::IllegalAccess)?
|
||||||
|
};
|
||||||
|
for (name, pattern) in &obj_pat.fields {
|
||||||
|
let Some(value) = obj.get(&name.0) else {
|
||||||
|
Err(RealmError::IllegalAccess)?
|
||||||
|
};
|
||||||
|
rec(scope, pattern, value)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
rec(&mut self.scope, &def.defined, &value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_assign(&mut self, assign: &ast::Assign) -> RealmResult<()> {
|
||||||
|
let value = self.eval_expr(&assign.value);
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn eval_expr(&mut self, expr: &ast::Expression) -> RealmResult<Value> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum RealmError {
|
||||||
|
IllegalAccess,
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub type RealmResult<T> = Result<T, RealmError>;
|
||||||
|
|
||||||
|
pub type BoxVal = Box<Value>;
|
||||||
|
pub type Object = Rc<HashMap<String, Value>>;
|
||||||
|
pub type Array = Rc<Vec<Value>>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Value {
|
||||||
|
Bool(bool),
|
||||||
|
Int(i32),
|
||||||
|
Float(f32),
|
||||||
|
String(String),
|
||||||
|
Obj(Object),
|
||||||
|
Array(Array),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error(message: impl Into<String>) -> Value {
|
||||||
|
Value::Obj(Rc::new(HashMap::from([(
|
||||||
|
"message".into(),
|
||||||
|
Value::String(message.into()),
|
||||||
|
)])))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
fn new_array(values: Vec<Value>) -> Self {
|
||||||
|
Self::Array(Rc::new(values))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn index(&self, key: &Self) -> Result<Self, Self> {
|
||||||
|
let result = match (self, key) {
|
||||||
|
(Self::Array(arr), Self::Int(num)) => (*num >= 0).then(|| arr.get(*num as usize)).flatten(),
|
||||||
|
(Self::Obj(obj), Self::String(str)) => obj.get(str),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(result) = result else {
|
||||||
|
Err(error("Illegal access"))?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(result.clone())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
|
pub mod eval;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
pub type Span = std::ops::Range<usize>;
|
pub type Span = std::ops::Range<usize>;
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
use crate::lib::parse::{token::Tok, AstParser};
|
use crate::lib::{
|
||||||
|
parse::{token::Tok, AstParser},
|
||||||
|
utils::Boxable,
|
||||||
|
};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
any::{type_name, type_name_of_val},
|
any::{type_name, type_name_of_val},
|
||||||
|
collections::HashMap,
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,7 +16,7 @@ use super::token::Key;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
body: Body,
|
pub body: Body,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Program {
|
impl Program {
|
||||||
|
@ -40,8 +44,8 @@ impl Statement {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Definition {
|
pub struct Definition {
|
||||||
defined: Pattern,
|
pub defined: Pattern,
|
||||||
value: Expression,
|
pub value: Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Definition {
|
impl Definition {
|
||||||
|
@ -56,8 +60,8 @@ impl Definition {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Assign {
|
pub struct Assign {
|
||||||
assigned: Pattern,
|
pub assigned: Pattern,
|
||||||
value: Expression,
|
pub value: Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Assign {
|
impl Assign {
|
||||||
|
@ -71,7 +75,7 @@ impl Assign {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Name(String);
|
pub struct Name(pub String);
|
||||||
|
|
||||||
impl Name {
|
impl Name {
|
||||||
fn parser() -> impl AstParser<Self> {
|
fn parser() -> impl AstParser<Self> {
|
||||||
|
@ -79,15 +83,84 @@ impl Name {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn name(name: impl ToString) -> Name {
|
||||||
|
Name(name.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
Name(Name),
|
Name(Name),
|
||||||
|
TuplDestr(TuplDestr),
|
||||||
|
ArrDestr(ArrDestr),
|
||||||
|
ObjDestr(ObjDestr),
|
||||||
|
// todo : decide if Index(Expression),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pattern {
|
impl Pattern {
|
||||||
fn parser() -> impl AstParser<Self> {
|
fn parser() -> impl AstParser<Self> {
|
||||||
Name::parser().map(Self::Name)
|
Name::parser().map(Self::Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_accessors(&self) -> Vec<(Name, Vec<Access>)> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_property_chain() {
|
||||||
|
let pattern = Pattern::ObjDestr(ObjDestr {
|
||||||
|
fields: vec![
|
||||||
|
(name("a"), Pattern::Name(name("a"))),
|
||||||
|
(name("b"), Pattern::Name(name("c"))),
|
||||||
|
(
|
||||||
|
name("d"),
|
||||||
|
Pattern::TuplDestr(TuplDestr {
|
||||||
|
fields: vec![Pattern::Name(name("e")), Pattern::Name(name("f"))],
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
(name("g"), Pattern::TuplDestr(TuplDestr { fields: vec![] })),
|
||||||
|
(
|
||||||
|
name("h"),
|
||||||
|
Pattern::ArrDestr(ArrDestr {
|
||||||
|
item_bef: vec![Pattern::Name(name("i")), Pattern::Name(name("j"))],
|
||||||
|
item_fold: None,
|
||||||
|
item_aft: vec![],
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
name("k"),
|
||||||
|
Pattern::ArrDestr(ArrDestr {
|
||||||
|
item_bef: vec![Pattern::Name(name("l"))],
|
||||||
|
item_fold: Some(Pattern::Name(name("m")).into_box()),
|
||||||
|
item_aft: vec![Pattern::Name(name("n")), Pattern::Name(name("o"))],
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
(name("p"), Pattern::ObjDestr(ObjDestr { fields: vec![] })),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct TuplDestr {
|
||||||
|
pub fields: Vec<Pattern>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ArrDestr {
|
||||||
|
pub item_bef: Vec<Pattern>,
|
||||||
|
pub item_fold: Option<Box<Pattern>>,
|
||||||
|
pub item_aft: Vec<Pattern>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct ObjDestr {
|
||||||
|
pub fields: Vec<(Name, Pattern)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjDestr {
|
||||||
|
fn parser() -> impl AstParser<Self> {
|
||||||
|
todo()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
@ -212,7 +285,7 @@ impl Access {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Invoke {
|
pub struct Invoke {
|
||||||
arguments: Vec<Expression>,
|
pub arguments: Vec<Expression>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Invoke {
|
impl Invoke {
|
||||||
|
@ -225,7 +298,7 @@ impl Invoke {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Index {
|
pub struct Index {
|
||||||
index: BoxEx,
|
pub index: BoxEx,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index {
|
impl Index {
|
||||||
|
@ -238,12 +311,12 @@ impl Index {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Property {
|
pub struct Property {
|
||||||
index: Name,
|
pub name: Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Property {
|
impl Property {
|
||||||
fn parser() -> impl AstParser<Self> {
|
fn parser() -> impl AstParser<Self> {
|
||||||
Name::parser().map(|index| Self { index })
|
Name::parser().map(|index| Self { name: index })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,8 +361,8 @@ impl Op {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Body {
|
pub struct Body {
|
||||||
statements: Vec<Statement>,
|
pub statements: Vec<Statement>,
|
||||||
last_expr: Option<BoxEx>,
|
pub last_expr: Option<BoxEx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Body {
|
impl Body {
|
||||||
|
|
9
src/lib/utils.rs
Normal file
9
src/lib/utils.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
pub trait Boxable {
|
||||||
|
fn into_box(self) -> Box<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Boxable for T {
|
||||||
|
fn into_box(self) -> Box<Self> {
|
||||||
|
Box::new(self)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue