feat: lisp/vec manipulation
first, last, nth, push, pop
This commit is contained in:
parent
5f7f7e4aed
commit
6a83d228bb
3 changed files with 165 additions and 8 deletions
155
mute-interpreter/src/env/core.rs
vendored
155
mute-interpreter/src/env/core.rs
vendored
|
@ -138,7 +138,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
}),
|
||||
),
|
||||
// Collections
|
||||
("list", NativeFunc(|args| Node::List(args.into()))),
|
||||
("list", NativeFunc(Node::List)),
|
||||
(
|
||||
"list?",
|
||||
NativeFunc(|args| {
|
||||
|
@ -151,7 +151,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
Node::Boolean(false)
|
||||
}),
|
||||
),
|
||||
("vector", NativeFunc(Node::Vector)),
|
||||
("vector", NativeFunc(|args| Node::Vector(args.into()))),
|
||||
(
|
||||
"vector?",
|
||||
NativeFunc(|args| {
|
||||
|
@ -202,8 +202,9 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
"empty?",
|
||||
NativeFunc(|args| {
|
||||
arg_count!(1, args.len());
|
||||
let mut args = args;
|
||||
|
||||
match args[0].borrow() {
|
||||
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::Map(map) => Node::Boolean(map.is_empty()),
|
||||
|
@ -218,8 +219,9 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
"count",
|
||||
NativeFunc(|args| {
|
||||
arg_count!(1, args.len());
|
||||
let mut args = args;
|
||||
|
||||
match args[0].borrow() {
|
||||
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::Map(map) => Node::Int(map.len() as i64),
|
||||
|
@ -240,6 +242,151 @@ pub(super) fn core() -> HashMap<String, Value> {
|
|||
Node::String(val.to_string())
|
||||
}),
|
||||
),
|
||||
// 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(|args| {
|
||||
arg_count!(1, args.len());
|
||||
|
||||
match args[0].borrow() {
|
||||
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(|args| {
|
||||
arg_count!(2, args.len());
|
||||
|
||||
let mut args = args;
|
||||
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()
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
list.get(nth).unwrap().clone()
|
||||
}),
|
||||
),
|
||||
(
|
||||
"push-back",
|
||||
NativeFunc(|args| {
|
||||
let mut args = 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(|args| {
|
||||
let mut args = 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(|args| {
|
||||
let mut args = 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(|args| {
|
||||
let mut args = 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)| (k.to_string(), Value::NativeFunc(v)))
|
||||
|
|
6
mute-interpreter/src/env/mod.rs
vendored
6
mute-interpreter/src/env/mod.rs
vendored
|
@ -1,5 +1,5 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::Node;
|
||||
|
@ -10,10 +10,10 @@ mod macros;
|
|||
mod standard;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NativeFunc(fn(args: Vec<Node>) -> Node);
|
||||
pub struct NativeFunc(fn(args: VecDeque<Node>) -> Node);
|
||||
|
||||
impl NativeFunc {
|
||||
pub fn call(&self, args: Vec<Node>) -> Node {
|
||||
pub fn call(&self, args: VecDeque<Node>) -> Node {
|
||||
(self.0)(args)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
|
|||
let args = list
|
||||
.into_iter()
|
||||
.map(|node| eval_node(env, node))
|
||||
.collect::<Result<Vec<Node>>>()?;
|
||||
.collect::<Result<VecDeque<Node>>>()?;
|
||||
|
||||
func.call(args)
|
||||
}
|
||||
|
@ -420,6 +420,16 @@ mod test {
|
|||
// Strings
|
||||
#[case("(str (+ 1 2))", "3")]
|
||||
#[case("(str (list 1 2 3))", "(1 2 3)")]
|
||||
// List Manipulation
|
||||
#[case("(first (list 1 2 3))", "1")]
|
||||
#[case("(last (list 1 2 3))", "3")]
|
||||
#[case("(nth (list 1 2 3) 1)", "2")]
|
||||
#[case("(push-front (list 1 2 3) 0)", "(0 1 2 3)")]
|
||||
#[case("(push-back (list 1 2 3) 4)", "(1 2 3 4)")]
|
||||
#[case("(pop-front (list 1 2 3))", "(2 3)")]
|
||||
#[case("(pop-back (list 1 2 3))", "(1 2)")]
|
||||
#[case("(push-back [1 2 3] 4)", "[1 2 3 4]")]
|
||||
#[case("(pop-back [1 2 3 4])", "[1 2 3]")]
|
||||
fn test_evaluator(#[case] input: &str, #[case] expected: &str) {
|
||||
dbg!(input);
|
||||
|
||||
|
|
Loading…
Reference in a new issue