1use std::collections::{HashMap, HashSet};
9use std::ops::Range;
10use std::sync::Arc;
11
12use crate::array::{Array, Data};
13use crate::error::{Error, ErrorKind, Result, Span};
14use crate::frontend::{Segment, SourceParts};
15use crate::ir::{Branch, Control, ExplicitDef, Expr, Scope};
16use crate::verb::{
17 BoolDyad, DyadOp, Enclose, MonadOp, Power, Prim, ScalarDyad, ScalarMonad, Verb, WindowKind,
18 RANK_INF,
19};
20
21pub fn parse(src: &SourceParts) -> Result<Vec<Expr>> {
31 let mut scope = Names::default();
32 let lines = lex(src)?;
33 let mut out = Vec::new();
34 let mut i = 0usize;
35 while i < lines.len() {
36 let sentence = collect_definitions(&lines, &mut i, &mut scope, true)?;
39 if sentence.is_empty() {
40 continue;
41 }
42 let stmt = scope.parse_sentence(sentence)?;
43 scope.record(&stmt);
44 out.push(stmt);
45 }
46 Ok(out)
47}
48
49#[derive(Clone, Default)]
53struct Names {
54 verbs: HashMap<String, Verb>,
55 nouns: HashSet<String>,
59}
60
61impl Names {
62 fn parse_sentence(&self, mut sentence: Vec<Frag>) -> Result<Expr> {
63 substitute_verbs(&mut sentence, &self.verbs);
64 parse_sentence(sentence, &self.nouns)
65 }
66
67 fn record(&mut self, stmt: &Expr) {
69 match stmt {
70 Expr::VerbDef { name, verb, .. } => {
71 self.verbs.insert(name.clone(), verb.clone());
72 self.nouns.remove(name);
73 }
74 other => {
77 let mut assigned = Vec::new();
78 assigned_names(other, &mut assigned);
79 for name in assigned {
80 self.verbs.remove(&name);
81 self.nouns.insert(name);
82 }
83 }
84 }
85 }
86}
87
88const CONTROL_WORDS: [&str; 18] = [
93 "if.", "do.", "else.", "elseif.", "end.", "while.", "whilst.", "for.", "select.", "case.",
94 "fcase.", "return.", "break.", "continue.", "try.", "catch.", "catcht.", "throw.",
95];
96
97fn control_word(word: &str) -> Option<(&'static str, Option<String>)> {
99 if let Some(w) = CONTROL_WORDS.iter().copied().find(|&w| w == word) {
100 return Some((w, None));
101 }
102 for (stem, w) in [("for_", "for."), ("goto_", "goto."), ("label_", "label.")] {
103 if let Some(rest) = word.strip_prefix(stem) {
104 let name = rest.strip_suffix('.')?;
105 if !name.is_empty() && is_j_name(name) {
106 return Some((w, Some(name.to_string())));
107 }
108 }
109 }
110 None
111}
112
113fn is_j_name(s: &str) -> bool {
114 let mut cs = s.chars();
115 cs.next().is_some_and(|c| c.is_ascii_alphabetic())
116 && s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
117}
118
119#[derive(Clone, Debug)]
122enum Item {
123 Sentence(Vec<Frag>),
124 Word { word: &'static str, suffix: Option<String>, span: Span },
125}
126
127impl Item {
128 fn word(&self) -> Option<&'static str> {
129 match self {
130 Item::Word { word, .. } => Some(word),
131 Item::Sentence(_) => None,
132 }
133 }
134
135 fn span(&self) -> Span {
136 match self {
137 Item::Word { span, .. } => *span,
138 Item::Sentence(f) => sentence_span(f),
139 }
140 }
141}
142
143fn collect_definitions(
149 lines: &[Vec<Frag>],
150 i: &mut usize,
151 scope: &mut Names,
152 top_level: bool,
153) -> Result<Vec<Frag>> {
154 let mut sentence = lines[*i].clone();
155 *i += 1;
156 let self_name = match (sentence.first(), sentence.get(1)) {
159 (Some(Frag::Name(n, _)), Some(a)) if a.is_assign() => Some(n.clone()),
160 _ => None,
161 };
162 loop {
163 let Some(open) = sentence.iter().position(|f| matches!(f, Frag::DdOpen(_))) else {
164 match find_colon_definition(&sentence) {
165 Some(at) => {
166 take_colon_definition(&mut sentence, at, lines, i, scope, self_name.as_deref())?;
167 continue;
168 }
169 None => {
172 if top_level {
173 if let Some(Frag::Control(_, _, span)) =
174 sentence.iter().find(|f| matches!(f, Frag::Control(..)))
175 {
176 return Err(Error::parse(
177 "control words are only meaningful inside an explicit definition",
178 *span,
179 ));
180 }
181 }
182 return Ok(sentence);
183 }
184 }
185 };
186 take_direct_definition(&mut sentence, open, lines, i, scope, self_name.as_deref())?;
187 }
188}
189
190fn find_colon_definition(sentence: &[Frag]) -> Option<usize> {
192 (1..sentence.len().saturating_sub(1)).find(|&k| {
193 matches!(&sentence[k], Frag::Conj(":", _))
194 && as_const(&sentence[k - 1]).is_some_and(|a| a.rank() == 0)
195 && matches!(&sentence[k + 1], Frag::Noun(Expr::Const(..)))
196 })
197}
198
199fn take_colon_definition(
202 sentence: &mut Vec<Frag>,
203 at: usize,
204 lines: &[Vec<Frag>],
205 i: &mut usize,
206 scope: &mut Names,
207 self_name: Option<&str>,
208) -> Result<()> {
209 let span = Span::merge(sentence[at - 1].span(), sentence[at + 1].span());
210 let valence = as_const(&sentence[at - 1])
211 .and_then(Array::to_f64_vec)
212 .and_then(|v| v.first().copied())
213 .ok_or_else(|| Error::parse("an explicit definition starts with a number", span))?;
214 let body_arr = as_const(&sentence[at + 1]).cloned().expect("checked by the finder");
215 let body_span = sentence[at + 1].span();
216 let dyadic = match valence {
217 3.0 => false,
218 4.0 => true,
219 1.0 | 2.0 => {
220 return Err(Error::not_yet("explicit adverbs and conjunctions (1 : and 2 :)", span));
221 }
222 13.0 => return Err(Error::not_yet("tacit definitions (13 : '...')", span)),
223 v => return Err(Error::domain(format!("{v} is not an explicit definition"), span)),
224 };
225 let body = match &body_arr.data {
226 Data::I64(_)
228 | Data::F64(_)
229 | Data::Bool(_)
230 | Data::Ext(_)
231 | Data::Rat(_)
232 | Data::Complex(_) => {
233 if body_arr.to_f64_vec().as_deref() != Some(&[0.0]) {
234 return Err(Error::parse("an explicit definition takes 0 or a string", body_span));
235 }
236 take_lines_until_paren(lines, i, body_span)?
237 }
238 Data::Char(chars) => {
239 let text: String = chars.as_slice().iter().collect();
240 let mut frags = Vec::new();
241 lex_line(&text, body_span.start + 1, &mut frags)?;
244 vec![frags]
245 }
246 Data::Box(_) => {
247 return Err(Error::parse("an explicit definition takes 0 or a string", body_span))
248 }
249 };
250 let name = if dyadic { "4 : '...'" } else { "3 : '...'" };
251 let verb = build_definition(body, dyadic, name, scope, self_name)?;
252 sentence.splice(at - 1..at + 2, [Frag::Verb(VerbFrag::V(verb), span)]);
253 Ok(())
254}
255
256fn take_lines_until_paren(
258 lines: &[Vec<Frag>],
259 i: &mut usize,
260 span: Span,
261) -> Result<Vec<Vec<Frag>>> {
262 let mut body = Vec::new();
263 loop {
264 let Some(line) = lines.get(*i) else {
265 return Err(Error::parse("this definition's body has no closing `)`", span));
266 };
267 *i += 1;
268 if line.len() == 1 && matches!(line[0], Frag::RParen(_)) {
269 return Ok(body);
270 }
271 body.push(line.clone());
272 }
273}
274
275fn take_direct_definition(
278 sentence: &mut Vec<Frag>,
279 open: usize,
280 lines: &[Vec<Frag>],
281 i: &mut usize,
282 scope: &mut Names,
283 self_name: Option<&str>,
284) -> Result<()> {
285 let open_span = sentence[open].span();
286 let mut depth = 1usize;
287 let mut body: Vec<Vec<Frag>> = Vec::new();
288 let mut tail: Vec<Frag> = Vec::new();
289 let mut close_span = open_span;
290 let mut line: Vec<Frag> = sentence[open + 1..].to_vec();
291 let mut cur: Vec<Frag> = Vec::new();
292 loop {
293 let mut closed = false;
294 for (k, f) in line.iter().enumerate() {
295 match f {
296 Frag::DdOpen(_) => {
297 depth += 1;
298 cur.push(f.clone());
299 }
300 Frag::DdClose(s) => {
301 depth -= 1;
302 if depth == 0 {
303 close_span = *s;
304 tail = line[k + 1..].to_vec();
305 closed = true;
306 break;
307 }
308 cur.push(f.clone());
309 }
310 _ => cur.push(f.clone()),
311 }
312 }
313 if !cur.is_empty() {
314 body.push(std::mem::take(&mut cur));
315 }
316 if closed {
317 break;
318 }
319 let Some(next) = lines.get(*i) else {
320 return Err(Error::parse("this definition has no closing `}}`", open_span));
321 };
322 *i += 1;
323 line = next.clone();
324 }
325 let span = Span::merge(open_span, close_span);
326 for l in &body {
328 for f in l {
329 if let Frag::Name(n, s) = f {
330 if matches!(n.as_str(), "u" | "v" | "m" | "n") {
331 return Err(Error::not_yet(
332 "direct definitions of adverbs and conjunctions ({{ with u v m n }})",
333 *s,
334 ));
335 }
336 }
337 }
338 }
339 let dyadic = body
340 .iter()
341 .any(|l| l.iter().any(|f| matches!(f, Frag::Name(n, _) if n == "x")));
342 let verb = build_definition(body, dyadic, "{{ ... }}", scope, self_name)?;
343 let mut head: Vec<Frag> = sentence[..open].to_vec();
344 head.push(Frag::Verb(VerbFrag::V(verb), span));
345 head.extend(tail);
346 *sentence = head;
347 Ok(())
348}
349
350fn build_definition(
352 body: Vec<Vec<Frag>>,
353 dyadic: bool,
354 name: &str,
355 scope: &Names,
356 self_name: Option<&str>,
357) -> Result<Verb> {
358 let mut inner = scope.clone();
361 inner.nouns.insert("y".to_string());
362 inner.verbs.remove("y");
363 if dyadic {
364 inner.nouns.insert("x".to_string());
365 inner.verbs.remove("x");
366 }
367 if let Some(n) = self_name {
368 inner.nouns.remove(n);
369 inner.verbs.insert(n.to_string(), Verb::Named(n.to_string()));
370 }
371 let mut lines: Vec<Vec<Frag>> = Vec::new();
375 let mut k = 0usize;
376 while k < body.len() {
377 let line = collect_definitions(&body, &mut k, &mut inner, false)?;
378 if !line.is_empty() {
379 lines.push(line);
380 }
381 }
382 let items = split_items(&lines);
383 let mut cursor = Cursor { items: &items, at: 0 };
384 let stmts = parse_block(&mut cursor, &mut inner, &[])?;
385 if let Some(item) = cursor.peek() {
386 return Err(Error::parse(
387 format!("`{}` has no matching opening word", item.word().unwrap_or("word")),
388 item.span(),
389 ));
390 }
391 let pure = stmts.iter().all(block_is_pure);
392 Ok(Verb::Explicit(Arc::new(ExplicitDef {
393 name: name.to_string(),
394 left: dyadic.then(|| "x".to_string()),
395 right: "y".to_string(),
396 dyad_only: dyadic,
399 result: None,
400 locals: Vec::new(),
401 body: stmts,
402 labels: Vec::new(),
404 empty: Some(crate::ir::empty_result()),
405 pure,
406 })))
407}
408
409fn block_is_pure(e: &Expr) -> bool {
411 match e {
412 Expr::Const(..) | Expr::Param(..) | Expr::Name(..) => true,
413 Expr::Monad { verb, y, .. } => verb.is_pure() && block_is_pure(y),
414 Expr::Dyad { verb, x, y, .. } => {
415 verb.is_pure() && block_is_pure(x) && block_is_pure(y)
416 }
417 Expr::Assign { value, .. } => block_is_pure(value),
418 Expr::Control(c, _) => control_is_pure(c),
419 _ => false,
420 }
421}
422
423fn control_is_pure(c: &Control) -> bool {
424 let all = |b: &Vec<Expr>| b.iter().all(block_is_pure);
425 match c {
426 Control::Return | Control::Break | Control::Continue => true,
427 Control::Branch(target) => block_is_pure(target),
430 Control::If { arms, otherwise } => {
431 arms.iter().all(|a| {
432 a.test.as_ref().is_none_or(all) && all(&a.body)
433 }) && otherwise.as_ref().is_none_or(all)
434 }
435 Control::While { test, body, .. } => all(test) && all(body),
436 Control::For { source, body, .. } => block_is_pure(source) && all(body),
437 Control::Select { subject, cases } => {
438 block_is_pure(subject)
439 && cases.iter().all(|c| c.test.as_ref().is_none_or(all) && all(&c.body))
440 }
441 Control::Try { body, catch } => all(body) && all(catch),
442 }
443}
444
445fn split_items(lines: &[Vec<Frag>]) -> Vec<Item> {
447 let mut items = Vec::new();
448 for line in lines {
449 let mut run: Vec<Frag> = Vec::new();
450 for f in line {
451 match f {
452 Frag::Control(word, suffix, span) => {
453 if !run.is_empty() {
454 items.push(Item::Sentence(std::mem::take(&mut run)));
455 }
456 items.push(Item::Word {
457 word,
458 suffix: suffix.clone(),
459 span: *span,
460 });
461 }
462 _ => run.push(f.clone()),
463 }
464 }
465 if !run.is_empty() {
466 items.push(Item::Sentence(run));
467 }
468 }
469 items
470}
471
472struct Cursor<'a> {
473 items: &'a [Item],
474 at: usize,
475}
476
477impl<'a> Cursor<'a> {
478 fn peek(&self) -> Option<&'a Item> {
479 self.items.get(self.at)
480 }
481
482 fn peek_word(&self) -> Option<&'static str> {
483 self.peek().and_then(Item::word)
484 }
485
486 fn next(&mut self) -> Option<&'a Item> {
487 let it = self.items.get(self.at);
488 if it.is_some() {
489 self.at += 1;
490 }
491 it
492 }
493
494 fn last_span(&self) -> Span {
495 self.items
496 .get(self.at.saturating_sub(1))
497 .map_or_else(|| Span::new(0, 0), Item::span)
498 }
499
500 fn expect(&mut self, want: &str) -> Result<Span> {
502 match self.peek() {
503 Some(Item::Word { word, span, .. }) if *word == want => {
504 self.at += 1;
505 Ok(*span)
506 }
507 Some(other) => {
508 Err(Error::parse(format!("expected `{want}` here"), other.span()))
509 }
510 None => Err(Error::parse(format!("this block needs a `{want}`"), self.last_span())),
511 }
512 }
513}
514
515fn parse_block(cur: &mut Cursor<'_>, scope: &mut Names, stop: &[&str]) -> Result<Vec<Expr>> {
517 let mut out = Vec::new();
518 loop {
519 match cur.peek() {
520 None => return Ok(out),
521 Some(Item::Word { word, .. }) if stop.contains(word) => return Ok(out),
522 Some(Item::Sentence(frags)) => {
523 cur.at += 1;
524 let stmt = scope.parse_sentence(frags.clone())?;
525 scope.record(&stmt);
526 out.push(stmt);
527 }
528 Some(Item::Word { .. }) => out.push(parse_control(cur, scope)?),
529 }
530 }
531}
532
533fn parse_control(cur: &mut Cursor<'_>, scope: &mut Names) -> Result<Expr> {
534 let Some(Item::Word { word, suffix, span }) = cur.next() else {
535 return Err(Error::internal("expected a control word"));
536 };
537 let start = *span;
538 let control = match *word {
539 "if." => parse_if(cur, scope)?,
540 "while." | "whilst." => {
541 let body_first = *word == "whilst.";
542 let test = parse_block(cur, scope, &["do."])?;
543 cur.expect("do.")?;
544 let body = parse_block(cur, scope, &["end."])?;
545 cur.expect("end.")?;
546 Control::While { test, body, body_first, until: false }
547 }
548 "for." => {
549 if let Some(name) = suffix {
550 scope.nouns.insert(name.clone());
551 scope.nouns.insert(format!("{name}_index"));
552 scope.verbs.remove(name);
553 }
554 let source = parse_block(cur, scope, &["do."])?;
555 cur.expect("do.")?;
556 let body = parse_block(cur, scope, &["end."])?;
557 let end = cur.expect("end.")?;
558 let source = one_expr(source, Span::merge(start, end))?;
559 Control::For { name: suffix.clone(), source: Box::new(source), body }
560 }
561 "select." => parse_select(cur, scope, start)?,
562 "try." => {
563 let body = parse_block(cur, scope, &["catch.", "catcht.", "end."])?;
564 if cur.peek_word() == Some("catcht.") {
565 return Err(Error::not_yet("throw. and catcht.", cur.last_span()));
566 }
567 let catch = if cur.peek_word() == Some("catch.") {
568 cur.expect("catch.")?;
569 parse_block(cur, scope, &["end."])?
570 } else {
571 Vec::new()
572 };
573 cur.expect("end.")?;
574 Control::Try { body, catch }
575 }
576 "return." => Control::Return,
577 "break." => Control::Break,
578 "continue." => Control::Continue,
579 "throw." | "catcht." => return Err(Error::not_yet("throw. and catcht.", start)),
580 "goto." | "label." => {
581 return Err(Error::not_yet("goto_name. and label_name.", start))
582 }
583 other => {
584 return Err(Error::parse(
585 format!("`{other}` has no matching opening word"),
586 start,
587 ))
588 }
589 };
590 let span = Span::merge(start, cur.last_span());
591 Ok(Expr::Control(Box::new(control), span))
592}
593
594fn parse_if(cur: &mut Cursor<'_>, scope: &mut Names) -> Result<Control> {
595 let mut arms = Vec::new();
596 let mut otherwise = None;
597 loop {
598 let test = parse_block(cur, scope, &["do."])?;
599 cur.expect("do.")?;
600 let body = parse_block(cur, scope, &["elseif.", "else.", "end."])?;
601 arms.push(Branch { test: Some(test), body, fall_through: false });
602 match cur.peek_word() {
603 Some("elseif.") => {
604 cur.at += 1;
605 }
606 Some("else.") => {
607 cur.at += 1;
608 otherwise = Some(parse_block(cur, scope, &["end."])?);
609 cur.expect("end.")?;
610 break;
611 }
612 _ => {
613 cur.expect("end.")?;
614 break;
615 }
616 }
617 }
618 if let Some(last) = arms.last_mut() {
621 if last.test.as_ref().is_some_and(Vec::is_empty) {
622 last.test = None;
623 }
624 }
625 Ok(Control::If { arms, otherwise })
626}
627
628fn parse_select(cur: &mut Cursor<'_>, scope: &mut Names, start: Span) -> Result<Control> {
629 let subject = parse_block(cur, scope, &["case.", "fcase.", "end."])?;
630 let subject = one_expr(subject, start)?;
631 let mut cases = Vec::new();
632 loop {
633 let fall_through = match cur.peek_word() {
634 Some("case.") => false,
635 Some("fcase.") => true,
636 _ => {
637 cur.expect("end.")?;
638 break;
639 }
640 };
641 cur.at += 1;
642 let test = parse_block(cur, scope, &["do."])?;
643 cur.expect("do.")?;
644 let body = parse_block(cur, scope, &["case.", "fcase.", "end."])?;
645 let test = (!test.is_empty()).then_some(test);
647 cases.push(Branch { test, body, fall_through });
648 }
649 Ok(Control::Select { subject: Box::new(subject), cases })
650}
651
652fn one_expr(mut stmts: Vec<Expr>, span: Span) -> Result<Expr> {
655 match stmts.pop() {
656 Some(e) if stmts.is_empty() => Ok(e),
657 Some(_) => Err(Error::not_yet("several sentences where one value is needed", span)),
658 None => Err(Error::parse("this control word needs a value", span)),
659 }
660}
661
662fn substitute_verbs(sentence: &mut [Frag], verbs: &HashMap<String, Verb>) {
666 for i in 0..sentence.len() {
667 let Frag::Name(name, span) = &sentence[i] else { continue };
668 if sentence.get(i + 1).is_some_and(Frag::is_assign) {
669 continue;
670 }
671 if let Some(v) = verbs.get(name) {
672 sentence[i] = Frag::Verb(VerbFrag::V(v.clone()), *span);
673 }
674 }
675}
676
677fn assigned_names(e: &Expr, out: &mut Vec<String>) {
679 match e {
680 Expr::Assign { name, value, .. } => {
681 out.push(name.clone());
682 assigned_names(value, out);
683 }
684 Expr::Monad { y, .. } => assigned_names(y, out),
685 Expr::Dyad { x, y, .. } => {
686 assigned_names(x, out);
687 assigned_names(y, out);
688 }
689 Expr::PrintPass { value, .. } => assigned_names(value, out),
690 _ => {}
691 }
692}
693
694#[derive(Clone, Debug)]
700enum Frag {
701 Mark,
703 Noun(Expr),
704 Name(String, Span),
706 Verb(VerbFrag, Span),
707 Adverb(&'static str, Span),
708 Conj(&'static str, Span),
709 LParen(Span),
710 RParen(Span),
711 AssignLocal(Span),
712 AssignGlobal(Span),
713 VerbDef(String, Verb, Span),
716 Control(&'static str, Option<String>, Span),
719 DdOpen(Span),
721 DdClose(Span),
722 Gerund(Vec<Verb>, Span),
726}
727
728#[derive(Clone, Debug)]
731enum VerbFrag {
732 V(Verb),
733 Cap,
734}
735
736impl Frag {
737 fn span(&self) -> Span {
738 match self {
739 Frag::Mark => Span::new(0, 0),
740 Frag::Noun(e) => e.span(),
741 Frag::Name(_, s)
742 | Frag::Verb(_, s)
743 | Frag::Adverb(_, s)
744 | Frag::Conj(_, s)
745 | Frag::LParen(s)
746 | Frag::RParen(s)
747 | Frag::AssignLocal(s)
748 | Frag::AssignGlobal(s)
749 | Frag::DdOpen(s)
750 | Frag::DdClose(s)
751 | Frag::VerbDef(_, _, s) => *s,
752 Frag::Control(_, _, s) => *s,
753 Frag::Gerund(_, s) => *s,
754 }
755 }
756
757 fn is_edge(&self) -> bool {
758 matches!(self, Frag::Mark | Frag::AssignLocal(_) | Frag::AssignGlobal(_) | Frag::LParen(_))
759 }
760
761 fn is_verb(&self) -> bool {
763 matches!(self, Frag::Verb(..))
764 }
765
766 fn is_real_verb(&self) -> bool {
768 matches!(self, Frag::Verb(VerbFrag::V(_), _))
769 }
770
771 fn is_noun(&self) -> bool {
773 matches!(self, Frag::Noun(_) | Frag::Name(..))
774 }
775
776 fn is_adverb(&self) -> bool {
777 matches!(self, Frag::Adverb(..))
778 }
779
780 fn is_conj(&self) -> bool {
781 matches!(self, Frag::Conj(..))
782 }
783
784 fn is_gerund(&self) -> bool {
785 matches!(self, Frag::Gerund(..))
786 }
787
788 fn is_avn(&self) -> bool {
789 self.is_adverb() || self.is_verb() || self.is_noun() || self.is_gerund()
790 }
791
792 fn is_cavn(&self) -> bool {
793 self.is_conj() || self.is_avn()
794 }
795
796 fn is_assign(&self) -> bool {
797 matches!(self, Frag::AssignLocal(_) | Frag::AssignGlobal(_))
798 }
799}
800
801const fn prim(name: &'static str, monad: MonadOp, dyad: DyadOp, ranks: [i64; 3]) -> Prim {
804 Prim { name, monad, dyad, ranks }
805}
806
807fn primitive(word: &str) -> Option<Prim> {
811 use DyadOp as D;
812 use MonadOp as M;
813 use ScalarDyad as SD;
814 use ScalarMonad as SM;
815 const INF: i64 = RANK_INF;
816 Some(match word {
817 "+" => prim("+", M::Scalar(SM::Conj), D::Scalar(SD::Add), [0, 0, 0]),
818 "-" => prim("-", M::Scalar(SM::Neg), D::Scalar(SD::Sub), [0, 0, 0]),
819 "*" => prim("*", M::Scalar(SM::Signum), D::Scalar(SD::Mul), [0, 0, 0]),
820 "%" => prim("%", M::Scalar(SM::Recip), D::Scalar(SD::DivJ), [0, 0, 0]),
821 "^" => prim("^", M::Scalar(SM::Exp), D::Scalar(SD::Pow), [0, 0, 0]),
822 "%:" => prim("%:", M::Scalar(SM::Sqrt), D::Scalar(SD::Root), [0, 0, 0]),
823 "^." => prim("^.", M::Scalar(SM::Ln), D::Scalar(SD::Log), [0, 0, 0]),
824 "|" => prim("|", M::Scalar(SM::Abs), D::Scalar(SD::Residue), [0, 0, 0]),
825 "<." => prim("<.", M::Scalar(SM::Floor), D::Scalar(SD::Min), [0, 0, 0]),
826 ">." => prim(">.", M::Scalar(SM::Ceil), D::Scalar(SD::Max), [0, 0, 0]),
827 "=" => prim("=", M::SelfClassify, D::Scalar(SD::Eq), [INF, 0, 0]),
828 "<" => prim("<", M::Enclose(Enclose::Always), D::Scalar(SD::Lt), [INF, 0, 0]),
829 ">" => prim(">", M::Open, D::Scalar(SD::Gt), [0, 0, 0]),
830 "<:" => prim("<:", M::Scalar(SM::Dec), D::Scalar(SD::Le), [0, 0, 0]),
831 ">:" => prim(">:", M::Scalar(SM::Inc), D::Scalar(SD::Ge), [0, 0, 0]),
832 "+:" => prim("+:", M::Scalar(SM::Double), D::Boolean(BoolDyad::Nor), [0, 0, 0]),
833 "*:" => prim("*:", M::Scalar(SM::Square), D::Boolean(BoolDyad::Nand), [0, 0, 0]),
834 "-:" => prim("-:", M::Scalar(SM::Halve), D::Match, [0, INF, INF]),
835 "-." => prim("-.", M::Scalar(SM::OneMinus), D::Less, [0, INF, INF]),
836 "*." => prim("*.", M::ComplexParts { polar: true }, D::Scalar(SD::Lcm), [0, 0, 0]),
837 "+." => prim("+.", M::ComplexParts { polar: false }, D::Scalar(SD::Gcd), [0, 0, 0]),
838 "~:" => prim("~:", M::NubSieve, D::Scalar(SD::Ne), [INF, 0, 0]),
839 "~." => prim("~.", M::Nub, D::None, [INF, INF, INF]),
840 "$" => prim("$", M::ShapeOf, D::Reshape, [INF, 1, INF]),
841 "," => prim(",", M::Ravel, D::AppendLeading, [INF, INF, INF]),
842 ",." => prim(",.", M::Ravel, D::AppendLeading, [INF, INF, INF]),
844 ",:" => prim(",:", M::Itemize, D::Laminate, [INF, INF, INF]),
845 "#" => prim("#", M::Tally, D::Copy, [INF, 1, INF]),
846 "#." => prim("#.", M::DecodeBits, D::Decode, [1, 1, 1]),
847 "#:" => prim("#:", M::EncodeBits, D::Encode, [INF, 1, 0]),
850 "!" => prim("!", M::Scalar(SM::Factorial), D::Scalar(SD::Binomial), [0, 0, 0]),
851 "\":" => {
852 prim("\":", M::Format, D::NotYet("format with a specification"), [INF, 1, INF])
853 }
854 "o." => prim("o.", M::Scalar(SM::Pi), D::Scalar(SD::Circle), [0, 0, 0]),
855 "j." => prim("j.", M::Scalar(SM::Imaginary), D::Scalar(SD::MakeComplex), [0, 0, 0]),
856 "r." => prim("r.", M::Scalar(SM::Polar), D::Scalar(SD::PolarBy), [0, 0, 0]),
857 "{" => prim("{", M::NotYet("catalogue (monadic {)"), D::From, [INF, 0, INF]),
858 "{." => prim("{.", M::Head, D::Take, [INF, 1, INF]),
859 "}." => prim("}.", M::Behead, D::Drop, [INF, 1, INF]),
860 "{:" => prim("{:", M::Tail, D::None, [INF, INF, INF]),
861 "}:" => prim("}:", M::Curtail, D::None, [INF, INF, INF]),
862 "|." => prim("|.", M::Reverse, D::Rotate, [INF, 1, INF]),
863 "|:" => prim("|:", M::TransposeAxes, D::NotYet("dyadic transpose"), [INF, 1, INF]),
864 "i." => prim("i.", M::IotaJ, D::IndexOf { origin: 0 }, [1, INF, INF]),
865 "i:" => prim("i:", M::Steps, D::IndexOfLast { origin: 0 }, [0, INF, INF]),
866 "I." => prim(
867 "I.",
868 M::Indices { origin: 0, boxed_coords: false },
869 D::IntervalIndex { offset: 0 },
870 [1, 1, INF],
871 ),
872 "x:" => prim("x:", M::ToExact, D::ExactForm, [INF, 0, INF]),
875 "p:" => prim("p:", M::NthPrime, D::PrimeMeta, [0, 0, 0]),
876 "p." => prim("p.", M::PolyRoots, D::PolyEval, [1, 1, 0]),
879 "p.." => prim("p..", M::PolyDeriv, D::PolyIntegral, [1, 0, 1]),
880 "$." => prim(
881 "$.",
882 M::NotYet("sparse arrays ($.)"),
883 D::NotYet("sparse arrays ($.)"),
884 [INF, INF, INF],
885 ),
886 "q:" => prim("q:", M::PrimeFactors, D::PrimeExponents, [0, 0, 0]),
887 "%." => prim("%.", M::MatrixInverse, D::MatrixDivide, [2, INF, 2]),
888 "?" => prim(
891 "?",
892 M::Roll { origin: 0, fixed: false, float_at_zero: true },
893 D::Deal { origin: 0, fixed: false },
894 [INF, 0, 0],
895 ),
896 "?." => prim(
897 "?.",
898 M::Roll { origin: 0, fixed: true, float_at_zero: true },
899 D::Deal { origin: 0, fixed: true },
900 [INF, 0, 0],
901 ),
902 "{::" => prim("{::", M::MapPaths, D::Fetch, [INF, INF, INF]),
903 "e." => prim("e.", M::NotYet("raze-in (monadic e.)"), D::MemberJ, [INF, INF, INF]),
904 "/:" => prim(
905 "/:",
906 M::GradeUp { origin: 0 },
907 D::GradeSelect { down: false },
908 [INF, INF, INF],
909 ),
910 "\\:" => prim(
911 "\\:",
912 M::GradeDown { origin: 0 },
913 D::GradeSelect { down: true },
914 [INF, INF, INF],
915 ),
916 ";" => prim(";", M::Raze, D::Link, [INF, INF, INF]),
917 ";:" => prim(
918 ";:",
919 M::Words,
920 D::NotYet("sequential machine (dyadic ;:)"),
921 [INF, INF, INF],
922 ),
923 "L." => prim("L.", M::LevelOf, D::None, [INF, INF, INF]),
924 "\"." => prim(
925 "\".",
926 M::Execute { apl: false },
927 D::NotYet("numbers from text (dyadic \".)"),
928 [1, INF, INF],
929 ),
930 "A." => prim("A.", M::AnagramIndex, D::AnagramFrom, [1, 0, INF]),
931 "C." => prim("C.", M::CycleForm, D::Permute, [INF, INF, INF]),
932 "E." => prim("E.", M::None, D::FindSeq, [INF, INF, INF]),
933 "u:" => prim("u:", M::Unicode { pass_chars: true }, D::UnicodeForm, [INF, 0, INF]),
934 "s:" => prim(
935 "s:",
936 M::NotYet("symbols (s:)"),
937 D::NotYet("symbols (s:)"),
938 [INF, INF, INF],
939 ),
940 "]" => prim("]", M::Same, D::Right, [INF, INF, INF]),
941 "[" => prim("[", M::Same, D::Left, [INF, INF, INF]),
942 "echo" => prim("echo", M::Echo, D::None, [INF, INF, INF]),
943 _ => return None,
944 })
945}
946
947fn noun_word(word: &str) -> Option<Array> {
951 match word {
952 "a." => Some(Array::from_chars(
953 (0u32..256).map(|c| char::from_u32(c).expect("a Latin-1 codepoint")).collect(),
954 )),
955 "a:" => Some(Array::boxed(Array::empty(crate::dtype::DType::I64))),
956 _ => None,
957 }
958}
959
960fn verb_for(word: &str) -> Option<Verb> {
963 let p = primitive(word)?;
964 if word == ",." {
965 return Some(Verb::Rank(Box::new(Verb::Prim(p)), [-1, -1, -1]));
966 }
967 Some(Verb::Prim(p))
968}
969
970fn constant_verb(n: Array) -> Verb {
973 Verb::NounFork(
976 n,
977 Box::new(verb_for("[").expect("`[` is a primitive")),
978 Box::new(verb_for("]").expect("`]` is a primitive")),
979 )
980}
981
982fn constant_verb_word(cs: &[(usize, char)], i: usize) -> Option<(usize, Array)> {
986 let at = |k: usize| cs.get(k).map(|&(_, c)| c);
987 let (digits, value) = match (at(i), at(i + 1), at(i + 2)) {
988 (Some('_'), Some(':'), _) => (2, f64::INFINITY),
989 (Some('_'), Some(d), Some(':')) if d.is_ascii_digit() => {
990 (3, -((d as u8 - b'0') as f64))
991 }
992 (Some(d), Some(':'), _) if d.is_ascii_digit() => (2, (d as u8 - b'0') as f64),
993 _ => return None,
994 };
995 if at(i + digits) == Some(':') {
996 return None;
997 }
998 let arr = if value.is_infinite() {
999 Array::scalar_f64(value)
1000 } else {
1001 Array::scalar_i64(value as i64)
1002 };
1003 Some((digits, arr))
1004}
1005
1006pub(crate) fn verb_named(word: &str) -> Option<Verb> {
1009 verb_for(word)
1010}
1011
1012const ADVERBS: [&str; 9] = ["/", "\\", "/.", "\\.", "~", "}", "f.", "M.", "b."];
1013
1014const CONJUNCTIONS: [&str; 24] = [
1017 "\"", "@", "@.", "@:", "&", "&.", "&.:", "&:", "^:", ";.", "!.", "!:", "`", "`:", ".", ":",
1018 ":.", "::", "L:", "S:", "H.", "T.", "t.", "t:",
1019];
1020
1021fn adverb(word: &str) -> Option<&'static str> {
1022 ADVERBS.iter().copied().find(|&g| g == word)
1023}
1024
1025fn conjunction(word: &str) -> Option<&'static str> {
1026 CONJUNCTIONS.iter().copied().find(|&g| g == word)
1027}
1028
1029fn lex(src: &SourceParts) -> Result<Vec<Vec<Frag>>> {
1034 let mut sentences: Vec<Vec<Frag>> = Vec::new();
1035 let mut cur: Vec<Frag> = Vec::new();
1036 for seg in &src.segments {
1037 match seg {
1038 Segment::Text { text, offset } => {
1039 let mut pos = 0usize;
1040 for (n, line) in text.split('\n').enumerate() {
1041 if n > 0 && !cur.is_empty() {
1042 sentences.push(std::mem::take(&mut cur));
1043 }
1044 lex_line(line, offset + pos, &mut cur)?;
1045 pos += line.len() + 1;
1046 }
1047 }
1048 Segment::Param { index, offset, len } => {
1049 let span = Span::new(*offset, *offset + *len);
1050 cur.push(Frag::Noun(Expr::Param(*index, span)));
1051 }
1052 }
1053 }
1054 if !cur.is_empty() {
1055 sentences.push(cur);
1056 }
1057 Ok(sentences)
1058}
1059
1060#[derive(Clone, Debug)]
1063enum Num {
1064 I(i64),
1065 F(f64),
1066 X(crate::exact::Ext),
1068 R(crate::exact::Rat),
1070 C(crate::complex::Cx),
1071}
1072
1073fn lex_line(text: &str, base: usize, out: &mut Vec<Frag>) -> Result<()> {
1074 let cs: Vec<(usize, char)> = text.char_indices().collect();
1075 let at = |i: usize| cs.get(i).map(|&(_, c)| c);
1076 let off = |i: usize| cs.get(i).map(|&(o, _)| o).unwrap_or(text.len());
1077 let span = |a: usize, b: usize| Span::new(base + off(a), base + off(b));
1078 let mut i = 0usize;
1079 while i < cs.len() {
1080 let c = cs[i].1;
1081 if c.is_whitespace() {
1082 i += 1;
1083 continue;
1084 }
1085 if c == 'N' && at(i + 1) == Some('B') && at(i + 2) == Some('.') {
1088 break;
1089 }
1090 if c == '\'' {
1091 let start = i;
1092 i += 1;
1093 let mut chars: Vec<char> = Vec::new();
1094 loop {
1095 match at(i) {
1096 None => {
1097 return Err(Error::parse(
1098 "unterminated string literal",
1099 span(start, cs.len()),
1100 ));
1101 }
1102 Some('\'') if at(i + 1) == Some('\'') => {
1103 chars.push('\'');
1104 i += 2;
1105 }
1106 Some('\'') => {
1107 i += 1;
1108 break;
1109 }
1110 Some(ch) => {
1111 chars.push(ch);
1112 i += 1;
1113 }
1114 }
1115 }
1116 let shape = if chars.len() == 1 { vec![] } else { vec![chars.len()] };
1118 let arr = Array::new(shape, Data::Char(chars.into()));
1119 out.push(Frag::Noun(Expr::Const(arr, span(start, i))));
1120 continue;
1121 }
1122 if let Some((len, n)) = constant_verb_word(&cs, i) {
1123 out.push(Frag::Verb(VerbFrag::V(constant_verb(n)), span(i, i + len)));
1124 i += len;
1125 continue;
1126 }
1127 if starts_number(&cs, i) {
1128 let start = i;
1130 let mut nums: Vec<Num> = Vec::new();
1131 let mut end;
1132 loop {
1133 let ws = i;
1134 while at(i).is_some_and(|c| c.is_ascii_alphanumeric() || c == '.' || c == '_') {
1135 i += 1;
1136 }
1137 nums.push(parse_number(&text[off(ws)..off(i)], span(ws, i))?);
1138 end = i;
1139 let mut k = i;
1140 while at(k).is_some_and(char::is_whitespace) {
1141 k += 1;
1142 }
1143 if k < cs.len()
1146 && starts_number(&cs, k)
1147 && constant_verb_word(&cs, k).is_none()
1148 {
1149 i = k;
1150 } else {
1151 break;
1152 }
1153 }
1154 out.push(Frag::Noun(Expr::Const(num_array(&nums), span(start, end))));
1155 continue;
1156 }
1157 if c.is_ascii_alphabetic() {
1158 let start = i;
1159 i += 1;
1160 while at(i).is_some_and(|c| c.is_ascii_alphanumeric() || c == '_') {
1161 i += 1;
1162 }
1163 let mut inflected = None;
1168 if matches!(at(i), Some('.') | Some(':')) {
1169 let most = if matches!(at(i + 1), Some('.') | Some(':')) { 2 } else { 1 };
1170 for n in (1..=most).rev() {
1171 let word = &text[off(start)..off(i + n)];
1172 let sp = span(start, i + n);
1173 let frag = if let Some(v) = verb_for(word) {
1174 Frag::Verb(VerbFrag::V(v), sp)
1175 } else if let Some(value) = noun_word(word) {
1176 Frag::Noun(Expr::Const(value, sp))
1177 } else if let Some(g) = adverb(word) {
1178 Frag::Adverb(g, sp)
1179 } else if let Some(g) = conjunction(word) {
1180 Frag::Conj(g, sp)
1181 } else if let Some((cw, suffix)) = control_word(word) {
1182 Frag::Control(cw, suffix, sp)
1183 } else {
1184 continue;
1185 };
1186 inflected = Some((frag, n));
1187 break;
1188 }
1189 }
1190 if let Some((frag, n)) = inflected {
1191 i += n;
1192 out.push(frag);
1193 continue;
1194 }
1195 let word = &text[off(start)..off(i)];
1196 match verb_for(word) {
1197 Some(v) => out.push(Frag::Verb(VerbFrag::V(v), span(start, i))),
1198 None => out.push(Frag::Name(word.to_string(), span(start, i))),
1199 }
1200 continue;
1201 }
1202 if c == '{' && at(i + 1) == Some('{') {
1204 out.push(Frag::DdOpen(span(i, i + 2)));
1205 i += 2;
1206 continue;
1207 }
1208 if c == '}' && at(i + 1) == Some('}') {
1209 out.push(Frag::DdClose(span(i, i + 2)));
1210 i += 2;
1211 continue;
1212 }
1213 let inflectable = c != '(' && c != ')';
1217 let mut len =
1218 if inflectable && matches!(at(i + 1), Some('.') | Some(':')) { 2 } else { 1 };
1219 if len == 2 && at(i + 2) == Some(':') {
1222 let w = &text[off(i)..off(i + 3)];
1223 if conjunction(w).is_some() || verb_for(w).is_some() {
1224 len = 3;
1225 }
1226 }
1227 let word = &text[off(i)..off(i + len)];
1228 match symbol_frag(word, span(i, i + len)) {
1229 Some(frag) => {
1230 out.push(frag);
1231 i += len;
1232 }
1233 None => {
1234 return Err(Error::parse(format!("unknown word: {word}"), span(i, i + len)));
1235 }
1236 }
1237 }
1238 Ok(())
1239}
1240
1241fn symbol_frag(word: &str, span: Span) -> Option<Frag> {
1242 Some(match word {
1243 "(" => Frag::LParen(span),
1244 ")" => Frag::RParen(span),
1245 "=." => Frag::AssignLocal(span),
1246 "=:" => Frag::AssignGlobal(span),
1247 "[:" => Frag::Verb(VerbFrag::Cap, span),
1248 "$:" => Frag::Verb(VerbFrag::V(Verb::SelfRef), span),
1250 _ => {
1253 if let Some(v) = verb_for(word) {
1254 Frag::Verb(VerbFrag::V(v), span)
1255 } else if let Some(g) = adverb(word) {
1256 Frag::Adverb(g, span)
1257 } else {
1258 Frag::Conj(conjunction(word)?, span)
1259 }
1260 }
1261 })
1262}
1263
1264fn starts_number(cs: &[(usize, char)], i: usize) -> bool {
1267 let c = cs[i].1;
1268 if c.is_ascii_digit() {
1269 return true;
1270 }
1271 if c != '_' {
1272 return false;
1273 }
1274 match cs.get(i + 1).map(|&(_, c)| c) {
1275 None => true,
1276 Some(d) => d.is_ascii_digit() || d == '.' || !d.is_alphanumeric(),
1277 }
1278}
1279
1280fn parse_number(word: &str, span: Span) -> Result<Num> {
1281 if let Some(k) = word.find(['p', 'x']) {
1285 if word[k + 1..].is_empty() {
1286 if word.as_bytes()[k] == b'x' {
1290 return extended_literal(&word[..k], word, span);
1291 }
1292 return Err(Error::parse(format!("invalid number: {word}"), span));
1293 }
1294 let base =
1295 if word.as_bytes()[k] == b'p' { std::f64::consts::PI } else { std::f64::consts::E };
1296 let mantissa = plain_number(&word[..k], word, span)?;
1297 let exponent = plain_number(&word[k + 1..], word, span)?;
1298 return Ok(scale(mantissa, base, exponent));
1299 }
1300 if let Some(k) = word.find('j') {
1303 if !word[..k].contains('b') {
1304 let re = as_f64(plain_number(&word[..k], word, span)?);
1305 let im = as_f64(plain_number(&word[k + 1..], word, span)?);
1306 return Ok(Num::C([re, im]));
1307 }
1308 }
1309 if let Some(k) = word.find("ad").or_else(|| word.find("ar")) {
1312 if !word[..k].contains('b') {
1313 let magnitude = as_f64(plain_number(&word[..k], word, span)?);
1314 let angle = as_f64(plain_number(&word[k + 2..], word, span)?);
1315 return Ok(Num::C(if word.as_bytes()[k + 1] == b'd' {
1316 crate::complex::from_degrees(magnitude, angle)
1317 } else {
1318 crate::complex::from_radians(magnitude, angle)
1319 }));
1320 }
1321 }
1322 if let Some(k) = word.find('r') {
1326 if !word[..k].contains('b') {
1327 return rational_literal(&word[..k], &word[k + 1..], word, span);
1328 }
1329 }
1330 if let Some(k) = word.find('b') {
1331 return base_literal(&word[..k], &word[k + 1..], word, span);
1332 }
1333 plain_number(word, word, span)
1334}
1335
1336fn extended_literal(digits: &str, word: &str, span: Span) -> Result<Num> {
1339 Ok(Num::X(whole_digits(digits, word, span)?))
1340}
1341
1342fn rational_literal(num: &str, den: &str, word: &str, span: Span) -> Result<Num> {
1345 use num_traits::Zero;
1346 let num = whole_digits(num, word, span)?;
1347 let den = whole_digits(den, word, span)?;
1348 if den.is_zero() {
1349 if num.is_zero() {
1350 return Ok(Num::I(0));
1351 }
1352 return Ok(Num::F(if num.sign() == num_bigint::Sign::Minus {
1353 f64::NEG_INFINITY
1354 } else {
1355 f64::INFINITY
1356 }));
1357 }
1358 Ok(Num::R(
1359 crate::exact::Rat::new(num, den).ok_or_else(|| Error::internal("a zero denominator"))?,
1360 ))
1361}
1362
1363fn whole_digits(word: &str, whole: &str, span: Span) -> Result<crate::exact::Ext> {
1365 let invalid = || Error::parse(format!("invalid number: {whole}"), span);
1366 let (digits, negative) = match word.strip_prefix('_') {
1367 Some(rest) => (rest, true),
1368 None => (word, false),
1369 };
1370 if digits.is_empty() || !digits.bytes().all(|b| b.is_ascii_digit()) {
1371 return Err(invalid());
1372 }
1373 let v: crate::exact::Ext = digits.parse().map_err(|_| invalid())?;
1374 Ok(if negative { -v } else { v })
1375}
1376
1377fn scale(mantissa: Num, base: f64, exponent: Num) -> Num {
1380 if matches!(mantissa, Num::C(_)) || matches!(exponent, Num::C(_)) {
1381 let m = as_cx(mantissa);
1382 let f = crate::complex::pow([base, 0.0], as_cx(exponent));
1383 return Num::C(crate::complex::mul(m, f));
1384 }
1385 Num::F(as_f64(mantissa) * base.powf(as_f64(exponent)))
1386}
1387
1388fn as_cx(n: Num) -> crate::complex::Cx {
1389 match n {
1390 Num::C(z) => z,
1391 other => [as_f64(other), 0.0],
1392 }
1393}
1394
1395fn as_f64(n: Num) -> f64 {
1396 match n {
1397 Num::I(v) => v as f64,
1398 Num::F(v) => v,
1399 Num::X(v) => crate::exact::ext_to_f64(&v),
1400 Num::R(v) => v.to_f64(),
1401 Num::C(z) => z[0],
1404 }
1405}
1406
1407fn base_literal(base: &str, digits: &str, word: &str, span: Span) -> Result<Num> {
1410 let invalid = || Error::parse(format!("invalid number: {word}"), span);
1411 let base = as_f64(plain_number(base, word, span)?);
1412 let (digits, negative) = match digits.strip_prefix('_') {
1413 Some(rest) => (rest, true),
1414 None => (digits, false),
1415 };
1416 if digits.is_empty() {
1417 return Err(invalid());
1418 }
1419 let mut value = 0.0f64;
1420 for ch in digits.chars() {
1421 let d = match ch {
1422 '0'..='9' => ch as u32 - '0' as u32,
1423 'a'..='z' => ch as u32 - 'a' as u32 + 10,
1424 _ => return Err(invalid()),
1425 };
1426 value = value * base + f64::from(d);
1427 }
1428 if negative {
1429 value = -value;
1430 }
1431 if value.fract() == 0.0 && value.abs() < 9.007_199_254_740_992e15 {
1433 return Ok(Num::I(value as i64));
1434 }
1435 Ok(Num::F(value))
1436}
1437
1438fn plain_number(word: &str, whole: &str, span: Span) -> Result<Num> {
1442 if word.is_empty() {
1443 return Err(Error::parse(format!("invalid number: {whole}"), span));
1444 }
1445 if word.contains(['j', 'p', 'x', 'b', 'r']) || word.contains("ad") || word.contains("ar") {
1446 return parse_number(word, span);
1447 }
1448 parse_plain(word, span)
1449}
1450
1451fn parse_plain(word: &str, span: Span) -> Result<Num> {
1452 if word == "_" {
1453 return Ok(Num::F(f64::INFINITY));
1454 }
1455 if word == "__" {
1456 return Ok(Num::F(f64::NEG_INFINITY));
1457 }
1458 let invalid = || Error::parse(format!("invalid number: {word}"), span);
1459 let mut norm = String::with_capacity(word.len());
1461 for (k, ch) in word.char_indices() {
1462 if ch == '_' {
1463 if k != 0 && !word[..k].ends_with('e') {
1464 return Err(invalid());
1465 }
1466 norm.push('-');
1467 } else {
1468 norm.push(ch);
1469 }
1470 }
1471 if norm.contains('.') || norm.contains('e') {
1473 return norm.parse::<f64>().map(Num::F).map_err(|_| invalid());
1474 }
1475 match norm.parse::<i64>() {
1478 Ok(v) => Ok(Num::I(v)),
1479 Err(_) => norm.parse::<f64>().map(Num::F).map_err(|_| invalid()),
1480 }
1481}
1482
1483fn num_array(nums: &[Num]) -> Array {
1487 use crate::exact::{Ext, Rat};
1488 let shape = if nums.len() == 1 { vec![] } else { vec![nums.len()] };
1489 let has = |f: fn(&Num) -> bool| nums.iter().any(f);
1490 if has(|n| matches!(n, Num::C(_))) {
1491 let data = nums.iter().map(|n| as_cx(n.clone())).collect();
1492 return Array::new(shape, Data::Complex(data));
1493 }
1494 if has(|n| matches!(n, Num::F(_))) {
1495 let data = nums.iter().map(|n| as_f64(n.clone())).collect();
1496 return Array::new(shape, Data::F64(data));
1497 }
1498 if has(|n| matches!(n, Num::R(_))) {
1499 let data = nums
1500 .iter()
1501 .map(|n| match n {
1502 Num::I(v) => Rat::from_int(Ext::from(*v)),
1503 Num::X(v) => Rat::from_int(v.clone()),
1504 Num::R(v) => v.clone(),
1505 Num::F(_) | Num::C(_) => Rat::zero(),
1506 })
1507 .collect();
1508 return Array::new(shape, Data::Rat(data));
1509 }
1510 if has(|n| matches!(n, Num::X(_))) {
1511 let data = nums
1512 .iter()
1513 .map(|n| match n {
1514 Num::I(v) => Ext::from(*v),
1515 Num::X(v) => v.clone(),
1516 _ => Ext::default(),
1517 })
1518 .collect();
1519 return Array::new(shape, Data::Ext(data));
1520 }
1521 let data = nums
1522 .iter()
1523 .map(|n| match n {
1524 Num::I(v) => *v,
1525 _ => 0,
1526 })
1527 .collect();
1528 Array::new(shape, Data::I64(data))
1529}
1530
1531#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1534enum Rule {
1535 Monad1,
1536 Monad2,
1537 Dyad3,
1538 Adverb4,
1539 Conj5,
1540 Fork6,
1541 Bident7,
1542 Assign8,
1543 Paren9,
1544}
1545
1546fn parse_sentence(tokens: Vec<Frag>, nouns: &HashSet<String>) -> Result<Expr> {
1547 let sentence = sentence_span(&tokens);
1548 check_parens(&tokens)?;
1549 let mut stack: Vec<Frag> = Vec::new();
1550 for frag in tokens.into_iter().rev() {
1551 stack.insert(0, frag);
1552 reduce(&mut stack, nouns)?;
1553 }
1554 stack.insert(0, Frag::Mark);
1555 reduce(&mut stack, nouns)?;
1556 if stack.len() == 2 {
1557 match stack.pop().expect("checked length") {
1558 f @ (Frag::Noun(_) | Frag::Name(..)) => return as_noun(f),
1559 Frag::VerbDef(name, verb, span) => return Ok(Expr::VerbDef { name, verb, span }),
1560 Frag::Verb(VerbFrag::V(_), span) => {
1561 return Err(Error::not_yet(
1562 "tacit verb definitions (a sentence that is a verb)",
1563 span,
1564 ));
1565 }
1566 _ => {}
1567 }
1568 }
1569 Err(Error::parse("syntax error", sentence))
1570}
1571
1572fn check_parens(tokens: &[Frag]) -> Result<()> {
1576 let mut open: Vec<Span> = Vec::new();
1577 for frag in tokens {
1578 match frag {
1579 Frag::LParen(s) => open.push(*s),
1580 Frag::RParen(s) => {
1581 if open.pop().is_none() {
1582 return Err(Error::parse("this `)` has no opening `(`", *s));
1583 }
1584 }
1585 _ => {}
1586 }
1587 }
1588 match open.pop() {
1589 None => Ok(()),
1590 Some(s) => Err(Error::parse("this `(` has no closing `)`", s)),
1591 }
1592}
1593
1594fn sentence_span(tokens: &[Frag]) -> Span {
1595 tokens
1596 .iter()
1597 .map(Frag::span)
1598 .reduce(Span::merge)
1599 .unwrap_or_else(|| Span::new(0, 0))
1600}
1601
1602fn reduce(stack: &mut Vec<Frag>, nouns: &HashSet<String>) -> Result<()> {
1603 while apply(stack, nouns)? {}
1604 Ok(())
1605}
1606
1607fn match_rule(s: &[Frag]) -> Option<Rule> {
1610 let is = |i: usize, f: fn(&Frag) -> bool| s.get(i).is_some_and(f);
1611 let ctx = |i: usize| s.get(i).is_some_and(|f| f.is_edge() || f.is_avn());
1614 let verb_or_noun =
1615 |i: usize| s.get(i).is_some_and(|f| f.is_real_verb() || f.is_noun() || f.is_gerund());
1616 if is(0, Frag::is_edge) && is(1, Frag::is_real_verb) && is(2, Frag::is_noun) {
1617 return Some(Rule::Monad1);
1618 }
1619 if ctx(0) && is(1, Frag::is_verb) && is(2, Frag::is_real_verb) && is(3, Frag::is_noun) {
1620 return Some(Rule::Monad2);
1621 }
1622 if ctx(0) && is(1, Frag::is_noun) && is(2, Frag::is_real_verb) && is(3, Frag::is_noun) {
1623 return Some(Rule::Dyad3);
1624 }
1625 if ctx(0) && verb_or_noun(1) && is(2, Frag::is_adverb) {
1626 return Some(Rule::Adverb4);
1627 }
1628 if ctx(0) && verb_or_noun(1) && is(2, Frag::is_conj) && verb_or_noun(3) {
1629 return Some(Rule::Conj5);
1630 }
1631 if ctx(0)
1632 && s.get(1).is_some_and(|f| f.is_verb() || f.is_noun())
1633 && is(2, Frag::is_real_verb)
1634 && is(3, Frag::is_real_verb)
1635 {
1636 return Some(Rule::Fork6);
1637 }
1638 if is(0, Frag::is_edge) && is(1, Frag::is_cavn) && is(2, Frag::is_cavn) {
1639 return Some(Rule::Bident7);
1640 }
1641 if is(0, Frag::is_noun) && is(1, Frag::is_assign) && is(2, Frag::is_cavn) {
1642 return Some(Rule::Assign8);
1643 }
1644 if matches!(s.first(), Some(Frag::LParen(_)))
1645 && is(1, Frag::is_cavn)
1646 && matches!(s.get(2), Some(Frag::RParen(_)))
1647 {
1648 return Some(Rule::Paren9);
1649 }
1650 None
1651}
1652
1653fn take(stack: &mut Vec<Frag>, range: Range<usize>) -> Vec<Frag> {
1654 stack.drain(range).collect()
1655}
1656
1657fn respan(f: Frag, to: Span) -> Frag {
1661 match f {
1662 Frag::Noun(mut e) => {
1663 e.set_span(to);
1664 Frag::Noun(e)
1665 }
1666 Frag::Name(n, _) => Frag::Name(n, to),
1667 Frag::Verb(v, _) => Frag::Verb(v, to),
1668 Frag::Adverb(a, _) => Frag::Adverb(a, to),
1669 Frag::Conj(c, _) => Frag::Conj(c, to),
1670 Frag::Gerund(vs, _) => Frag::Gerund(vs, to),
1671 other => other,
1672 }
1673}
1674
1675fn apply(stack: &mut Vec<Frag>, nouns: &HashSet<String>) -> Result<bool> {
1676 let Some(rule) = match_rule(stack) else {
1677 return Ok(false);
1678 };
1679 match rule {
1680 Rule::Monad1 => {
1681 let mut t = take(stack, 1..3);
1682 let y = t.pop().expect("two slots");
1683 let v = t.pop().expect("two slots");
1684 let frag = monad(v, y)?;
1685 stack.insert(1, frag);
1686 }
1687 Rule::Monad2 => {
1688 let mut t = take(stack, 2..4);
1689 let y = t.pop().expect("two slots");
1690 let v = t.pop().expect("two slots");
1691 let frag = monad(v, y)?;
1692 stack.insert(2, frag);
1693 }
1694 Rule::Dyad3 => {
1695 let mut t = take(stack, 1..4);
1696 let y = t.pop().expect("three slots");
1697 let v = t.pop().expect("three slots");
1698 let x = t.pop().expect("three slots");
1699 let frag = dyad(x, v, y)?;
1700 stack.insert(1, frag);
1701 }
1702 Rule::Adverb4 => {
1703 let mut t = take(stack, 1..3);
1704 let a = t.pop().expect("two slots");
1705 let u = t.pop().expect("two slots");
1706 let frag = apply_adverb(u, a)?;
1707 stack.insert(1, frag);
1708 }
1709 Rule::Conj5 => {
1710 let mut t = take(stack, 1..4);
1711 let v = t.pop().expect("three slots");
1712 let c = t.pop().expect("three slots");
1713 let u = t.pop().expect("three slots");
1714 let frag = apply_conj(u, c, v)?;
1715 stack.insert(1, frag);
1716 }
1717 Rule::Fork6 => {
1718 let mut t = take(stack, 1..4);
1719 let h = t.pop().expect("three slots");
1720 let g = t.pop().expect("three slots");
1721 let f = t.pop().expect("three slots");
1722 let frag = apply_fork(f, g, h)?;
1723 stack.insert(1, frag);
1724 }
1725 Rule::Bident7 => {
1726 let mut t = take(stack, 1..3);
1727 let b = t.pop().expect("two slots");
1728 let a = t.pop().expect("two slots");
1729 let frag = apply_bident(a, b, nouns)?;
1730 stack.insert(1, frag);
1731 }
1732 Rule::Assign8 => {
1733 let mut t = take(stack, 0..3);
1734 let value = t.pop().expect("three slots");
1735 let assign = t.pop().expect("three slots");
1736 let target = t.pop().expect("three slots");
1737 let scope = match assign {
1738 Frag::AssignGlobal(_) => Scope::Global,
1739 _ => Scope::Local,
1740 };
1741 let frag = apply_assign(target, value, scope)?;
1742 stack.insert(0, frag);
1743 }
1744 Rule::Paren9 => {
1745 let mut t = take(stack, 0..3);
1746 let close = t.pop().expect("three slots");
1747 let inner = t.pop().expect("three slots");
1748 let open = t.pop().expect("three slots");
1749 let outer = Span::merge(open.span(), close.span());
1750 stack.insert(0, respan(inner, outer));
1751 }
1752 }
1753 Ok(true)
1754}
1755
1756fn as_noun(f: Frag) -> Result<Expr> {
1759 match f {
1760 Frag::Noun(e) => Ok(e),
1761 Frag::Name(n, s) => Ok(Expr::Name(n, s)),
1762 other => Err(Error::internal(format!("expected a noun fragment, got {other:?}"))),
1763 }
1764}
1765
1766fn as_verb(f: Frag) -> Result<(Verb, Span)> {
1767 match f {
1768 Frag::Verb(VerbFrag::V(v), s) => Ok((v, s)),
1769 other => Err(Error::internal(format!("expected a verb fragment, got {other:?}"))),
1770 }
1771}
1772
1773fn as_const(f: &Frag) -> Option<&Array> {
1776 match f {
1777 Frag::Noun(Expr::Const(a, _)) => Some(a),
1778 _ => None,
1779 }
1780}
1781
1782fn noun_value(f: &Frag) -> Option<Array> {
1787 if let Some(a) = as_const(f) {
1788 return Some(a.clone());
1789 }
1790 let Frag::Noun(e) = f else { return None };
1791 let cfg = crate::verb::EvalCfg {
1792 agreement: crate::verb::Agreement::LeadingPrefix,
1793 fmt: crate::fmt::FmtOpts::J,
1794 tol: crate::verb::Tol::J,
1795 rules: crate::frontend::Rules::default(),
1796 };
1797 crate::ir::fold_const(e, cfg)
1798}
1799
1800fn monad(v: Frag, y: Frag) -> Result<Frag> {
1801 let (verb, vspan) = as_verb(v)?;
1802 let y = as_noun(y)?;
1803 let span = Span::merge(vspan, y.span());
1804 Ok(Frag::Noun(Expr::Monad { verb, y: Box::new(y), span }))
1805}
1806
1807fn dyad(x: Frag, v: Frag, y: Frag) -> Result<Frag> {
1808 let x = as_noun(x)?;
1809 let (verb, vspan) = as_verb(v)?;
1810 let y = as_noun(y)?;
1811 let span = Span::merge(Span::merge(x.span(), vspan), y.span());
1812 Ok(Frag::Noun(Expr::Dyad { verb, x: Box::new(x), y: Box::new(y), span }))
1813}
1814
1815fn apply_adverb(u: Frag, a: Frag) -> Result<Frag> {
1816 let Frag::Adverb(glyph, aspan) = a else {
1817 return Err(Error::internal("expected an adverb fragment"));
1818 };
1819 let span = Span::merge(u.span(), aspan);
1820 if glyph == "}" {
1823 if !u.is_real_verb() {
1824 let m = noun_value(&u)
1825 .ok_or_else(|| Error::not_yet("amend over a computed index", span))?;
1826 return Ok(Frag::Verb(VerbFrag::V(Verb::Amend(m)), span));
1827 }
1828 let (v, _) = as_verb(u)?;
1829 return Ok(Frag::Verb(VerbFrag::V(Verb::AmendVerb(Box::new(v))), span));
1830 }
1831 if glyph == "b." && !u.is_real_verb() {
1834 let m = as_const(&u)
1835 .and_then(Array::to_i64_vec)
1836 .and_then(|v| v.first().copied())
1837 .filter(|&m| (0..32).contains(&m))
1838 .ok_or_else(|| {
1839 Error::not_yet("a boolean function outside `0 b.` … `31 b.`", span)
1840 })?;
1841 let p = crate::verb::Prim {
1842 name: "b.",
1843 monad: MonadOp::None,
1844 dyad: DyadOp::TruthTable(m as u8),
1845 ranks: [crate::verb::RANK_INF, 0, 0],
1846 };
1847 return Ok(Frag::Verb(VerbFrag::V(Verb::Prim(p)), span));
1848 }
1849 if !u.is_real_verb() {
1850 return Err(Error::not_yet("noun-operand adverbs", span));
1851 }
1852 let (v, _) = as_verb(u)?;
1853 let derived = match glyph {
1854 "/" => Verb::Reduce(Box::new(v)),
1855 "\\" => Verb::Windowed(Box::new(v), WindowKind::Prefix),
1856 "\\." => Verb::Windowed(Box::new(v), WindowKind::Suffix),
1857 "~" => Verb::Commute(Box::new(v)),
1858 "/." => Verb::Key(Box::new(v)),
1859 "f." => v,
1862 "M." => Verb::Memo(Box::new(v), Default::default()),
1863 "b." => Verb::Characteristics(Box::new(v)),
1864 _ => return Err(Error::not_yet(format!("adverb ({glyph})"), span)),
1865 };
1866 Ok(Frag::Verb(VerbFrag::V(derived), span))
1867}
1868
1869fn apply_conj(u: Frag, c: Frag, v: Frag) -> Result<Frag> {
1870 let Frag::Conj(glyph, cspan) = c else {
1871 return Err(Error::internal("expected a conjunction fragment"));
1872 };
1873 let span = Span::merge(Span::merge(u.span(), cspan), v.span());
1874 match glyph {
1875 "\"" => {
1876 let f = verb_operand(u, span)?;
1877 if v.is_verb() {
1878 return Err(Error::not_yet("verb rank (u\"v)", span));
1879 }
1880 let ranks = rank_spec(&v, span)?;
1881 Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(f), ranks)), span))
1882 }
1883 "@:" => {
1884 let f = verb_operand(u, span)?;
1885 let g = verb_operand(v, span)?;
1886 Ok(Frag::Verb(VerbFrag::V(Verb::Atop(Box::new(f), Box::new(g))), span))
1887 }
1888 "@" => {
1892 let f = verb_operand(u, span)?;
1893 let g = verb_operand(v, span)?;
1894 let ranks = g.ranks();
1895 let atop = Verb::Atop(Box::new(f), Box::new(g));
1896 Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(atop), ranks)), span))
1897 }
1898 "&" => compose(u, v, false, span),
1899 "&:" => compose(u, v, true, span),
1900 "&." if is_open(&v) => {
1903 let f = verb_operand(u, span)?;
1904 Ok(Frag::Verb(VerbFrag::V(Verb::Each(Box::new(f), Enclose::Always)), span))
1905 }
1906 "&." | "&.:" => {
1911 let f = verb_operand(u, span)?;
1912 let g = verb_operand(v, span)?;
1913 let back = obverse_of(&g, span)?;
1914 let composed = Verb::Compose(Box::new(f), Box::new(g.clone()));
1915 let under = Verb::Atop(Box::new(back), Box::new(composed));
1916 if glyph == "&.:" {
1917 return Ok(Frag::Verb(VerbFrag::V(under), span));
1918 }
1919 let rank = g.ranks()[0];
1920 Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(under), [rank; 3])), span))
1921 }
1922 "^:" => {
1923 let f = verb_operand(u, span)?;
1924 if v.is_verb() {
1925 let g = verb_operand(v, span)?;
1928 let p = Verb::PowerV(Box::new(f), Box::new(g));
1929 return Ok(Frag::Verb(VerbFrag::V(p), span));
1930 }
1931 let negative = as_const(&v).and_then(Array::to_f64_vec).is_some_and(|n| n[0] < 0.0);
1934 let p = power_spec(&v, span)?;
1935 let f = if negative { obverse_of(&f, span)? } else { f };
1936 Ok(Frag::Verb(VerbFrag::V(Verb::PowerN(Box::new(f), p)), span))
1937 }
1938 ";." => {
1939 let f = verb_operand(u, span)?;
1940 let n = one_atom(&v, "cut", span)?;
1941 if n.fract() != 0.0 || !matches!(n as i64, -3..=3) {
1942 return Err(Error::not_yet(format!("cut (u;.{n})"), span));
1943 }
1944 Ok(Frag::Verb(VerbFrag::V(Verb::Cut(Box::new(f), n as i64)), span))
1945 }
1946 "!." => {
1950 let f = verb_operand(u, span)?;
1951 if matches!(&f, Verb::Prim(p) if p.name == "|.") {
1954 let fill = as_const(&v)
1955 .cloned()
1956 .ok_or_else(|| Error::not_yet("a computed fill (|.!.n)", span))?;
1957 return Ok(Frag::Verb(VerbFrag::V(Verb::ShiftFill(fill)), span));
1958 }
1959 let n = one_atom(&v, "fit", span)?;
1960 if !f.uses_tolerance() {
1961 return Err(Error::not_yet(
1962 format!("fill specification ({}!.n)", f.name()),
1963 span,
1964 ));
1965 }
1966 if !(0.0..=LARGEST_TOLERANCE).contains(&n) {
1968 return Err(Error::domain(
1969 format!("a comparison tolerance must be between 0 and {LARGEST_TOLERANCE}"),
1970 span,
1971 ));
1972 }
1973 Ok(Frag::Verb(VerbFrag::V(Verb::Fit(Box::new(f), n)), span))
1974 }
1975 ":." => {
1978 let f = verb_operand(u, span)?;
1979 let g = verb_operand(v, span)?;
1980 Ok(Frag::Verb(
1981 VerbFrag::V(Verb::WithObverse(Box::new(f), Box::new(g))),
1982 span,
1983 ))
1984 }
1985 "@." => {
1988 let vs = gerund_verbs(&u, span)?;
1989 if v.is_verb() {
1990 let w = verb_operand(v, span)?;
1991 return Ok(Frag::Verb(VerbFrag::V(Verb::Agenda(vs, Box::new(w))), span));
1992 }
1993 let at = one_atom(&v, "agenda", span)?;
1994 if at.fract() != 0.0 {
1995 return Err(Error::parse("an agenda index must be a whole number", span));
1996 }
1997 let picked = crate::verb::pick_gerund(&vs, at as i64, span)?;
1998 Ok(Frag::Verb(VerbFrag::V(picked), span))
1999 }
2000 "`" => {
2002 let mut vs = gerund_verbs(&u, span)?;
2003 vs.extend(gerund_verbs(&v, span)?);
2004 Ok(Frag::Gerund(vs, span))
2005 }
2006 "::" => {
2009 let f = verb_operand(u, span)?;
2010 let g = if v.is_noun() {
2011 constant_verb(bond_noun(&v, span)?)
2012 } else {
2013 verb_operand(v, span)?
2014 };
2015 Ok(Frag::Verb(VerbFrag::V(Verb::Adverse(Box::new(f), Box::new(g))), span))
2016 }
2017 "L:" | "S:" => {
2021 let f = verb_operand(u, span)?;
2022 let n = one_atom(&v, "level", span)?;
2023 if n.fract() != 0.0 || !n.is_finite() {
2024 return Err(Error::not_yet(format!("a level of {n} ({glyph})"), span));
2025 }
2026 let level = Verb::Level {
2027 u: Box::new(f),
2028 level: n as i64,
2029 spread: glyph == "S:",
2030 };
2031 Ok(Frag::Verb(VerbFrag::V(level), span))
2032 }
2033 "`:" => Err(Error::not_yet("evoke gerund (`:)", span)),
2034 "H." => Err(Error::not_yet("the hypergeometric conjunction (m H. n)", span)),
2035 "T." => Err(Error::language(
2039 "T. starts J's own threads, which libjay's sandbox does not open",
2040 span,
2041 )),
2042 "t." => Err(Error::not_yet("the Taylor series (u t. n)", span)),
2043 "t:" => Err(Error::not_yet("the weighted Taylor series (u t: n)", span)),
2044 "." => Err(Error::not_yet("the inner product (u . v)", span)),
2045 "!:" => Err(Error::not_yet("the foreign conjunction (m !: n)", span)),
2046 ":" => Err(Error::not_yet("the monad-dyad conjunction (u : v)", span)),
2050 _ => Err(Error::not_yet(format!("the conjunction {glyph}"), span)),
2051 }
2052}
2053
2054fn compose(u: Frag, v: Frag, infinite: bool, span: Span) -> Result<Frag> {
2062 let verb = |v: Verb| Ok(Frag::Verb(VerbFrag::V(v), span));
2063 if infinite || (!u.is_noun() && !v.is_noun()) {
2064 let f = verb_operand(u, span)?;
2065 let g = verb_operand(v, span)?;
2066 let monadic_rank = g.ranks()[0];
2067 let composed = Verb::Compose(Box::new(f), Box::new(g));
2068 if infinite {
2069 return verb(composed);
2070 }
2071 return verb(Verb::Rank(Box::new(composed), [monadic_rank; 3]));
2072 }
2073 if u.is_noun() && v.is_noun() {
2074 return Err(Error::not_yet("noun-operand conjunctions", span));
2075 }
2076 if u.is_noun() {
2079 let m = bond_noun(&u, span)?;
2080 let g = as_verb(v)?.0;
2081 let rank = g.ranks()[2];
2082 return verb(Verb::Rank(Box::new(Verb::BondLeft(m, Box::new(g))), [rank; 3]));
2083 }
2084 let f = as_verb(u)?.0;
2085 let n = bond_noun(&v, span)?;
2086 let rank = f.ranks()[1];
2087 verb(Verb::Rank(Box::new(Verb::BondRight(Box::new(f), n)), [rank; 3]))
2088}
2089
2090const LARGEST_TOLERANCE: f64 = 5.820_766_091_346_741e-11;
2092
2093fn one_atom(f: &Frag, what: &str, span: Span) -> Result<f64> {
2095 let Some(arr) = as_const(f) else {
2096 return Err(Error::not_yet(format!("a computed {what} specification"), span));
2097 };
2098 let Some(vals) = arr.to_f64_vec() else {
2099 return Err(Error::parse(format!("{what} takes a numeric operand"), span));
2100 };
2101 match vals[..] {
2102 [n] => Ok(n),
2103 _ => Err(Error::parse(format!("{what} takes one atom"), span)),
2104 }
2105}
2106
2107fn bond_noun(f: &Frag, span: Span) -> Result<Array> {
2109 as_const(f)
2110 .cloned()
2111 .ok_or_else(|| Error::not_yet("bonds over a non-literal noun", span))
2112}
2113
2114fn is_open(f: &Frag) -> bool {
2117 matches!(f, Frag::Verb(VerbFrag::V(Verb::Prim(p)), _) if p.monad == MonadOp::Open)
2118}
2119
2120fn verb_operand(f: Frag, span: Span) -> Result<Verb> {
2121 if f.is_noun() {
2122 return Err(Error::not_yet("noun-operand conjunctions", span));
2123 }
2124 Ok(as_verb(f)?.0)
2125}
2126
2127fn rank_spec(f: &Frag, span: Span) -> Result<[i64; 3]> {
2130 let Some(arr) = as_const(f) else {
2131 return Err(Error::not_yet("computed rank specifications", span));
2132 };
2133 let Some(vals) = arr.to_f64_vec() else {
2134 return Err(Error::parse("rank must be numeric", span));
2135 };
2136 if vals.is_empty() || vals.len() > 3 {
2137 return Err(Error::parse("rank takes 1 to 3 atoms", span));
2138 }
2139 let mut r = Vec::with_capacity(vals.len());
2140 for x in vals {
2141 if x == f64::INFINITY {
2142 r.push(RANK_INF);
2143 } else if x == f64::NEG_INFINITY {
2144 r.push(-RANK_INF);
2145 } else if x.fract() != 0.0 {
2146 return Err(Error::parse("rank must be an integer", span));
2147 } else {
2148 r.push(x as i64);
2149 }
2150 }
2151 Ok(match r.len() {
2152 1 => [r[0], r[0], r[0]],
2153 2 => [r[1], r[0], r[1]],
2154 _ => [r[0], r[1], r[2]],
2155 })
2156}
2157
2158fn power_spec(f: &Frag, span: Span) -> Result<Power> {
2161 let Some(arr) = as_const(f) else {
2162 return Err(Error::not_yet("computed power (u^:n)", span));
2163 };
2164 let Some(vals) = arr.to_f64_vec() else {
2165 return Err(Error::parse("power must be numeric", span));
2166 };
2167 let [n] = vals[..] else {
2168 return Err(Error::not_yet("power over a list of counts (u^:n)", span));
2169 };
2170 if n == f64::INFINITY {
2171 return Ok(Power::Converge);
2172 }
2173 if n.fract() != 0.0 {
2174 return Err(Error::parse("power must be a whole number", span));
2175 }
2176 if n < 0.0 {
2177 return Ok(Power::Times((-n) as u64));
2180 }
2181 Ok(Power::Times(n as u64))
2182}
2183
2184fn obverse_of(v: &Verb, span: Span) -> Result<Verb> {
2186 crate::verb::obverse(v).ok_or_else(|| {
2187 Error::not_yet(format!("the obverse of {} (no inverse is known)", v.name()), span)
2188 })
2189}
2190
2191fn gerund_verbs(f: &Frag, span: Span) -> Result<Vec<Verb>> {
2194 match f {
2195 Frag::Gerund(vs, _) => Ok(vs.clone()),
2196 Frag::Verb(VerbFrag::V(v), _) => Ok(vec![v.clone()]),
2197 _ => Err(Error::not_yet("a gerund of anything but verbs", span)),
2198 }
2199}
2200
2201fn apply_fork(f: Frag, g: Frag, h: Frag) -> Result<Frag> {
2202 let span = Span::merge(Span::merge(f.span(), g.span()), h.span());
2203 let (gv, _) = as_verb(g)?;
2204 let (hv, _) = as_verb(h)?;
2205 match f {
2206 Frag::Verb(VerbFrag::Cap, _) => {
2208 Ok(Frag::Verb(VerbFrag::V(Verb::Atop(Box::new(gv), Box::new(hv))), span))
2209 }
2210 Frag::Verb(VerbFrag::V(fv), _) => Ok(Frag::Verb(
2211 VerbFrag::V(Verb::Fork(Box::new(fv), Box::new(gv), Box::new(hv))),
2212 span,
2213 )),
2214 noun => {
2215 let Some(arr) = as_const(&noun) else {
2216 return Err(Error::not_yet("noun forks over a non-literal noun", span));
2217 };
2218 Ok(Frag::Verb(
2219 VerbFrag::V(Verb::NounFork(arr.clone(), Box::new(gv), Box::new(hv))),
2220 span,
2221 ))
2222 }
2223 }
2224}
2225
2226fn apply_bident(a: Frag, b: Frag, nouns: &HashSet<String>) -> Result<Frag> {
2227 let span = Span::merge(a.span(), b.span());
2228 if let Frag::Name(n, nspan) = &a {
2232 if !nouns.contains(n) {
2233 return Err(Error::new(
2234 ErrorKind::Value,
2235 format!("undefined name: {n}"),
2236 Some(*nspan),
2237 ));
2238 }
2239 }
2240 if a.is_real_verb() && b.is_real_verb() {
2241 let (f, _) = as_verb(a)?;
2242 let (g, _) = as_verb(b)?;
2243 return Ok(Frag::Verb(VerbFrag::V(Verb::Hook(Box::new(f), Box::new(g))), span));
2244 }
2245 if matches!(a, Frag::Verb(VerbFrag::Cap, _)) {
2250 return Err(Error::parse("`[:` caps a fork; it has no verb of its own", span));
2251 }
2252 Err(Error::parse("syntax error", span))
2253}
2254
2255fn apply_assign(target: Frag, value: Frag, scope: Scope) -> Result<Frag> {
2256 let span = Span::merge(target.span(), value.span());
2257 match target {
2258 Frag::Name(name, _) => match value {
2262 Frag::Verb(VerbFrag::V(verb), _) => Ok(Frag::VerbDef(name, verb, span)),
2265 Frag::Verb(VerbFrag::Cap, _) => Err(Error::not_yet("assigning [: on its own", span)),
2266 v if v.is_noun() => {
2267 let value = as_noun(v)?;
2268 Ok(Frag::Noun(Expr::Assign { name, value: Box::new(value), scope, span }))
2269 }
2270 _ => Err(Error::not_yet("adverb and conjunction assignment", span)),
2271 },
2272 Frag::Noun(_) => Err(Error::not_yet("multiple assignment", span)),
2273 other => Err(Error::internal(format!("expected an assignment target, got {other:?}"))),
2274 }
2275}
2276
2277#[cfg(test)]
2278mod tests {
2279 use super::*;
2280 use crate::dtype::DType;
2281 use crate::error::ErrorKind;
2282 use rstest::rstest;
2283
2284 fn parse_str(src: &str) -> Result<Vec<Expr>> {
2285 parse(&SourceParts::from_source(src).expect("source parts"))
2286 }
2287
2288 fn one_literal(src: &str) -> Expr {
2292 let sp = SourceParts::from_parts(&[src], &[]);
2293 let mut s = parse(&sp).unwrap_or_else(|e| panic!("parse of {src:?} failed: {e}"));
2294 assert_eq!(s.len(), 1, "expected one sentence in {src:?}");
2295 s.pop().expect("one sentence")
2296 }
2297
2298 fn stmts(src: &str) -> Vec<Expr> {
2299 parse_str(src).unwrap_or_else(|e| panic!("parse of {src:?} failed: {e}"))
2300 }
2301
2302 fn one(src: &str) -> Expr {
2304 let mut s = stmts(src);
2305 assert_eq!(s.len(), 1, "expected one sentence in {src:?}");
2306 s.pop().expect("one sentence")
2307 }
2308
2309 fn err(src: &str) -> Error {
2310 match parse_str(src) {
2311 Ok(v) => panic!("expected an error for {src:?}, got {v:?}"),
2312 Err(e) => e,
2313 }
2314 }
2315
2316 fn konst(e: &Expr) -> Array {
2320 match e {
2321 Expr::Const(a, _) => a.clone(),
2322 other => panic!("expected a constant, got {other:?}"),
2323 }
2324 }
2325
2326 fn ints(e: &Expr) -> Vec<i64> {
2327 konst(e).as_i64_slice().expect("integer data").to_vec()
2328 }
2329
2330 fn prim_of(v: &Verb) -> Prim {
2331 match v {
2332 Verb::Prim(p) => *p,
2333 other => panic!("expected a primitive, got {other:?}"),
2334 }
2335 }
2336
2337 fn monad_of(e: &Expr) -> (Verb, Expr) {
2338 match e {
2339 Expr::Monad { verb, y, .. } => (verb.clone(), (**y).clone()),
2340 other => panic!("expected a monad, got {other:?}"),
2341 }
2342 }
2343
2344 fn dyad_of(e: &Expr) -> (Verb, Expr, Expr) {
2345 match e {
2346 Expr::Dyad { verb, x, y, .. } => (verb.clone(), (**x).clone(), (**y).clone()),
2347 other => panic!("expected a dyad, got {other:?}"),
2348 }
2349 }
2350
2351 #[test]
2354 fn single_number_is_an_atom() {
2355 let e = one("5");
2356 assert_eq!(konst(&e).shape, Vec::<usize>::new());
2357 assert_eq!(ints(&e), vec![5]);
2358 assert_eq!(e.span(), Span::new(0, 1));
2359 }
2360
2361 #[test]
2362 fn adjacent_numbers_merge_into_one_vector() {
2363 let e = one("1 2 3");
2364 assert_eq!(konst(&e).shape, vec![3]);
2365 assert_eq!(ints(&e), vec![1, 2, 3]);
2366 assert_eq!(e.span(), Span::new(0, 5));
2367 }
2368
2369 #[test]
2370 fn a_float_makes_the_whole_vector_float() {
2371 let a = konst(&one("1 2.5 3"));
2372 assert_eq!(a.dtype(), DType::F64);
2373 assert_eq!(a.as_f64_slice(), Some(&[1.0, 2.5, 3.0][..]));
2374 }
2375
2376 #[test]
2377 fn negatives_and_infinities() {
2378 let a = konst(&one("_3 1.5 _ __"));
2379 assert_eq!(a.shape, vec![4]);
2380 let v = a.as_f64_slice().expect("float vector");
2381 assert_eq!(v[0], -3.0);
2382 assert_eq!(v[1], 1.5);
2383 assert!(v[2].is_infinite() && v[2] > 0.0);
2384 assert!(v[3].is_infinite() && v[3] < 0.0);
2385 }
2386
2387 #[test]
2388 fn negative_integers_stay_integers() {
2389 let a = konst(&one("_3 _4"));
2390 assert_eq!(a.dtype(), DType::I64);
2391 assert_eq!(a.as_i64_slice(), Some(&[-3i64, -4][..]));
2392 }
2393
2394 #[rstest]
2395 #[case("1e3", 1000.0)]
2396 #[case("1e_3", 0.001)]
2397 #[case("2.5e2", 250.0)]
2398 #[case("_1.5", -1.5)]
2399 fn exponent_and_sign_forms(#[case] src: &str, #[case] want: f64) {
2400 let a = konst(&one(src));
2401 assert_eq!(a.dtype(), DType::F64);
2402 assert_eq!(a.to_f64_vec().expect("numeric"), vec![want]);
2403 }
2404
2405 #[test]
2406 fn adjacent_numbers_stop_at_a_non_number() {
2407 let (_, x, y) = dyad_of(&one("2 3 i. 4"));
2409 assert_eq!(konst(&x).shape, vec![2]);
2410 assert_eq!(konst(&y).shape, Vec::<usize>::new());
2411 }
2412
2413 #[test]
2414 fn string_of_several_characters_is_a_vector() {
2415 let e = one("'abc'");
2416 let a = konst(&e);
2417 assert_eq!(a.shape, vec![3]);
2418 assert_eq!(a.data, Data::Char(vec!['a', 'b', 'c'].into()));
2419 assert_eq!(e.span(), Span::new(0, 5));
2420 }
2421
2422 #[test]
2423 fn one_character_string_is_an_atom() {
2424 let a = konst(&one("'a'"));
2425 assert_eq!(a.shape, Vec::<usize>::new());
2426 assert_eq!(a.data, Data::Char(vec!['a'].into()));
2427 }
2428
2429 #[test]
2430 fn empty_string_is_an_empty_vector() {
2431 let a = konst(&one("''"));
2432 assert_eq!(a.shape, vec![0]);
2433 assert_eq!(a.dtype(), DType::Char);
2434 }
2435
2436 #[test]
2437 fn doubled_quote_is_an_escaped_quote() {
2438 let a = konst(&one("'it''s'"));
2439 assert_eq!(a.shape, vec![4]);
2440 assert_eq!(a.data, Data::Char(vec!['i', 't', '\'', 's'].into()));
2441 }
2442
2443 #[test]
2444 fn unterminated_string_is_a_parse_error() {
2445 let e = err("'abc");
2446 assert_eq!(e.kind, ErrorKind::Parse);
2447 assert!(e.msg.contains("unterminated"), "{}", e.msg);
2448 assert_eq!(e.span, Some(Span::new(0, 4)));
2449 }
2450
2451 #[test]
2454 fn comment_runs_to_end_of_line() {
2455 let e = one("1 2 NB. and the rest + - ' is ignored");
2456 assert_eq!(konst(&e).shape, vec![2]);
2457 }
2458
2459 #[test]
2460 fn comment_only_line_yields_no_sentence() {
2461 assert!(stmts("NB. nothing here").is_empty());
2462 let s = stmts("NB. header\n5");
2463 assert_eq!(s.len(), 1);
2464 assert_eq!(ints(&s[0]), vec![5]);
2465 }
2466
2467 #[test]
2468 fn nb_inside_a_name_is_not_a_comment() {
2469 match one("aNB") {
2471 Expr::Name(n, _) => assert_eq!(n, "aNB"),
2472 other => panic!("expected a name, got {other:?}"),
2473 }
2474 }
2475
2476 #[test]
2479 fn empty_program_has_no_sentences() {
2480 assert!(stmts("").is_empty());
2481 assert!(stmts("\n\n").is_empty());
2482 }
2483
2484 #[test]
2485 fn trains_of_dyads_are_right_associative() {
2486 let e = one("1 + 2 + 3");
2487 let (v, x, y) = dyad_of(&e);
2488 assert_eq!(prim_of(&v).name, "+");
2489 assert_eq!(ints(&x), vec![1]);
2490 let (v2, x2, y2) = dyad_of(&y);
2491 assert_eq!(prim_of(&v2).name, "+");
2492 assert_eq!(ints(&x2), vec![2]);
2493 assert_eq!(ints(&y2), vec![3]);
2494 assert_eq!(e.span(), Span::new(0, 9));
2495 }
2496
2497 #[test]
2498 fn a_verb_with_no_left_argument_is_a_monad() {
2499 let e = one("- 5");
2500 let (v, y) = monad_of(&e);
2501 assert_eq!(prim_of(&v).monad, MonadOp::Scalar(ScalarMonad::Neg));
2502 assert_eq!(ints(&y), vec![5]);
2503 assert_eq!(e.span(), Span::new(0, 3));
2504 }
2505
2506 #[test]
2507 fn a_verb_with_a_left_argument_is_a_dyad() {
2508 let (v, _, _) = dyad_of(&one("1 - 5"));
2509 assert_eq!(prim_of(&v).dyad, DyadOp::Scalar(ScalarDyad::Sub));
2510 }
2511
2512 #[test]
2513 fn a_monad_binds_to_the_right_inside_a_dyad() {
2514 let (v, x, y) = dyad_of(&one("2 * - 3"));
2515 assert_eq!(prim_of(&v).name, "*");
2516 assert_eq!(ints(&x), vec![2]);
2517 let (mv, my) = monad_of(&y);
2518 assert_eq!(prim_of(&mv).name, "-");
2519 assert_eq!(ints(&my), vec![3]);
2520 }
2521
2522 #[test]
2523 fn parentheses_group_the_left_argument() {
2524 let (v, x, y) = dyad_of(&one("(1 + 2) * 3"));
2525 assert_eq!(prim_of(&v).name, "*");
2526 let (iv, _, _) = dyad_of(&x);
2527 assert_eq!(prim_of(&iv).name, "+");
2528 assert_eq!(x.span(), Span::new(0, 7));
2531 assert_eq!(ints(&y), vec![3]);
2532 }
2533
2534 #[test]
2535 fn names_are_nouns() {
2536 match one("x") {
2537 Expr::Name(n, s) => {
2538 assert_eq!(n, "x");
2539 assert_eq!(s, Span::new(0, 1));
2540 }
2541 other => panic!("expected a name, got {other:?}"),
2542 }
2543 let (_, x, y) = dyad_of(&one("x + y"));
2544 assert!(matches!(x, Expr::Name(..)));
2545 assert!(matches!(y, Expr::Name(..)));
2546 }
2547
2548 #[test]
2549 fn echo_is_a_verb() {
2550 let (v, y) = monad_of(&one("echo 5"));
2551 assert_eq!(prim_of(&v).monad, MonadOp::Echo);
2552 assert_eq!(ints(&y), vec![5]);
2553 }
2554
2555 #[test]
2556 fn inflected_letter_words_are_primitives() {
2557 let (v, _) = monad_of(&one("i. 3"));
2558 let p = prim_of(&v);
2559 assert_eq!(p.monad, MonadOp::IotaJ);
2560 assert_eq!(p.ranks, [1, RANK_INF, RANK_INF]);
2561 }
2562
2563 #[rstest]
2564 #[case("|: 1 2 3", MonadOp::TransposeAxes)]
2565 #[case("$ 1 2 3", MonadOp::ShapeOf)]
2566 #[case("# 1 2 3", MonadOp::Tally)]
2567 #[case(", 1 2 3", MonadOp::Ravel)]
2568 #[case("%: 1 2 3", MonadOp::Scalar(ScalarMonad::Sqrt))]
2569 #[case("<. 1.5", MonadOp::Scalar(ScalarMonad::Floor))]
2570 fn inflected_symbol_words(#[case] src: &str, #[case] want: MonadOp) {
2571 let (v, _) = monad_of(&one(src));
2572 assert_eq!(prim_of(&v).monad, want);
2573 }
2574
2575 #[rstest]
2576 #[case("{. 1 2 3", MonadOp::Head, DyadOp::Take)]
2577 #[case("}. 1 2 3", MonadOp::Behead, DyadOp::Drop)]
2578 fn brace_words(#[case] src: &str, #[case] monad: MonadOp, #[case] dyad: DyadOp) {
2579 let (v, _) = monad_of(&one_literal(src));
2580 let p = prim_of(&v);
2581 assert_eq!(p.monad, monad);
2582 assert_eq!(p.dyad, dyad);
2583 assert_eq!(p.ranks, [RANK_INF, 1, RANK_INF]);
2584 }
2585
2586 #[test]
2587 fn a_brace_word_takes_a_left_argument() {
2588 let (v, x, y) = dyad_of(&one_literal("2 {. 1 2 3"));
2589 assert_eq!(prim_of(&v).dyad, DyadOp::Take);
2590 assert_eq!(ints(&x), vec![2]);
2591 assert_eq!(konst(&y).shape, vec![3]);
2592 }
2593
2594 #[rstest]
2595 #[case("2 $ 1 2 3", DyadOp::Reshape)]
2596 #[case("2 [ 3", DyadOp::Left)]
2597 #[case("2 ] 3", DyadOp::Right)]
2598 #[case("2 <. 3", DyadOp::Scalar(ScalarDyad::Min))]
2599 #[case("2 >: 3", DyadOp::Scalar(ScalarDyad::Ge))]
2600 fn dyadic_primitives(#[case] src: &str, #[case] want: DyadOp) {
2601 let (v, _, _) = dyad_of(&one(src));
2602 assert_eq!(prim_of(&v).dyad, want);
2603 }
2604
2605 #[test]
2606 fn unimplemented_meanings_reach_the_verb_not_the_parser() {
2607 let (v, _, _) = dyad_of(&one("2 ;: 'a b'"));
2608 assert_eq!(prim_of(&v).dyad, DyadOp::NotYet("sequential machine (dyadic ;:)"));
2609 let (v, _) = monad_of(&one("e. 1 2"));
2610 assert_eq!(prim_of(&v).monad, MonadOp::NotYet("raze-in (monadic e.)"));
2611 }
2612
2613 #[test]
2614 fn multiple_sentences_become_multiple_statements() {
2615 let s = stmts("a =. 1 2\n+/ a\n");
2616 assert_eq!(s.len(), 2);
2617 assert!(matches!(s[0], Expr::Assign { .. }));
2618 assert!(matches!(s[1], Expr::Monad { .. }));
2619 }
2620
2621 #[test]
2624 fn an_adverb_binds_before_the_verb_is_applied() {
2625 let e = one("+/ 1 2 3");
2626 let (v, y) = monad_of(&e);
2627 match &v {
2628 Verb::Reduce(inner) => assert_eq!(prim_of(inner).name, "+"),
2629 other => panic!("expected a reduction, got {other:?}"),
2630 }
2631 assert_eq!(konst(&y).shape, vec![3]);
2632 assert_eq!(e.span(), Span::new(0, 8));
2633 }
2634
2635 #[test]
2636 fn rank_applies_to_the_derived_verb() {
2637 let (v, _) = monad_of(&one("+/\"1 m"));
2638 match &v {
2639 Verb::Rank(inner, ranks) => {
2640 assert_eq!(*ranks, [1, 1, 1]);
2641 assert!(matches!(**inner, Verb::Reduce(_)), "got {inner:?}");
2642 }
2643 other => panic!("expected a ranked verb, got {other:?}"),
2644 }
2645 }
2646
2647 #[rstest]
2648 #[case("+\"1 m", [1, 1, 1])]
2649 #[case("+\"1 2 m", [2, 1, 2])]
2650 #[case("+\"0 1 2 m", [0, 1, 2])]
2651 #[case("+\"_ m", [RANK_INF, RANK_INF, RANK_INF])]
2652 #[case("+\"_1 m", [-1, -1, -1])]
2653 #[case("+\"2.0 m", [2, 2, 2])]
2654 fn rank_specifications(#[case] src: &str, #[case] want: [i64; 3]) {
2655 let (v, _) = monad_of(&one(src));
2656 assert_eq!(v.ranks(), want);
2657 }
2658
2659 #[test]
2660 fn rank_must_be_one_to_three_integer_atoms() {
2661 let e = err("+\"1 2 3 4 m");
2662 assert_eq!(e.kind, ErrorKind::Parse);
2663 assert!(e.msg.contains("1 to 3 atoms"), "{}", e.msg);
2664 let e = err("+\"1.5 m");
2665 assert_eq!(e.kind, ErrorKind::Parse);
2666 assert!(e.msg.contains("integer"), "{}", e.msg);
2667 let e = err("+\"'a' m");
2668 assert_eq!(e.kind, ErrorKind::Parse);
2669 assert!(e.msg.contains("numeric"), "{}", e.msg);
2670 }
2671
2672 #[test]
2673 fn verb_rank_is_not_supported_yet() {
2674 let e = err("+\"- m");
2675 assert_eq!(e.kind, ErrorKind::NotYet);
2676 assert!(e.msg.contains("verb rank"), "{}", e.msg);
2677 }
2678
2679 #[test]
2680 fn computed_rank_is_not_supported_yet() {
2681 let e = err("+\"{r} m");
2682 assert_eq!(e.kind, ErrorKind::NotYet);
2683 assert!(e.msg.contains("computed rank"), "{}", e.msg);
2684 }
2685
2686 #[test]
2687 fn atop_conjunction() {
2688 let (v, _) = monad_of(&one("+/ @: , y"));
2689 match &v {
2690 Verb::Atop(f, g) => {
2691 assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
2692 assert_eq!(prim_of(g).name, ",");
2693 }
2694 other => panic!("expected an atop, got {other:?}"),
2695 }
2696 }
2697
2698 #[rstest]
2699 #[case("+ ^: {n} y", "computed power")]
2700 #[case("(+/ % #) ^: _1 y", "the obverse of")]
2701 #[case("(+/ % #) &. , y", "the obverse of")]
2702 #[case("(1 + 2) & , y", "bonds over a non-literal noun")]
2703 #[case("+ `: 6 y", "evoke gerund")]
2704 fn other_conjunctions_are_not_supported_yet(#[case] src: &str, #[case] msg: &str) {
2705 let e = err(src);
2706 assert_eq!(e.kind, ErrorKind::NotYet);
2707 assert!(e.msg.contains(msg), "{}", e.msg);
2708 }
2709
2710 #[test]
2711 fn atop_at_rank_and_compose() {
2712 let (v, _) = monad_of(&one("+/ @ (,\"1) y"));
2715 match &v {
2716 Verb::Rank(inner, ranks) => {
2717 assert_eq!(*ranks, [1, 1, 1]);
2718 assert!(matches!(**inner, Verb::Atop(..)), "got {inner:?}");
2719 }
2720 other => panic!("expected a ranked atop, got {other:?}"),
2721 }
2722 let (v, _) = monad_of(&one("+ & (*:\"0) y"));
2723 match &v {
2724 Verb::Rank(inner, ranks) => {
2725 assert_eq!(*ranks, [0, 0, 0]);
2726 assert!(matches!(**inner, Verb::Compose(..)), "got {inner:?}");
2727 }
2728 other => panic!("expected a ranked composition, got {other:?}"),
2729 }
2730 let (v, _) = monad_of(&one("+ &: *: y"));
2731 assert!(matches!(v, Verb::Compose(..)), "got {v:?}");
2732 }
2733
2734 #[test]
2735 fn a_noun_operand_bonds_the_conjunction() {
2736 let (v, _) = monad_of(&one("1 & + y"));
2738 match &v {
2739 Verb::Rank(inner, ranks) => {
2740 assert_eq!(*ranks, [0, 0, 0]);
2741 match &**inner {
2742 Verb::BondLeft(a, g) => {
2743 assert_eq!(a.as_i64_slice(), Some(&[1i64][..]));
2744 assert_eq!(prim_of(g).name, "+");
2745 }
2746 other => panic!("expected a left bond, got {other:?}"),
2747 }
2748 }
2749 other => panic!("expected a ranked bond, got {other:?}"),
2750 }
2751 let (v, _) = monad_of(&one("{. & 2 y"));
2752 match &v {
2753 Verb::Rank(inner, ranks) => {
2755 assert_eq!(*ranks, [1, 1, 1]);
2756 assert!(matches!(**inner, Verb::BondRight(..)), "got {inner:?}");
2757 }
2758 other => panic!("expected a ranked bond, got {other:?}"),
2759 }
2760 }
2761
2762 #[test]
2763 fn window_scan_and_commute_adverbs() {
2764 let (v, _) = monad_of(&one("+/\\ 1 2 3"));
2765 match &v {
2766 Verb::Windowed(u, WindowKind::Prefix) => assert!(matches!(**u, Verb::Reduce(_))),
2767 other => panic!("expected a prefix application, got {other:?}"),
2768 }
2769 assert_eq!(v.ranks(), [RANK_INF, 0, RANK_INF]);
2772 let (v, _, _) = dyad_of(&one("2 +/\\ 1 2 3"));
2773 assert!(matches!(v, Verb::Windowed(_, WindowKind::Prefix)));
2774 let (v, _) = monad_of(&one("+/\\. 1 2 3"));
2775 assert!(matches!(v, Verb::Windowed(_, WindowKind::Suffix)));
2776 let (v, _) = monad_of(&one("+~ 1 2 3"));
2777 match &v {
2778 Verb::Commute(u) => assert_eq!(prim_of(u).name, "+"),
2779 other => panic!("expected a commute, got {other:?}"),
2780 }
2781 let (v, _) = monad_of(&one("+:^:3 (1)"));
2782 assert!(matches!(v, Verb::PowerN(_, Power::Times(3))));
2783 let (v, _) = monad_of(&one("%:^:_ (100)"));
2784 assert!(matches!(v, Verb::PowerN(_, Power::Converge)));
2785 }
2786
2787 #[test]
2788 fn the_key_adverb_derives_a_verb() {
2789 match one("+/. 1 2 3") {
2790 Expr::Monad { verb: Verb::Key(_), .. } => {}
2791 other => panic!("expected a key, got {other:?}"),
2792 }
2793 }
2794
2795 #[test]
2796 fn noun_operand_adverbs_are_not_supported_yet() {
2797 let e = err("1/ 2");
2798 assert_eq!(e.kind, ErrorKind::NotYet);
2799 assert!(e.msg.contains("noun-operand adverbs"), "{}", e.msg);
2800 }
2801
2802 #[test]
2803 fn noun_operand_conjunctions_are_not_supported_yet() {
2804 let e = err("1 @: + y");
2805 assert_eq!(e.kind, ErrorKind::NotYet);
2806 assert!(e.msg.contains("noun-operand conjunctions"), "{}", e.msg);
2807 }
2808
2809 #[test]
2812 fn three_verbs_in_parentheses_are_a_fork() {
2813 let (v, y) = monad_of(&one("(+/ % #) 1 2 3"));
2814 match &v {
2815 Verb::Fork(f, g, h) => {
2816 assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
2817 assert_eq!(prim_of(g).name, "%");
2818 assert_eq!(prim_of(h).name, "#");
2819 }
2820 other => panic!("expected a fork, got {other:?}"),
2821 }
2822 assert_eq!(konst(&y).shape, vec![3]);
2823 }
2824
2825 #[test]
2826 fn a_noun_left_tine_is_a_noun_fork() {
2827 let (v, _) = monad_of(&one("(2 + #) 1 2 3"));
2828 match &v {
2829 Verb::NounFork(a, g, h) => {
2830 assert_eq!(a.as_i64_slice(), Some(&[2i64][..]));
2831 assert_eq!(prim_of(g).name, "+");
2832 assert_eq!(prim_of(h).name, "#");
2833 }
2834 other => panic!("expected a noun fork, got {other:?}"),
2835 }
2836 }
2837
2838 #[test]
2839 fn two_verbs_in_parentheses_are_a_hook() {
2840 let (v, _) = monad_of(&one("(+ #) 1 2 3"));
2841 match &v {
2842 Verb::Hook(f, g) => {
2843 assert_eq!(prim_of(f).name, "+");
2844 assert_eq!(prim_of(g).name, "#");
2845 }
2846 other => panic!("expected a hook, got {other:?}"),
2847 }
2848 }
2849
2850 #[test]
2851 fn cap_makes_a_fork_an_atop() {
2852 let (v, _) = monad_of(&one("([: +/ ,) 1 2 3"));
2853 match &v {
2854 Verb::Atop(f, g) => {
2855 assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
2856 assert_eq!(prim_of(g).name, ",");
2857 }
2858 other => panic!("expected an atop, got {other:?}"),
2859 }
2860 }
2861
2862 #[test]
2863 fn a_five_verb_train_folds_from_the_right() {
2864 let (v, _) = monad_of(&one("(] , [ , ]) 1 2 3"));
2866 match &v {
2867 Verb::Fork(f, g, h) => {
2868 assert_eq!(prim_of(f).name, "]");
2869 assert_eq!(prim_of(g).name, ",");
2870 assert!(matches!(**h, Verb::Fork(..)), "got {h:?}");
2871 }
2872 other => panic!("expected a fork, got {other:?}"),
2873 }
2874 }
2875
2876 #[test]
2877 fn a_noun_fork_needs_a_literal_noun() {
2878 let e = err("({n} + #) 1 2 3");
2879 assert_eq!(e.kind, ErrorKind::NotYet);
2880 assert!(e.msg.contains("noun forks"), "{}", e.msg);
2881 }
2882
2883 #[test]
2884 fn cap_is_never_applied_as_a_verb() {
2885 let e = err("[: # 1 2 3");
2888 assert_eq!(e.kind, ErrorKind::Parse);
2889 assert!(e.msg.contains("caps a fork"), "{}", e.msg);
2890 }
2891
2892 #[test]
2893 fn two_nouns_side_by_side_are_a_syntax_error() {
2894 let e = err("'ab' 'cd'");
2896 assert_eq!(e.kind, ErrorKind::Parse);
2897 assert_eq!(e.msg, "syntax error");
2898 }
2899
2900 #[test]
2901 fn a_sentence_that_is_a_verb_is_not_supported_yet() {
2902 let e = err("+/ % #");
2903 assert_eq!(e.kind, ErrorKind::NotYet);
2904 assert!(e.msg.contains("tacit"), "{}", e.msg);
2905 }
2906
2907 #[rstest]
2910 #[case("x =. 5", Scope::Local)]
2911 #[case("x =: 5", Scope::Global)]
2912 fn assignment_yields_an_assign_node(#[case] src: &str, #[case] want: Scope) {
2913 match one(src) {
2914 Expr::Assign { name, value, scope, span } => {
2915 assert_eq!(name, "x");
2916 assert_eq!(ints(&value), vec![5]);
2917 assert_eq!(scope, want);
2918 assert_eq!(span, Span::new(0, 6));
2919 }
2920 other => panic!("expected an assignment, got {other:?}"),
2921 }
2922 }
2923
2924 #[test]
2925 fn assignment_in_expression_position() {
2926 let (v, x, y) = dyad_of(&one("y + x =. 3"));
2927 assert_eq!(prim_of(&v).name, "+");
2928 assert!(matches!(x, Expr::Name(..)));
2929 match y {
2930 Expr::Assign { name, span, .. } => {
2931 assert_eq!(name, "x");
2932 assert_eq!(span, Span::new(4, 10));
2933 }
2934 other => panic!("expected an assignment, got {other:?}"),
2935 }
2936 }
2937
2938 #[test]
2939 fn assignment_takes_the_whole_right_hand_sentence() {
2940 match one("x =. 1 + 2") {
2941 Expr::Assign { value, .. } => {
2942 let (v, _, _) = dyad_of(&value);
2943 assert_eq!(prim_of(&v).name, "+");
2944 }
2945 other => panic!("expected an assignment, got {other:?}"),
2946 }
2947 }
2948
2949 #[test]
2952 fn assigning_a_verb_names_it_and_runs_nothing() {
2953 let s = stmts("mean =. +/ % #");
2954 assert_eq!(s.len(), 1);
2955 match &s[0] {
2956 Expr::VerbDef { name, verb, span } => {
2957 assert_eq!(name, "mean");
2958 assert!(matches!(verb, Verb::Fork(..)), "got {verb:?}");
2959 assert_eq!(*span, Span::new(0, 14));
2960 }
2961 other => panic!("expected a verb definition, got {other:?}"),
2962 }
2963 }
2964
2965 #[test]
2966 fn a_named_verb_applies_in_a_later_sentence() {
2967 let s = stmts("mean =. +/ % #\nmean 1 2 3 4");
2968 assert_eq!(s.len(), 2);
2969 let (v, y) = monad_of(&s[1]);
2970 assert!(matches!(v, Verb::Fork(..)), "got {v:?}");
2971 assert_eq!(konst(&y).shape, vec![4]);
2972 }
2973
2974 #[test]
2975 fn a_named_verb_is_a_verb_inside_a_train_and_under_a_conjunction() {
2976 let (v, _) = monad_of(&stmts("mean =. +/ % #\n(mean - {.) 1 2 3 4").pop().expect("two"));
2977 match &v {
2978 Verb::Fork(f, g, h) => {
2979 assert!(matches!(**f, Verb::Fork(..)), "got {f:?}");
2980 assert_eq!(prim_of(g).name, "-");
2981 assert_eq!(prim_of(h).name, "{.");
2982 }
2983 other => panic!("expected a fork, got {other:?}"),
2984 }
2985 let (v, _) = monad_of(&stmts("mean =. +/ % #\nmean\"1 m").pop().expect("two"));
2986 match &v {
2987 Verb::Rank(inner, r) => {
2988 assert_eq!(*r, [1, 1, 1]);
2989 assert!(matches!(**inner, Verb::Fork(..)), "got {inner:?}");
2990 }
2991 other => panic!("expected a ranked verb, got {other:?}"),
2992 }
2993 }
2994
2995 #[test]
2996 fn redefinition_rebinds_from_that_sentence_on() {
2997 let s = stmts("f =. +/\nf 1 2 3\nf =. #\nf 1 2 3");
2998 assert_eq!(s.len(), 4);
2999 assert!(matches!(monad_of(&s[1]).0, Verb::Reduce(_)));
3000 assert_eq!(prim_of(&monad_of(&s[3]).0).name, "#");
3001 }
3002
3003 #[test]
3004 fn a_name_may_change_part_of_speech_in_either_direction() {
3005 let s = stmts("a =. 1 2 3\na =. +/\na 1 2 3");
3007 assert!(matches!(s[0], Expr::Assign { .. }));
3008 assert!(matches!(s[1], Expr::VerbDef { .. }));
3009 assert!(matches!(monad_of(&s[2]).0, Verb::Reduce(_)));
3010 let s = stmts("f =. +/\nf =. 10 20\nf");
3011 assert!(matches!(s[0], Expr::VerbDef { .. }));
3012 assert!(matches!(s[1], Expr::Assign { .. }));
3013 assert!(matches!(s[2], Expr::Name(..)));
3014 }
3015
3016 #[test]
3017 fn an_undefined_name_applied_as_a_verb_is_a_value_error() {
3018 let e = err("zz 1 2 3");
3020 assert_eq!(e.kind, ErrorKind::Value);
3021 assert_eq!(e.msg, "undefined name: zz");
3022 assert_eq!(e.span, Some(Span::new(0, 2)));
3023 let e = err("a =. 5\na 1 2 3");
3026 assert_eq!(e.kind, ErrorKind::Parse);
3027 assert_eq!(e.msg, "syntax error");
3028 }
3029
3030 #[test]
3031 fn adverb_and_conjunction_assignment_are_not_supported_yet() {
3032 let e = err("insert =. /");
3033 assert_eq!(e.kind, ErrorKind::NotYet);
3034 assert!(e.msg.contains("adverb and conjunction assignment"), "{}", e.msg);
3035 }
3036
3037 #[rstest]
3038 #[case("f =. 3 : 'y + 1'", None)]
3039 #[case("f =. 4 : 'x + y'", Some("x"))]
3040 #[case("f =. {{ y + 1 }}", None)]
3041 #[case("f =. {{ x + y }}", Some("x"))]
3042 fn an_explicit_definition_names_a_verb(#[case] src: &str, #[case] left: Option<&str>) {
3043 match one(src) {
3044 Expr::VerbDef { name, verb: Verb::Explicit(d), .. } => {
3045 assert_eq!(name, "f");
3046 assert_eq!(d.left.as_deref(), left);
3047 assert_eq!(d.right, "y");
3048 assert_eq!(d.body.len(), 1);
3049 }
3050 other => panic!("expected an explicit verb definition, got {other:?}"),
3051 }
3052 }
3053
3054 #[rstest]
3055 #[case("f =. 1 : 'y + 1'", "explicit adverbs and conjunctions")]
3056 #[case("f =. 13 : 'y + 1'", "tacit definitions")]
3057 #[case("f =. {{ u y }}", "direct definitions of adverbs and conjunctions")]
3058 fn definition_forms_libjay_has_not_are_named(#[case] src: &str, #[case] msg: &str) {
3059 let e = err(src);
3060 assert_eq!(e.kind, ErrorKind::NotYet);
3061 assert!(e.msg.contains(msg), "{}", e.msg);
3062 }
3063
3064 #[test]
3065 fn a_control_word_outside_a_definition_is_a_parse_error() {
3066 let e = err("if. 1 do. 2 end.");
3067 assert_eq!(e.kind, ErrorKind::Parse);
3068 assert!(e.msg.contains("only meaningful inside an explicit definition"), "{}", e.msg);
3069 }
3070
3071 #[test]
3072 fn multiple_assignment_is_not_supported_yet() {
3073 let e = err("'a b' =. 1 2");
3074 assert_eq!(e.kind, ErrorKind::NotYet);
3075 assert!(e.msg.contains("multiple assignment"), "{}", e.msg);
3076 }
3077
3078 #[test]
3081 fn a_hole_is_a_noun() {
3082 let e = one("{a} + 1");
3083 let (_, x, y) = dyad_of(&e);
3084 match x {
3085 Expr::Param(i, s) => {
3086 assert_eq!(i, 0);
3087 assert_eq!(s, Span::new(0, 3));
3088 }
3089 other => panic!("expected a parameter, got {other:?}"),
3090 }
3091 assert_eq!(ints(&y), vec![1]);
3092 assert_eq!(e.span(), Span::new(0, 7));
3093 }
3094
3095 #[test]
3096 fn holes_are_numbered_and_shared_by_name() {
3097 let sp = SourceParts::from_source("{a} + {b} + {a}").expect("source parts");
3098 assert_eq!(sp.param_names, vec!["a".to_string(), "b".to_string()]);
3099 let e = parse(&sp).expect("parse").pop().expect("one sentence");
3100 let (_, x, y) = dyad_of(&e);
3101 assert!(matches!(x, Expr::Param(0, _)));
3102 let (_, x2, y2) = dyad_of(&y);
3103 assert!(matches!(x2, Expr::Param(1, _)));
3104 assert!(matches!(y2, Expr::Param(0, _)));
3105 }
3106
3107 #[rstest]
3108 #[case("3j4", 3.0, 4.0)]
3109 #[case("_1j_2", -1.0, -2.0)]
3110 #[case("1e1j2", 10.0, 2.0)]
3111 #[case("2ad90", 0.0, 2.0)]
3112 #[case("1ad180", -1.0, 0.0)]
3113 fn complex_literals(#[case] src: &str, #[case] re: f64, #[case] im: f64) {
3114 let a = konst(&one(src));
3115 assert_eq!(a.dtype(), DType::Complex);
3116 let z = a.as_complex_slice().expect("complex data")[0];
3117 assert!((z[0] - re).abs() < 1e-12 && (z[1] - im).abs() < 1e-12, "{z:?}");
3118 }
3119
3120 #[test]
3121 fn a_hole_takes_a_verb_like_any_noun() {
3122 let (v, y) = monad_of(&one("+/ {data}"));
3123 assert!(matches!(v, Verb::Reduce(_)));
3124 assert!(matches!(y, Expr::Param(0, _)));
3125 }
3126
3127 #[test]
3128 fn braces_inside_a_string_are_not_holes() {
3129 let sp = SourceParts::from_source("'{a}'").expect("source parts");
3130 assert!(sp.param_names.is_empty());
3131 let a = konst(&parse(&sp).expect("parse")[0]);
3132 assert_eq!(a.data, Data::Char(vec!['{', 'a', '}'].into()));
3133 }
3134
3135 #[test]
3136 fn parts_of_one_sentence_lex_across_a_hole() {
3137 let sp = SourceParts::from_parts(&["1 + ", " * 2"], &["v"]);
3139 assert_eq!(sp.display, "1 + {v} * 2");
3140 let e = parse(&sp).expect("parse").pop().expect("one sentence");
3141 let (_, x, y) = dyad_of(&e);
3142 assert_eq!(ints(&x), vec![1]);
3143 let (_, x2, y2) = dyad_of(&y);
3144 assert!(matches!(x2, Expr::Param(0, _)));
3145 assert_eq!(ints(&y2), vec![2]);
3146 }
3147
3148 #[test]
3149 fn spans_of_later_sentences_index_the_whole_source() {
3150 let src = "5\n1 + 2";
3151 let s = stmts(src);
3152 assert_eq!(s[1].span(), Span::new(2, 7));
3153 assert_eq!(&src[2..7], "1 + 2");
3154 }
3155
3156 #[test]
3159 fn unknown_word_reports_its_span() {
3160 let e = err("1 [. 2");
3161 assert_eq!(e.kind, ErrorKind::Parse);
3162 assert_eq!(e.msg, "unknown word: [.");
3163 assert_eq!(e.span, Some(Span::new(2, 4)));
3164 }
3165
3166 #[test]
3167 fn an_inflected_unknown_word_is_reported_whole() {
3168 let e = err("1 ]: 2");
3169 assert_eq!(e.msg, "unknown word: ]:");
3170 assert_eq!(e.span, Some(Span::new(2, 4)));
3171 }
3172
3173 #[rstest]
3175 #[case("1.5x", 0, 4)]
3176 #[case("1e10x", 0, 5)]
3177 fn a_fractional_extended_literal_is_ill_formed(
3178 #[case] src: &str,
3179 #[case] start: usize,
3180 #[case] end: usize,
3181 ) {
3182 let e = err(src);
3183 assert_eq!(e.kind, ErrorKind::Parse);
3184 assert!(e.msg.contains("invalid number"), "{}", e.msg);
3185 assert_eq!(e.span, Some(Span::new(start, end)));
3186 }
3187
3188 #[test]
3189 fn a_malformed_number_is_a_parse_error() {
3190 let e = err("1.2.3");
3191 assert_eq!(e.kind, ErrorKind::Parse);
3192 assert!(e.msg.contains("invalid number"), "{}", e.msg);
3193 }
3194
3195 #[test]
3196 fn an_unbalanced_sentence_is_a_syntax_error() {
3197 let e = err("(1 + 2");
3200 assert_eq!(e.kind, ErrorKind::Parse);
3201 assert!(e.msg.contains("no closing"), "{}", e.msg);
3202 assert_eq!(e.span, Some(Span::new(0, 1)));
3203 }
3204
3205 #[test]
3206 fn a_stray_right_parenthesis_is_a_syntax_error() {
3207 let e = err("1 + 2)");
3208 assert_eq!(e.kind, ErrorKind::Parse);
3209 assert!(e.msg.contains("no opening"), "{}", e.msg);
3210 assert_eq!(e.span, Some(Span::new(5, 6)));
3211 }
3212
3213 #[test]
3214 fn the_error_of_a_later_sentence_points_at_that_sentence() {
3215 let e = err("1 + 2\n3 [. 4");
3216 assert_eq!(e.span, Some(Span::new(8, 10)));
3217 }
3218}