refactor: prep for switching to Node in evaluator
Involves the following 1. Node True/False to Boolean 2. Removing parser tests 3. Other stuff 4. This is a bad commit
This commit is contained in:
parent
040a2518cc
commit
4808904571
5 changed files with 222 additions and 119 deletions
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -1 +1,10 @@
|
||||||
/target
|
/target
|
||||||
|
# Devenv
|
||||||
|
.devenv*
|
||||||
|
devenv.local.nix
|
||||||
|
|
||||||
|
# direnv
|
||||||
|
.direnv
|
||||||
|
|
||||||
|
# pre-commit
|
||||||
|
.pre-commit-config.yaml
|
||||||
|
|
156
devenv.lock
Normal file
156
devenv.lock
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"devenv": {
|
||||||
|
"locked": {
|
||||||
|
"dir": "src/modules",
|
||||||
|
"lastModified": 1714390914,
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "devenv",
|
||||||
|
"rev": "34e6461fd76b5f51ad5f8214f5cf22c4cd7a196e",
|
||||||
|
"treeHash": "5c5dc481030d6e30f8aa506e6d0c0d0809490d65",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"dir": "src/modules",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "devenv",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1696426674,
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||||
|
"treeHash": "2addb7b71a20a25ea74feeaf5c2f6a6b30898ecb",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1710146030,
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||||
|
"treeHash": "bd263f021e345cb4a39d80c126ab650bebc3c10c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gitignore": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"pre-commit-hooks",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1709087332,
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||||
|
"treeHash": "ca14199cabdfe1a06a7b1654c76ed49100a689f9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1713361204,
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "devenv-nixpkgs",
|
||||||
|
"rev": "285676e87ad9f0ca23d8714a6ab61e7e027020c6",
|
||||||
|
"treeHash": "50354b35a3e0277d4a83a0a88fa0b0866b5f392f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"ref": "rolling",
|
||||||
|
"repo": "devenv-nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-stable": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1714531828,
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "0638fe2715d998fa81d173aad264eb671ce2ebc1",
|
||||||
|
"treeHash": "f72314bde6c77cbdf35f68581c4758f9ff28461f",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-23.11",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pre-commit-hooks": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"gitignore": "gitignore",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"nixpkgs-stable": "nixpkgs-stable"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1714478972,
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "pre-commit-hooks.nix",
|
||||||
|
"rev": "2849da033884f54822af194400f8dff435ada242",
|
||||||
|
"treeHash": "578180deb59a545b0032e9a66da4c0c043c5057d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "pre-commit-hooks.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"devenv": "devenv",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"pre-commit-hooks": "pre-commit-hooks"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"treeHash": "cce81f2a0f0743b2eb61bc2eb6c7adbe2f2c6beb",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ use super::{eval_ast_node, Error, Expression};
|
||||||
use crate::parser::Node;
|
use crate::parser::Node;
|
||||||
|
|
||||||
pub type RawEnvironment = HashMap<String, Rc<Expression>>;
|
pub type RawEnvironment = HashMap<String, Rc<Expression>>;
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
current: RefCell<RawEnvironment>,
|
current: RefCell<RawEnvironment>,
|
||||||
outer: Option<Rc<Environment>>,
|
outer: Option<Rc<Environment>>,
|
||||||
|
@ -104,6 +104,18 @@ pub fn core_environment() -> Rc<Environment> {
|
||||||
"vector",
|
"vector",
|
||||||
Expression::NativeFunc(|args| Ok(Rc::new(Expression::Vector(args)))),
|
Expression::NativeFunc(|args| Ok(Rc::new(Expression::Vector(args)))),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"vector?",
|
||||||
|
Expression::NativeFunc(|args| {
|
||||||
|
arg_count!(1, args.len());
|
||||||
|
|
||||||
|
if let Expression::Vector(_vec) = args[0].borrow() {
|
||||||
|
return Ok(Expression::Boolean(true).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Expression::Boolean(false).into())
|
||||||
|
}),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"hashmap",
|
"hashmap",
|
||||||
Expression::NativeFunc(|args| {
|
Expression::NativeFunc(|args| {
|
||||||
|
@ -127,23 +139,48 @@ pub fn core_environment() -> Rc<Environment> {
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"eq?",
|
"hashmap?",
|
||||||
Expression::NativeFunc(|args| {
|
Expression::NativeFunc(|args| {
|
||||||
arg_count!(2, args.len());
|
arg_count!(1, args.len());
|
||||||
|
|
||||||
if args[0] == args[1] {
|
if let Expression::HashMap(_map) = args[0].borrow() {
|
||||||
return Ok(Expression::Boolean(true).into());
|
return Ok(Expression::Boolean(true).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Expression::Boolean(false).into())
|
Ok(Expression::Boolean(false).into())
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
// Ordering
|
||||||
|
(
|
||||||
|
"eq?",
|
||||||
|
Expression::NativeFunc(|args| {
|
||||||
|
arg_count!(2, args.len());
|
||||||
|
|
||||||
|
let lhs: &Expression = args[0].borrow();
|
||||||
|
let rhs: &Expression = args[1].borrow();
|
||||||
|
|
||||||
|
match (lhs, rhs) {
|
||||||
|
(Expression::Int(lhs), Expression::Int(rhs)) => {
|
||||||
|
Ok(Expression::Boolean(lhs == rhs).into())
|
||||||
|
}
|
||||||
|
(Expression::Boolean(lhs), Expression::Boolean(rhs)) => {
|
||||||
|
Ok(Expression::Boolean(lhs == rhs).into())
|
||||||
|
}
|
||||||
|
(Expression::String(lhs), Expression::String(rhs)) => {
|
||||||
|
Ok(Expression::Boolean(lhs == rhs).into())
|
||||||
|
}
|
||||||
|
(Expression::Nil, Expression::Nil) => Ok(Expression::Boolean(true).into()),
|
||||||
|
_ => Err(Error::ExpectedNumber)?,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"not",
|
"not",
|
||||||
Expression::NativeFunc(|args| {
|
Expression::NativeFunc(|args| {
|
||||||
arg_count!(1, args.len());
|
arg_count!(1, args.len());
|
||||||
|
|
||||||
if *args[0] == Expression::Boolean(false) {
|
let expr: &Expression = args[0].borrow();
|
||||||
|
if let Expression::Boolean(false) = expr {
|
||||||
return Ok(Expression::Boolean(true).into());
|
return Ok(Expression::Boolean(true).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +249,7 @@ pub fn core_environment() -> Rc<Environment> {
|
||||||
(args[0].clone(), args[1].clone(), args[2].clone());
|
(args[0].clone(), args[1].clone(), args[2].clone());
|
||||||
|
|
||||||
// If the value is anything other than false, then it is truthy
|
// If the value is anything other than false, then it is truthy
|
||||||
if *cond == Expression::Boolean(false) {
|
if let Expression::Boolean(false) = cond.borrow() {
|
||||||
return Ok(alternative);
|
return Ok(alternative);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ mod macros;
|
||||||
|
|
||||||
pub use env::{core_environment, Environment};
|
pub use env::{core_environment, Environment};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
// Values
|
// Values
|
||||||
Int(i64),
|
Int(i64),
|
||||||
|
@ -163,9 +163,12 @@ fn eval_ast_node(env: Rc<Environment>, ast_node: Node) -> Result<Rc<Expression>>
|
||||||
Node::Keyword(val) => Expression::Keyword(val).into(),
|
Node::Keyword(val) => Expression::Keyword(val).into(),
|
||||||
Node::String(s) => Expression::String(s).into(),
|
Node::String(s) => Expression::String(s).into(),
|
||||||
|
|
||||||
Node::True => Expression::Boolean(true).into(),
|
Node::Boolean(true) => Expression::Boolean(true).into(),
|
||||||
Node::False => Expression::Boolean(false).into(),
|
Node::Boolean(false) => Expression::Boolean(false).into(),
|
||||||
Node::Nil => Expression::Nil.into(),
|
Node::Nil => Expression::Nil.into(),
|
||||||
|
|
||||||
|
Node::Vector(vec) => todo!(),
|
||||||
|
Node::Map(map) => todo!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
|
|
118
src/parser.rs
118
src/parser.rs
|
@ -1,10 +1,10 @@
|
||||||
use std::{iter::Peekable, vec::IntoIter};
|
use std::{collections::HashMap, iter::Peekable, vec::IntoIter};
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
|
||||||
use crate::lexer::Token;
|
use crate::lexer::Token;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, PartialOrd, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Node {
|
pub enum Node {
|
||||||
List(Vec<Node>),
|
List(Vec<Node>),
|
||||||
|
|
||||||
|
@ -12,9 +12,11 @@ pub enum Node {
|
||||||
Keyword(String),
|
Keyword(String),
|
||||||
Int(i64),
|
Int(i64),
|
||||||
String(String),
|
String(String),
|
||||||
True,
|
Boolean(bool),
|
||||||
False,
|
|
||||||
Nil,
|
Nil,
|
||||||
|
|
||||||
|
Vector(Vec<Node>),
|
||||||
|
Map(HashMap<String, Node>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(tokens: Vec<Token>) -> Result<Vec<Node>> {
|
pub fn parse(tokens: Vec<Token>) -> Result<Vec<Node>> {
|
||||||
|
@ -68,8 +70,8 @@ fn next_statement(tokens: &mut Peekable<IntoIter<Token>>) -> Result<Option<Node>
|
||||||
Token::Ident(val) => Node::Symbol(val),
|
Token::Ident(val) => Node::Symbol(val),
|
||||||
Token::String(val) => Node::String(val),
|
Token::String(val) => Node::String(val),
|
||||||
Token::Int(int) => Node::Int(int),
|
Token::Int(int) => Node::Int(int),
|
||||||
Token::True => Node::True,
|
Token::True => Node::Boolean(true),
|
||||||
Token::False => Node::False,
|
Token::False => Node::Boolean(false),
|
||||||
Token::Nil => Node::Nil,
|
Token::Nil => Node::Nil,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -120,107 +122,3 @@ fn read_quote(tokens: &mut Peekable<IntoIter<Token>>, quote_type: &str) -> Resul
|
||||||
follower_node,
|
follower_node,
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use crate::lexer;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use rstest::rstest;
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
#[case("10", vec![
|
|
||||||
Node::Int(10)])]
|
|
||||||
#[case(":owo", vec![
|
|
||||||
Node::Keyword("owo".into())])]
|
|
||||||
#[case("\"uwu\"", vec![
|
|
||||||
Node::String("uwu".into())])]
|
|
||||||
#[case("(10 2)", vec![
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Int(10),
|
|
||||||
Node::Int(2)])])]
|
|
||||||
#[case("[10 2]", vec![
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Symbol("vector".into()),
|
|
||||||
Node::Int(10),
|
|
||||||
Node::Int(2)])])]
|
|
||||||
#[case("{10 2}", vec![
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Symbol("hashmap".into()),
|
|
||||||
Node::Int(10),
|
|
||||||
Node::Int(2)])])]
|
|
||||||
#[case("(+ - * /)", vec![
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Symbol("+".into()),
|
|
||||||
Node::Symbol("-".into()),
|
|
||||||
Node::Symbol("*".into()),
|
|
||||||
Node::Symbol("/".into())])])]
|
|
||||||
#[case("'(1 2 3)", vec![
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Symbol("quote".into()),
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Int(1),
|
|
||||||
Node::Int(2),
|
|
||||||
Node::Int(3)])])])]
|
|
||||||
#[case("`(1 2 3)", vec![
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Symbol("quasiquote".into()),
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Int(1),
|
|
||||||
Node::Int(2),
|
|
||||||
Node::Int(3)])])])]
|
|
||||||
#[case("~(1 2 3)", vec![
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Symbol("unquote".into()),
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Int(1),
|
|
||||||
Node::Int(2),
|
|
||||||
Node::Int(3)])])])]
|
|
||||||
#[case("~@(1 2 3)", vec![
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Symbol("splice-unquote".into()),
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Int(1),
|
|
||||||
Node::Int(2),
|
|
||||||
Node::Int(3)])])])]
|
|
||||||
#[case("(+ 1 2)", vec![
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Symbol("+".into()),
|
|
||||||
Node::Int(1),
|
|
||||||
Node::Int(2)])])]
|
|
||||||
#[case("(+ 1 2 (- 1 2))", vec![
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Symbol("+".into()),
|
|
||||||
Node::Int(1),
|
|
||||||
Node::Int(2),
|
|
||||||
Node::List(vec![
|
|
||||||
Node::Symbol("-".into()),
|
|
||||||
Node::Int(1),
|
|
||||||
Node::Int(2)])])])]
|
|
||||||
fn test_parsing(#[case] input: &str, #[case] expected: Vec<Node>) {
|
|
||||||
let tokens = lexer::read(input).unwrap();
|
|
||||||
let res = parse(tokens).unwrap();
|
|
||||||
assert_eq!(res, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
#[case(")")]
|
|
||||||
#[case("]")]
|
|
||||||
#[case("}")]
|
|
||||||
#[case("(1 2")]
|
|
||||||
#[case("[1 2")]
|
|
||||||
#[case("{1 2")]
|
|
||||||
#[case("(1 2 '")]
|
|
||||||
#[case("(1 2 ')")]
|
|
||||||
#[case("(1 2 ~")]
|
|
||||||
#[case("(1 2 ~)")]
|
|
||||||
#[case("(1 2 `")]
|
|
||||||
#[case("(1 2 `)")]
|
|
||||||
#[case("(1 2 ~@")]
|
|
||||||
#[case("(1 2 ~@)")]
|
|
||||||
fn test_parsing_fail(#[case] input: &str) {
|
|
||||||
let tokens = lexer::read(input).unwrap();
|
|
||||||
let res = parse(tokens);
|
|
||||||
assert!(res.is_err());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue