Refractor into modules
parent
bc0d17e58f
commit
93266a980e
|
@ -1 +1 @@
|
||||||
nightly-2021-12-16
|
nightly-2021-12-27
|
|
@ -0,0 +1,23 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Debug, debug2::Debug, PartialEq)]
|
||||||
|
|
||||||
|
crate enum Tree {
|
||||||
|
Leaf(Literal),
|
||||||
|
Define(String, Box<Tree>),
|
||||||
|
If(Box<[Tree; 3]>),
|
||||||
|
Lambda(Lambda),
|
||||||
|
Branch(Vec<Tree>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, debug2::Debug, PartialEq, Clone)]
|
||||||
|
|
||||||
|
crate struct Lambda(crate Rc<[String]>, crate Rc<[Tree]>);
|
||||||
|
|
||||||
|
#[derive(Debug, debug2::Debug, PartialEq)]
|
||||||
|
|
||||||
|
crate enum Literal {
|
||||||
|
Sym(String),
|
||||||
|
Num(f64),
|
||||||
|
Bool(bool),
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
use std::assert_matches::assert_matches;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::value::Value;
|
||||||
|
use crate::{ast, prims};
|
||||||
|
|
||||||
|
pub(crate) fn eval(t: &ast::Tree, env: &mut Env) -> Result<Value, RTError> {
|
||||||
|
Ok(match t {
|
||||||
|
ast::Tree::Leaf(l) => match l {
|
||||||
|
ast::Literal::Sym(s) => match env.lookup(s) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return err(format!("Undefined variable `{}`", s)),
|
||||||
|
},
|
||||||
|
ast::Literal::Num(v) => Value::Num(*v),
|
||||||
|
ast::Literal::Bool(b) => Value::Bool(*b),
|
||||||
|
},
|
||||||
|
ast::Tree::Lambda(l) => Value::Lambda(l.clone()),
|
||||||
|
ast::Tree::Branch(args) => {
|
||||||
|
let Some(fun) = args.get(0) else { return err("No argument given".to_owned()) };
|
||||||
|
let fun = eval(fun, env)?;
|
||||||
|
let fun = fun.as_func()?;
|
||||||
|
let args = args
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.map(|a| eval(a, env))
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
// return fun(&args);
|
||||||
|
match fun {
|
||||||
|
Callable::Func(f) => f(&args)?,
|
||||||
|
Callable::Lambda(l) => {
|
||||||
|
if l.0.len() == args.len() {
|
||||||
|
let mut env = env.child();
|
||||||
|
for (x, y) in l.0.iter().zip(args) {
|
||||||
|
env.define(x.clone(), y)
|
||||||
|
}
|
||||||
|
|
||||||
|
let [main @ .., tail] = &l.1[..] else { unreachable!("Body has 1+ element by parser") };
|
||||||
|
for i in main {
|
||||||
|
eval(i, &mut env)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
eval(tail, &mut env)?
|
||||||
|
} else {
|
||||||
|
return err(format!("Need {} args, got {}", l.0.len(), args.len()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast::Tree::Define(name, to) => {
|
||||||
|
let val = eval(to, env)?;
|
||||||
|
env.define(name.to_owned(), val);
|
||||||
|
Value::Trap
|
||||||
|
}
|
||||||
|
ast::Tree::If(box [cond, tcase, fcase]) => {
|
||||||
|
let b = eval(cond, env)?.as_bool()?;
|
||||||
|
let body = if b { tcase } else { fcase };
|
||||||
|
eval(body, env)?
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
crate struct RTError(crate String);
|
||||||
|
|
||||||
|
pub(crate) fn err<T>(s: String) -> Result<T, RTError> {
|
||||||
|
Err(RTError(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) enum Callable<'a> {
|
||||||
|
Func(prims::Func),
|
||||||
|
Lambda(&'a ast::Lambda),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Env<'a> {
|
||||||
|
pub(crate) vars: HashMap<String, Value>,
|
||||||
|
pub(crate) enclosing: Option<&'a Env<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Env<'a> {
|
||||||
|
pub(crate) fn child(&'a self) -> Env<'a> {
|
||||||
|
Env {
|
||||||
|
vars: HashMap::new(),
|
||||||
|
enclosing: Some(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn lookup(&self, s: &str) -> Option<Value> {
|
||||||
|
if let Some(v) = self.vars.get(s) {
|
||||||
|
Some(v.clone())
|
||||||
|
} else if let Some(parent) = self.enclosing {
|
||||||
|
parent.lookup(s)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn define(&mut self, name: String, val: Value) {
|
||||||
|
self.vars.insert(name, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn default_env() -> Env<'static> {
|
||||||
|
let mut vars = HashMap::new();
|
||||||
|
|
||||||
|
for (name, fun) in prims::prims() {
|
||||||
|
assert_matches!(vars.insert((*name).to_owned(), Value::Func(*fun)), None)
|
||||||
|
}
|
||||||
|
|
||||||
|
Env {
|
||||||
|
vars,
|
||||||
|
enclosing: None,
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{Tree, Literal, Lambda};
|
use crate::ast::*;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
grammar<'s>();
|
grammar<'s>();
|
||||||
|
|
447
src/grammar.rs
447
src/grammar.rs
|
@ -1,19 +1,19 @@
|
||||||
// auto-generated: "lalrpop 0.19.6"
|
// auto-generated: "lalrpop 0.19.6"
|
||||||
// sha3: 081836a45e94e7f63b8cab92d6c3fb6f3fd286189113e73ef425a1afba86
|
// sha3: c1daa5330c6265bff388c19ed1642efbf9924c741dbad19b8016bd2a5a646
|
||||||
use crate::{Tree, Literal, Lambda};
|
use crate::ast::*;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
extern crate lalrpop_util as __lalrpop_util;
|
extern crate lalrpop_util as __lalrpop_util;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use self::__lalrpop_util::state_machine as __state_machine;
|
use self::__lalrpop_util::state_machine as __state_machine;
|
||||||
extern crate core;
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
extern crate core;
|
||||||
|
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
mod __parse__File {
|
mod __parse__File {
|
||||||
#![allow(non_snake_case, non_camel_case_types, unused_mut, unused_variables, unused_imports, unused_parens)]
|
#![allow(non_snake_case, non_camel_case_types, unused_mut, unused_variables, unused_imports, unused_parens)]
|
||||||
|
|
||||||
use crate::{Tree, Literal, Lambda};
|
use crate::ast::*;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
extern crate lalrpop_util as __lalrpop_util;
|
extern crate lalrpop_util as __lalrpop_util;
|
||||||
|
@ -1454,7 +1454,7 @@ pub(crate) use self::__parse__File::FileParser;
|
||||||
mod __parse__Tree {
|
mod __parse__Tree {
|
||||||
#![allow(non_snake_case, non_camel_case_types, unused_mut, unused_variables, unused_imports, unused_parens)]
|
#![allow(non_snake_case, non_camel_case_types, unused_mut, unused_variables, unused_imports, unused_parens)]
|
||||||
|
|
||||||
use crate::{Tree, Literal, Lambda};
|
use crate::ast::*;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
extern crate lalrpop_util as __lalrpop_util;
|
extern crate lalrpop_util as __lalrpop_util;
|
||||||
|
@ -2854,7 +2854,7 @@ pub(crate) use self::__parse__Tree::TreeParser;
|
||||||
#[cfg_attr(rustfmt, rustfmt_skip)]
|
#[cfg_attr(rustfmt, rustfmt_skip)]
|
||||||
mod __intern_token {
|
mod __intern_token {
|
||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
use crate::{Tree, Literal, Lambda};
|
use crate::ast::*;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
extern crate lalrpop_util as __lalrpop_util;
|
extern crate lalrpop_util as __lalrpop_util;
|
||||||
|
@ -2885,89 +2885,59 @@ mod __intern_token {
|
||||||
pub(crate) use self::__lalrpop_util::lexer::Token;
|
pub(crate) use self::__lalrpop_util::lexer::Token;
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action0<
|
fn __action0<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, __0, _): (usize, alloc::vec::Vec<Tree>, usize),
|
(_, __0, _): (usize, alloc::vec::Vec<Tree>, usize),
|
||||||
) -> alloc::vec::Vec<Tree>
|
) -> alloc::vec::Vec<Tree> {
|
||||||
{
|
|
||||||
__0
|
__0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action1<
|
fn __action1<'input, 's>(input: &'input str, (_, __0, _): (usize, Tree, usize)) -> Tree {
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
|
||||||
(_, __0, _): (usize, Tree, usize),
|
|
||||||
) -> Tree
|
|
||||||
{
|
|
||||||
__0
|
__0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action2<
|
fn __action2<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, _, _): (usize, core::option::Option<()>, usize),
|
(_, _, _): (usize, core::option::Option<()>, usize),
|
||||||
(_, __0, _): (usize, alloc::vec::Vec<Tree>, usize),
|
(_, __0, _): (usize, alloc::vec::Vec<Tree>, usize),
|
||||||
) -> alloc::vec::Vec<Tree>
|
) -> alloc::vec::Vec<Tree> {
|
||||||
{
|
|
||||||
__0
|
__0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action3<
|
fn __action3<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, __0, _): (usize, alloc::vec::Vec<Tree>, usize),
|
(_, __0, _): (usize, alloc::vec::Vec<Tree>, usize),
|
||||||
) -> alloc::vec::Vec<Tree>
|
) -> alloc::vec::Vec<Tree> {
|
||||||
{
|
|
||||||
__0
|
__0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action4<
|
fn __action4<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
(_, __0, _): (usize, alloc::vec::Vec<Tree>, usize),
|
(_, __0, _): (usize, alloc::vec::Vec<Tree>, usize),
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
) -> Tree
|
) -> Tree {
|
||||||
{
|
|
||||||
Tree::Branch(__0)
|
Tree::Branch(__0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action5<
|
fn __action5<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
(_, __0, _): (usize, String, usize),
|
(_, __0, _): (usize, String, usize),
|
||||||
(_, __1, _): (usize, Box<Tree>, usize),
|
(_, __1, _): (usize, Box<Tree>, usize),
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
) -> Tree
|
) -> Tree {
|
||||||
{
|
|
||||||
Tree::Define(__0, __1)
|
Tree::Define(__0, __1)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action6<
|
fn __action6<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
|
@ -2977,16 +2947,12 @@ fn __action6<
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
(_, body, _): (usize, Rc<[Tree]>, usize),
|
(_, body, _): (usize, Rc<[Tree]>, usize),
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
) -> Tree
|
) -> Tree {
|
||||||
{
|
|
||||||
Tree::Define(name, Box::new(Tree::Lambda(Lambda(args, body))))
|
Tree::Define(name, Box::new(Tree::Lambda(Lambda(args, body))))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action7<
|
fn __action7<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
|
@ -2994,16 +2960,12 @@ fn __action7<
|
||||||
(_, __1, _): (usize, Tree, usize),
|
(_, __1, _): (usize, Tree, usize),
|
||||||
(_, __2, _): (usize, Tree, usize),
|
(_, __2, _): (usize, Tree, usize),
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
) -> Tree
|
) -> Tree {
|
||||||
{
|
|
||||||
Tree::If(Box::new([__0, __1, __2]))
|
Tree::If(Box::new([__0, __1, __2]))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action8<
|
fn __action8<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
|
@ -3011,468 +2973,295 @@ fn __action8<
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
(_, __1, _): (usize, Rc<[Tree]>, usize),
|
(_, __1, _): (usize, Rc<[Tree]>, usize),
|
||||||
(_, _, _): (usize, &'input str, usize),
|
(_, _, _): (usize, &'input str, usize),
|
||||||
) -> Tree
|
) -> Tree {
|
||||||
{
|
|
||||||
Tree::Lambda(Lambda(__0, __1))
|
Tree::Lambda(Lambda(__0, __1))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action9<
|
fn __action9<'input, 's>(input: &'input str, (_, __0, _): (usize, Literal, usize)) -> Tree {
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
|
||||||
(_, __0, _): (usize, Literal, usize),
|
|
||||||
) -> Tree
|
|
||||||
{
|
|
||||||
Tree::Leaf(__0)
|
Tree::Leaf(__0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action10<
|
fn __action10<'input, 's>(input: &'input str, (_, __0, _): (usize, Box<Tree>, usize)) -> Box<Tree> {
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
|
||||||
(_, __0, _): (usize, Box<Tree>, usize),
|
|
||||||
) -> Box<Tree>
|
|
||||||
{
|
|
||||||
__0
|
__0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action11<
|
fn __action11<'input, 's>(input: &'input str, (_, __0, _): (usize, String, usize)) -> Literal {
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
|
||||||
(_, __0, _): (usize, String, usize),
|
|
||||||
) -> Literal
|
|
||||||
{
|
|
||||||
Literal::Sym(__0)
|
Literal::Sym(__0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action12<
|
fn __action12<'input, 's>(input: &'input str, (_, __0, _): (usize, f64, usize)) -> Literal {
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
|
||||||
(_, __0, _): (usize, f64, usize),
|
|
||||||
) -> Literal
|
|
||||||
{
|
|
||||||
Literal::Num(__0)
|
Literal::Num(__0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action13<
|
fn __action13<'input, 's>(input: &'input str, (_, __0, _): (usize, bool, usize)) -> Literal {
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
|
||||||
(_, __0, _): (usize, bool, usize),
|
|
||||||
) -> Literal
|
|
||||||
{
|
|
||||||
Literal::Bool(__0)
|
Literal::Bool(__0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action14<
|
fn __action14<'input, 's>(input: &'input str, (_, __0, _): (usize, &'input str, usize)) -> String {
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
|
||||||
(_, __0, _): (usize, &'input str, usize),
|
|
||||||
) -> String
|
|
||||||
{
|
|
||||||
__0.to_owned()
|
__0.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action15<
|
fn __action15<'input, 's>(input: &'input str, (_, __0, _): (usize, &'input str, usize)) -> f64 {
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
|
||||||
(_, __0, _): (usize, &'input str, usize),
|
|
||||||
) -> f64
|
|
||||||
{
|
|
||||||
__0.parse().unwrap()
|
__0.parse().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action16<
|
fn __action16<'input, 's>(input: &'input str, (_, __0, _): (usize, &'input str, usize)) -> bool {
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
|
||||||
(_, __0, _): (usize, &'input str, usize),
|
|
||||||
) -> bool
|
|
||||||
{
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action17<
|
fn __action17<'input, 's>(input: &'input str, (_, __0, _): (usize, &'input str, usize)) -> bool {
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
|
||||||
(_, __0, _): (usize, &'input str, usize),
|
|
||||||
) -> bool
|
|
||||||
{
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action18<
|
fn __action18<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, __0, _): (usize, &'input str, usize),
|
(_, __0, _): (usize, &'input str, usize),
|
||||||
(_, __1, _): (usize, &'input str, usize),
|
(_, __1, _): (usize, &'input str, usize),
|
||||||
) -> ()
|
) -> () {
|
||||||
{
|
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action19<
|
fn __action19<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, __0, _): (usize, &'input str, usize),
|
(_, __0, _): (usize, &'input str, usize),
|
||||||
) -> &'input str
|
) -> &'input str {
|
||||||
{
|
|
||||||
__0
|
__0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action20<
|
fn __action20<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, __0, _): (usize, &'input str, usize),
|
(_, __0, _): (usize, &'input str, usize),
|
||||||
) -> &'input str
|
) -> &'input str {
|
||||||
{
|
|
||||||
__0
|
__0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action21<
|
fn __action21<'input, 's>(input: &'input str, (_, __0, _): (usize, Tree, usize)) -> Box<Tree> {
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
|
||||||
(_, __0, _): (usize, Tree, usize),
|
|
||||||
) -> Box<Tree>
|
|
||||||
{
|
|
||||||
Box::new(__0)
|
Box::new(__0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action22<
|
fn __action22<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, __0, _): (usize, alloc::vec::Vec<Tree>, usize),
|
(_, __0, _): (usize, alloc::vec::Vec<Tree>, usize),
|
||||||
) -> Rc<[Tree]>
|
) -> Rc<[Tree]> {
|
||||||
{
|
|
||||||
__0.into()
|
__0.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action23<
|
fn __action23<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, __0, _): (usize, alloc::vec::Vec<String>, usize),
|
(_, __0, _): (usize, alloc::vec::Vec<String>, usize),
|
||||||
) -> Rc<[String]>
|
) -> Rc<[String]> {
|
||||||
{
|
|
||||||
__0.into()
|
__0.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action24<
|
fn __action24<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, __0, _): (usize, Tree, usize),
|
(_, __0, _): (usize, Tree, usize),
|
||||||
) -> alloc::vec::Vec<Tree>
|
) -> alloc::vec::Vec<Tree> {
|
||||||
{
|
|
||||||
alloc::vec![__0]
|
alloc::vec![__0]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action25<
|
fn __action25<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, v, _): (usize, alloc::vec::Vec<Tree>, usize),
|
(_, v, _): (usize, alloc::vec::Vec<Tree>, usize),
|
||||||
(_, e, _): (usize, Tree, usize),
|
(_, e, _): (usize, Tree, usize),
|
||||||
) -> alloc::vec::Vec<Tree>
|
) -> alloc::vec::Vec<Tree> {
|
||||||
{
|
{
|
||||||
{ let mut v = v; v.push(e); v }
|
let mut v = v;
|
||||||
|
v.push(e);
|
||||||
|
v
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action26<
|
fn __action26<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, __0, _): (usize, (), usize),
|
(_, __0, _): (usize, (), usize),
|
||||||
) -> core::option::Option<()>
|
) -> core::option::Option<()> {
|
||||||
{
|
|
||||||
Some(__0)
|
Some(__0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action27<
|
fn __action27<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
__lookbehind: &usize,
|
__lookbehind: &usize,
|
||||||
__lookahead: &usize,
|
__lookahead: &usize,
|
||||||
) -> core::option::Option<()>
|
) -> core::option::Option<()> {
|
||||||
{
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action28<
|
fn __action28<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
__lookbehind: &usize,
|
__lookbehind: &usize,
|
||||||
__lookahead: &usize,
|
__lookahead: &usize,
|
||||||
) -> alloc::vec::Vec<String>
|
) -> alloc::vec::Vec<String> {
|
||||||
{
|
|
||||||
alloc::vec![]
|
alloc::vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action29<
|
fn __action29<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, v, _): (usize, alloc::vec::Vec<String>, usize),
|
(_, v, _): (usize, alloc::vec::Vec<String>, usize),
|
||||||
) -> alloc::vec::Vec<String>
|
) -> alloc::vec::Vec<String> {
|
||||||
{
|
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action30<
|
fn __action30<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
__lookbehind: &usize,
|
__lookbehind: &usize,
|
||||||
__lookahead: &usize,
|
__lookahead: &usize,
|
||||||
) -> alloc::vec::Vec<Tree>
|
) -> alloc::vec::Vec<Tree> {
|
||||||
{
|
|
||||||
alloc::vec![]
|
alloc::vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action31<
|
fn __action31<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, v, _): (usize, alloc::vec::Vec<Tree>, usize),
|
(_, v, _): (usize, alloc::vec::Vec<Tree>, usize),
|
||||||
) -> alloc::vec::Vec<Tree>
|
) -> alloc::vec::Vec<Tree> {
|
||||||
{
|
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action32<
|
fn __action32<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, __0, _): (usize, String, usize),
|
(_, __0, _): (usize, String, usize),
|
||||||
) -> alloc::vec::Vec<String>
|
) -> alloc::vec::Vec<String> {
|
||||||
{
|
|
||||||
alloc::vec![__0]
|
alloc::vec![__0]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action33<
|
fn __action33<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
(_, v, _): (usize, alloc::vec::Vec<String>, usize),
|
(_, v, _): (usize, alloc::vec::Vec<String>, usize),
|
||||||
(_, e, _): (usize, String, usize),
|
(_, e, _): (usize, String, usize),
|
||||||
) -> alloc::vec::Vec<String>
|
) -> alloc::vec::Vec<String> {
|
||||||
{
|
{
|
||||||
{ let mut v = v; v.push(e); v }
|
let mut v = v;
|
||||||
|
v.push(e);
|
||||||
|
v
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action34<
|
fn __action34<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
__0: (usize, (), usize),
|
__0: (usize, (), usize),
|
||||||
__1: (usize, alloc::vec::Vec<Tree>, usize),
|
__1: (usize, alloc::vec::Vec<Tree>, usize),
|
||||||
) -> alloc::vec::Vec<Tree>
|
) -> alloc::vec::Vec<Tree> {
|
||||||
{
|
|
||||||
let __start0 = __0.0.clone();
|
let __start0 = __0.0.clone();
|
||||||
let __end0 = __0.2.clone();
|
let __end0 = __0.2.clone();
|
||||||
let __temp0 = __action26(
|
let __temp0 = __action26(input, __0);
|
||||||
input,
|
|
||||||
__0,
|
|
||||||
);
|
|
||||||
let __temp0 = (__start0, __temp0, __end0);
|
let __temp0 = (__start0, __temp0, __end0);
|
||||||
__action2(
|
__action2(input, __temp0, __1)
|
||||||
input,
|
|
||||||
__temp0,
|
|
||||||
__1,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action35<
|
fn __action35<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
__0: (usize, alloc::vec::Vec<Tree>, usize),
|
__0: (usize, alloc::vec::Vec<Tree>, usize),
|
||||||
) -> alloc::vec::Vec<Tree>
|
) -> alloc::vec::Vec<Tree> {
|
||||||
{
|
|
||||||
let __start0 = __0.0.clone();
|
let __start0 = __0.0.clone();
|
||||||
let __end0 = __0.0.clone();
|
let __end0 = __0.0.clone();
|
||||||
let __temp0 = __action27(
|
let __temp0 = __action27(input, &__start0, &__end0);
|
||||||
input,
|
|
||||||
&__start0,
|
|
||||||
&__end0,
|
|
||||||
);
|
|
||||||
let __temp0 = (__start0, __temp0, __end0);
|
let __temp0 = (__start0, __temp0, __end0);
|
||||||
__action2(
|
__action2(input, __temp0, __0)
|
||||||
input,
|
|
||||||
__temp0,
|
|
||||||
__0,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action36<
|
fn __action36<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
__lookbehind: &usize,
|
__lookbehind: &usize,
|
||||||
__lookahead: &usize,
|
__lookahead: &usize,
|
||||||
) -> Rc<[String]>
|
) -> Rc<[String]> {
|
||||||
{
|
|
||||||
let __start0 = __lookbehind.clone();
|
let __start0 = __lookbehind.clone();
|
||||||
let __end0 = __lookahead.clone();
|
let __end0 = __lookahead.clone();
|
||||||
let __temp0 = __action28(
|
let __temp0 = __action28(input, &__start0, &__end0);
|
||||||
input,
|
|
||||||
&__start0,
|
|
||||||
&__end0,
|
|
||||||
);
|
|
||||||
let __temp0 = (__start0, __temp0, __end0);
|
let __temp0 = (__start0, __temp0, __end0);
|
||||||
__action23(
|
__action23(input, __temp0)
|
||||||
input,
|
|
||||||
__temp0,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action37<
|
fn __action37<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
__0: (usize, alloc::vec::Vec<String>, usize),
|
__0: (usize, alloc::vec::Vec<String>, usize),
|
||||||
) -> Rc<[String]>
|
) -> Rc<[String]> {
|
||||||
{
|
|
||||||
let __start0 = __0.0.clone();
|
let __start0 = __0.0.clone();
|
||||||
let __end0 = __0.2.clone();
|
let __end0 = __0.2.clone();
|
||||||
let __temp0 = __action29(
|
let __temp0 = __action29(input, __0);
|
||||||
input,
|
|
||||||
__0,
|
|
||||||
);
|
|
||||||
let __temp0 = (__start0, __temp0, __end0);
|
let __temp0 = (__start0, __temp0, __end0);
|
||||||
__action23(
|
__action23(input, __temp0)
|
||||||
input,
|
|
||||||
__temp0,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action38<
|
fn __action38<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
__lookbehind: &usize,
|
__lookbehind: &usize,
|
||||||
__lookahead: &usize,
|
__lookahead: &usize,
|
||||||
) -> Rc<[Tree]>
|
) -> Rc<[Tree]> {
|
||||||
{
|
|
||||||
let __start0 = __lookbehind.clone();
|
let __start0 = __lookbehind.clone();
|
||||||
let __end0 = __lookahead.clone();
|
let __end0 = __lookahead.clone();
|
||||||
let __temp0 = __action30(
|
let __temp0 = __action30(input, &__start0, &__end0);
|
||||||
input,
|
|
||||||
&__start0,
|
|
||||||
&__end0,
|
|
||||||
);
|
|
||||||
let __temp0 = (__start0, __temp0, __end0);
|
let __temp0 = (__start0, __temp0, __end0);
|
||||||
__action22(
|
__action22(input, __temp0)
|
||||||
input,
|
|
||||||
__temp0,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn __action39<
|
fn __action39<'input, 's>(
|
||||||
'input,
|
|
||||||
's,
|
|
||||||
>(
|
|
||||||
input: &'input str,
|
input: &'input str,
|
||||||
__0: (usize, alloc::vec::Vec<Tree>, usize),
|
__0: (usize, alloc::vec::Vec<Tree>, usize),
|
||||||
) -> Rc<[Tree]>
|
) -> Rc<[Tree]> {
|
||||||
{
|
|
||||||
let __start0 = __0.0.clone();
|
let __start0 = __0.0.clone();
|
||||||
let __end0 = __0.2.clone();
|
let __end0 = __0.2.clone();
|
||||||
let __temp0 = __action31(
|
let __temp0 = __action31(input, __0);
|
||||||
input,
|
|
||||||
__0,
|
|
||||||
);
|
|
||||||
let __temp0 = (__start0, __temp0, __end0);
|
let __temp0 = (__start0, __temp0, __end0);
|
||||||
__action22(
|
__action22(input, __temp0)
|
||||||
input,
|
|
||||||
__temp0,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait __ToTriple<'input, 's, > {
|
pub trait __ToTriple<'input, 's> {
|
||||||
fn to_triple(value: Self) -> Result<(usize,Token<'input>,usize), __lalrpop_util::ParseError<usize, Token<'input>, &'static str>>;
|
fn to_triple(
|
||||||
|
value: Self,
|
||||||
|
) -> Result<
|
||||||
|
(usize, Token<'input>, usize),
|
||||||
|
__lalrpop_util::ParseError<usize, Token<'input>, &'static str>,
|
||||||
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'input, 's, > __ToTriple<'input, 's, > for (usize, Token<'input>, usize) {
|
impl<'input, 's> __ToTriple<'input, 's> for (usize, Token<'input>, usize) {
|
||||||
fn to_triple(value: Self) -> Result<(usize,Token<'input>,usize), __lalrpop_util::ParseError<usize, Token<'input>, &'static str>> {
|
fn to_triple(
|
||||||
|
value: Self,
|
||||||
|
) -> Result<
|
||||||
|
(usize, Token<'input>, usize),
|
||||||
|
__lalrpop_util::ParseError<usize, Token<'input>, &'static str>,
|
||||||
|
> {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'input, 's, > __ToTriple<'input, 's, > for Result<(usize, Token<'input>, usize), &'static str> {
|
impl<'input, 's> __ToTriple<'input, 's> for Result<(usize, Token<'input>, usize), &'static str> {
|
||||||
fn to_triple(value: Self) -> Result<(usize,Token<'input>,usize), __lalrpop_util::ParseError<usize, Token<'input>, &'static str>> {
|
fn to_triple(
|
||||||
|
value: Self,
|
||||||
|
) -> Result<
|
||||||
|
(usize, Token<'input>, usize),
|
||||||
|
__lalrpop_util::ParseError<usize, Token<'input>, &'static str>,
|
||||||
|
> {
|
||||||
match value {
|
match value {
|
||||||
Ok(v) => Ok(v),
|
Ok(v) => Ok(v),
|
||||||
Err(error) => Err(__lalrpop_util::ParseError::User { error }),
|
Err(error) => Err(__lalrpop_util::ParseError::User { error }),
|
||||||
|
|
367
src/main.rs
367
src/main.rs
|
@ -1,150 +1,25 @@
|
||||||
#![feature(array_windows)]
|
#![feature(array_windows)]
|
||||||
#![feature(assert_matches)]
|
#![feature(assert_matches)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
|
#![feature(crate_visibility_modifier)]
|
||||||
#![feature(let_else)]
|
#![feature(let_else)]
|
||||||
|
|
||||||
mod grammar;
|
use std::io;
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests;
|
|
||||||
|
|
||||||
// use debug2::dbg;
|
|
||||||
use rustyline::validate::{
|
use rustyline::validate::{
|
||||||
MatchingBracketValidator, ValidationContext, ValidationResult, Validator,
|
MatchingBracketValidator, ValidationContext, ValidationResult, Validator,
|
||||||
};
|
};
|
||||||
use rustyline::Editor;
|
use rustyline::Editor;
|
||||||
use rustyline_derive::{Completer, Helper, Highlighter, Hinter};
|
use rustyline_derive::{Completer, Helper, Highlighter, Hinter};
|
||||||
use std::assert_matches::assert_matches;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::io;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
#[derive(Debug, debug2::Debug, PartialEq)]
|
mod ast;
|
||||||
enum Tree {
|
mod eval;
|
||||||
Leaf(Literal),
|
#[allow(clippy::all)]
|
||||||
Define(String, Box<Tree>),
|
mod grammar;
|
||||||
If(Box<[Tree; 3]>),
|
mod prims;
|
||||||
Lambda(Lambda),
|
#[cfg(test)]
|
||||||
Branch(Vec<Tree>),
|
mod tests;
|
||||||
}
|
mod value;
|
||||||
|
|
||||||
#[derive(Debug, debug2::Debug, PartialEq, Clone)]
|
|
||||||
struct Lambda(Rc<[String]>, Rc<[Tree]>);
|
|
||||||
|
|
||||||
#[derive(Debug, debug2::Debug, PartialEq)]
|
|
||||||
enum Literal {
|
|
||||||
Sym(String),
|
|
||||||
Num(f64),
|
|
||||||
Bool(bool),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct RTError(String);
|
|
||||||
|
|
||||||
fn err<T>(s: String) -> Result<T, RTError> {
|
|
||||||
Err(RTError(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Func = fn(&[Value]) -> Result<Value, RTError>;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
enum Value {
|
|
||||||
Num(f64),
|
|
||||||
Func(Func),
|
|
||||||
Lambda(Lambda),
|
|
||||||
Bool(bool),
|
|
||||||
NotAValue,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Value {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
use Value::*;
|
|
||||||
match (self, other) {
|
|
||||||
(Num(l), Num(r)) => l == r,
|
|
||||||
(Func(l), Func(r)) => *l as usize == *r as usize,
|
|
||||||
(Bool(l), Bool(r)) => l == r,
|
|
||||||
(Lambda(l), Lambda(r)) => Rc::ptr_eq(&l.0, &r.0) && Rc::ptr_eq(&l.1, &r.1),
|
|
||||||
|
|
||||||
(Num(_), _) => false,
|
|
||||||
(Func(_), _) => false,
|
|
||||||
(Bool(_), _) => false,
|
|
||||||
(Lambda(_), _) => false,
|
|
||||||
|
|
||||||
(NotAValue, _) => panic!("Trap value"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for Value {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Num(n) => n.fmt(f),
|
|
||||||
Self::Func(_) => f.write_str("#<procedure>"),
|
|
||||||
Self::Lambda(_) => f.write_str("#<procedure>"),
|
|
||||||
Self::Bool(b) => f.write_str(if *b { "#t" } else { "#f" }),
|
|
||||||
Self::NotAValue => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Value {
|
|
||||||
fn as_num(&self) -> Result<f64, RTError> {
|
|
||||||
if let Self::Num(n) = self {
|
|
||||||
Ok(*n)
|
|
||||||
} else {
|
|
||||||
Err(RTError("Expected a number".to_owned()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_func(&self) -> Result<Callable, RTError> {
|
|
||||||
match self {
|
|
||||||
Self::Func(f) => Ok(Callable::Func(*f)),
|
|
||||||
Self::Lambda(l) => Ok(Callable::Lambda(l)),
|
|
||||||
_ => Err(RTError(format!("Expected a function, got {:?}", self))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_bool(&self) -> Result<bool, RTError> {
|
|
||||||
if let Self::Bool(b) = self {
|
|
||||||
Ok(*b)
|
|
||||||
} else {
|
|
||||||
Err(RTError("Expected a bool".to_owned()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Callable<'a> {
|
|
||||||
Func(Func),
|
|
||||||
Lambda(&'a Lambda),
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Env<'a> {
|
|
||||||
vars: HashMap<String, Value>,
|
|
||||||
enclosing: Option<&'a Env<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Env<'a> {
|
|
||||||
fn child(&'a self) -> Env<'a> {
|
|
||||||
Env {
|
|
||||||
vars: HashMap::new(),
|
|
||||||
enclosing: Some(self),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lookup(&self, s: &str) -> Option<Value> {
|
|
||||||
if let Some(v) = self.vars.get(s) {
|
|
||||||
Some(v.clone())
|
|
||||||
} else if let Some(parent) = self.enclosing {
|
|
||||||
parent.lookup(s)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn define(&mut self, name: String, val: Value) {
|
|
||||||
self.vars.insert(name, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = std::env::args().collect::<Vec<_>>();
|
let args = std::env::args().collect::<Vec<_>>();
|
||||||
|
@ -158,9 +33,9 @@ fn main() {
|
||||||
fn run_file(file: &str) -> io::Result<()> {
|
fn run_file(file: &str) -> io::Result<()> {
|
||||||
let src = std::fs::read_to_string(file)?;
|
let src = std::fs::read_to_string(file)?;
|
||||||
let tree = grammar::FileParser::new().parse(&src).unwrap();
|
let tree = grammar::FileParser::new().parse(&src).unwrap();
|
||||||
let mut env = default_env();
|
let mut env = eval::default_env();
|
||||||
for i in tree {
|
for i in tree {
|
||||||
eval(&i, &mut env).unwrap();
|
eval::eval(&i, &mut env).unwrap();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -171,231 +46,17 @@ fn repl() {
|
||||||
brackets: MatchingBracketValidator::new(),
|
brackets: MatchingBracketValidator::new(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let mut env = default_env();
|
let mut env = eval::default_env();
|
||||||
|
|
||||||
while let Ok(line) = rl.readline("> ") {
|
while let Ok(line) = rl.readline("> ") {
|
||||||
rl.add_history_entry(&line);
|
rl.add_history_entry(&line);
|
||||||
|
|
||||||
let tree = grammar::TreeParser::new().parse(&line).unwrap();
|
let tree = grammar::TreeParser::new().parse(&line).unwrap();
|
||||||
// dbg!(&tree);
|
// dbg!(&tree);
|
||||||
println!("< {:?}", eval(&tree, &mut env))
|
println!("< {:?}", eval::eval(&tree, &mut env))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(t: &Tree, env: &mut Env) -> Result<Value, RTError> {
|
|
||||||
Ok(match t {
|
|
||||||
Tree::Leaf(l) => match l {
|
|
||||||
Literal::Sym(s) => match env.lookup(s) {
|
|
||||||
Some(v) => v.clone(),
|
|
||||||
None => return err(format!("Undefined variable `{}`", s)),
|
|
||||||
},
|
|
||||||
Literal::Num(v) => Value::Num(*v),
|
|
||||||
Literal::Bool(b) => Value::Bool(*b),
|
|
||||||
},
|
|
||||||
Tree::Lambda(l) => Value::Lambda(l.clone()),
|
|
||||||
Tree::Branch(args) => {
|
|
||||||
let Some(fun) = args.get(0) else { return err("No argument given".to_owned()) };
|
|
||||||
let fun = eval(fun, env)?;
|
|
||||||
let fun = fun.as_func()?;
|
|
||||||
let args = args
|
|
||||||
.iter()
|
|
||||||
.skip(1)
|
|
||||||
.map(|a| eval(a, env))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
// return fun(&args);
|
|
||||||
match fun {
|
|
||||||
Callable::Func(f) => f(&args)?,
|
|
||||||
Callable::Lambda(l) => {
|
|
||||||
if l.0.len() == args.len() {
|
|
||||||
let mut env = env.child();
|
|
||||||
for (x, y) in l.0.iter().zip(args) {
|
|
||||||
env.define(x.clone(), y)
|
|
||||||
}
|
|
||||||
|
|
||||||
let [main @ .., tail] = &l.1[..] else { unreachable!("Body has 1+ element by parser") };
|
|
||||||
for i in main {
|
|
||||||
eval(i, &mut env)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
eval(tail, &mut env)?
|
|
||||||
} else {
|
|
||||||
return err(format!("Need {} args, got {}", l.0.len(), args.len()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Tree::Define(name, to) => {
|
|
||||||
let val = eval(to, env)?;
|
|
||||||
env.define(name.to_owned(), val);
|
|
||||||
Value::NotAValue
|
|
||||||
}
|
|
||||||
Tree::If(box [cond, tcase, fcase]) => {
|
|
||||||
let b = eval(cond, env)?.as_bool()?;
|
|
||||||
let body = if b { tcase } else { fcase };
|
|
||||||
eval(body, env)?
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn default_env() -> Env<'static> {
|
|
||||||
let mut vars = HashMap::new();
|
|
||||||
|
|
||||||
for (name, fun) in prims::prims() {
|
|
||||||
assert_matches!(vars.insert((*name).to_owned(), Value::Func(*fun)), None)
|
|
||||||
}
|
|
||||||
|
|
||||||
Env {
|
|
||||||
vars,
|
|
||||||
enclosing: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod prims {
|
|
||||||
use crate::{err, Func, RTError, Value};
|
|
||||||
|
|
||||||
pub(crate) fn prims() -> &'static [(&'static str, Func)] {
|
|
||||||
&[
|
|
||||||
("*", mul),
|
|
||||||
("+", add),
|
|
||||||
("-", sub),
|
|
||||||
("/", div),
|
|
||||||
// TODO: Spec compiance
|
|
||||||
("=", equals),
|
|
||||||
("eq?", equals),
|
|
||||||
("eqv?", equals),
|
|
||||||
("equal?", equals),
|
|
||||||
("display", display),
|
|
||||||
("newline", newline),
|
|
||||||
("abs", abs),
|
|
||||||
("<", lt),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: DRY +-/*
|
|
||||||
fn add(args: &[Value]) -> Result<Value, RTError> {
|
|
||||||
args.iter()
|
|
||||||
.map(Value::as_num)
|
|
||||||
.try_fold(0.0, |a, b| Ok(a + b?))
|
|
||||||
.map(Value::Num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mul(args: &[Value]) -> Result<Value, RTError> {
|
|
||||||
args.iter()
|
|
||||||
.map(Value::as_num)
|
|
||||||
.try_fold(1.0, |a, b| Ok(a * b?))
|
|
||||||
.map(Value::Num)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn div(args: &[Value]) -> Result<Value, RTError> {
|
|
||||||
let init = args
|
|
||||||
.get(0)
|
|
||||||
.ok_or_else(|| RTError("`div` needs at least one argument".to_owned()))?
|
|
||||||
.as_num()?;
|
|
||||||
|
|
||||||
Ok(Value::Num(if args.len() == 1 {
|
|
||||||
1.0 / init
|
|
||||||
} else {
|
|
||||||
let rest = mul(&args[1..])?.as_num().unwrap();
|
|
||||||
init / rest
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sub(args: &[Value]) -> Result<Value, RTError> {
|
|
||||||
let init = args
|
|
||||||
.get(0)
|
|
||||||
.ok_or_else(|| RTError("`sub` needs at least one argument".to_owned()))?
|
|
||||||
.as_num()?;
|
|
||||||
|
|
||||||
Ok(Value::Num(if args.len() == 1 {
|
|
||||||
-init
|
|
||||||
} else {
|
|
||||||
let rest = add(&args[1..])?.as_num().unwrap();
|
|
||||||
init - rest
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn equals(args: &[Value]) -> Result<Value, RTError> {
|
|
||||||
Ok(Value::Bool(args.array_windows().all(|[l, r]| l == r)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn display(args: &[Value]) -> Result<Value, RTError> {
|
|
||||||
let [arg] = args else {return err("To many args to `display`".to_owned())};
|
|
||||||
print!("{:?}", arg);
|
|
||||||
Ok(Value::NotAValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn newline(args: &[Value]) -> Result<Value, RTError> {
|
|
||||||
if !args.is_empty() {
|
|
||||||
return err("Newline takes no args".to_owned());
|
|
||||||
}
|
|
||||||
println!("");
|
|
||||||
Ok(Value::NotAValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn abs(args: &[Value]) -> Result<Value, RTError> {
|
|
||||||
let [v] = args else { return err("abs takes 1 arg".to_owned()) };
|
|
||||||
let ans = v.as_num()?.abs();
|
|
||||||
Ok(Value::Num(ans))
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: gt le ge
|
|
||||||
fn lt(args: &[Value]) -> Result<Value, RTError> {
|
|
||||||
for [l, r] in args.array_windows() {
|
|
||||||
let (Value::Num(l), Value::Num(r)) = (l,r) else { return err("lt args must be numbers".to_owned()); };
|
|
||||||
if !(l < r) {
|
|
||||||
return Ok(Value::Bool(false));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Value::Bool(true))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[cfg(test)]
|
|
||||||
// mod tests {
|
|
||||||
// use super::*;
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn simple_math_space() {
|
|
||||||
// let t = grammar::TreeParser::new()
|
|
||||||
// .parse("( + 1 2 ( / 2 3 4 5) )")
|
|
||||||
// .unwrap();
|
|
||||||
// assert_eq!(
|
|
||||||
// t,
|
|
||||||
// Tree::Add(vec![
|
|
||||||
// Tree::Val(1.0),
|
|
||||||
// Tree::Val(2.0),
|
|
||||||
// Tree::Div(vec![
|
|
||||||
// Tree::Val(2.0),
|
|
||||||
// Tree::Val(3.0),
|
|
||||||
// Tree::Val(4.0),
|
|
||||||
// Tree::Val(5.0),
|
|
||||||
// ])
|
|
||||||
// ])
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn simple_math_dence() {
|
|
||||||
// let t = grammar::TreeParser::new()
|
|
||||||
// .parse("(+ 1 2 (/ 2 3 4 5))")
|
|
||||||
// .unwrap();
|
|
||||||
// assert_eq!(
|
|
||||||
// t,
|
|
||||||
// Tree::Add(vec![
|
|
||||||
// Tree::Val(1.0),
|
|
||||||
// Tree::Val(2.0),
|
|
||||||
// Tree::Div(vec![
|
|
||||||
// Tree::Val(2.0),
|
|
||||||
// Tree::Val(3.0),
|
|
||||||
// Tree::Val(4.0),
|
|
||||||
// Tree::Val(5.0),
|
|
||||||
// ])
|
|
||||||
// ])
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[derive(Completer, Helper, Highlighter, Hinter)]
|
#[derive(Completer, Helper, Highlighter, Hinter)]
|
||||||
struct InputValidator {
|
struct InputValidator {
|
||||||
brackets: MatchingBracketValidator,
|
brackets: MatchingBracketValidator,
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
use crate::eval::{err, RTError};
|
||||||
|
use crate::value::Value;
|
||||||
|
|
||||||
|
crate type Func = fn(&[Value]) -> Result<Value, RTError>;
|
||||||
|
|
||||||
|
crate fn prims() -> &'static [(&'static str, Func)] {
|
||||||
|
&[
|
||||||
|
("*", mul),
|
||||||
|
("+", add),
|
||||||
|
("-", sub),
|
||||||
|
("/", div),
|
||||||
|
// TODO: Spec compiance
|
||||||
|
("=", equals),
|
||||||
|
("eq?", equals),
|
||||||
|
("eqv?", equals),
|
||||||
|
("equal?", equals),
|
||||||
|
("display", display),
|
||||||
|
("newline", newline),
|
||||||
|
("abs", abs),
|
||||||
|
("<", lt),
|
||||||
|
(">", gt),
|
||||||
|
("<=", le),
|
||||||
|
(">=", ge),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: DRY +-/*
|
||||||
|
fn add(args: &[Value]) -> Result<Value, RTError> {
|
||||||
|
args.iter()
|
||||||
|
.map(Value::as_num)
|
||||||
|
.try_fold(0.0, |a, b| Ok(a + b?))
|
||||||
|
.map(Value::Num)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mul(args: &[Value]) -> Result<Value, RTError> {
|
||||||
|
args.iter()
|
||||||
|
.map(Value::as_num)
|
||||||
|
.try_fold(1.0, |a, b| Ok(a * b?))
|
||||||
|
.map(Value::Num)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn div(args: &[Value]) -> Result<Value, RTError> {
|
||||||
|
let init = args
|
||||||
|
.get(0)
|
||||||
|
.ok_or_else(|| RTError("`div` needs at least one argument".to_owned()))?
|
||||||
|
.as_num()?;
|
||||||
|
|
||||||
|
Ok(Value::Num(if args.len() == 1 {
|
||||||
|
1.0 / init
|
||||||
|
} else {
|
||||||
|
let rest = mul(&args[1..])?.as_num().unwrap();
|
||||||
|
init / rest
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sub(args: &[Value]) -> Result<Value, RTError> {
|
||||||
|
let init = args
|
||||||
|
.get(0)
|
||||||
|
.ok_or_else(|| RTError("`sub` needs at least one argument".to_owned()))?
|
||||||
|
.as_num()?;
|
||||||
|
|
||||||
|
Ok(Value::Num(if args.len() == 1 {
|
||||||
|
-init
|
||||||
|
} else {
|
||||||
|
let rest = add(&args[1..])?.as_num().unwrap();
|
||||||
|
init - rest
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn equals(args: &[Value]) -> Result<Value, RTError> {
|
||||||
|
Ok(Value::Bool(args.array_windows().all(|[l, r]| l == r)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display(args: &[Value]) -> Result<Value, RTError> {
|
||||||
|
let [arg] = args else {return err("To many args to `display`".to_owned())};
|
||||||
|
print!("{:?}", arg);
|
||||||
|
Ok(Value::Trap)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn newline(args: &[Value]) -> Result<Value, RTError> {
|
||||||
|
if !args.is_empty() {
|
||||||
|
return err("Newline takes no args".to_owned());
|
||||||
|
}
|
||||||
|
println!();
|
||||||
|
Ok(Value::Trap)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn abs(args: &[Value]) -> Result<Value, RTError> {
|
||||||
|
let [v] = args else { return err("abs takes 1 arg".to_owned()) };
|
||||||
|
let ans = v.as_num()?.abs();
|
||||||
|
Ok(Value::Num(ans))
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn compare_core(
|
||||||
|
args: &[Value],
|
||||||
|
f: fn(f64, f64) -> bool,
|
||||||
|
name: &'static str,
|
||||||
|
) -> Result<Value, RTError> {
|
||||||
|
for [l, r] in args.array_windows() {
|
||||||
|
let (Value::Num(l), Value::Num(r)) = (l,r) else
|
||||||
|
{
|
||||||
|
return err(format!("`{}` args must be numbers", name));
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Ensure this is correct wrt NaN
|
||||||
|
if !f(*l, *r) {
|
||||||
|
return Ok(Value::Bool(false));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Value::Bool(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! cmps {
|
||||||
|
($(($name:ident $op:tt))*) => {
|
||||||
|
$(
|
||||||
|
fn $name(args: &[Value]) -> Result<Value, RTError> {
|
||||||
|
compare_core(args, |l, r| l $op r, stringify!($op))
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
cmps! { (lt <) (gt >) (le <=) (ge >=) }
|
|
@ -0,0 +1,72 @@
|
||||||
|
use crate::{ast, eval, prims};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
crate enum Value {
|
||||||
|
Num(f64),
|
||||||
|
Func(prims::Func),
|
||||||
|
Lambda(ast::Lambda),
|
||||||
|
Bool(bool),
|
||||||
|
/// Result of things that shouldnt have values, like (define x 3)
|
||||||
|
Trap,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Value {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
use Value::*;
|
||||||
|
match (self, other) {
|
||||||
|
(Num(l), Num(r)) => l == r,
|
||||||
|
(Func(l), Func(r)) => *l as usize == *r as usize,
|
||||||
|
(Bool(l), Bool(r)) => l == r,
|
||||||
|
(Lambda(l), Lambda(r)) => Rc::ptr_eq(&l.0, &r.0) && Rc::ptr_eq(&l.1, &r.1),
|
||||||
|
|
||||||
|
(Num(_), _) => false,
|
||||||
|
(Func(_), _) => false,
|
||||||
|
(Bool(_), _) => false,
|
||||||
|
(Lambda(_), _) => false,
|
||||||
|
|
||||||
|
(Trap, _) => panic!("Trap value"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Value {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Num(n) => n.fmt(f),
|
||||||
|
Self::Func(_) => f.write_str("#<procedure>"),
|
||||||
|
Self::Lambda(_) => f.write_str("#<procedure>"),
|
||||||
|
Self::Bool(b) => f.write_str(if *b { "#t" } else { "#f" }),
|
||||||
|
Self::Trap => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
crate fn as_num(&self) -> Result<f64, eval::RTError> {
|
||||||
|
if let Self::Num(n) = self {
|
||||||
|
Ok(*n)
|
||||||
|
} else {
|
||||||
|
Err(eval::RTError("Expected a number".to_owned()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn as_func(&self) -> Result<eval::Callable, eval::RTError> {
|
||||||
|
match self {
|
||||||
|
Self::Func(f) => Ok(eval::Callable::Func(*f)),
|
||||||
|
Self::Lambda(l) => Ok(eval::Callable::Lambda(l)),
|
||||||
|
_ => Err(eval::RTError(format!(
|
||||||
|
"Expected a function, got {:?}",
|
||||||
|
self
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate fn as_bool(&self) -> Result<bool, eval::RTError> {
|
||||||
|
if let Self::Bool(b) = self {
|
||||||
|
Ok(*b)
|
||||||
|
} else {
|
||||||
|
Err(eval::RTError("Expected a bool".to_owned()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue