parent
69b7714892
commit
dadf839cca
|
@ -3,13 +3,14 @@ use std::rc::Rc;
|
||||||
|
|
||||||
grammar<'s>();
|
grammar<'s>();
|
||||||
|
|
||||||
|
pub(crate) Trees = Tree+;
|
||||||
|
|
||||||
pub(crate) Tree: Tree = {
|
pub(crate) Tree: Tree = {
|
||||||
"(" <Tree+> ")" => Tree::Branch(<>),
|
"(" <Tree+> ")" => Tree::Branch(<>),
|
||||||
"(" "define" <Sym> <BTree> ")" => Tree::Define(<>),
|
"(" "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([<>])),
|
"(" "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(<>),
|
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;
|
mod grammar;
|
||||||
|
|
||||||
use debug2::dbg;
|
// 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::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::io;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Debug, debug2::Debug, PartialEq)]
|
#[derive(Debug, debug2::Debug, PartialEq)]
|
||||||
|
@ -23,7 +24,7 @@ enum Tree {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, debug2::Debug, PartialEq, Clone)]
|
#[derive(Debug, debug2::Debug, PartialEq, Clone)]
|
||||||
struct Lambda(Rc<[String]>, Rc<Tree>);
|
struct Lambda(Rc<[String]>, Rc<[Tree]>);
|
||||||
|
|
||||||
#[derive(Debug, debug2::Debug, PartialEq)]
|
#[derive(Debug, debug2::Debug, PartialEq)]
|
||||||
enum Literal {
|
enum Literal {
|
||||||
|
@ -94,7 +95,7 @@ impl Value {
|
||||||
match self {
|
match self {
|
||||||
Self::Func(f) => Ok(Callable::Func(*f)),
|
Self::Func(f) => Ok(Callable::Func(*f)),
|
||||||
Self::Lambda(l) => Ok(Callable::Lambda(l)),
|
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() {
|
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();
|
let mut rl = Editor::new();
|
||||||
rl.set_helper(Some(InputValidator {
|
rl.set_helper(Some(InputValidator {
|
||||||
brackets: MatchingBracketValidator::new(),
|
brackets: MatchingBracketValidator::new(),
|
||||||
|
@ -182,11 +202,17 @@ fn eval(t: &Tree, env: &mut Env) -> Result<Value, RTError> {
|
||||||
Callable::Func(f) => f(&args)?,
|
Callable::Func(f) => f(&args)?,
|
||||||
Callable::Lambda(l) => {
|
Callable::Lambda(l) => {
|
||||||
if l.0.len() == args.len() {
|
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) {
|
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 {
|
} else {
|
||||||
return err(format!("Need {} args, got {}", l.0.len(), args.len()));
|
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::add as Func),
|
||||||
("-", prims::sub as Func),
|
("-", prims::sub as Func),
|
||||||
("/", prims::div as Func),
|
("/", prims::div as Func),
|
||||||
|
// TODO: Spec compiance
|
||||||
("=", prims::equals as Func),
|
("=", 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));
|
vars.insert(name.to_owned(), Value::Func(fun));
|
||||||
}
|
}
|
||||||
|
@ -226,8 +258,9 @@ fn default_env() -> Env<'static> {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod prims {
|
mod prims {
|
||||||
use crate::{RTError, Value};
|
use crate::{err, RTError, Value};
|
||||||
|
|
||||||
|
// TODO: DRY +-/*
|
||||||
pub(crate) fn add(args: &[Value]) -> Result<Value, RTError> {
|
pub(crate) fn add(args: &[Value]) -> Result<Value, RTError> {
|
||||||
args.iter()
|
args.iter()
|
||||||
.map(Value::as_num)
|
.map(Value::as_num)
|
||||||
|
@ -247,8 +280,13 @@ mod prims {
|
||||||
.get(0)
|
.get(0)
|
||||||
.ok_or_else(|| RTError("`div` needs at least one argument".to_owned()))?
|
.ok_or_else(|| RTError("`div` needs at least one argument".to_owned()))?
|
||||||
.as_num()?;
|
.as_num()?;
|
||||||
|
|
||||||
|
Ok(Value::Num(if args.len() == 1 {
|
||||||
|
1.0 / init
|
||||||
|
} else {
|
||||||
let rest = mul(&args[1..])?.as_num().unwrap();
|
let rest = mul(&args[1..])?.as_num().unwrap();
|
||||||
Ok(Value::Num(init / rest))
|
init / rest
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn sub(args: &[Value]) -> Result<Value, RTError> {
|
pub(crate) fn sub(args: &[Value]) -> Result<Value, RTError> {
|
||||||
|
@ -256,13 +294,32 @@ mod prims {
|
||||||
.get(0)
|
.get(0)
|
||||||
.ok_or_else(|| RTError("`sub` needs at least one argument".to_owned()))?
|
.ok_or_else(|| RTError("`sub` needs at least one argument".to_owned()))?
|
||||||
.as_num()?;
|
.as_num()?;
|
||||||
|
|
||||||
|
Ok(Value::Num(if args.len() == 1 {
|
||||||
|
-init
|
||||||
|
} else {
|
||||||
let rest = add(&args[1..])?.as_num().unwrap();
|
let rest = add(&args[1..])?.as_num().unwrap();
|
||||||
Ok(Value::Num(init - rest))
|
init - rest
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn equals(args: &[Value]) -> Result<Value, RTError> {
|
pub(crate) fn equals(args: &[Value]) -> Result<Value, RTError> {
|
||||||
Ok(Value::Bool(args.array_windows().all(|[l, r]| l == r)))
|
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)]
|
// #[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