This commit is contained in:
Matthieu Jolimaitre 2024-10-24 05:27:45 +02:00
commit da82c775db
9 changed files with 1066 additions and 0 deletions

454
src/ast.rs Normal file
View file

@ -0,0 +1,454 @@
use core::cell::RefCell;
use alloc::{boxed::Box, format, rc::Rc, string::String, vec::Vec};
use crate::{util::Boxable, Context, EvalError, FunImpl, Function, Value};
use chumsky::{
error::Simple,
prelude::{end, just, none_of, one_of, recursive, Recursive},
text::{whitespace, TextParser},
Parser,
};
use hashbrown::HashMap;
extern crate alloc;
pub trait Parse<O>: Parser<char, O, Error = Simple<char>> + Clone + 'static {}
impl<T: Parser<char, O, Error = Simple<char>> + Clone + 'static, O> Parse<O> for T {}
fn lx(word: &'static str) -> impl Parse<&'static str> {
whitespace()
.ignore_then(just(word))
.then_ignore(whitespace())
.labelled("token")
}
fn id() -> impl Parse<String> {
let allowed_first_chars = "_azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN";
let allowed_other_chars = "_azertyuiopqsdfghjklmwxcvbnAZERTYUIOPQSDFGHJKLMWXCVBN0123456789";
(one_of(allowed_first_chars).map(Some))
.then(one_of(allowed_other_chars).repeated())
.map(|(f, o)| f.iter().chain(o.iter()).collect())
.labelled("identifier")
}
#[derive(Debug, Clone)]
pub struct Block {
instructions: Vec<Instr>,
expression: Option<Box<Expr>>,
}
impl Block {
pub fn parser(instr: impl Parse<Instr>, expr: impl Parse<Expr>) -> impl Parse<Self> {
instr
.clone()
.then_ignore(lx(";"))
.repeated()
.then(expr.map(Boxable::to_box).or_not())
.map(|(instructions, expression)| Self {
expression,
instructions,
})
.labelled("block")
}
pub fn program_parser() -> impl Parse<Self> {
let mut expr_decl = Recursive::declare();
let mut instr_decl = Recursive::declare();
expr_decl.define(Expr::parser(instr_decl.clone()));
instr_decl.define(Instr::parser(expr_decl.clone()));
Self::parser(instr_decl, expr_decl)
.then_ignore(end())
.labelled("program")
}
pub fn eval(&self, context: &mut Context) -> Result<(Option<Short>, Value), EvalError> {
for instr in &self.instructions {
let short = instr.eval(context)?;
if short.is_some() {
return Ok((short, Value::None));
}
}
Ok(match self.expression.as_ref() {
Some(expr) => (None, expr.eval(context)?),
None => (None, Value::None),
})
}
}
#[derive(Debug, Clone)]
pub struct FunDef {
pub args: Vec<String>,
pub body: Block,
}
impl FunDef {
pub fn parser_def(instr: impl Parse<Instr>, expr: impl Parse<Expr>) -> impl Parse<(String, Self)> {
let arguments = id().separated_by(lx(","));
(lx("fn").ignore_then(id()))
.then(lx("(").ignore_then(arguments).then_ignore(lx(")")))
.then(lx("{").ignore_then(Block::parser(instr, expr)).then_ignore(lx("}")))
.map(|((id, args), body)| (id, Self { args, body }))
.labelled("function definition")
}
pub fn parser_lamb(instr: impl Parse<Instr>, expr: impl Parse<Expr>) -> impl Parse<Self> {
let arguments = id().separated_by(lx(","));
(lx("(").ignore_then(arguments).then_ignore(lx(")")))
.then(lx("{").ignore_then(Block::parser(instr, expr)).then_ignore(lx("}")))
.map(|(args, body)| Self { args, body })
.labelled("lambda")
}
}
#[derive(Debug, Clone)]
pub enum Instr {
Nop,
Block(Block),
Expr(Expr),
Init(String, Expr),
Assign(String, Expr),
Branch(Expr, Box<Instr>, Box<Instr>),
Loop(Box<Instr>),
FnDef(String, FunDef),
Short(ShortDef),
}
// TODO : while, for, obj prop assign.
impl Instr {
pub fn parser(expr: impl Parse<Expr>) -> impl Parse<Self> {
recursive(|instr: Recursive<'_, _, Self, _>| {
(lx("{")
.ignore_then(Block::parser(instr.clone(), expr.clone()))
.then_ignore(lx("}"))
.map(Self::Block))
.labelled("block instruction")
.or(lx("let")
.ignore_then(id())
.then_ignore(lx("="))
.then(expr.clone())
.map(|(id, ex)| Self::Init(id, ex)))
.labelled("variable initialization")
.or(lx("if")
.ignore_then(lx("(").ignore_then(expr.clone()).then_ignore(lx(")")))
.then((instr.clone()).then((lx("else").ignore_then(instr.clone())).or_not()))
.map(|(cond, (then, els))| Self::Branch(cond, then.to_box(), els.unwrap_or(Instr::Nop).to_box())))
.labelled("condition instruction")
.or(lx("loop")
.ignore_then(instr.clone())
.map(|body| Self::Loop(body.to_box())))
.labelled("loop instruction")
.or(ShortDef::parser(expr.clone())
.map(Self::Short)
.labelled("shortcut instruction"))
.or(FunDef::parser_def(instr, expr.clone())
.map(|(name, fun)| Self::FnDef(name, fun))
.labelled("function definition"))
.or(id()
.then_ignore(lx("="))
.then(expr.clone())
.map(|(id, ex)| Self::Assign(id, ex))
.labelled("variable assigniation."))
.or(expr.map(Self::Expr))
})
.labelled("instruction")
}
pub fn eval(&self, context: &mut Context) -> Result<Option<Short>, EvalError> {
Ok(match self {
Self::Nop => None,
Self::Block(block) => block.eval(context)?.0,
Self::Expr(expr) => no_short(expr.eval(context)?),
Self::Init(name, expr) => {
let value = expr.eval(context)?;
context.scope().borrow_mut().append(name.clone(), value);
no_short(())
}
Self::Assign(name, expr) => {
let value = expr.eval(context)?;
context.scope().borrow_mut().update(name, value)?;
None
}
Self::Branch(cond, t, e) => {
let condition = cond.eval(context)?;
match condition {
Value::Bool(true) => t.eval(context)?,
Value::Bool(false) => e.eval(context)?,
_ => Err(EvalError::WrongType)?,
}
}
Self::Loop(b) => loop {
match b.eval(context)? {
None => continue,
Some(Short::Break) => break None,
Some(Short::Continue) => continue,
Some(Short::Return(ret)) => break Some(Short::Return(ret)),
}
},
Self::Short(s) => return Ok(Some(s.eval(context)?)),
Self::FnDef(name, fun) => {
Self::Init(name.clone(), Expr::Litteral(Litteral::Function(fun.clone()))).eval(context)?
}
})
}
}
fn no_short<T>(value: T) -> Option<Short> {
drop(value);
None
}
#[derive(Debug, Clone)]
pub enum ShortDef {
Break,
Continue,
Return(Expr),
}
#[derive(Debug, Clone)]
pub enum Short {
Break,
Continue,
Return(Value),
}
impl ShortDef {
pub fn parser(expr: impl Parse<Expr>) -> impl Parse<Self> {
(lx("break").map(|_| Self::Break))
.or(lx("continue").map(|_| Self::Continue))
.or(lx("return").map(|_| Self::Return(Expr::Litteral(Litteral::None))))
.or(lx("return").ignore_then(expr).map(Self::Return))
}
pub fn eval(&self, context: &mut Context) -> Result<Short, EvalError> {
Ok(match self {
Self::Break => Short::Break,
Self::Continue => Short::Continue,
Self::Return(expr) => Short::Return(expr.eval(context)?),
})
}
}
#[derive(Debug, Clone)]
pub enum Expr {
Litteral(Litteral),
Parens(Box<Expr>),
UniOp(UniOp, Box<Expr>),
Var(String),
BinOps(Box<Expr>, Vec<(Op, Expr)>),
Access(Box<Expr>, String),
Call(Box<Expr>, Vec<Expr>),
Index(Box<Expr>, Box<Expr>),
}
impl Expr {
pub fn parser(instr: impl Parse<Instr>) -> impl Parse<Self> {
recursive(|expr: Recursive<'_, _, Self, _>| {
let left = (Litteral::parser(instr, expr.clone()).map(Self::Litteral))
.or((lx("(").ignore_then(expr.clone()).then_ignore(lx(")"))).map(|e| Self::Parens(e.to_box())))
.or((UniOp::parser().then(expr.clone())).map(|(o, e)| Self::UniOp(o, e.to_box())))
.or(id().map(Self::Var).padded());
(left
.clone()
.then(Op::parser().then(expr.clone()).repeated().at_least(1)))
.map(|(f, o)| Self::BinOps(f.to_box(), o))
.or((left.clone())
.then_ignore(lx("."))
.then(id())
.map(|(e, a)| Self::Access(e.to_box(), a)))
.or((left.clone())
.then_ignore(lx("("))
.then(expr.clone().then_ignore(lx(",")).repeated())
.then_ignore(lx(")"))
.map(|(e, a)| Self::Call(e.to_box(), a)))
.or((left.clone())
.then_ignore(lx("["))
.then(expr.clone())
.then_ignore(lx("]"))
.map(|(e, i)| Self::Index(e.to_box(), i.to_box())))
.or(left)
.labelled("expression")
})
}
pub fn eval(&self, context: &mut Context) -> Result<Value, EvalError> {
match self {
Self::Litteral(litt) => litt.eval(context),
Self::Parens(expr) => expr.eval(context),
Self::UniOp(op, expr) => op.apply(&expr.eval(context)?),
Self::Var(name) => context.scope().borrow().get(name),
Self::BinOps(first, rest) => {
let mut l = first.eval(context)?;
for (op, r) in rest {
let r = r.eval(context)?;
l = op.apply(&l, &r)?;
}
Ok(l)
}
Self::Access(e, p) => {
let index = Box::new(Expr::Litteral(Litteral::Str(p.clone())));
Self::Index(e.clone(), index).eval(context)
}
Self::Call(e, a) => {
let Value::Function(fun) = e.eval(context)? else {
return Err(EvalError::WrongType);
};
let mut args = Vec::new();
for arg in a {
let arg = arg.eval(context)?;
args.push(arg);
}
let fun = fun.borrow();
fun.call(args, context)
}
Self::Index(expr, index) => {
let value = expr.eval(context)?;
let index = index.eval(context)?;
match (value, index) {
(Value::Array(v), Value::Num(n)) => Ok(v
.borrow()
.get(n.floor().max(0.) as usize)
.cloned()
.unwrap_or(Value::None)),
(Value::Object(m), Value::Str(s)) => Ok(m.borrow().get(&s).cloned().unwrap_or(Value::None)),
_ => Err(EvalError::WrongType),
}
}
}
}
}
#[derive(Debug, Clone)]
pub enum Op {
Add,
Sub,
Div,
Prod,
Eq,
Neq,
Lt,
Gt,
Leq,
Geq,
}
impl Op {
pub fn parser() -> impl Parse<Self> {
(lx("+").map(|_| Self::Add))
.or(lx("-").map(|_| Self::Sub))
.or(lx("/").map(|_| Self::Div))
.or(lx("*").map(|_| Self::Prod))
.or(lx("==").map(|_| Self::Eq))
.or(lx("!=").map(|_| Self::Neq))
.or(lx("<").map(|_| Self::Lt))
.or(lx(">").map(|_| Self::Gt))
.or(lx("<=").map(|_| Self::Leq))
.or(lx(">=").map(|_| Self::Geq))
}
pub fn apply(&self, l: &Value, r: &Value) -> Result<Value, EvalError> {
Ok(match (self, l, r) {
(Self::Add, Value::Str(l), Value::Str(r)) => Value::Str(format!("{l}{r}")),
(Self::Add, Value::Num(l), Value::Num(r)) => Value::Num(l + r),
_ => Err(EvalError::WrongType)?,
})
}
}
#[derive(Debug, Clone)]
pub enum UniOp {
Neg,
Inv,
}
impl UniOp {
pub fn parser() -> impl Parse<Self> {
(lx("-").map(|_| Self::Neg)).or(lx("!").map(|_| Self::Inv))
}
pub fn apply(&self, value: &Value) -> Result<Value, EvalError> {
Ok(match (self, value) {
(Self::Inv, Value::Bool(b)) => Value::Bool(!b),
(Self::Neg, Value::Num(n)) => Value::Num(-n),
_ => Err(EvalError::WrongType)?,
})
}
}
#[derive(Debug, Clone)]
pub enum Litteral {
None,
Bool(bool),
Num(f64),
Str(String),
Object(Vec<(String, Expr)>),
Array(Vec<Expr>),
Function(FunDef),
}
impl Litteral {
pub fn parser(instr: impl Parse<Instr>, expr: impl Parse<Expr>) -> impl Parse<Self> {
let char = none_of('"')
.or(just("\\\\").map(|_| '\\'))
.or(just("\\\"").map(|_| '"'));
let digit = one_of("0123456789");
(just("\"")
.ignore_then(char.repeated())
.then_ignore(just("\""))
.map(|s| Self::Str(s.iter().collect())))
.or(just("true")
.map(|_| true)
.or(just("false").map(|_| false))
.map(Self::Bool))
.or((digit.clone().repeated().at_least(1))
.map(|v| v.into_iter().collect::<String>())
.then(lx(".").or_not().map(Option::unwrap_or_default))
.then(digit.repeated().map(|v| v.into_iter().collect::<String>()))
.map(|((l, d), r)| Litteral::Num(format!("{l}{d}{r}").parse::<f64>().unwrap())))
.or(lx("{")
.ignore_then(id().then_ignore(lx(":")).then(expr.clone()).separated_by(lx(",")))
.then_ignore(lx("}"))
.map(Self::Object))
.or(lx("[")
.ignore_then(expr.clone().separated_by(lx(",")))
.then_ignore(lx("]"))
.map(Self::Array))
.or(FunDef::parser_lamb(instr, expr).map(Self::Function))
.labelled("litteral")
}
pub fn eval(&self, context: &mut Context) -> Result<Value, EvalError> {
Ok(match self {
Self::None => Value::None,
Self::Bool(b) => Value::Bool(*b),
Self::Num(n) => Value::Num(*n),
Self::Str(s) => Value::Str(s.clone()),
Self::Object(keys) => {
let mut res = HashMap::new();
for (key, expr) in keys {
let value = expr.eval(context)?;
res.insert(key.clone(), value);
}
Value::Object(Rc::new(RefCell::new(res)))
}
Self::Array(items) => {
let mut res = Vec::new();
for expr in items {
let item = expr.eval(context)?;
res.push(item);
}
Value::Array(Rc::new(RefCell::new(res)))
}
Self::Function(def) => {
let capturing = context.scope().clone();
let def = FunImpl::Def(def.clone());
let function = Function { capturing, def };
Value::Function(Rc::new(RefCell::new(function)))
}
})
}
}

188
src/lib.rs Normal file
View file

@ -0,0 +1,188 @@
#![no_std]
mod util;
use core::{cell::RefCell, fmt::Debug, iter::repeat};
use alloc::{rc::Rc, string::String, vec::Vec};
use ast::{Block, FunDef, Short};
use chumsky::{error::Simple, Parser};
use hashbrown::HashMap;
extern crate alloc;
#[derive(Debug)]
pub struct Context {
pub frame: Rc<RefCell<Scope>>,
}
#[derive(Debug)]
pub enum Error {
ParsingErr(Vec<Simple<char>>),
EvalErr(EvalError),
}
#[derive(Debug)]
pub enum EvalError {
Exit,
NotFound(String),
IllegalShort(Short),
WrongType, // add type names ?
}
impl Context {
pub fn empty() -> Self {
let frame = Rc::new(RefCell::new(Scope::new(None)));
Self { frame }
}
pub fn eval(&mut self, script: String) -> Result<(Block, Value), Error> {
let parsed = match Block::program_parser().parse(script) {
Ok(parsed) => parsed,
Err(err) => Err(Error::ParsingErr(err))?,
};
let value = match parsed.eval(self) {
Ok((_short, value)) => value,
Err(err) => Err(Error::EvalErr(err))?,
};
Ok((parsed, value))
}
pub fn scope(&self) -> Rc<RefCell<Scope>> {
self.frame.clone()
}
}
#[derive(Debug, Clone)]
pub struct Scope {
pub parent: Option<Rc<RefCell<Self>>>,
pub defs: HashMap<String, Value>,
}
impl Scope {
pub fn new(parent: Option<Rc<RefCell<Self>>>) -> Self {
let defs = HashMap::new();
Self { defs, parent }
}
pub fn child<F: FnOnce(&mut Context) -> O, O>(context: &mut Context, op: F) -> O {
let parent = context.frame.clone();
let child = Rc::new(RefCell::new(Scope::new(Some(parent.clone()))));
context.frame = child;
let result = op(context);
context.frame = parent;
result
}
pub fn alt<F: FnOnce(&mut Context) -> O, O>(context: &mut Context, captures: Rc<RefCell<Self>>, op: F) -> O {
let parent = context.frame.clone();
let alt = Rc::new(RefCell::new(Scope::new(Some(captures.clone()))));
context.frame = alt;
let result = op(context);
context.frame = parent;
result
}
pub fn append(&mut self, name: String, value: Value) {
self.defs.insert(name, value);
}
pub fn update(&mut self, name: &str, value: Value) -> Result<(), EvalError> {
let Some(variable) = self.defs.get_mut(name) else {
if let Some(parent) = &self.parent {
return parent.borrow_mut().update(name, value);
}
return Err(EvalError::NotFound(name.into()));
};
*variable = value;
Ok(())
}
pub fn get(&self, name: &str) -> Result<Value, EvalError> {
let Some(value) = self.defs.get(name) else {
if let Some(parent) = &self.parent {
return parent.borrow_mut().get(name);
}
return Err(EvalError::NotFound(name.into()));
};
Ok(value.clone())
}
}
#[derive(Debug, Clone)]
pub enum Value {
None,
Bool(bool),
Num(f64),
Str(String),
Object(Rc<RefCell<HashMap<String, Value>>>),
Array(Rc<RefCell<Vec<Value>>>),
Function(Rc<RefCell<Function>>),
}
pub enum InstrOutput {
Short(Short),
Value(Value),
}
#[derive(Debug, Clone)]
pub struct Function {
pub capturing: Rc<RefCell<Scope>>,
pub def: FunImpl,
}
#[derive(Clone)]
pub enum FunImpl {
Def(FunDef),
Built(Rc<dyn Fn(Vec<Value>, &mut Context) -> Result<Value, EvalError>>),
}
impl Debug for FunImpl {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Built(_) => f.debug_struct("Built").finish(),
Self::Def(def) => f.debug_tuple("Def").field(def).finish(),
}
}
}
impl Function {
pub fn call(&self, args: Vec<Value>, context: &mut Context) -> Result<Value, EvalError> {
match &self.def {
FunImpl::Built(op) => op(args, context),
FunImpl::Def(def) => Scope::alt(context, self.capturing.clone(), |context| {
let names = def.args.iter().cloned();
for (name, value) in names.zip(args.into_iter().chain(repeat(Value::None))) {
context.scope().borrow_mut().append(name, value);
}
match def.body.eval(context) {
Err(err) => Err(err),
Ok((None, value)) => Ok(value),
Ok((Some(Short::Return(ret)), _)) => Ok(ret),
Ok((Some(s), _)) => Err(EvalError::IllegalShort(s)),
}
}),
}
}
}
pub mod ast;
/*
let a = 3;
fn f1() {
let a = 5;
fn f2() {
a = 3;
}
f2
}
let f2 = f1();
f2();
a = 3
*/

9
src/util.rs Normal file
View file

@ -0,0 +1,9 @@
use alloc::boxed::Box;
pub trait Boxable: Sized {
fn to_box(self) -> Box<Self> {
Box::new(self)
}
}
impl<T: Sized> Boxable for T {}