refactor: namespaces(?)

And move list functions over there
This commit is contained in:
Roman Godmaire 2024-05-14 20:04:35 -04:00
parent 285b93aa89
commit ab20f6e85e
5 changed files with 231 additions and 213 deletions

View file

@ -1,5 +1,7 @@
use std::collections::HashMap; use std::{
use std::{borrow::Borrow, collections::VecDeque}; borrow::Borrow,
collections::{HashMap, VecDeque},
};
use super::{macros::arg_count, NativeFunc, Value}; use super::{macros::arg_count, NativeFunc, Value};
use crate::Node; use crate::Node;
@ -170,18 +172,6 @@ pub(super) fn core() -> HashMap<String, Value> {
Node::List(list) Node::List(list)
}), }),
), ),
(
"list?",
NativeFunc(|args| {
arg_count!(1, args.len());
if let Node::List(_list) = args[0].borrow() {
return Node::Boolean(true);
}
Node::Boolean(false)
}),
),
("vector", NativeFunc(|args| Node::Vector(args.into()))), ("vector", NativeFunc(|args| Node::Vector(args.into()))),
( (
"vector?", "vector?",
@ -229,38 +219,6 @@ pub(super) fn core() -> HashMap<String, Value> {
Node::Boolean(false) Node::Boolean(false)
}), }),
), ),
(
"empty?",
NativeFunc(|mut args| {
arg_count!(1, args.len());
match args.pop_front().expect("argument length checked above") {
Node::List(list) => Node::Boolean(list.is_empty()),
Node::Vector(vec) => Node::Boolean(vec.is_empty()),
Node::Hashmap(map) => Node::Boolean(map.is_empty()),
arg => Node::Error(format!(
"TypeError: expected list, vector, or hashmap, got {}.",
arg.get_type()
)),
}
}),
),
(
"count",
NativeFunc(|mut args| {
arg_count!(1, args.len());
match args.pop_front().expect("argument length checked above") {
Node::List(list) => Node::Int(list.len() as i64),
Node::Vector(vec) => Node::Int(vec.len() as i64),
Node::Hashmap(map) => Node::Int(map.len() as i64),
arg => Node::Error(format!(
"TypeError: expected list, vector, or hashmap, got {}.",
arg.get_type()
)),
}
}),
),
// Strings // Strings
( (
"str", "str",
@ -272,149 +230,6 @@ pub(super) fn core() -> HashMap<String, Value> {
}), }),
), ),
// List stuff // List stuff
(
"first",
NativeFunc(|args| {
arg_count!(1, args.len());
match args[0].borrow() {
Node::List(list) if list.is_empty() => Node::Nil,
Node::Vector(vec) if vec.is_empty() => Node::Nil,
Node::List(list) => list.front().unwrap().clone(),
Node::Vector(vec) => vec.first().unwrap().clone(),
arg => Node::Error(format!(
"TypeError: expected list or vector, got {}.",
arg.get_type()
)),
}
}),
),
(
"last",
NativeFunc(|mut args| {
arg_count!(1, args.len());
match args.pop_front().expect("argument length checked above") {
Node::List(list) if list.is_empty() => Node::Nil,
Node::Vector(list) if list.is_empty() => Node::Nil,
Node::List(list) => list.back().unwrap().clone(),
Node::Vector(vec) => vec.last().unwrap().clone(),
arg => Node::Error(format!(
"TypeError: expected list or vector, got {}.",
arg.get_type()
)),
}
}),
),
(
"nth",
NativeFunc(|mut args| {
arg_count!(2, args.len());
let list = match args.pop_front().expect("argument length checked above") {
Node::List(list) => list,
Node::Vector(vec) => vec.into(),
arg => {
return Node::Error(format!(
"TypeError: expected list or vector, got {}.",
arg.get_type()
))
}
};
let nth = match args.pop_front().expect("argument length checked above") {
Node::Int(val) => val as usize,
Node::Float(val) => val as usize,
arg => {
return Node::Error(format!(
"TypeError: expected int or float, got {}.",
arg.get_type()
))
}
};
if nth < 1 {
return Node::Error(format!("TypeError: expected positive int, got {}", nth));
}
list.get(nth - 1).unwrap().clone()
}),
),
(
"push-back",
NativeFunc(
|mut args| match args.pop_front().expect("argument length checked above") {
Node::List(mut list) => {
while let Some(val) = args.pop_front() {
list.push_back(val);
}
Node::List(list)
}
Node::Vector(mut vec) => {
while let Some(val) = args.pop_front() {
vec.push(val);
}
Node::Vector(vec)
}
arg => Node::Error(format!(
"TypeError: expected list or vector, got {}.",
arg.get_type()
)),
},
),
),
(
"push-front",
NativeFunc(
|mut args| match args.pop_front().expect("argument length checked above") {
Node::List(mut list) => {
while let Some(val) = args.pop_back() {
list.push_front(val);
}
Node::List(list)
}
arg => {
Node::Error(format!("TypeError: expected list, got {}.", arg.get_type()))
}
},
),
),
(
"pop-front",
NativeFunc(
|mut args| match args.pop_front().expect("argument length checked above") {
Node::List(mut list) => {
list.pop_front();
Node::List(list)
}
arg => {
Node::Error(format!("TypeError: expected list, got {}.", arg.get_type()))
}
},
),
),
(
"pop-back",
NativeFunc(
|mut args| match args.pop_front().expect("argument length checked above") {
Node::List(mut list) => {
list.pop_back();
Node::List(list)
}
Node::Vector(mut vec) => {
vec.pop();
Node::Vector(vec)
}
arg => {
Node::Error(format!("TypeError: expected list, got {}.", arg.get_type()))
}
},
),
),
] ]
.into_iter() .into_iter()
.map(|(k, v)| (k.to_string(), Value::NativeFunc(v))) .map(|(k, v)| (k.to_string(), Value::NativeFunc(v)))

200
mute-interpreter/src/env/list.rs vendored Normal file
View file

@ -0,0 +1,200 @@
use std::borrow::Borrow;
use std::collections::HashMap;
use super::{macros::arg_count, NativeFunc, Value};
use crate::Node;
pub(super) fn lib() -> HashMap<String, Value> {
[
(
"list?",
NativeFunc(|args| {
arg_count!(1, args.len());
if let Node::List(_list) = args[0].borrow() {
return Node::Boolean(true);
}
Node::Boolean(false)
}),
),
(
"empty?",
NativeFunc(|mut args| {
arg_count!(1, args.len());
match args.pop_front().expect("argument length checked above") {
Node::List(list) => Node::Boolean(list.is_empty()),
Node::Vector(vec) => Node::Boolean(vec.is_empty()),
Node::Hashmap(map) => Node::Boolean(map.is_empty()),
arg => Node::Error(format!(
"TypeError: expected list, vector, or hashmap, got {}.",
arg.get_type()
)),
}
}),
),
(
"count",
NativeFunc(|mut args| {
arg_count!(1, args.len());
match args.pop_front().expect("argument length checked above") {
Node::List(list) => Node::Int(list.len() as i64),
Node::Vector(vec) => Node::Int(vec.len() as i64),
Node::Hashmap(map) => Node::Int(map.len() as i64),
arg => Node::Error(format!(
"TypeError: expected list, vector, or hashmap, got {}.",
arg.get_type()
)),
}
}),
),
(
"first",
NativeFunc(|args| {
arg_count!(1, args.len());
match args[0].borrow() {
Node::List(list) if list.is_empty() => Node::Nil,
Node::Vector(vec) if vec.is_empty() => Node::Nil,
Node::List(list) => list.front().unwrap().clone(),
Node::Vector(vec) => vec.first().unwrap().clone(),
arg => Node::Error(format!(
"TypeError: expected list or vector, got {}.",
arg.get_type()
)),
}
}),
),
(
"last",
NativeFunc(|mut args| {
arg_count!(1, args.len());
match args.pop_front().expect("argument length checked above") {
Node::List(list) if list.is_empty() => Node::Nil,
Node::Vector(list) if list.is_empty() => Node::Nil,
Node::List(list) => list.back().unwrap().clone(),
Node::Vector(vec) => vec.last().unwrap().clone(),
arg => Node::Error(format!(
"TypeError: expected list or vector, got {}.",
arg.get_type()
)),
}
}),
),
(
"nth",
NativeFunc(|mut args| {
arg_count!(2, args.len());
let list = match args.pop_front().expect("argument length checked above") {
Node::List(list) => list,
Node::Vector(vec) => vec.into(),
arg => {
return Node::Error(format!(
"TypeError: expected list or vector, got {}.",
arg.get_type()
))
}
};
let nth = match args.pop_front().expect("argument length checked above") {
Node::Int(val) => val as usize,
Node::Float(val) => val as usize,
arg => {
return Node::Error(format!(
"TypeError: expected int or float, got {}.",
arg.get_type()
))
}
};
if nth < 1 {
return Node::Error(format!("TypeError: expected positive int, got {}", nth));
}
list.get(nth - 1).unwrap().clone()
}),
),
(
"push-back",
NativeFunc(
|mut args| match args.pop_front().expect("argument length checked above") {
Node::List(mut list) => {
while let Some(val) = args.pop_front() {
list.push_back(val);
}
Node::List(list)
}
Node::Vector(mut vec) => {
while let Some(val) = args.pop_front() {
vec.push(val);
}
Node::Vector(vec)
}
arg => Node::Error(format!(
"TypeError: expected list or vector, got {}.",
arg.get_type()
)),
},
),
),
(
"push-front",
NativeFunc(
|mut args| match args.pop_front().expect("argument length checked above") {
Node::List(mut list) => {
while let Some(val) = args.pop_back() {
list.push_front(val);
}
Node::List(list)
}
arg => {
Node::Error(format!("TypeError: expected list, got {}.", arg.get_type()))
}
},
),
),
(
"pop-front",
NativeFunc(
|mut args| match args.pop_front().expect("argument length checked above") {
Node::List(mut list) => {
list.pop_front();
Node::List(list)
}
arg => {
Node::Error(format!("TypeError: expected list, got {}.", arg.get_type()))
}
},
),
),
(
"pop-back",
NativeFunc(
|mut args| match args.pop_front().expect("argument length checked above") {
Node::List(mut list) => {
list.pop_back();
Node::List(list)
}
Node::Vector(mut vec) => {
vec.pop();
Node::Vector(vec)
}
arg => {
Node::Error(format!("TypeError: expected list, got {}.", arg.get_type()))
}
},
),
),
]
.into_iter()
.map(|(k, v)| (format!("List.{k}"), Value::NativeFunc(v)))
.collect()
}

View file

@ -6,6 +6,7 @@ use crate::Node;
mod core; mod core;
mod io; mod io;
mod list;
mod macros; mod macros;
mod standard; mod standard;
@ -74,10 +75,12 @@ impl std::default::Default for Environment {
let mut env = HashMap::new(); let mut env = HashMap::new();
let core = core::core(); let core = core::core();
let io = io::io(); let io = io::io();
let list = list::lib();
let stdlib = standard::standard(); let stdlib = standard::standard();
env.extend(core); env.extend(core);
env.extend(io); env.extend(io);
env.extend(list);
env.extend(stdlib); env.extend(stdlib);
let env = RawEnvironment { let env = RawEnvironment {

View file

@ -456,30 +456,30 @@ mod test {
#[case("{:a \"uwu\"}", "{:a: uwu}")] #[case("{:a \"uwu\"}", "{:a: uwu}")]
// Lists // Lists
#[case("(list 1 2 3)", "(1 2 3)")] #[case("(list 1 2 3)", "(1 2 3)")]
#[case("(list? (list))", "true")] #[case("(List.list? (list))", "true")]
#[case("(list? 23)", "false")] #[case("(List.list? 23)", "false")]
#[case("(empty? (list 1 2 3))", "false")]
#[case("(empty? (list))", "true")]
#[case("(count (list))", "0")]
#[case("(count (list 1 2 3))", "3")]
#[case("(range 5)", "(1 2 3 4 5)")] #[case("(range 5)", "(1 2 3 4 5)")]
#[case("(range 6 10)", "(6 7 8 9 10)")] #[case("(range 6 10)", "(6 7 8 9 10)")]
#[case("(List.empty? (list 1 2 3))", "false")]
#[case("(List.empty? (list))", "true")]
#[case("(List.count (list))", "0")]
#[case("(List.count (list 1 2 3))", "3")]
// Vectors // Vectors
#[case("(vector 1 2 3)", "[1 2 3]")] #[case("(vector 1 2 3)", "[1 2 3]")]
#[case("(vector? [])", "true")] #[case("(vector? [])", "true")]
#[case("(vector? 23)", "false")] #[case("(vector? 23)", "false")]
#[case("(empty? [1 2 3])", "false")] #[case("(List.empty? [1 2 3])", "false")]
#[case("(empty? [])", "true")] #[case("(List.empty? [])", "true")]
#[case("(count [])", "0")] #[case("(List.count [])", "0")]
#[case("(count [1 2 3])", "3")] #[case("(List.count [1 2 3])", "3")]
// Hashmaps // Hashmaps
#[case("(hashmap :a 1)", "{:a: 1}")] #[case("(hashmap :a 1)", "{:a: 1}")]
#[case("(hashmap? {})", "true")] #[case("(hashmap? {})", "true")]
#[case("(hashmap? 23)", "false")] #[case("(hashmap? 23)", "false")]
#[case("(empty? {:a 1})", "false")] #[case("(List.empty? {:a 1})", "false")]
#[case("(empty? {})", "true")] #[case("(List.empty? {})", "true")]
#[case("(count {})", "0")] #[case("(List.count {})", "0")]
#[case("(count {:a 1})", "1")] #[case("(List.count {:a 1})", "1")]
// Environment manipulation // Environment manipulation
#[case("(define (asdf (+ 2 2))) (+ asdf 2)", "6")] #[case("(define (asdf (+ 2 2))) (+ asdf 2)", "6")]
#[case("(define (add (fn* (a b) (+ a b)))) (add 1 2)", "3")] #[case("(define (add (fn* (a b) (+ a b)))) (add 1 2)", "3")]
@ -526,15 +526,15 @@ mod test {
#[case("(str (+ 1 2))", "3")] #[case("(str (+ 1 2))", "3")]
#[case("(str (list 1 2 3))", "(1 2 3)")] #[case("(str (list 1 2 3))", "(1 2 3)")]
// List Manipulation // List Manipulation
#[case("(first (list 1 2 3))", "1")] #[case("(List.first (list 1 2 3))", "1")]
#[case("(last (list 1 2 3))", "3")] #[case("(List.last (list 1 2 3))", "3")]
#[case("(nth (list 1 2 3) 2)", "2")] #[case("(List.nth (list 1 2 3) 2)", "2")]
#[case("(push-front (list 1 2 3) 0)", "(0 1 2 3)")] #[case("(List.push-front (list 1 2 3) 0)", "(0 1 2 3)")]
#[case("(push-back (list 1 2 3) 4)", "(1 2 3 4)")] #[case("(List.push-back (list 1 2 3) 4)", "(1 2 3 4)")]
#[case("(pop-front (list 1 2 3))", "(2 3)")] #[case("(List.pop-front (list 1 2 3))", "(2 3)")]
#[case("(pop-back (list 1 2 3))", "(1 2)")] #[case("(List.pop-back (list 1 2 3))", "(1 2)")]
#[case("(push-back [1 2 3] 4)", "[1 2 3 4]")] #[case("(List.push-back [1 2 3] 4)", "[1 2 3 4]")]
#[case("(pop-back [1 2 3 4])", "[1 2 3]")] #[case("(List.pop-back [1 2 3 4])", "[1 2 3]")]
// Iteration // Iteration
#[case("(map '(1 2 3) (fn* (x) (* x x)))", "(1 4 9)")] #[case("(map '(1 2 3) (fn* (x) (* x x)))", "(1 4 9)")]
#[case("(filter '(1 2 3) (fn* (x) (> x 1)))", "(2 3)")] #[case("(filter '(1 2 3) (fn* (x) (> x 1)))", "(2 3)")]

View file

@ -199,7 +199,7 @@ fn read_int(input: &mut Peekable<Chars>, first: char) -> Token {
} }
fn read_ident(input: &mut Peekable<Chars>, first: char) -> Token { fn read_ident(input: &mut Peekable<Chars>, first: char) -> Token {
let special_characters = ['!', '?', '*', '-', '_']; let special_characters = ['!', '?', '*', '-', '_', '.'];
let mut raw_ident = vec![first]; let mut raw_ident = vec![first];
while let Some(c) = input.peek() { while let Some(c) = input.peek() {