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
|
// Collections
|
||||||
("list", NativeFunc(|args| Node::List(args.into()))),
|
("list", NativeFunc(Node::List)),
|
||||||
(
|
(
|
||||||
"list?",
|
"list?",
|
||||||
NativeFunc(|args| {
|
NativeFunc(|args| {
|
||||||
|
@ -151,7 +151,7 @@ pub(super) fn core() -> HashMap<String, Value> {
|
||||||
Node::Boolean(false)
|
Node::Boolean(false)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
("vector", NativeFunc(Node::Vector)),
|
("vector", NativeFunc(|args| Node::Vector(args.into()))),
|
||||||
(
|
(
|
||||||
"vector?",
|
"vector?",
|
||||||
NativeFunc(|args| {
|
NativeFunc(|args| {
|
||||||
|
@ -202,8 +202,9 @@ pub(super) fn core() -> HashMap<String, Value> {
|
||||||
"empty?",
|
"empty?",
|
||||||
NativeFunc(|args| {
|
NativeFunc(|args| {
|
||||||
arg_count!(1, args.len());
|
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::List(list) => Node::Boolean(list.is_empty()),
|
||||||
Node::Vector(vec) => Node::Boolean(vec.is_empty()),
|
Node::Vector(vec) => Node::Boolean(vec.is_empty()),
|
||||||
Node::Map(map) => Node::Boolean(map.is_empty()),
|
Node::Map(map) => Node::Boolean(map.is_empty()),
|
||||||
|
@ -218,8 +219,9 @@ pub(super) fn core() -> HashMap<String, Value> {
|
||||||
"count",
|
"count",
|
||||||
NativeFunc(|args| {
|
NativeFunc(|args| {
|
||||||
arg_count!(1, args.len());
|
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::List(list) => Node::Int(list.len() as i64),
|
||||||
Node::Vector(vec) => Node::Int(vec.len() as i64),
|
Node::Vector(vec) => Node::Int(vec.len() as i64),
|
||||||
Node::Map(map) => Node::Int(map.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())
|
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()
|
.into_iter()
|
||||||
.map(|(k, v)| (k.to_string(), Value::NativeFunc(v)))
|
.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::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, VecDeque};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::Node;
|
use crate::Node;
|
||||||
|
@ -10,10 +10,10 @@ mod macros;
|
||||||
mod standard;
|
mod standard;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NativeFunc(fn(args: Vec<Node>) -> Node);
|
pub struct NativeFunc(fn(args: VecDeque<Node>) -> Node);
|
||||||
|
|
||||||
impl NativeFunc {
|
impl NativeFunc {
|
||||||
pub fn call(&self, args: Vec<Node>) -> Node {
|
pub fn call(&self, args: VecDeque<Node>) -> Node {
|
||||||
(self.0)(args)
|
(self.0)(args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ pub fn eval_node(env: &Environment, ast_node: Node) -> Result<Node> {
|
||||||
let args = list
|
let args = list
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|node| eval_node(env, node))
|
.map(|node| eval_node(env, node))
|
||||||
.collect::<Result<Vec<Node>>>()?;
|
.collect::<Result<VecDeque<Node>>>()?;
|
||||||
|
|
||||||
func.call(args)
|
func.call(args)
|
||||||
}
|
}
|
||||||
|
@ -420,6 +420,16 @@ mod test {
|
||||||
// Strings
|
// Strings
|
||||||
#[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
|
||||||
|
#[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) {
|
fn test_evaluator(#[case] input: &str, #[case] expected: &str) {
|
||||||
dbg!(input);
|
dbg!(input);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue