parent
69b7714892
commit
dadf839cca
|
@ -3,13 +3,14 @@ use std::rc::Rc;
|
|||
|
||||
grammar<'s>();
|
||||
|
||||
pub(crate) Trees = Tree+;
|
||||
|
||||
pub(crate) Tree: Tree = {
|
||||
"(" <Tree+> ")" => Tree::Branch(<>),
|
||||
"(" "define" <Sym> <BTree> ")" => Tree::Define(<>),
|
||||
"(" "define" "(" <name:Sym> <args:RcSlice<Sym>> ")" <body:Rc<Tree>> ")" => Tree::Define(name, Box::new(Tree::Lambda(Lambda(args, body)))),
|
||||
"(" "define" "(" <name:Sym> <args:RcSlice<Sym>> ")" <body:RcSlice<Tree>> ")" => Tree::Define(name, Box::new(Tree::Lambda(Lambda(args, body)))),
|
||||
"(" "if" <Tree> <Tree> <Tree> ")" => Tree::If(Box::new([<>])),
|
||||
"(" "lambda (" <RcSlice<Sym>> ")" <Rc<Tree>> ")" => Tree::Lambda(Lambda(<>)),
|
||||
"(" "lambda (" <RcSlice<Sym>> ")" <RcSlice<Tree>> ")" => Tree::Lambda(Lambda(<>)),
|
||||
Literal => Tree::Leaf(<>),
|
||||
}
|
||||
|
||||
|
|
1941
src/grammar.rs
1941
src/grammar.rs
File diff suppressed because it is too large
Load Diff
75
src/main.rs
75
src/main.rs
|
@ -4,13 +4,14 @@
|
|||
|
||||
mod grammar;
|
||||
|
||||
use debug2::dbg;
|
||||
// use debug2::dbg;
|
||||
use rustyline::validate::{
|
||||
MatchingBracketValidator, ValidationContext, ValidationResult, Validator,
|
||||
};
|
||||
use rustyline::Editor;
|
||||
use rustyline_derive::{Completer, Helper, Highlighter, Hinter};
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, debug2::Debug, PartialEq)]
|
||||
|
@ -23,7 +24,7 @@ enum Tree {
|
|||
}
|
||||
|
||||
#[derive(Debug, debug2::Debug, PartialEq, Clone)]
|
||||
struct Lambda(Rc<[String]>, Rc<Tree>);
|
||||
struct Lambda(Rc<[String]>, Rc<[Tree]>);
|
||||
|
||||
#[derive(Debug, debug2::Debug, PartialEq)]
|
||||
enum Literal {
|
||||
|
@ -94,7 +95,7 @@ impl Value {
|
|||
match self {
|
||||
Self::Func(f) => Ok(Callable::Func(*f)),
|
||||
Self::Lambda(l) => Ok(Callable::Lambda(l)),
|
||||
_ => Err(RTError("Expected a function".to_owned())),
|
||||
_ => Err(RTError(format!("Expected a function, got {:?}", self))),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,6 +142,25 @@ impl<'a> Env<'a> {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
let args = std::env::args().collect::<Vec<_>>();
|
||||
match &args[..] {
|
||||
[_] => repl(),
|
||||
[_, file] => run_file(file).unwrap(),
|
||||
_ => panic!("To many args `{:?}`", args),
|
||||
}
|
||||
}
|
||||
|
||||
fn run_file(file: &str) -> io::Result<()> {
|
||||
let src = std::fs::read_to_string(file)?;
|
||||
let tree = grammar::TreesParser::new().parse(&src).unwrap();
|
||||
let mut env = default_env();
|
||||
for i in tree {
|
||||
eval(&i, &mut env).unwrap();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn repl() {
|
||||
let mut rl = Editor::new();
|
||||
rl.set_helper(Some(InputValidator {
|
||||
brackets: MatchingBracketValidator::new(),
|
||||
|
@ -182,11 +202,17 @@ fn eval(t: &Tree, env: &mut Env) -> Result<Value, RTError> {
|
|||
Callable::Func(f) => f(&args)?,
|
||||
Callable::Lambda(l) => {
|
||||
if l.0.len() == args.len() {
|
||||
let mut new_env = env.child();
|
||||
let mut env = env.child();
|
||||
for (x, y) in l.0.iter().zip(args) {
|
||||
new_env.define(x.clone(), y)
|
||||
env.define(x.clone(), y)
|
||||
}
|
||||
eval(&l.1, &mut new_env)?
|
||||
|
||||
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()));
|
||||
}
|
||||
|
@ -214,7 +240,13 @@ fn default_env() -> Env<'static> {
|
|||
("+", prims::add as Func),
|
||||
("-", prims::sub as Func),
|
||||
("/", prims::div as Func),
|
||||
// TODO: Spec compiance
|
||||
("=", prims::equals as Func),
|
||||
("eq?", prims::equals as Func),
|
||||
("eqv?", prims::equals as Func),
|
||||
("equal?", prims::equals as Func),
|
||||
("display", prims::display as Func),
|
||||
("newline", prims::newline as Func),
|
||||
] {
|
||||
vars.insert(name.to_owned(), Value::Func(fun));
|
||||
}
|
||||
|
@ -226,8 +258,9 @@ fn default_env() -> Env<'static> {
|
|||
}
|
||||
|
||||
mod prims {
|
||||
use crate::{RTError, Value};
|
||||
use crate::{err, RTError, Value};
|
||||
|
||||
// TODO: DRY +-/*
|
||||
pub(crate) fn add(args: &[Value]) -> Result<Value, RTError> {
|
||||
args.iter()
|
||||
.map(Value::as_num)
|
||||
|
@ -247,8 +280,13 @@ mod prims {
|
|||
.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();
|
||||
Ok(Value::Num(init / rest))
|
||||
init / rest
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn sub(args: &[Value]) -> Result<Value, RTError> {
|
||||
|
@ -256,13 +294,32 @@ mod prims {
|
|||
.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();
|
||||
Ok(Value::Num(init - rest))
|
||||
init - rest
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn equals(args: &[Value]) -> Result<Value, RTError> {
|
||||
Ok(Value::Bool(args.array_windows().all(|[l, r]| l == r)))
|
||||
}
|
||||
|
||||
pub(crate) 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)
|
||||
}
|
||||
|
||||
pub(crate) fn newline(args: &[Value]) -> Result<Value, RTError> {
|
||||
if !args.is_empty() {
|
||||
return err("Newline takes no args".to_owned());
|
||||
}
|
||||
println!("");
|
||||
Ok(Value::NotAValue)
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
(define (displayln x) (display x) (newline))
|
||||
(define (printbool x) (displayln (bool->int x)))
|
||||
|
||||
(define (true x y) x)
|
||||
(define (false x y) y)
|
||||
(define (and x y) (x y x))
|
||||
(define (or x y) (x x y))
|
||||
(define (not x) (x false true))
|
||||
|
||||
(define (bool->int x)
|
||||
(if
|
||||
(equal? x true) 1
|
||||
(if (equal? x false) 0 (- 1))))
|
||||
|
||||
(printbool true)
|
||||
(printbool false)
|
||||
(printbool bool->int)
|
||||
(printbool (not true))
|
||||
(printbool (not false))
|
||||
(printbool (and true true))
|
||||
(printbool (and true false))
|
||||
(printbool (and false true))
|
||||
(printbool (and false false))
|
||||
(printbool (or true true))
|
||||
(printbool (or true false))
|
||||
(printbool (or false true))
|
||||
(printbool (or false false))
|
||||
(printbool (and (or true false) (or false true)))
|
|
@ -1 +1,16 @@
|
|||
( + 1 2 ( / 2 3 4 5) )
|
||||
(define (displayln x) (display x) (newline))
|
||||
|
||||
(displayln (+))
|
||||
(displayln (+ 1))
|
||||
(displayln (+ 1 2 3 4))
|
||||
(displayln (+))
|
||||
|
||||
(displayln (- 1))
|
||||
(displayln (- 1 2 3 4))
|
||||
|
||||
(displayln (* 1))
|
||||
(displayln (* 1 2))
|
||||
(displayln (*))
|
||||
|
||||
(displayln (/ 10))
|
||||
(displayln (/ 10 5 2))
|
||||
|
|
Loading…
Reference in New Issue