init
This commit is contained in:
commit
da82c775db
9 changed files with 1066 additions and 0 deletions
454
src/ast.rs
Normal file
454
src/ast.rs
Normal 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
188
src/lib.rs
Normal 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
9
src/util.rs
Normal 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 {}
|
Loading…
Add table
Add a link
Reference in a new issue