Skip to content

Commit 420283f

Browse files
committed
Promote LangItem::Args to Head::Args
1 parent 12c4182 commit 420283f

File tree

2 files changed

+40
-46
lines changed

2 files changed

+40
-46
lines changed

src/base.rs

+39-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![allow(clippy::borrowed_box)]
1+
#![allow(clippy::redundant_closure_call, clippy::borrowed_box)]
22
use std::fmt::{Display, Formatter, Debug};
33
use dyn_clone::DynClone;
44
pub use num::*;
@@ -228,9 +228,10 @@ impl Node {
228228
Ok(func) => func(self, env),
229229
Err(e) => Err(StreamError::new(e, self))
230230
},
231+
Head::Lang(ref lang) => find_keyword(lang.keyword()).unwrap()(self, env),
231232
Head::Block(blk) => (*blk).apply(&self.source, &self.args)?.eval_env(env),
232-
Head::Repl(_, _) => Err(StreamError::new("out of context", self)),
233-
Head::Lang(ref lang) => find_keyword(lang.keyword()).unwrap()(self, env)
233+
Head::Args(_) => Node::eval_at(self, env),
234+
Head::Repl(_, _) => Err(StreamError::new("out of context", self))
234235
}
235236
}
236237

@@ -259,6 +260,24 @@ impl Node {
259260
Ok(self)
260261
}*/
261262

263+
fn eval_at(node: Node, env: &Rc<Env>) -> Result<Item, StreamError> {
264+
let node = node.eval_all(env)?;
265+
assert!(node.args.len() == 1);
266+
let src_stream = try_with!(node, node.args[0].as_stream());
267+
if src_stream.length() == Length::Infinite {
268+
return Err(StreamError::new("stream is infinite", node));
269+
}
270+
let Head::Args(head) = node.head else { unreachable!() };
271+
let expr = Expr::Eval(Node{
272+
head: *head,
273+
source: node.source.map(|item| Box::new(item.into())),
274+
args: src_stream.iter()
275+
.map(|res| res.map(Expr::from))
276+
.collect::<Result<Vec<_>, _>>()?
277+
});
278+
expr.eval_env(env)
279+
}
280+
262281
pub(crate) fn apply(self, source: &Option<Box<Expr>>, args: &Vec<Expr>) -> Result<Node, StreamError> {
263282
Ok(Node {
264283
head: self.head,
@@ -418,6 +437,7 @@ pub enum Head {
418437
Symbol(String),
419438
Oper(String),
420439
Block(Box<Expr>),
440+
Args(Box<Head>), /// At-sign (source.head@args)
421441
Lang(LangItem),
422442
Repl(char, Option<usize>)
423443
}
@@ -431,13 +451,13 @@ impl Head {
431451
Head::Oper(_) => Default::default(),
432452
Head::Repl(chr, None) => chr.to_string(),
433453
Head::Repl(chr, Some(num)) => format!("{chr}{num}"),
434-
Head::Lang(LangItem::Args(head)) => format!("{}@", head.describe()),
454+
Head::Args(head) => format!("{}@", head.describe()),
435455
Head::Lang(_) => Default::default(),
436456
}
437457
}
438458

439-
pub fn args<T>(head: T) -> Head where T: Into<Head> {
440-
Head::Lang(LangItem::Args(Box::new(head.into())))
459+
pub fn args(head: impl Into<Head>) -> Head {
460+
Head::Args(Box::new(head.into()))
441461
}
442462
}
443463

@@ -490,8 +510,6 @@ pub enum LangItem {
490510
Part,
491511
/// Colon (`source:func` ~ `source.$map(func)`)
492512
Map,
493-
/// At-sign (`source.head@args` ~ `source.$args{head}(args)`)
494-
Args(Box<Head>)
495513
}
496514

497515
impl LangItem {
@@ -500,8 +518,7 @@ impl LangItem {
500518
match self {
501519
List => "$list",
502520
Part => "$part",
503-
Map => "$map",
504-
Args(_) => "$args"
521+
Map => "$map"
505522
}
506523
}
507524
}
@@ -1145,6 +1162,18 @@ fn test_block() {
11451162
assert_eq!(parse("{#1}({#2}(3,4),5)").unwrap().eval().unwrap().to_string(), "4");
11461163
}
11471164

1165+
#[test]
1166+
fn test_args() {
1167+
use crate::parser::parse;
1168+
assert_eq!(parse("range@[3]").unwrap().eval().unwrap().to_string(), "[1, 2, 3]");
1169+
assert_eq!(parse("range@range(3)").unwrap().eval().unwrap().to_string(), "[1]");
1170+
assert_eq!(parse("range@range(3)").unwrap().eval().unwrap().to_string(), "[1]");
1171+
assert_eq!(parse("range@[3][2]").unwrap().eval().unwrap().to_string(), "2");
1172+
assert_eq!(parse("range@range(3)[1]").unwrap().eval().unwrap().to_string(), "1");
1173+
assert!(parse("range@3").unwrap().eval().is_err());
1174+
assert!(parse("range@seq").unwrap().eval().is_err());
1175+
}
1176+
11481177
#[test]
11491178
fn test_describe() {
11501179
use crate::parser::parse;

src/lang.rs

+1-36
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ impl Part {
135135
match &mut node.head {
136136
Head::Lang(LangItem::Part) => return Ok(()), // $part does not enter into args
137137
Head::Block(expr) => subs_len(expr, length)?,
138-
Head::Lang(LangItem::Args(head)) => {
138+
Head::Args(head) => {
139139
if let Head::Block(ref mut expr) = **head {
140140
subs_len(expr, length)?
141141
}
@@ -782,45 +782,10 @@ fn test_join() {
782782
}
783783

784784

785-
fn eval_args(node: Node, env: &Rc<Env>) -> Result<Item, StreamError> {
786-
let node = node.eval_all(env)?;
787-
if node.args.len() != 1 {
788-
return Err(StreamError::new("exactly 1 argument expected", node));
789-
}
790-
let src_stream = try_with!(node, node.args[0].as_stream());
791-
if src_stream.length() == Length::Infinite {
792-
return Err(StreamError::new("stream is infinite", node));
793-
}
794-
let Head::Lang(LangItem::Args(head)) = node.head
795-
else { panic!("eval_args() called on something else than $args") };
796-
let expr = Expr::Eval(Node{
797-
head: *head,
798-
source: node.source.map(|item| Box::new(item.into())),
799-
args: src_stream.iter()
800-
.map(|res| res.map(Expr::from))
801-
.collect::<Result<Vec<_>, _>>()?
802-
});
803-
expr.eval_env(env)
804-
}
805-
806-
#[test]
807-
fn test_args() {
808-
use crate::parser::parse;
809-
assert_eq!(parse("range@[3]").unwrap().eval().unwrap().to_string(), "[1, 2, 3]");
810-
assert_eq!(parse("range@range(3)").unwrap().eval().unwrap().to_string(), "[1]");
811-
assert_eq!(parse("range@range(3)").unwrap().eval().unwrap().to_string(), "[1]");
812-
assert_eq!(parse("range@[3][2]").unwrap().eval().unwrap().to_string(), "2");
813-
assert_eq!(parse("range@range(3)[1]").unwrap().eval().unwrap().to_string(), "1");
814-
assert!(parse("range@3").unwrap().eval().is_err());
815-
assert!(parse("range@seq").unwrap().eval().is_err());
816-
}
817-
818-
819785
pub(crate) fn init(keywords: &mut crate::keywords::Keywords) {
820786
keywords.insert("$list", List::eval);
821787
keywords.insert("$part", Part::eval);
822788
keywords.insert("$map", Map::eval);
823-
keywords.insert("$args", eval_args);
824789
keywords.insert("+", MathOp::eval);
825790
keywords.insert("-", MathOp::eval);
826791
keywords.insert("*", MathOp::eval);

0 commit comments

Comments
 (0)