add start of eval impl

This commit is contained in:
JOLIMAITRE Matthieu 2024-06-22 22:44:01 +02:00
parent e6d013c716
commit 054993a6ed
4 changed files with 291 additions and 13 deletions

194
src/lib/eval/mod.rs Normal file
View 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())
}
}

View file

@ -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>;

View file

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