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 out.push(scope.parse_sentence(sentence)?);
43 }
44 Ok(out)
45}
46
47#[derive(Clone, Debug)]
49enum Modifier {
50 Prim(&'static str),
52 Explicit(Arc<ModSource>),
54}
55
56impl Modifier {
57 fn spelling(&self) -> String {
59 match self {
60 Modifier::Prim(g) => (*g).to_string(),
61 Modifier::Explicit(src) => src.name.clone(),
62 }
63 }
64}
65
66#[derive(Clone, Default)]
70struct Names {
71 verbs: HashMap<String, Verb>,
72 mods: HashMap<String, (bool, Modifier)>,
77 nouns: HashSet<String>,
81 consts: HashMap<String, Array>,
86}
87
88impl Names {
89 fn parse_sentence(&mut self, mut sentence: Vec<Frag>) -> Result<Expr> {
92 substitute_names(&mut sentence, &self.verbs, &self.mods);
93 let whole = sentence_span(&sentence);
94 let frag = reduce_to_fragment(sentence, self)?;
95 if let Some(Frag::ModDef(name, conj, m, span)) = frag {
99 let spelling = m.spelling();
100 self.mods.insert(name.clone(), (conj, m));
101 self.verbs.remove(&name);
102 self.nouns.remove(&name);
103 return Ok(Expr::ModDef { name, spelling, conjunction: conj, span });
104 }
105 let stmt = lower_sentence(frag, whole)?;
106 self.record(&stmt);
107 Ok(stmt)
108 }
109
110 fn record(&mut self, stmt: &Expr) {
112 match stmt {
113 Expr::VerbDef { name, verb, .. } => {
114 self.verbs.insert(name.clone(), verb.clone());
115 self.mods.remove(name);
116 self.nouns.remove(name);
117 }
118 other => {
121 let mut assigned = Vec::new();
122 assigned_names(other, &mut assigned);
123 for name in assigned {
124 self.verbs.remove(&name);
125 self.mods.remove(&name);
126 self.nouns.insert(name.clone());
127 match literal_assigned(other, &name) {
128 Some(a) => self.consts.insert(name, a),
129 None => self.consts.remove(&name),
130 };
131 }
132 }
133 }
134 }
135}
136
137fn literal_assigned(stmt: &Expr, name: &str) -> Option<Array> {
140 match stmt {
141 Expr::Assign { name: n, value, .. } if n == name => match &**value {
142 Expr::Const(a, _) => Some(a.clone()),
143 _ => None,
144 },
145 _ => None,
146 }
147}
148
149const CONTROL_WORDS: [&str; 18] = [
154 "if.", "do.", "else.", "elseif.", "end.", "while.", "whilst.", "for.", "select.", "case.",
155 "fcase.", "return.", "break.", "continue.", "try.", "catch.", "catcht.", "throw.",
156];
157
158fn control_word(word: &str) -> Option<(&'static str, Option<String>)> {
160 if let Some(w) = CONTROL_WORDS.iter().copied().find(|&w| w == word) {
161 return Some((w, None));
162 }
163 for (stem, w) in [("for_", "for."), ("goto_", "goto."), ("label_", "label.")] {
164 if let Some(rest) = word.strip_prefix(stem) {
165 let name = rest.strip_suffix('.')?;
166 if !name.is_empty() && is_j_name(name) {
167 return Some((w, Some(name.to_string())));
168 }
169 }
170 }
171 None
172}
173
174fn is_j_name(s: &str) -> bool {
175 let mut cs = s.chars();
176 cs.next().is_some_and(|c| c.is_ascii_alphabetic())
177 && s.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')
178}
179
180#[derive(Clone, Debug)]
183enum Item {
184 Sentence(Vec<Frag>),
185 Word { word: &'static str, suffix: Option<String>, span: Span },
186}
187
188impl Item {
189 fn word(&self) -> Option<&'static str> {
190 match self {
191 Item::Word { word, .. } => Some(word),
192 Item::Sentence(_) => None,
193 }
194 }
195
196 fn span(&self) -> Span {
197 match self {
198 Item::Word { span, .. } => *span,
199 Item::Sentence(f) => sentence_span(f),
200 }
201 }
202}
203
204fn collect_definitions(
210 lines: &[Vec<Frag>],
211 i: &mut usize,
212 scope: &mut Names,
213 top_level: bool,
214) -> Result<Vec<Frag>> {
215 let mut sentence = lines[*i].clone();
216 *i += 1;
217 let self_name = match (sentence.first(), sentence.get(1)) {
220 (Some(Frag::Name(n, _)), Some(a)) if a.is_assign() => Some(n.clone()),
221 _ => None,
222 };
223 loop {
224 let Some(open) = sentence.iter().position(|f| matches!(f, Frag::DdOpen(..))) else {
225 match find_colon_definition(&sentence) {
226 Some(at) => {
227 take_colon_definition(&mut sentence, at, lines, i, scope, self_name.as_deref())?;
228 continue;
229 }
230 None => {
233 if top_level
234 && let Some(Frag::Control(_, _, span)) =
235 sentence.iter().find(|f| matches!(f, Frag::Control(..)))
236 {
237 return Err(Error::parse(
238 "control words are only meaningful inside an explicit definition",
239 *span,
240 ));
241 }
242 return Ok(sentence);
243 }
244 }
245 };
246 take_direct_definition(&mut sentence, open, lines, i, scope, self_name.as_deref())?;
247 }
248}
249
250fn find_colon_definition(sentence: &[Frag]) -> Option<usize> {
252 (1..sentence.len().saturating_sub(1)).find(|&k| {
253 matches!(&sentence[k], Frag::Conj(Modifier::Prim(":"), _))
254 && as_const(&sentence[k - 1]).is_some_and(|a| a.rank() == 0)
255 && matches!(&sentence[k + 1], Frag::Noun(Expr::Const(..)))
256 })
257}
258
259fn take_colon_definition(
262 sentence: &mut Vec<Frag>,
263 at: usize,
264 lines: &[Vec<Frag>],
265 i: &mut usize,
266 scope: &mut Names,
267 self_name: Option<&str>,
268) -> Result<()> {
269 let span = Span::merge(sentence[at - 1].span(), sentence[at + 1].span());
270 let valence = as_const(&sentence[at - 1])
271 .and_then(Array::to_f64_vec)
272 .and_then(|v| v.first().copied())
273 .ok_or_else(|| Error::parse("an explicit definition starts with a number", span))?;
274 let body_arr = as_const(&sentence[at + 1]).cloned().expect("checked by the finder");
275 let body_span = sentence[at + 1].span();
276 let (dyadic, modifier) = match valence {
277 3.0 => (false, None),
278 4.0 => (true, None),
279 1.0 => (false, Some(false)),
280 2.0 => (false, Some(true)),
281 13.0 => return Err(Error::not_yet("tacit definitions (13 : '...')", span)),
282 v => return Err(Error::domain(format!("{v} is not an explicit definition"), span)),
283 };
284 let body = match &body_arr.data {
285 Data::I64(_)
287 | Data::F64(_)
288 | Data::Bool(_)
289 | Data::Ext(_)
290 | Data::Rat(_)
291 | Data::Complex(_) => {
292 if body_arr.to_f64_vec().as_deref() != Some(&[0.0]) {
293 return Err(Error::parse("an explicit definition takes 0 or a string", body_span));
294 }
295 take_lines_until_paren(lines, i, body_span)?
296 }
297 Data::Char(chars) => {
298 let text: String = chars.as_slice().iter().collect();
299 let mut frags = Vec::new();
300 lex_line(&text, body_span.start + 1, &mut frags)?;
303 vec![frags]
304 }
305 Data::Symbol(_) | Data::Box(_) => {
306 return Err(Error::parse("an explicit definition takes 0 or a string", body_span))
307 }
308 };
309 if let Some(conjunction) = modifier {
310 let name = if conjunction { "2 : '...'" } else { "1 : '...'" };
311 let src = mod_source(name, conjunction, body, self_name);
312 let frag = if conjunction {
313 Frag::Conj(Modifier::Explicit(Arc::new(src)), span)
314 } else {
315 Frag::Adverb(Modifier::Explicit(Arc::new(src)), span)
316 };
317 sentence.splice(at - 1..at + 2, [frag]);
318 return Ok(());
319 }
320 let name = if dyadic { "4 : '...'" } else { "3 : '...'" };
321 let verb = build_definition(body, dyadic, name, scope, self_name)?;
322 sentence.splice(at - 1..at + 2, [Frag::Verb(VerbFrag::V(verb), span)]);
323 Ok(())
324}
325
326fn take_lines_until_paren(
328 lines: &[Vec<Frag>],
329 i: &mut usize,
330 span: Span,
331) -> Result<Vec<Vec<Frag>>> {
332 let mut body = Vec::new();
333 loop {
334 let Some(line) = lines.get(*i) else {
335 return Err(Error::parse("this definition's body has no closing `)`", span));
336 };
337 *i += 1;
338 if line.len() == 1 && matches!(line[0], Frag::RParen(_)) {
339 return Ok(body);
340 }
341 body.push(line.clone());
342 }
343}
344
345fn take_direct_definition(
348 sentence: &mut Vec<Frag>,
349 open: usize,
350 lines: &[Vec<Frag>],
351 i: &mut usize,
352 scope: &mut Names,
353 self_name: Option<&str>,
354) -> Result<()> {
355 let open_span = sentence[open].span();
356 let Frag::DdOpen(marker, _) = sentence[open] else {
357 return Err(Error::internal("expected a direct definition's opening brackets"));
358 };
359 let mut depth = 1usize;
360 let mut body: Vec<Vec<Frag>> = Vec::new();
361 let mut tail: Vec<Frag> = Vec::new();
362 let mut close_span = open_span;
363 let mut line: Vec<Frag> = sentence[open + 1..].to_vec();
364 let mut cur: Vec<Frag> = Vec::new();
365 loop {
366 let mut closed = false;
367 for (k, f) in line.iter().enumerate() {
368 match f {
369 Frag::DdOpen(..) => {
370 depth += 1;
371 cur.push(f.clone());
372 }
373 Frag::DdClose(s) => {
374 depth -= 1;
375 if depth == 0 {
376 close_span = *s;
377 tail = line[k + 1..].to_vec();
378 closed = true;
379 break;
380 }
381 cur.push(f.clone());
382 }
383 _ => cur.push(f.clone()),
384 }
385 }
386 if !cur.is_empty() {
387 body.push(std::mem::take(&mut cur));
388 }
389 if closed {
390 break;
391 }
392 let Some(next) = lines.get(*i) else {
393 return Err(Error::parse("this definition has no closing `}}`", open_span));
394 };
395 *i += 1;
396 line = next.clone();
397 }
398 let span = Span::merge(open_span, close_span);
399 let part = match marker {
404 None => {
405 if mentions(&body, "v") || mentions(&body, "n") {
406 Some(true)
407 } else if mentions(&body, "u") || mentions(&body, "m") {
408 Some(false)
409 } else {
410 None
411 }
412 }
413 Some('a') => Some(false),
414 Some('c') => Some(true),
415 Some('v' | 'm' | 'd') => None,
416 Some(other) => {
417 return Err(Error::not_yet(
418 format!("a direct definition marked `){other}`"),
419 open_span,
420 ))
421 }
422 };
423 let frag = match part {
424 Some(conjunction) => {
425 let src = mod_source("{{ ... }}", conjunction, body, self_name);
426 let m = Modifier::Explicit(Arc::new(src));
427 if conjunction { Frag::Conj(m, span) } else { Frag::Adverb(m, span) }
428 }
429 None => {
430 let dyadic = match marker {
433 Some('d') => true,
434 Some('m') => false,
435 _ => mentions(&body, "x"),
436 };
437 let verb = build_definition(body, dyadic, "{{ ... }}", scope, self_name)?;
438 Frag::Verb(VerbFrag::V(verb), span)
439 }
440 };
441 let mut head: Vec<Frag> = sentence[..open].to_vec();
442 head.push(frag);
443 head.extend(tail);
444 *sentence = head;
445 Ok(())
446}
447
448fn mentions(body: &[Vec<Frag>], name: &str) -> bool {
450 body.iter().any(|l| l.iter().any(|f| matches!(f, Frag::Name(n, _) if n == name)))
451}
452
453fn build_definition(
455 body: Vec<Vec<Frag>>,
456 dyadic: bool,
457 name: &str,
458 scope: &Names,
459 self_name: Option<&str>,
460) -> Result<Verb> {
461 let mut inner = scope.clone();
464 inner.nouns.insert("y".to_string());
465 inner.verbs.remove("y");
466 inner.consts.remove("y");
467 if dyadic {
468 inner.nouns.insert("x".to_string());
469 inner.verbs.remove("x");
470 inner.consts.remove("x");
471 }
472 if let Some(n) = self_name {
473 inner.nouns.remove(n);
474 inner.consts.remove(n);
475 inner.verbs.insert(n.to_string(), Verb::Named(n.to_string()));
476 }
477 let mut lines: Vec<Vec<Frag>> = Vec::new();
481 let mut k = 0usize;
482 while k < body.len() {
483 let line = collect_definitions(&body, &mut k, &mut inner, false)?;
484 if !line.is_empty() {
485 lines.push(line);
486 }
487 }
488 let items = split_items(&lines);
489 let mut cursor = Cursor { items: &items, at: 0 };
490 let stmts = parse_block(&mut cursor, &mut inner, &[])?;
491 if let Some(item) = cursor.peek() {
492 return Err(Error::parse(
493 format!("`{}` has no matching opening word", item.word().unwrap_or("word")),
494 item.span(),
495 ));
496 }
497 let pure = stmts.iter().all(block_is_pure);
498 Ok(Verb::Explicit(Arc::new(ExplicitDef {
499 name: name.to_string(),
500 left: dyadic.then(|| "x".to_string()),
501 right: "y".to_string(),
502 dyad_only: dyadic,
505 spare_left: false,
508 enclosing: Vec::new(),
509 id: 0,
510 result: None,
511 locals: Vec::new(),
512 body: stmts,
513 labels: Vec::new(),
515 empty: Some(crate::ir::empty_result()),
516 pure,
517 })))
518}
519
520#[derive(Debug)]
530struct ModSource {
531 name: String,
533 conjunction: bool,
535 body: Vec<Vec<Frag>>,
536 deferred: bool,
540 dyadic: bool,
542 self_name: Option<String>,
545}
546
547fn mod_source(
548 name: &str,
549 conjunction: bool,
550 body: Vec<Vec<Frag>>,
551 self_name: Option<&str>,
552) -> ModSource {
553 let dyadic = mentions(&body, "x");
554 ModSource {
555 name: name.to_string(),
556 conjunction,
557 deferred: dyadic || mentions(&body, "y"),
558 dyadic,
559 self_name: self_name.map(str::to_string),
560 body,
561 }
562}
563
564thread_local! {
565 static DERIVING: std::cell::RefCell<Vec<usize>> = const { std::cell::RefCell::new(Vec::new()) };
569}
570
571struct Deriving;
574
575impl Drop for Deriving {
576 fn drop(&mut self) {
577 DERIVING.with(|d| {
578 d.borrow_mut().pop();
579 });
580 }
581}
582
583fn derive_explicit(
591 src: &Arc<ModSource>,
592 u: Frag,
593 v: Option<Frag>,
594 scope: &Names,
595 span: Span,
596) -> Result<Frag> {
597 let addr = Arc::as_ptr(src) as usize;
598 let recursive = DERIVING.with(|d| {
599 let mut d = d.borrow_mut();
600 if d.contains(&addr) {
601 return true;
602 }
603 d.push(addr);
604 false
605 });
606 if recursive {
607 return Err(Error::not_yet(
608 "an explicit modifier whose body derives the modifier itself",
609 span,
610 ));
611 }
612 let _guard = Deriving;
613 let mut body = src.body.clone();
614 bind_operand(&mut body, "u", "m", &u);
615 if let Some(v) = &v {
616 bind_operand(&mut body, "v", "n", v);
617 }
618 let mut inner = scope.clone();
622 if let Some(n) = &src.self_name {
623 inner.verbs.remove(n);
624 inner.nouns.remove(n);
625 inner.consts.remove(n);
626 inner.mods.insert(n.clone(), (src.conjunction, Modifier::Explicit(Arc::clone(src))));
627 }
628 if src.deferred {
629 let verb = build_definition(body, src.dyadic, &src.name, &inner, None)?;
630 return Ok(Frag::Verb(VerbFrag::V(verb), span));
631 }
632 let mut lines: Vec<Vec<Frag>> = Vec::new();
635 let mut k = 0usize;
636 while k < body.len() {
637 let line = collect_definitions(&body, &mut k, &mut inner, false)?;
638 if !line.is_empty() {
639 lines.push(line);
640 }
641 }
642 if lines.len() != 1 {
643 return Err(Error::not_yet(
644 "an explicit modifier that names no argument and is more than one sentence",
645 span,
646 ));
647 }
648 let mut sentence = lines.pop().expect("checked length");
649 substitute_names(&mut sentence, &inner.verbs, &inner.mods);
650 match reduce_to_fragment(sentence, &inner)? {
651 Some(f) if f.is_real_verb() || f.is_noun() => Ok(respan(f, span)),
652 Some(f) => Err(Error::not_yet(
653 format!("an explicit modifier that produces {}", part_of_speech(&f)),
654 span,
655 )),
656 None => Err(Error::parse("syntax error", span)),
657 }
658}
659
660fn part_of_speech(f: &Frag) -> &'static str {
662 match f {
663 Frag::Adverb(..) => "an adverb",
664 Frag::Conj(..) => "a conjunction",
665 _ => "no value",
666 }
667}
668
669fn bind_operand(body: &mut [Vec<Frag>], verb_name: &str, noun_name: &str, operand: &Frag) {
674 let wanted = if operand.is_real_verb() { verb_name } else { noun_name };
675 for line in body.iter_mut() {
676 for i in 0..line.len() {
677 let Frag::Name(n, span) = &line[i] else { continue };
678 if n != wanted {
679 continue;
680 }
681 let span = *span;
682 if line.get(i + 1).is_some_and(Frag::is_assign) {
684 continue;
685 }
686 line[i] = respan(operand.clone(), span);
687 }
688 }
689}
690
691fn block_is_pure(e: &Expr) -> bool {
693 match e {
694 Expr::Const(..) | Expr::Param(..) | Expr::Name(..) => true,
695 Expr::Monad { verb, y, .. } => verb.is_pure() && block_is_pure(y),
696 Expr::Dyad { verb, x, y, .. } => {
697 verb.is_pure() && block_is_pure(x) && block_is_pure(y)
698 }
699 Expr::Assign { value, .. } => block_is_pure(value),
700 Expr::Control(c, _) => control_is_pure(c),
701 _ => false,
702 }
703}
704
705fn control_is_pure(c: &Control) -> bool {
706 let all = |b: &Vec<Expr>| b.iter().all(block_is_pure);
707 match c {
708 Control::Return | Control::Break | Control::Continue => true,
709 Control::Branch(target) => block_is_pure(target),
712 Control::If { arms, otherwise } => {
713 arms.iter().all(|a| {
714 a.test.as_ref().is_none_or(all) && all(&a.body)
715 }) && otherwise.as_ref().is_none_or(all)
716 }
717 Control::While { test, body, .. } | Control::Guard { test, body } => {
720 all(test) && all(body)
721 }
722 Control::For { source, body, .. } => block_is_pure(source) && all(body),
723 Control::Select { subject, cases } => {
724 block_is_pure(subject)
725 && cases.iter().all(|c| c.test.as_ref().is_none_or(all) && all(&c.body))
726 }
727 Control::Try { body, catch } => all(body) && all(catch),
728 }
729}
730
731fn split_items(lines: &[Vec<Frag>]) -> Vec<Item> {
733 let mut items = Vec::new();
734 for line in lines {
735 let mut run: Vec<Frag> = Vec::new();
736 for f in line {
737 match f {
738 Frag::Control(word, suffix, span) => {
739 if !run.is_empty() {
740 items.push(Item::Sentence(std::mem::take(&mut run)));
741 }
742 items.push(Item::Word {
743 word,
744 suffix: suffix.clone(),
745 span: *span,
746 });
747 }
748 _ => run.push(f.clone()),
749 }
750 }
751 if !run.is_empty() {
752 items.push(Item::Sentence(run));
753 }
754 }
755 items
756}
757
758struct Cursor<'a> {
759 items: &'a [Item],
760 at: usize,
761}
762
763impl<'a> Cursor<'a> {
764 fn peek(&self) -> Option<&'a Item> {
765 self.items.get(self.at)
766 }
767
768 fn peek_word(&self) -> Option<&'static str> {
769 self.peek().and_then(Item::word)
770 }
771
772 fn next(&mut self) -> Option<&'a Item> {
773 let it = self.items.get(self.at);
774 if it.is_some() {
775 self.at += 1;
776 }
777 it
778 }
779
780 fn last_span(&self) -> Span {
781 self.items
782 .get(self.at.saturating_sub(1))
783 .map_or_else(|| Span::new(0, 0), Item::span)
784 }
785
786 fn expect(&mut self, want: &str) -> Result<Span> {
788 match self.peek() {
789 Some(Item::Word { word, span, .. }) if *word == want => {
790 self.at += 1;
791 Ok(*span)
792 }
793 Some(other) => {
794 Err(Error::parse(format!("expected `{want}` here"), other.span()))
795 }
796 None => Err(Error::parse(format!("this block needs a `{want}`"), self.last_span())),
797 }
798 }
799}
800
801fn parse_block(cur: &mut Cursor<'_>, scope: &mut Names, stop: &[&str]) -> Result<Vec<Expr>> {
803 let mut out = Vec::new();
804 loop {
805 match cur.peek() {
806 None => return Ok(out),
807 Some(Item::Word { word, .. }) if stop.contains(word) => return Ok(out),
808 Some(Item::Sentence(frags)) => {
809 cur.at += 1;
810 out.push(scope.parse_sentence(frags.clone())?);
811 }
812 Some(Item::Word { .. }) => out.push(parse_control(cur, scope)?),
813 }
814 }
815}
816
817fn parse_control(cur: &mut Cursor<'_>, scope: &mut Names) -> Result<Expr> {
818 let Some(Item::Word { word, suffix, span }) = cur.next() else {
819 return Err(Error::internal("expected a control word"));
820 };
821 let start = *span;
822 let control = match *word {
823 "if." => parse_if(cur, scope)?,
824 "while." | "whilst." => {
825 let body_first = *word == "whilst.";
826 let test = parse_block(cur, scope, &["do."])?;
827 cur.expect("do.")?;
828 let body = parse_block(cur, scope, &["end."])?;
829 cur.expect("end.")?;
830 Control::While { test, body, body_first, until: false }
831 }
832 "for." => {
833 if let Some(name) = suffix {
834 scope.nouns.insert(name.clone());
835 scope.nouns.insert(format!("{name}_index"));
836 scope.verbs.remove(name);
837 scope.consts.remove(name);
838 }
839 let source = parse_block(cur, scope, &["do."])?;
840 cur.expect("do.")?;
841 let body = parse_block(cur, scope, &["end."])?;
842 let end = cur.expect("end.")?;
843 let source = one_expr(source, Span::merge(start, end))?;
844 Control::For { names: suffix.iter().cloned().collect(), source: Box::new(source), body }
845 }
846 "select." => parse_select(cur, scope, start)?,
847 "try." => {
848 let body = parse_block(cur, scope, &["catch.", "catcht.", "end."])?;
849 if cur.peek_word() == Some("catcht.") {
850 return Err(Error::not_yet("throw. and catcht.", cur.last_span()));
851 }
852 let catch = if cur.peek_word() == Some("catch.") {
853 cur.expect("catch.")?;
854 parse_block(cur, scope, &["end."])?
855 } else {
856 Vec::new()
857 };
858 cur.expect("end.")?;
859 Control::Try { body, catch }
860 }
861 "return." => Control::Return,
862 "break." => Control::Break,
863 "continue." => Control::Continue,
864 "throw." | "catcht." => return Err(Error::not_yet("throw. and catcht.", start)),
865 "goto." | "label." => {
866 return Err(Error::not_yet("goto_name. and label_name.", start))
867 }
868 other => {
869 return Err(Error::parse(
870 format!("`{other}` has no matching opening word"),
871 start,
872 ))
873 }
874 };
875 let span = Span::merge(start, cur.last_span());
876 Ok(Expr::Control(Box::new(control), span))
877}
878
879fn parse_if(cur: &mut Cursor<'_>, scope: &mut Names) -> Result<Control> {
880 let mut arms = Vec::new();
881 let mut otherwise = None;
882 loop {
883 let test = parse_block(cur, scope, &["do."])?;
884 cur.expect("do.")?;
885 let body = parse_block(cur, scope, &["elseif.", "else.", "end."])?;
886 arms.push(Branch { test: Some(test), body, fall_through: false, list: false });
887 match cur.peek_word() {
888 Some("elseif.") => {
889 cur.at += 1;
890 }
891 Some("else.") => {
892 cur.at += 1;
893 otherwise = Some(parse_block(cur, scope, &["end."])?);
894 cur.expect("end.")?;
895 break;
896 }
897 _ => {
898 cur.expect("end.")?;
899 break;
900 }
901 }
902 }
903 if let Some(last) = arms.last_mut() && last.test.as_ref().is_some_and(Vec::is_empty) {
906 last.test = None;
907 }
908 Ok(Control::If { arms, otherwise })
909}
910
911fn parse_select(cur: &mut Cursor<'_>, scope: &mut Names, start: Span) -> Result<Control> {
912 let subject = parse_block(cur, scope, &["case.", "fcase.", "end."])?;
913 let subject = one_expr(subject, start)?;
914 let mut cases = Vec::new();
915 loop {
916 let fall_through = match cur.peek_word() {
917 Some("case.") => false,
918 Some("fcase.") => true,
919 _ => {
920 cur.expect("end.")?;
921 break;
922 }
923 };
924 cur.at += 1;
925 let test = parse_block(cur, scope, &["do."])?;
926 cur.expect("do.")?;
927 let body = parse_block(cur, scope, &["case.", "fcase.", "end."])?;
928 let test = (!test.is_empty()).then_some(test);
930 cases.push(Branch { test, body, fall_through, list: false });
931 }
932 Ok(Control::Select { subject: Box::new(subject), cases })
933}
934
935fn one_expr(mut stmts: Vec<Expr>, span: Span) -> Result<Expr> {
938 match stmts.pop() {
939 Some(e) if stmts.is_empty() => Ok(e),
940 Some(_) => Err(Error::not_yet("several sentences where one value is needed", span)),
941 None => Err(Error::parse("this control word needs a value", span)),
942 }
943}
944
945fn substitute_names(
949 sentence: &mut [Frag],
950 verbs: &HashMap<String, Verb>,
951 mods: &HashMap<String, (bool, Modifier)>,
952) {
953 for i in 0..sentence.len() {
954 let Frag::Name(name, span) = &sentence[i] else { continue };
955 let (name, span) = (name.clone(), *span);
956 if sentence.get(i + 1).is_some_and(Frag::is_assign) {
957 continue;
958 }
959 if let Some(v) = verbs.get(&name) {
960 sentence[i] = Frag::Verb(VerbFrag::V(v.clone()), span);
961 } else if let Some((conj, m)) = mods.get(&name) {
962 sentence[i] = if *conj {
963 Frag::Conj(m.clone(), span)
964 } else {
965 Frag::Adverb(m.clone(), span)
966 };
967 }
968 }
969}
970
971fn assigned_names(e: &Expr, out: &mut Vec<String>) {
973 match e {
974 Expr::Assign { name, value, .. } => {
975 out.push(name.clone());
976 assigned_names(value, out);
977 }
978 Expr::Monad { y, .. } => assigned_names(y, out),
979 Expr::Dyad { x, y, .. } => {
980 assigned_names(x, out);
981 assigned_names(y, out);
982 }
983 Expr::PrintPass { value, .. } => assigned_names(value, out),
984 _ => {}
985 }
986}
987
988#[derive(Clone, Debug)]
994enum Frag {
995 Mark,
997 Noun(Expr),
998 Name(String, Span),
1000 Verb(VerbFrag, Span),
1001 Adverb(Modifier, Span),
1002 Conj(Modifier, Span),
1003 LParen(Span),
1004 RParen(Span),
1005 AssignLocal(Span),
1006 AssignGlobal(Span),
1007 VerbDef(String, Verb, Span),
1010 ModDef(String, bool, Modifier, Span),
1014 Control(&'static str, Option<String>, Span),
1017 DdOpen(Option<char>, Span),
1020 DdClose(Span),
1021}
1022
1023#[derive(Clone, Debug)]
1026enum VerbFrag {
1027 V(Verb),
1028 Cap,
1029}
1030
1031impl Frag {
1032 fn span(&self) -> Span {
1033 match self {
1034 Frag::Mark => Span::new(0, 0),
1035 Frag::Noun(e) => e.span(),
1036 Frag::Name(_, s)
1037 | Frag::Verb(_, s)
1038 | Frag::Adverb(_, s)
1039 | Frag::Conj(_, s)
1040 | Frag::LParen(s)
1041 | Frag::RParen(s)
1042 | Frag::AssignLocal(s)
1043 | Frag::AssignGlobal(s)
1044 | Frag::DdClose(s)
1045 | Frag::VerbDef(_, _, s)
1046 | Frag::ModDef(_, _, _, s) => *s,
1047 Frag::DdOpen(_, s) => *s,
1048 Frag::Control(_, _, s) => *s,
1049 }
1050 }
1051
1052 fn is_edge(&self) -> bool {
1053 matches!(self, Frag::Mark | Frag::AssignLocal(_) | Frag::AssignGlobal(_) | Frag::LParen(_))
1054 }
1055
1056 fn is_verb(&self) -> bool {
1058 matches!(self, Frag::Verb(..))
1059 }
1060
1061 fn is_real_verb(&self) -> bool {
1063 matches!(self, Frag::Verb(VerbFrag::V(_), _))
1064 }
1065
1066 fn is_noun(&self) -> bool {
1068 matches!(self, Frag::Noun(_) | Frag::Name(..))
1069 }
1070
1071 fn is_adverb(&self) -> bool {
1072 matches!(self, Frag::Adverb(..))
1073 }
1074
1075 fn is_conj(&self) -> bool {
1076 matches!(self, Frag::Conj(..))
1077 }
1078
1079 fn is_avn(&self) -> bool {
1080 self.is_adverb() || self.is_verb() || self.is_noun()
1081 }
1082
1083 fn is_cavn(&self) -> bool {
1084 self.is_conj() || self.is_avn()
1085 }
1086
1087 fn is_assign(&self) -> bool {
1088 matches!(self, Frag::AssignLocal(_) | Frag::AssignGlobal(_))
1089 }
1090}
1091
1092const fn prim(name: &'static str, monad: MonadOp, dyad: DyadOp, ranks: [i64; 3]) -> Prim {
1095 Prim { name, monad, dyad, ranks }
1096}
1097
1098fn primitive(word: &str) -> Option<Prim> {
1102 use DyadOp as D;
1103 use MonadOp as M;
1104 use ScalarDyad as SD;
1105 use ScalarMonad as SM;
1106 const INF: i64 = RANK_INF;
1107 Some(match word {
1108 "+" => prim("+", M::Scalar(SM::Conj), D::Scalar(SD::Add), [0, 0, 0]),
1109 "-" => prim("-", M::Scalar(SM::Neg), D::Scalar(SD::Sub), [0, 0, 0]),
1110 "*" => prim("*", M::Scalar(SM::Signum), D::Scalar(SD::Mul), [0, 0, 0]),
1111 "%" => prim("%", M::Scalar(SM::Recip), D::Scalar(SD::DivJ), [0, 0, 0]),
1112 "^" => prim("^", M::Scalar(SM::Exp), D::Scalar(SD::Pow), [0, 0, 0]),
1113 "%:" => prim("%:", M::Scalar(SM::Sqrt), D::Scalar(SD::Root), [0, 0, 0]),
1114 "^." => prim("^.", M::Scalar(SM::Ln), D::Scalar(SD::Log), [0, 0, 0]),
1115 "|" => prim("|", M::Scalar(SM::Abs), D::Scalar(SD::Residue), [0, 0, 0]),
1116 "<." => prim("<.", M::Scalar(SM::Floor), D::Scalar(SD::Min), [0, 0, 0]),
1117 ">." => prim(">.", M::Scalar(SM::Ceil), D::Scalar(SD::Max), [0, 0, 0]),
1118 "=" => prim("=", M::SelfClassify, D::Scalar(SD::Eq), [INF, 0, 0]),
1119 "<" => prim("<", M::Enclose(Enclose::Always), D::Scalar(SD::Lt), [INF, 0, 0]),
1120 ">" => prim(">", M::Open, D::Scalar(SD::Gt), [0, 0, 0]),
1121 "<:" => prim("<:", M::Scalar(SM::Dec), D::Scalar(SD::Le), [0, 0, 0]),
1122 ">:" => prim(">:", M::Scalar(SM::Inc), D::Scalar(SD::Ge), [0, 0, 0]),
1123 "+:" => prim("+:", M::Scalar(SM::Double), D::Boolean(BoolDyad::Nor), [0, 0, 0]),
1124 "*:" => prim("*:", M::Scalar(SM::Square), D::Boolean(BoolDyad::Nand), [0, 0, 0]),
1125 "-:" => prim("-:", M::Scalar(SM::Halve), D::Match, [0, INF, INF]),
1126 "-." => prim("-.", M::Scalar(SM::OneMinus), D::Less, [0, INF, INF]),
1127 "*." => prim("*.", M::ComplexParts { polar: true }, D::Scalar(SD::Lcm), [0, 0, 0]),
1128 "+." => prim("+.", M::ComplexParts { polar: false }, D::Scalar(SD::Gcd), [0, 0, 0]),
1129 "~:" => prim("~:", M::NubSieve, D::Scalar(SD::Ne), [INF, 0, 0]),
1130 "~." => prim("~.", M::Nub, D::None, [INF, INF, INF]),
1131 "$" => prim("$", M::ShapeOf, D::Reshape, [INF, 1, INF]),
1132 "," => prim(",", M::Ravel, D::AppendLeading, [INF, INF, INF]),
1133 ",." => prim(",.", M::RavelItems, D::AppendLeading, [INF, -1, -1]),
1137 ",:" => prim(",:", M::Itemize, D::Laminate, [INF, INF, INF]),
1138 "#" => prim("#", M::Tally, D::Copy, [INF, 1, INF]),
1139 "#." => prim("#.", M::DecodeBits, D::Decode, [1, 1, 1]),
1140 "#:" => prim("#:", M::EncodeBits, D::Encode, [INF, 1, 0]),
1143 "!" => prim("!", M::Scalar(SM::Factorial), D::Scalar(SD::Binomial), [0, 0, 0]),
1144 "\":" => {
1145 prim("\":", M::Format, D::FormatSpecJ, [INF, 1, INF])
1146 }
1147 "o." => prim("o.", M::Scalar(SM::Pi), D::Scalar(SD::Circle), [0, 0, 0]),
1148 "j." => prim("j.", M::Scalar(SM::Imaginary), D::Scalar(SD::MakeComplex), [0, 0, 0]),
1149 "r." => prim("r.", M::Scalar(SM::Polar), D::Scalar(SD::PolarBy), [0, 0, 0]),
1150 "{" => prim("{", M::Catalogue, D::From, [INF, 0, INF]),
1151 "{." => prim("{.", M::Head, D::Take, [INF, 1, INF]),
1152 "}." => prim("}.", M::Behead, D::Drop, [INF, 1, INF]),
1153 "{:" => prim("{:", M::Tail, D::None, [INF, INF, INF]),
1154 "}:" => prim("}:", M::Curtail, D::None, [INF, INF, INF]),
1155 "|." => prim("|.", M::Reverse, D::Rotate, [INF, 1, INF]),
1156 "|:" => prim("|:", M::TransposeAxes, D::TransposeJ, [INF, 1, INF]),
1157 "i." => prim("i.", M::IotaJ, D::IndexOf { origin: 0, vector_left: false }, [1, INF, INF]),
1158 "i:" => prim("i:", M::Steps, D::IndexOfLast { origin: 0 }, [0, INF, INF]),
1159 "I." => prim(
1160 "I.",
1161 M::Indices { origin: 0, boxed_coords: false },
1162 D::IntervalIndex { offset: 0, closed: false },
1163 [1, 1, INF],
1164 ),
1165 "x:" => prim("x:", M::ToExact, D::ExactForm, [INF, 0, INF]),
1168 "p:" => prim("p:", M::NthPrime, D::PrimeMeta, [0, 0, 0]),
1169 "p." => prim("p.", M::PolyRoots, D::PolyEval, [1, 1, 0]),
1172 "p.." => prim("p..", M::PolyDeriv, D::PolyIntegral, [1, 0, 1]),
1173 "$." => prim("$.", M::Sparse, D::SparseForm, [INF, INF, INF]),
1174 "q:" => prim("q:", M::PrimeFactors, D::PrimeExponents, [0, 0, 0]),
1175 "%." => prim("%.", M::MatrixInverse, D::MatrixDivide, [2, INF, 2]),
1176 "?" => prim(
1179 "?",
1180 M::Roll { origin: 0, fixed: false, float_at_zero: true },
1181 D::Deal { origin: 0, fixed: false },
1182 [INF, 0, 0],
1183 ),
1184 "?." => prim(
1185 "?.",
1186 M::Roll { origin: 0, fixed: true, float_at_zero: true },
1187 D::Deal { origin: 0, fixed: true },
1188 [INF, 0, 0],
1189 ),
1190 "{::" => prim("{::", M::MapPaths, D::Fetch, [INF, INF, INF]),
1191 "e." => prim("e.", M::RazeIn, D::MemberJ, [INF, INF, INF]),
1192 "/:" => prim(
1193 "/:",
1194 M::GradeUp { origin: 0 },
1195 D::GradeSelect { down: false },
1196 [INF, INF, INF],
1197 ),
1198 "\\:" => prim(
1199 "\\:",
1200 M::GradeDown { origin: 0 },
1201 D::GradeSelect { down: true },
1202 [INF, INF, INF],
1203 ),
1204 ";" => prim(";", M::Raze, D::Link, [INF, INF, INF]),
1205 ";:" => prim(
1206 ";:",
1207 M::Words,
1208 D::SequentialMachine,
1209 [INF, INF, INF],
1210 ),
1211 "L." => prim("L.", M::LevelOf, D::None, [INF, INF, INF]),
1212 "\"." => prim(
1213 "\".",
1214 M::Execute { apl: false },
1215 D::ParseNumbers,
1216 [1, INF, 1],
1217 ),
1218 "A." => prim("A.", M::AnagramIndex, D::AnagramFrom, [1, 0, INF]),
1219 "C." => prim("C.", M::CycleForm, D::Permute, [1, 1, INF]),
1220 "E." => prim("E.", M::None, D::FindSeq, [INF, INF, INF]),
1221 "u:" => prim("u:", M::Unicode { pass_chars: true }, D::UnicodeForm, [INF, 0, INF]),
1222 "s:" => prim("s:", M::Symbols, D::SymbolForm, [INF, 0, INF]),
1225 "]" => prim("]", M::Same, D::Right, [INF, INF, INF]),
1226 "[" => prim("[", M::Same, D::Left, [INF, INF, INF]),
1227 "echo" => prim("echo", M::Echo, D::None, [INF, INF, INF]),
1228 _ => return None,
1229 })
1230}
1231
1232fn noun_word(word: &str) -> Option<Array> {
1237 match word {
1238 "a." => Some(Array::from_chars(
1239 (0u32..256).map(|c| char::from_u32(c).expect("a Latin-1 codepoint")).collect(),
1240 )),
1241 "a:" => Some(Array::boxed(Array::empty(crate::dtype::DType::I64))),
1242 "_." => Some(Array::scalar_f64(f64::NAN)),
1243 _ => None,
1244 }
1245}
1246
1247fn verb_for(word: &str) -> Option<Verb> {
1250 Some(Verb::Prim(primitive(word)?))
1251}
1252
1253fn constant_verb(n: Array) -> Verb {
1256 Verb::NounFork(
1259 n,
1260 Box::new(verb_for("[").expect("`[` is a primitive")),
1261 Box::new(verb_for("]").expect("`]` is a primitive")),
1262 )
1263}
1264
1265fn constant_verb_word(cs: &[(usize, char)], i: usize) -> Option<(usize, Array)> {
1269 let at = |k: usize| cs.get(k).map(|&(_, c)| c);
1270 let (digits, value) = match (at(i), at(i + 1), at(i + 2)) {
1271 (Some('_'), Some(':'), _) => (2, f64::INFINITY),
1272 (Some('_'), Some(d), Some(':')) if d.is_ascii_digit() => {
1273 (3, -((d as u8 - b'0') as f64))
1274 }
1275 (Some(d), Some(':'), _) if d.is_ascii_digit() => (2, (d as u8 - b'0') as f64),
1276 _ => return None,
1277 };
1278 if at(i + digits) == Some(':') {
1279 return None;
1280 }
1281 let arr = if value.is_infinite() {
1282 Array::scalar_f64(value)
1283 } else {
1284 Array::scalar_i64(value as i64)
1285 };
1286 Some((digits, arr))
1287}
1288
1289pub(crate) fn verb_named(word: &str) -> Option<Verb> {
1292 verb_for(word)
1293}
1294
1295const ADVERBS: [&str; 9] = ["/", "\\", "/.", "\\.", "~", "}", "f.", "M.", "b."];
1296
1297const CONJUNCTIONS: [&str; 24] = [
1300 "\"", "@", "@.", "@:", "&", "&.", "&.:", "&:", "^:", ";.", "!.", "!:", "`", "`:", ".", ":",
1301 ":.", "::", "L:", "S:", "H.", "T.", "t.", "t:",
1302];
1303
1304fn adverb(word: &str) -> Option<&'static str> {
1305 ADVERBS.iter().copied().find(|&g| g == word)
1306}
1307
1308fn conjunction(word: &str) -> Option<&'static str> {
1309 CONJUNCTIONS.iter().copied().find(|&g| g == word)
1310}
1311
1312fn lex(src: &SourceParts) -> Result<Vec<Vec<Frag>>> {
1317 let mut sentences: Vec<Vec<Frag>> = Vec::new();
1318 let mut cur: Vec<Frag> = Vec::new();
1319 for seg in &src.segments {
1320 match seg {
1321 Segment::Text { text, offset } => {
1322 let mut pos = 0usize;
1323 for (n, line) in text.split('\n').enumerate() {
1324 if n > 0 && !cur.is_empty() {
1325 sentences.push(std::mem::take(&mut cur));
1326 }
1327 lex_line(line, offset + pos, &mut cur)?;
1328 pos += line.len() + 1;
1329 }
1330 }
1331 Segment::Param { index, offset, len } => {
1332 let span = Span::new(*offset, *offset + *len);
1333 cur.push(Frag::Noun(Expr::Param(*index, span)));
1334 }
1335 }
1336 }
1337 if !cur.is_empty() {
1338 sentences.push(cur);
1339 }
1340 Ok(sentences)
1341}
1342
1343#[derive(Clone, Debug)]
1346enum Num {
1347 I(i64),
1348 F(f64),
1349 X(crate::exact::Ext),
1351 R(crate::exact::Rat),
1353 C(crate::complex::Cx),
1354}
1355
1356fn lex_line(text: &str, base: usize, out: &mut Vec<Frag>) -> Result<()> {
1357 let cs: Vec<(usize, char)> = text.char_indices().collect();
1358 let at = |i: usize| cs.get(i).map(|&(_, c)| c);
1359 let off = |i: usize| cs.get(i).map(|&(o, _)| o).unwrap_or(text.len());
1360 let span = |a: usize, b: usize| Span::new(base + off(a), base + off(b));
1361 let mut i = 0usize;
1362 while i < cs.len() {
1363 let c = cs[i].1;
1364 if c.is_whitespace() {
1365 i += 1;
1366 continue;
1367 }
1368 if c == 'N' && at(i + 1) == Some('B') && at(i + 2) == Some('.') {
1371 break;
1372 }
1373 if c == '\'' {
1374 let start = i;
1375 i += 1;
1376 let mut chars: Vec<char> = Vec::new();
1377 loop {
1378 match at(i) {
1379 None => {
1380 return Err(Error::parse(
1381 "unterminated string literal",
1382 span(start, cs.len()),
1383 ));
1384 }
1385 Some('\'') if at(i + 1) == Some('\'') => {
1386 chars.push('\'');
1387 i += 2;
1388 }
1389 Some('\'') => {
1390 i += 1;
1391 break;
1392 }
1393 Some(ch) => {
1394 chars.push(ch);
1395 i += 1;
1396 }
1397 }
1398 }
1399 let shape = if chars.len() == 1 { vec![] } else { vec![chars.len()] };
1401 let arr = Array::new(shape, Data::Char(chars.into()));
1402 out.push(Frag::Noun(Expr::Const(arr, span(start, i))));
1403 continue;
1404 }
1405 if let Some((len, n)) = constant_verb_word(&cs, i) {
1406 out.push(Frag::Verb(VerbFrag::V(constant_verb(n)), span(i, i + len)));
1407 i += len;
1408 continue;
1409 }
1410 if starts_number(&cs, i) {
1411 let start = i;
1413 let mut nums: Vec<Num> = Vec::new();
1414 let mut end;
1415 loop {
1416 let ws = i;
1417 while at(i).is_some_and(|c| c.is_ascii_alphanumeric() || c == '.' || c == '_') {
1418 i += 1;
1419 }
1420 nums.push(parse_number(&text[off(ws)..off(i)], span(ws, i))?);
1421 end = i;
1422 let mut k = i;
1423 while at(k).is_some_and(char::is_whitespace) {
1424 k += 1;
1425 }
1426 if k < cs.len()
1429 && starts_number(&cs, k)
1430 && constant_verb_word(&cs, k).is_none()
1431 {
1432 i = k;
1433 } else {
1434 break;
1435 }
1436 }
1437 out.push(Frag::Noun(Expr::Const(num_array(&nums), span(start, end))));
1438 continue;
1439 }
1440 if c.is_ascii_alphabetic() {
1441 let start = i;
1442 i += 1;
1443 while at(i).is_some_and(|c| c.is_ascii_alphanumeric() || c == '_') {
1444 i += 1;
1445 }
1446 let mut inflected = None;
1451 if matches!(at(i), Some('.') | Some(':')) {
1452 let most = if matches!(at(i + 1), Some('.') | Some(':')) { 2 } else { 1 };
1453 for n in (1..=most).rev() {
1454 let word = &text[off(start)..off(i + n)];
1455 let sp = span(start, i + n);
1456 let frag = if let Some(v) = verb_for(word) {
1457 Frag::Verb(VerbFrag::V(v), sp)
1458 } else if let Some(value) = noun_word(word) {
1459 Frag::Noun(Expr::Const(value, sp))
1460 } else if let Some(g) = adverb(word) {
1461 Frag::Adverb(Modifier::Prim(g), sp)
1462 } else if let Some(g) = conjunction(word) {
1463 Frag::Conj(Modifier::Prim(g), sp)
1464 } else if let Some((cw, suffix)) = control_word(word) {
1465 Frag::Control(cw, suffix, sp)
1466 } else {
1467 continue;
1468 };
1469 inflected = Some((frag, n));
1470 break;
1471 }
1472 }
1473 if let Some((frag, n)) = inflected {
1474 i += n;
1475 out.push(frag);
1476 continue;
1477 }
1478 let word = &text[off(start)..off(i)];
1479 match verb_for(word) {
1480 Some(v) => out.push(Frag::Verb(VerbFrag::V(v), span(start, i))),
1481 None => out.push(Frag::Name(word.to_string(), span(start, i))),
1482 }
1483 continue;
1484 }
1485 if c == '{' && at(i + 1) == Some('{') {
1487 let marker = match (at(i + 2), at(i + 3)) {
1492 (Some(')'), Some(m)) if m.is_ascii_alphabetic() => Some(m),
1493 _ => None,
1494 };
1495 if let Some(m) = marker {
1496 if cs[i + 4..].iter().any(|&(_, c)| !c.is_whitespace()) {
1497 return Err(Error::parse(
1498 format!("`)`{m} names the part of speech of a direct definition, \
1499 and has to be the last thing on its line"),
1500 span(i, i + 4),
1501 ));
1502 }
1503 out.push(Frag::DdOpen(Some(m), span(i, i + 4)));
1504 i += 4;
1505 continue;
1506 }
1507 out.push(Frag::DdOpen(None, span(i, i + 2)));
1508 i += 2;
1509 continue;
1510 }
1511 if c == '}' && at(i + 1) == Some('}') {
1512 out.push(Frag::DdClose(span(i, i + 2)));
1513 i += 2;
1514 continue;
1515 }
1516 let inflectable = c != '(' && c != ')';
1520 let mut len =
1521 if inflectable && matches!(at(i + 1), Some('.') | Some(':')) { 2 } else { 1 };
1522 if len == 2 && at(i + 2) == Some(':') {
1525 let w = &text[off(i)..off(i + 3)];
1526 if conjunction(w).is_some() || verb_for(w).is_some() {
1527 len = 3;
1528 }
1529 }
1530 let word = &text[off(i)..off(i + len)];
1531 match symbol_frag(word, span(i, i + len)) {
1532 Some(frag) => {
1533 out.push(frag);
1534 i += len;
1535 }
1536 None => {
1537 return Err(Error::parse(format!("unknown word: {word}"), span(i, i + len)));
1538 }
1539 }
1540 }
1541 Ok(())
1542}
1543
1544fn symbol_frag(word: &str, span: Span) -> Option<Frag> {
1545 Some(match word {
1546 "(" => Frag::LParen(span),
1547 ")" => Frag::RParen(span),
1548 "=." => Frag::AssignLocal(span),
1549 "=:" => Frag::AssignGlobal(span),
1550 "[:" => Frag::Verb(VerbFrag::Cap, span),
1551 "$:" => Frag::Verb(VerbFrag::V(Verb::SelfRef), span),
1553 _ => {
1556 if let Some(v) = verb_for(word) {
1557 Frag::Verb(VerbFrag::V(v), span)
1558 } else if let Some(g) = adverb(word) {
1559 Frag::Adverb(Modifier::Prim(g), span)
1560 } else {
1561 Frag::Conj(Modifier::Prim(conjunction(word)?), span)
1562 }
1563 }
1564 })
1565}
1566
1567fn starts_number(cs: &[(usize, char)], i: usize) -> bool {
1570 let c = cs[i].1;
1571 if c.is_ascii_digit() {
1572 return true;
1573 }
1574 if c != '_' {
1575 return false;
1576 }
1577 match cs.get(i + 1).map(|&(_, c)| c) {
1578 None => true,
1579 Some(d) => d.is_ascii_digit() || d == '.' || d == 'j' || !d.is_alphanumeric(),
1583 }
1584}
1585
1586fn parse_number(word: &str, span: Span) -> Result<Num> {
1587 if word == "_." {
1589 return Ok(Num::F(f64::NAN));
1590 }
1591 if let Some(k) = word.find(['p', 'x']) {
1595 if word[k + 1..].is_empty() {
1596 if word.as_bytes()[k] == b'x' {
1600 return extended_literal(&word[..k], word, span);
1601 }
1602 return Err(Error::parse(format!("invalid number: {word}"), span));
1603 }
1604 let base =
1605 if word.as_bytes()[k] == b'p' { std::f64::consts::PI } else { std::f64::consts::E };
1606 let mantissa = plain_number(&word[..k], word, span)?;
1607 let exponent = plain_number(&word[k + 1..], word, span)?;
1608 return Ok(scale(mantissa, base, exponent));
1609 }
1610 if let Some(k) = word.find('j') && !word[..k].contains('b') {
1613 let re = as_f64(plain_number(&word[..k], word, span)?);
1614 let im = as_f64(plain_number(&word[k + 1..], word, span)?);
1615 return Ok(Num::C([re, im]));
1616 }
1617 if let Some(k) = word.find("ad").or_else(|| word.find("ar")) && !word[..k].contains('b') {
1620 let magnitude = as_f64(plain_number(&word[..k], word, span)?);
1621 let angle = as_f64(plain_number(&word[k + 2..], word, span)?);
1622 return Ok(Num::C(if word.as_bytes()[k + 1] == b'd' {
1623 crate::complex::from_degrees(magnitude, angle)
1624 } else {
1625 crate::complex::from_radians(magnitude, angle)
1626 }));
1627 }
1628 if let Some(k) = word.find('r') && !word[..k].contains('b') {
1632 return rational_literal(&word[..k], &word[k + 1..], word, span);
1633 }
1634 if let Some(k) = word.find('b') {
1635 return base_literal(&word[..k], &word[k + 1..], word, span);
1636 }
1637 plain_number(word, word, span)
1638}
1639
1640fn extended_literal(digits: &str, word: &str, span: Span) -> Result<Num> {
1643 Ok(Num::X(whole_digits(digits, word, span)?))
1644}
1645
1646fn rational_literal(num: &str, den: &str, word: &str, span: Span) -> Result<Num> {
1649 use num_traits::Zero;
1650 let num = whole_digits(num, word, span)?;
1651 let den = whole_digits(den, word, span)?;
1652 if den.is_zero() {
1653 if num.is_zero() {
1654 return Ok(Num::I(0));
1655 }
1656 return Ok(Num::F(if num.sign() == num_bigint::Sign::Minus {
1657 f64::NEG_INFINITY
1658 } else {
1659 f64::INFINITY
1660 }));
1661 }
1662 Ok(Num::R(
1663 crate::exact::Rat::new(num, den).ok_or_else(|| Error::internal("a zero denominator"))?,
1664 ))
1665}
1666
1667fn whole_digits(word: &str, whole: &str, span: Span) -> Result<crate::exact::Ext> {
1669 let invalid = || Error::parse(format!("invalid number: {whole}"), span);
1670 let (digits, negative) = match word.strip_prefix('_') {
1671 Some(rest) => (rest, true),
1672 None => (word, false),
1673 };
1674 if digits.is_empty() || !digits.bytes().all(|b| b.is_ascii_digit()) {
1675 return Err(invalid());
1676 }
1677 let v: crate::exact::Ext = digits.parse().map_err(|_| invalid())?;
1678 Ok(if negative { -v } else { v })
1679}
1680
1681fn scale(mantissa: Num, base: f64, exponent: Num) -> Num {
1684 if matches!(mantissa, Num::C(_)) || matches!(exponent, Num::C(_)) {
1685 let m = as_cx(mantissa);
1686 let f = crate::complex::pow([base, 0.0], as_cx(exponent));
1687 return Num::C(crate::complex::mul(m, f));
1688 }
1689 Num::F(as_f64(mantissa) * base.powf(as_f64(exponent)))
1690}
1691
1692fn as_cx(n: Num) -> crate::complex::Cx {
1693 match n {
1694 Num::C(z) => z,
1695 other => [as_f64(other), 0.0],
1696 }
1697}
1698
1699fn as_f64(n: Num) -> f64 {
1700 match n {
1701 Num::I(v) => v as f64,
1702 Num::F(v) => v,
1703 Num::X(v) => crate::exact::ext_to_f64(&v),
1704 Num::R(v) => v.to_f64(),
1705 Num::C(z) => z[0],
1708 }
1709}
1710
1711fn base_literal(base: &str, digits: &str, word: &str, span: Span) -> Result<Num> {
1714 let invalid = || Error::parse(format!("invalid number: {word}"), span);
1715 let base = as_f64(plain_number(base, word, span)?);
1716 let (digits, negative) = match digits.strip_prefix('_') {
1717 Some(rest) => (rest, true),
1718 None => (digits, false),
1719 };
1720 if digits.is_empty() {
1721 return Err(invalid());
1722 }
1723 let mut value = 0.0f64;
1724 for ch in digits.chars() {
1725 let d = match ch {
1726 '0'..='9' => ch as u32 - '0' as u32,
1727 'a'..='z' => ch as u32 - 'a' as u32 + 10,
1728 _ => return Err(invalid()),
1729 };
1730 value = value * base + f64::from(d);
1731 }
1732 if negative {
1733 value = -value;
1734 }
1735 if value.fract() == 0.0 && value.abs() < 9.007_199_254_740_992e15 {
1737 return Ok(Num::I(value as i64));
1738 }
1739 Ok(Num::F(value))
1740}
1741
1742fn plain_number(word: &str, whole: &str, span: Span) -> Result<Num> {
1746 if word.is_empty() {
1747 return Err(Error::parse(format!("invalid number: {whole}"), span));
1748 }
1749 if word.contains(['j', 'p', 'x', 'b', 'r']) || word.contains("ad") || word.contains("ar") {
1750 return parse_number(word, span);
1751 }
1752 parse_plain(word, span)
1753}
1754
1755fn parse_plain(word: &str, span: Span) -> Result<Num> {
1756 if word == "_" {
1757 return Ok(Num::F(f64::INFINITY));
1758 }
1759 if word == "__" {
1760 return Ok(Num::F(f64::NEG_INFINITY));
1761 }
1762 if word == "_." {
1765 return Ok(Num::F(f64::NAN));
1766 }
1767 let invalid = || Error::parse(format!("invalid number: {word}"), span);
1768 let mut norm = String::with_capacity(word.len());
1770 for (k, ch) in word.char_indices() {
1771 if ch == '_' {
1772 if k != 0 && !word[..k].ends_with('e') {
1773 return Err(invalid());
1774 }
1775 norm.push('-');
1776 } else {
1777 norm.push(ch);
1778 }
1779 }
1780 if norm.contains('.') || norm.contains('e') {
1782 return norm.parse::<f64>().map(Num::F).map_err(|_| invalid());
1783 }
1784 match norm.parse::<i64>() {
1787 Ok(v) => Ok(Num::I(v)),
1788 Err(_) => norm.parse::<f64>().map(Num::F).map_err(|_| invalid()),
1789 }
1790}
1791
1792pub(crate) fn numbers_from_text(line: &str, fallback: &Array) -> Option<Array> {
1806 let stand_in = match &fallback.data {
1807 Data::Bool(v) => Num::I(i64::from(*v.as_slice().first()?)),
1808 Data::I64(v) => Num::I(*v.as_slice().first()?),
1809 Data::F64(v) => Num::F(*v.as_slice().first()?),
1810 Data::Ext(v) => Num::X(v.as_slice().first()?.clone()),
1811 Data::Rat(v) => Num::R(v.as_slice().first()?.clone()),
1812 Data::Complex(v) => Num::C(*v.as_slice().first()?),
1813 Data::Char(_) | Data::Symbol(_) | Data::Box(_) => return None,
1814 };
1815 let nums: Vec<Num> = line
1816 .split_whitespace()
1817 .map(|w| parse_number(w, Span::new(0, 0)).unwrap_or_else(|_| stand_in.clone()))
1818 .collect();
1819 Some(num_array(&nums))
1820}
1821
1822fn num_array(nums: &[Num]) -> Array {
1823 use crate::exact::{Ext, Rat};
1824 let shape = if nums.len() == 1 { vec![] } else { vec![nums.len()] };
1825 let has = |f: fn(&Num) -> bool| nums.iter().any(f);
1826 if has(|n| matches!(n, Num::C(_))) {
1827 let data = nums.iter().map(|n| as_cx(n.clone())).collect();
1828 return Array::new(shape, Data::Complex(data));
1829 }
1830 if has(|n| matches!(n, Num::F(_))) {
1831 let data = nums.iter().map(|n| as_f64(n.clone())).collect();
1832 return Array::new(shape, Data::F64(data));
1833 }
1834 if has(|n| matches!(n, Num::R(_))) {
1835 let data = nums
1836 .iter()
1837 .map(|n| match n {
1838 Num::I(v) => Rat::from_int(Ext::from(*v)),
1839 Num::X(v) => Rat::from_int(v.clone()),
1840 Num::R(v) => v.clone(),
1841 Num::F(_) | Num::C(_) => Rat::zero(),
1842 })
1843 .collect();
1844 return Array::new(shape, Data::Rat(data));
1845 }
1846 if has(|n| matches!(n, Num::X(_))) {
1847 let data = nums
1848 .iter()
1849 .map(|n| match n {
1850 Num::I(v) => Ext::from(*v),
1851 Num::X(v) => v.clone(),
1852 _ => Ext::default(),
1853 })
1854 .collect();
1855 return Array::new(shape, Data::Ext(data));
1856 }
1857 let data = nums
1858 .iter()
1859 .map(|n| match n {
1860 Num::I(v) => *v,
1861 _ => 0,
1862 })
1863 .collect();
1864 Array::new(shape, Data::I64(data))
1865}
1866
1867#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1870enum Rule {
1871 Monad1,
1872 Monad2,
1873 Dyad3,
1874 Adverb4,
1875 Conj5,
1876 Fork6,
1877 Bident7,
1878 Assign8,
1879 Paren9,
1880}
1881
1882fn reduce_to_fragment(tokens: Vec<Frag>, scope: &Names) -> Result<Option<Frag>> {
1886 check_parens(&tokens)?;
1887 let mut stack: Vec<Frag> = Vec::new();
1888 for frag in tokens.into_iter().rev() {
1889 stack.insert(0, frag);
1890 reduce(&mut stack, scope)?;
1891 }
1892 stack.insert(0, Frag::Mark);
1893 reduce(&mut stack, scope)?;
1894 if stack.len() == 2 {
1895 return Ok(Some(stack.pop().expect("checked length")));
1896 }
1897 Ok(None)
1898}
1899
1900fn lower_sentence(frag: Option<Frag>, whole: Span) -> Result<Expr> {
1903 match frag {
1904 Some(f @ (Frag::Noun(_) | Frag::Name(..))) => as_noun(f),
1905 Some(Frag::VerbDef(name, verb, span)) => Ok(Expr::VerbDef { name, verb, span }),
1906 Some(Frag::ModDef(name, conjunction, m, span)) => {
1907 Ok(Expr::ModDef { name, spelling: m.spelling(), conjunction, span })
1908 }
1909 Some(Frag::Verb(VerbFrag::V(_), span)) => {
1910 Err(Error::not_yet("tacit verb definitions (a sentence that is a verb)", span))
1911 }
1912 Some(Frag::Adverb(_, span) | Frag::Conj(_, span)) => Err(Error::not_yet(
1913 "displaying a modifier (a sentence that is an adverb or a conjunction)",
1914 span,
1915 )),
1916 _ => Err(Error::parse("syntax error", whole)),
1917 }
1918}
1919
1920fn check_parens(tokens: &[Frag]) -> Result<()> {
1924 let mut open: Vec<Span> = Vec::new();
1925 for frag in tokens {
1926 match frag {
1927 Frag::LParen(s) => open.push(*s),
1928 Frag::RParen(s) => {
1929 if open.pop().is_none() {
1930 return Err(Error::parse("this `)` has no opening `(`", *s));
1931 }
1932 }
1933 _ => {}
1934 }
1935 }
1936 match open.pop() {
1937 None => Ok(()),
1938 Some(s) => Err(Error::parse("this `(` has no closing `)`", s)),
1939 }
1940}
1941
1942fn sentence_span(tokens: &[Frag]) -> Span {
1943 tokens
1944 .iter()
1945 .map(Frag::span)
1946 .reduce(Span::merge)
1947 .unwrap_or_else(|| Span::new(0, 0))
1948}
1949
1950fn reduce(stack: &mut Vec<Frag>, scope: &Names) -> Result<()> {
1951 while apply(stack, scope)? {}
1952 Ok(())
1953}
1954
1955fn match_rule(s: &[Frag]) -> Option<Rule> {
1958 let is = |i: usize, f: fn(&Frag) -> bool| s.get(i).is_some_and(f);
1959 let ctx = |i: usize| s.get(i).is_some_and(|f| f.is_edge() || f.is_avn());
1962 let verb_or_noun =
1963 |i: usize| s.get(i).is_some_and(|f| f.is_real_verb() || f.is_noun());
1964 if is(0, Frag::is_edge) && is(1, Frag::is_real_verb) && is(2, Frag::is_noun) {
1965 return Some(Rule::Monad1);
1966 }
1967 if ctx(0) && is(1, Frag::is_verb) && is(2, Frag::is_real_verb) && is(3, Frag::is_noun) {
1968 return Some(Rule::Monad2);
1969 }
1970 if ctx(0) && is(1, Frag::is_noun) && is(2, Frag::is_real_verb) && is(3, Frag::is_noun) {
1971 return Some(Rule::Dyad3);
1972 }
1973 if ctx(0) && verb_or_noun(1) && is(2, Frag::is_adverb) {
1974 return Some(Rule::Adverb4);
1975 }
1976 if ctx(0) && verb_or_noun(1) && is(2, Frag::is_conj) && verb_or_noun(3) {
1977 return Some(Rule::Conj5);
1978 }
1979 if ctx(0)
1980 && s.get(1).is_some_and(|f| f.is_verb() || f.is_noun())
1981 && is(2, Frag::is_real_verb)
1982 && is(3, Frag::is_real_verb)
1983 {
1984 return Some(Rule::Fork6);
1985 }
1986 if is(0, Frag::is_edge) && is(1, Frag::is_cavn) && is(2, Frag::is_cavn) {
1987 return Some(Rule::Bident7);
1988 }
1989 if is(0, Frag::is_noun) && is(1, Frag::is_assign) && is(2, Frag::is_cavn) {
1990 return Some(Rule::Assign8);
1991 }
1992 if matches!(s.first(), Some(Frag::LParen(_)))
1993 && is(1, Frag::is_cavn)
1994 && matches!(s.get(2), Some(Frag::RParen(_)))
1995 {
1996 return Some(Rule::Paren9);
1997 }
1998 None
1999}
2000
2001fn take(stack: &mut Vec<Frag>, range: Range<usize>) -> Vec<Frag> {
2002 stack.drain(range).collect()
2003}
2004
2005fn respan(f: Frag, to: Span) -> Frag {
2009 match f {
2010 Frag::Noun(mut e) => {
2011 e.set_span(to);
2012 Frag::Noun(e)
2013 }
2014 Frag::Name(n, _) => Frag::Name(n, to),
2015 Frag::Verb(v, _) => Frag::Verb(v, to),
2016 Frag::Adverb(a, _) => Frag::Adverb(a, to),
2017 Frag::Conj(c, _) => Frag::Conj(c, to),
2018 other => other,
2019 }
2020}
2021
2022fn apply(stack: &mut Vec<Frag>, scope: &Names) -> Result<bool> {
2023 let Some(rule) = match_rule(stack) else {
2024 return Ok(false);
2025 };
2026 match rule {
2027 Rule::Monad1 => {
2028 let mut t = take(stack, 1..3);
2029 let y = t.pop().expect("two slots");
2030 let v = t.pop().expect("two slots");
2031 let frag = monad(v, y)?;
2032 stack.insert(1, frag);
2033 }
2034 Rule::Monad2 => {
2035 let mut t = take(stack, 2..4);
2036 let y = t.pop().expect("two slots");
2037 let v = t.pop().expect("two slots");
2038 let frag = monad(v, y)?;
2039 stack.insert(2, frag);
2040 }
2041 Rule::Dyad3 => {
2042 let mut t = take(stack, 1..4);
2043 let y = t.pop().expect("three slots");
2044 let v = t.pop().expect("three slots");
2045 let x = t.pop().expect("three slots");
2046 let frag = dyad(x, v, y)?;
2047 stack.insert(1, frag);
2048 }
2049 Rule::Adverb4 => {
2050 let mut t = take(stack, 1..3);
2051 let a = t.pop().expect("two slots");
2052 let u = t.pop().expect("two slots");
2053 let frag = apply_adverb(u, a, scope)?;
2054 stack.insert(1, frag);
2055 }
2056 Rule::Conj5 => {
2057 let mut t = take(stack, 1..4);
2058 let v = t.pop().expect("three slots");
2059 let c = t.pop().expect("three slots");
2060 let u = t.pop().expect("three slots");
2061 let frag = apply_conj(u, c, v, scope)?;
2062 stack.insert(1, frag);
2063 }
2064 Rule::Fork6 => {
2065 let mut t = take(stack, 1..4);
2066 let h = t.pop().expect("three slots");
2067 let g = t.pop().expect("three slots");
2068 let f = t.pop().expect("three slots");
2069 let frag = apply_fork(f, g, h)?;
2070 stack.insert(1, frag);
2071 }
2072 Rule::Bident7 => {
2073 let mut t = take(stack, 1..3);
2074 let b = t.pop().expect("two slots");
2075 let a = t.pop().expect("two slots");
2076 let frag = apply_bident(a, b, &scope.nouns)?;
2077 stack.insert(1, frag);
2078 }
2079 Rule::Assign8 => {
2080 let mut t = take(stack, 0..3);
2081 let value = t.pop().expect("three slots");
2082 let assign = t.pop().expect("three slots");
2083 let target = t.pop().expect("three slots");
2084 let scope = match assign {
2085 Frag::AssignGlobal(_) => Scope::Global,
2086 _ => Scope::Local,
2087 };
2088 let frag = apply_assign(target, value, scope)?;
2089 stack.insert(0, frag);
2090 }
2091 Rule::Paren9 => {
2092 let mut t = take(stack, 0..3);
2093 let close = t.pop().expect("three slots");
2094 let inner = t.pop().expect("three slots");
2095 let open = t.pop().expect("three slots");
2096 let outer = Span::merge(open.span(), close.span());
2097 stack.insert(0, respan(inner, outer));
2098 }
2099 }
2100 Ok(true)
2101}
2102
2103fn as_noun(f: Frag) -> Result<Expr> {
2106 match f {
2107 Frag::Noun(e) => Ok(e),
2108 Frag::Name(n, s) => Ok(Expr::Name(n, s)),
2109 other => Err(Error::internal(format!("expected a noun fragment, got {other:?}"))),
2110 }
2111}
2112
2113fn as_verb(f: Frag) -> Result<(Verb, Span)> {
2114 match f {
2115 Frag::Verb(VerbFrag::V(v), s) => Ok((v, s)),
2116 other => Err(Error::internal(format!("expected a verb fragment, got {other:?}"))),
2117 }
2118}
2119
2120fn as_const(f: &Frag) -> Option<&Array> {
2123 match f {
2124 Frag::Noun(Expr::Const(a, _)) => Some(a),
2125 _ => None,
2126 }
2127}
2128
2129fn noun_value(f: &Frag) -> Option<Array> {
2134 if let Some(a) = as_const(f) {
2135 return Some(a.clone());
2136 }
2137 let Frag::Noun(e) = f else { return None };
2138 let cfg = crate::verb::EvalCfg {
2139 agreement: crate::verb::Agreement::LeadingPrefix,
2140 fmt: crate::fmt::FmtOpts::J,
2141 tol: crate::verb::Tol::J,
2142 rules: crate::frontend::Rules::default(),
2143 };
2144 crate::ir::fold_const(e, cfg)
2145}
2146
2147fn monad(v: Frag, y: Frag) -> Result<Frag> {
2148 let (verb, vspan) = as_verb(v)?;
2149 let y = as_noun(y)?;
2150 let span = Span::merge(vspan, y.span());
2151 Ok(Frag::Noun(Expr::Monad { verb, y: Box::new(y), span }))
2152}
2153
2154fn dyad(x: Frag, v: Frag, y: Frag) -> Result<Frag> {
2155 let x = as_noun(x)?;
2156 let (verb, vspan) = as_verb(v)?;
2157 let y = as_noun(y)?;
2158 let span = Span::merge(Span::merge(x.span(), vspan), y.span());
2159 Ok(Frag::Noun(Expr::Dyad { verb, x: Box::new(x), y: Box::new(y), span }))
2160}
2161
2162fn apply_adverb(u: Frag, a: Frag, scope: &Names) -> Result<Frag> {
2163 let Frag::Adverb(m, aspan) = a else {
2164 return Err(Error::internal("expected an adverb fragment"));
2165 };
2166 let span = Span::merge(u.span(), aspan);
2167 let glyph = match m {
2168 Modifier::Prim(g) => g,
2169 Modifier::Explicit(src) => return derive_explicit(&src, u, None, scope, span),
2170 };
2171 if glyph == "}" {
2174 if !u.is_real_verb() {
2175 let m = noun_value(&u)
2176 .ok_or_else(|| Error::not_yet("amend over a computed index", span))?;
2177 return Ok(Frag::Verb(VerbFrag::V(Verb::Amend(m)), span));
2178 }
2179 let (v, _) = as_verb(u)?;
2180 return Ok(Frag::Verb(VerbFrag::V(Verb::AmendVerb(Box::new(v))), span));
2181 }
2182 if glyph == "b." && !u.is_real_verb() {
2185 let m = as_const(&u)
2186 .and_then(Array::to_i64_vec)
2187 .and_then(|v| v.first().copied())
2188 .filter(|&m| (0..32).contains(&m))
2189 .ok_or_else(|| {
2190 Error::not_yet("a boolean function outside `0 b.` … `31 b.`", span)
2191 })?;
2192 let p = crate::verb::Prim {
2193 name: "b.",
2194 monad: MonadOp::None,
2195 dyad: DyadOp::TruthTable(m as u8),
2196 ranks: [crate::verb::RANK_INF, 0, 0],
2197 };
2198 return Ok(Frag::Verb(VerbFrag::V(Verb::Prim(p)), span));
2199 }
2200 if !u.is_real_verb() {
2201 return Err(Error::not_yet("noun-operand adverbs", span));
2202 }
2203 let (v, _) = as_verb(u)?;
2204 let derived = match glyph {
2205 "/" => Verb::Reduce(Box::new(v)),
2206 "\\" => Verb::Windowed(Box::new(v), WindowKind::Prefix),
2207 "\\." => Verb::Windowed(Box::new(v), WindowKind::Suffix),
2208 "~" => Verb::Commute(Box::new(v)),
2209 "/." => Verb::Key(Box::new(v)),
2210 "f." => v,
2213 "M." => Verb::Memo(Box::new(v), Default::default()),
2214 "b." => Verb::Characteristics(Box::new(v)),
2215 _ => return Err(Error::not_yet(format!("adverb ({glyph})"), span)),
2216 };
2217 Ok(Frag::Verb(VerbFrag::V(derived), span))
2218}
2219
2220fn apply_conj(u: Frag, c: Frag, v: Frag, scope: &Names) -> Result<Frag> {
2221 let Frag::Conj(m, cspan) = c else {
2222 return Err(Error::internal("expected a conjunction fragment"));
2223 };
2224 let span = Span::merge(Span::merge(u.span(), cspan), v.span());
2225 let glyph = match m {
2226 Modifier::Prim(g) => g,
2227 Modifier::Explicit(src) => return derive_explicit(&src, u, Some(v), scope, span),
2228 };
2229 match glyph {
2230 "\"" => {
2231 let f = verb_operand(u, span)?;
2232 if v.is_verb() {
2233 return Err(Error::not_yet("verb rank (u\"v)", span));
2234 }
2235 let ranks = rank_spec(&v, span)?;
2236 Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(f), ranks)), span))
2237 }
2238 "@:" => {
2239 let f = verb_operand(u, span)?;
2240 let g = verb_operand(v, span)?;
2241 Ok(Frag::Verb(VerbFrag::V(Verb::Atop(Box::new(f), Box::new(g))), span))
2242 }
2243 "@" => {
2247 let f = verb_operand(u, span)?;
2248 let g = verb_operand(v, span)?;
2249 let ranks = g.ranks();
2250 let atop = Verb::Atop(Box::new(f), Box::new(g));
2251 Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(atop), ranks)), span))
2252 }
2253 "&" => compose(u, v, false, span),
2254 "&:" => compose(u, v, true, span),
2255 "&." if is_open(&v) => {
2258 let f = verb_operand(u, span)?;
2259 Ok(Frag::Verb(VerbFrag::V(Verb::Each(Box::new(f), Enclose::Always)), span))
2260 }
2261 "&." if is_ravel(&v) => {
2265 let f = verb_operand(u, span)?;
2266 Ok(Frag::Verb(VerbFrag::V(Verb::UnderRavel(Box::new(f))), span))
2267 }
2268 "&." | "&.:" => {
2273 let f = verb_operand(u, span)?;
2274 let g = verb_operand(v, span)?;
2275 let back = obverse_of(&g, span)?;
2276 let composed = Verb::Compose(Box::new(f), Box::new(g.clone()));
2277 let under = Verb::Atop(Box::new(back), Box::new(composed));
2278 if glyph == "&.:" {
2279 return Ok(Frag::Verb(VerbFrag::V(under), span));
2280 }
2281 let rank = g.ranks()[0];
2282 Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(under), [rank; 3])), span))
2283 }
2284 "^:" => {
2285 let f = verb_operand(u, span)?;
2286 if v.is_verb() {
2287 let g = verb_operand(v, span)?;
2290 let p = Verb::PowerV(Box::new(f), Box::new(g));
2291 return Ok(Frag::Verb(VerbFrag::V(p), span));
2292 }
2293 let negative = noun_value(&v).is_some_and(|a| {
2298 let inner = match a.as_boxes() {
2299 Some([b]) => b.clone(),
2300 _ => a,
2301 };
2302 inner.to_f64_vec().is_some_and(|n| n.len() == 1 && n[0] < 0.0)
2303 });
2304 let p = power_spec(&v, span)?;
2305 let f = if negative { obverse_of(&f, span)? } else { f };
2306 Ok(Frag::Verb(VerbFrag::V(Verb::PowerN(Box::new(f), p)), span))
2307 }
2308 ";." => {
2309 let f = verb_operand(u, span)?;
2310 let n = one_atom(&v, "cut", span)?;
2311 if n.fract() != 0.0 || !matches!(n as i64, -3..=3) {
2312 return Err(Error::not_yet(format!("cut (u;.{n})"), span));
2313 }
2314 Ok(Frag::Verb(VerbFrag::V(Verb::Cut(Box::new(f), n as i64)), span))
2315 }
2316 "!." => {
2320 let f = verb_operand(u, span)?;
2321 if matches!(&f, Verb::Prim(p) if p.name == "|.") {
2324 let fill = as_const(&v)
2325 .cloned()
2326 .ok_or_else(|| Error::not_yet("a computed fill (|.!.n)", span))?;
2327 return Ok(Frag::Verb(VerbFrag::V(Verb::ShiftFill(fill)), span));
2328 }
2329 let n = one_atom(&v, "fit", span)?;
2330 if !f.uses_tolerance() {
2331 return Err(Error::not_yet(
2332 format!("fill specification ({}!.n)", f.name()),
2333 span,
2334 ));
2335 }
2336 if !(0.0..=LARGEST_TOLERANCE).contains(&n) {
2338 return Err(Error::domain(
2339 format!("a comparison tolerance must be between 0 and {LARGEST_TOLERANCE}"),
2340 span,
2341 ));
2342 }
2343 Ok(Frag::Verb(VerbFrag::V(Verb::Fit(Box::new(f), n)), span))
2344 }
2345 ":." => {
2348 let f = verb_operand(u, span)?;
2349 let g = verb_operand(v, span)?;
2350 Ok(Frag::Verb(
2351 VerbFrag::V(Verb::WithObverse(Box::new(f), Box::new(g))),
2352 span,
2353 ))
2354 }
2355 "@." => {
2358 let vs = gerund_verbs(&u, scope, span)?;
2359 if v.is_verb() {
2360 let w = verb_operand(v, span)?;
2361 return Ok(Frag::Verb(VerbFrag::V(Verb::Agenda(vs, Box::new(w))), span));
2362 }
2363 let at = near_whole(one_atom(&v, "agenda", span)?);
2364 if at.fract() != 0.0 {
2365 return Err(Error::parse("an agenda index must be a whole number", span));
2366 }
2367 let picked = crate::verb::pick_gerund(&vs, at as i64, span)?;
2368 Ok(Frag::Verb(VerbFrag::V(picked), span))
2369 }
2370 "`" => {
2373 let left = tie_side(&u, scope, span)?;
2374 let right = tie_side(&v, scope, span)?;
2375 let tied = crate::verb::catenate(&left, &right, true, true, span)?;
2376 Ok(Frag::Noun(Expr::Const(tied, span)))
2377 }
2378 "::" => {
2381 let f = verb_operand(u, span)?;
2382 let g = if v.is_noun() {
2383 constant_verb(bond_noun(&v, span)?)
2384 } else {
2385 verb_operand(v, span)?
2386 };
2387 Ok(Frag::Verb(VerbFrag::V(Verb::Adverse(Box::new(f), Box::new(g))), span))
2388 }
2389 "L:" | "S:" => {
2393 let f = verb_operand(u, span)?;
2394 let n = one_atom(&v, "level", span)?;
2395 if n.fract() != 0.0 || !n.is_finite() {
2396 return Err(Error::not_yet(format!("a level of {n} ({glyph})"), span));
2397 }
2398 let level = Verb::Level {
2399 u: Box::new(f),
2400 level: n as i64,
2401 spread: glyph == "S:",
2402 };
2403 Ok(Frag::Verb(VerbFrag::V(level), span))
2404 }
2405 "`:" => {
2409 if u.is_verb() {
2410 return Err(Error::domain(
2411 "`: reads a gerund, which is boxed data, not a verb",
2412 span,
2413 ));
2414 }
2415 let vs = gerund_verbs(&u, scope, span)?;
2416 let n = one_atom(&v, "evoke gerund", span)?;
2417 if vs.is_empty() {
2418 return Err(Error::domain("an evoked gerund is empty", span));
2419 }
2420 match n {
2421 0.0 | 3.0 => {
2422 Ok(Frag::Verb(VerbFrag::V(Verb::Evoke(vs, n as i64)), span))
2423 }
2424 6.0 => train_of(vs, span),
2425 _ => Err(Error::domain(
2426 format!("`:{n} is not one of the evoke forms 0, 3 and 6"),
2427 span,
2428 )),
2429 }
2430 }
2431 "H." => {
2435 let num = series_parameters(&u, span)?;
2436 let den = series_parameters(&v, span)?;
2437 Ok(Frag::Verb(VerbFrag::V(Verb::Hypergeometric { num, den }), span))
2438 }
2439 "T." => Err(Error::sandbox(
2443 "T. starts J's own threads, which libjay does not open",
2444 span,
2445 )),
2446 "t:" => Err(Error::new(
2452 ErrorKind::Language,
2453 "t: is not a J inflection; the reference rejects the spelling",
2454 Some(span),
2455 )),
2456 "t." => Err(Error::sandbox(
2457 "t. runs a verb in one of J's thread pools, which libjay does not open",
2458 span,
2459 )),
2460 "." => {
2463 let f = verb_operand(u, span)?;
2464 let g = verb_operand(v, span)?;
2465 Ok(Frag::Verb(VerbFrag::V(Verb::InnerProduct {
2466 u: Box::new(f),
2467 v: Box::new(g),
2468 apl: false,
2469 }), span))
2470 }
2471 "!:" => foreign(&u, &v, span),
2472 ":" => Err(Error::not_yet("the monad-dyad conjunction (u : v)", span)),
2476 _ => Err(Error::not_yet(format!("the conjunction {glyph}"), span)),
2477 }
2478}
2479
2480fn compose(u: Frag, v: Frag, infinite: bool, span: Span) -> Result<Frag> {
2488 let verb = |v: Verb| Ok(Frag::Verb(VerbFrag::V(v), span));
2489 if infinite || (!u.is_noun() && !v.is_noun()) {
2490 let f = verb_operand(u, span)?;
2491 let g = verb_operand(v, span)?;
2492 let monadic_rank = g.ranks()[0];
2493 let composed = Verb::Compose(Box::new(f), Box::new(g));
2494 if infinite {
2495 return verb(composed);
2496 }
2497 return verb(Verb::Rank(Box::new(composed), [monadic_rank; 3]));
2498 }
2499 if u.is_noun() && v.is_noun() {
2500 return Err(Error::not_yet("noun-operand conjunctions", span));
2501 }
2502 if u.is_noun() {
2507 let m = bond_noun(&u, span)?;
2508 let g = as_verb(v)?.0;
2509 return verb(Verb::BondLeft(m, Box::new(g)));
2510 }
2511 let f = as_verb(u)?.0;
2512 let n = bond_noun(&v, span)?;
2513 verb(Verb::BondRight(Box::new(f), n))
2514}
2515
2516const LARGEST_TOLERANCE: f64 = 5.820_766_091_346_741e-11;
2518
2519fn series_parameters(f: &Frag, span: Span) -> Result<Vec<crate::complex::Cx>> {
2522 let Some(arr) = as_const(f) else {
2523 return Err(Error::not_yet("computed hypergeometric parameters (m H. n)", span));
2524 };
2525 if arr.count() == 0 {
2526 return Ok(Vec::new());
2527 }
2528 if arr.rank() > 1 {
2529 return Err(Error::parse("a hypergeometric parameter list is a vector", span));
2530 }
2531 match arr.data.cast(crate::dtype::DType::Complex) {
2532 Some(Data::Complex(v)) => Ok(v.as_slice().to_vec()),
2533 _ => Err(Error::parse("hypergeometric parameters are numbers", span)),
2534 }
2535}
2536
2537fn foreign(u: &Frag, v: &Frag, span: Span) -> Result<Frag> {
2549 let family = foreign_number(u, span)?;
2550 let member = foreign_number(v, span)?;
2551 let prim = |name, monad, dyad| {
2552 Ok(Frag::Verb(
2553 VerbFrag::V(Verb::Prim(Prim { name, monad, dyad, ranks: [RANK_INF; 3] })),
2554 span,
2555 ))
2556 };
2557 let closed = |what: &str| {
2558 Err(Error::sandbox(format!("{family}!:{member} {what}, which is outside the program"), span))
2559 };
2560 match (family, member) {
2561 (1, 1) => prim("1!:1", MonadOp::ReadStream, DyadOp::None),
2562 (1, 2) => prim("1!:2", MonadOp::None, DyadOp::WriteStream),
2563 (3, 0) => prim("3!:0", MonadOp::TypeCode, DyadOp::None),
2564 (5, 1) => prim("5!:1", MonadOp::AtomicRep, DyadOp::None),
2567 (0, _) => closed("runs a script file"),
2568 (1, _) => closed("reaches the filesystem"),
2571 (2, _) => closed("reaches the host — its environment, its shell, its processes"),
2572 (6, _) => closed("reads the clock"),
2573 (15, _) => closed("calls into a shared library"),
2574 _ => Err(Error::not_yet(format!("the foreign {family}!:{member}"), span)),
2575 }
2576}
2577
2578fn foreign_number(f: &Frag, span: Span) -> Result<i64> {
2581 if f.is_verb() {
2582 return Err(Error::parse("a foreign is spelled m!:n, with two numbers", span));
2583 }
2584 let Some(arr) = as_const(f) else {
2585 return Err(Error::not_yet("a computed foreign number (m!:n)", span));
2586 };
2587 match arr.to_i64_vec().as_deref() {
2588 Some([n]) if *n >= 0 => Ok(*n),
2589 _ => Err(Error::parse("a foreign is spelled m!:n, with two whole numbers", span)),
2590 }
2591}
2592
2593fn one_atom(f: &Frag, what: &str, span: Span) -> Result<f64> {
2594 let Some(arr) = as_const(f) else {
2595 return Err(Error::not_yet(format!("a computed {what} specification"), span));
2596 };
2597 let Some(vals) = arr.to_f64_vec() else {
2598 return Err(Error::parse(format!("{what} takes a numeric operand"), span));
2599 };
2600 match vals[..] {
2601 [n] => Ok(n),
2602 _ => Err(Error::parse(format!("{what} takes one atom"), span)),
2603 }
2604}
2605
2606fn bond_noun(f: &Frag, span: Span) -> Result<Array> {
2608 as_const(f)
2609 .cloned()
2610 .ok_or_else(|| Error::not_yet("bonds over a non-literal noun", span))
2611}
2612
2613fn is_open(f: &Frag) -> bool {
2616 matches!(f, Frag::Verb(VerbFrag::V(Verb::Prim(p)), _) if p.monad == MonadOp::Open)
2617}
2618
2619fn is_ravel(f: &Frag) -> bool {
2620 matches!(f, Frag::Verb(VerbFrag::V(Verb::Prim(p)), _) if p.monad == MonadOp::Ravel)
2621}
2622
2623fn verb_operand(f: Frag, span: Span) -> Result<Verb> {
2624 if f.is_noun() {
2625 return Err(Error::not_yet("noun-operand conjunctions", span));
2626 }
2627 Ok(as_verb(f)?.0)
2628}
2629
2630fn rank_spec(f: &Frag, span: Span) -> Result<[i64; 3]> {
2633 let Some(arr) = as_const(f) else {
2634 return Err(Error::not_yet("computed rank specifications", span));
2635 };
2636 let Some(vals) = arr.to_f64_vec() else {
2637 return Err(Error::parse("rank must be numeric", span));
2638 };
2639 if vals.is_empty() || vals.len() > 3 {
2640 return Err(Error::parse("rank takes 1 to 3 atoms", span));
2641 }
2642 let mut r = Vec::with_capacity(vals.len());
2643 for x in vals {
2644 if x == f64::INFINITY {
2645 r.push(RANK_INF);
2646 } else if x == f64::NEG_INFINITY {
2647 r.push(-RANK_INF);
2648 } else if x.fract() != 0.0 {
2649 return Err(Error::parse("rank must be an integer", span));
2650 } else {
2651 r.push(x as i64);
2652 }
2653 }
2654 Ok(match r.len() {
2655 1 => [r[0], r[0], r[0]],
2656 2 => [r[1], r[0], r[1]],
2657 _ => [r[0], r[1], r[2]],
2658 })
2659}
2660
2661fn near_whole(n: f64) -> f64 {
2669 crate::array::NearInt::J.round(n).map_or(n, |k| k as f64)
2670}
2671
2672fn power_spec(f: &Frag, span: Span) -> Result<Power> {
2673 let Some(arr) = noun_value(f) else {
2674 return Err(Error::not_yet("computed power (u^:n)", span));
2675 };
2676 let arr = &arr;
2677 if let Some(boxes) = arr.as_boxes() {
2680 let [inner] = boxes else {
2681 return Err(Error::parse("a boxed power takes one box", span));
2682 };
2683 if inner.count() == 0 {
2684 return Ok(Power::ConvergeTrace);
2685 }
2686 let Some(vals) = inner.to_f64_vec() else {
2687 return Err(Error::parse("power must be numeric", span));
2688 };
2689 let vals: Vec<f64> = vals.into_iter().map(near_whole).collect();
2690 let [n] = vals[..] else {
2691 return Err(Error::not_yet("a boxed list of power counts (u^:(<n))", span));
2692 };
2693 if n.fract() != 0.0 || n.abs() > 1e6 {
2694 return Err(Error::parse("a boxed power must be a whole count", span));
2695 }
2696 if n == 0.0 {
2698 return Err(Error::domain("a boxed power traces at least one application", span));
2699 }
2700 return Ok(Power::Each((0..n.abs() as u64).collect()));
2703 }
2704 let Some(vals) = arr.to_f64_vec() else {
2705 return Err(Error::parse("power must be numeric", span));
2706 };
2707 let vals: Vec<f64> = vals.into_iter().map(near_whole).collect();
2708 if vals.len() > 1 {
2709 let mut counts = Vec::with_capacity(vals.len());
2711 for n in &vals {
2712 if n.fract() != 0.0 || *n < 0.0 || *n > 1e6 {
2713 return Err(Error::not_yet("a power count outside 0 … 1e6", span));
2714 }
2715 counts.push(*n as u64);
2716 }
2717 return Ok(Power::Each(counts));
2718 }
2719 let [n] = vals[..] else {
2720 return Err(Error::not_yet("power over a list of counts (u^:n)", span));
2721 };
2722 if n == f64::INFINITY {
2723 return Ok(Power::Converge);
2724 }
2725 if n.fract() != 0.0 {
2726 return Err(Error::parse("power must be a whole number", span));
2727 }
2728 if n < 0.0 {
2729 return Ok(Power::Times((-n) as u64));
2732 }
2733 Ok(Power::Times(n as u64))
2734}
2735
2736pub(crate) fn obverse_of(v: &Verb, span: Span) -> Result<Verb> {
2738 crate::verb::obverse(v).ok_or_else(|| {
2739 Error::not_yet(format!("the obverse of {} (no inverse is known)", v.name()), span)
2740 })
2741}
2742
2743fn tie_side(f: &Frag, scope: &Names, span: Span) -> Result<Array> {
2747 if f.is_real_verb() {
2748 let (v, _) = as_verb(f.clone())?;
2749 return Ok(Array::boxed(verb_ar(&v, span)?.to_array()));
2750 }
2751 noun_in_scope(f, scope)
2752 .ok_or_else(|| Error::not_yet("a tie over a computed noun", span))
2753}
2754
2755fn verb_ar(v: &Verb, span: Span) -> Result<crate::gerund::Ar> {
2758 crate::gerund::verb_ar(v).ok_or_else(|| {
2759 Error::not_yet(format!("the atomic representation of {}", v.name()), span)
2760 })
2761}
2762
2763fn noun_in_scope(f: &Frag, scope: &Names) -> Option<Array> {
2766 if let Frag::Name(n, _) = f {
2767 return scope.consts.get(n).cloned();
2768 }
2769 noun_value(f)
2770}
2771
2772fn gerund_verbs(f: &Frag, scope: &Names, span: Span) -> Result<Vec<Verb>> {
2775 if f.is_real_verb() {
2776 return Ok(vec![as_verb(f.clone())?.0]);
2777 }
2778 let arr = noun_in_scope(f, scope)
2779 .ok_or_else(|| Error::not_yet("a gerund computed at run time", span))?;
2780 let Some(items) = arr.as_boxes() else {
2781 return Err(Error::domain("a gerund is boxed data", span));
2782 };
2783 items.iter().map(|a| ar_verb(a, scope, span)).collect()
2784}
2785
2786fn ar_verb(a: &Array, scope: &Names, span: Span) -> Result<Verb> {
2788 let ar = crate::gerund::Ar::from_array(a)
2789 .ok_or_else(|| Error::domain("this is not an atomic representation", span))?;
2790 let (v, _) = as_verb(ar_frag(&ar, scope, span)?)?;
2791 Ok(v)
2792}
2793
2794fn ar_frag(ar: &crate::gerund::Ar, scope: &Names, span: Span) -> Result<Frag> {
2797 use crate::gerund::Ar;
2798 match ar {
2799 Ar::Noun(a) => Ok(Frag::Noun(Expr::Const(a.clone(), span))),
2800 Ar::Prim(word) => {
2801 if word == "[:" {
2802 return Ok(Frag::Verb(VerbFrag::Cap, span));
2803 }
2804 match verb_for(word) {
2805 Some(v) => Ok(Frag::Verb(VerbFrag::V(v), span)),
2806 None => Err(Error::domain(
2807 format!("`{word}` is not a verb an atomic representation may name"),
2808 span,
2809 )),
2810 }
2811 }
2812 Ar::Train(parts) => {
2813 let frags: Result<Vec<Frag>> =
2814 parts.iter().map(|p| ar_frag(p, scope, span)).collect();
2815 let mut frags = frags?;
2816 match frags.len() {
2817 2 => {
2818 let b = frags.pop().expect("two parts");
2819 let a = frags.pop().expect("two parts");
2820 apply_bident(a, b, &scope.nouns)
2821 }
2822 3 => {
2823 let h = frags.pop().expect("three parts");
2824 let g = frags.pop().expect("three parts");
2825 let f = frags.pop().expect("three parts");
2826 apply_fork(f, g, h)
2827 }
2828 _ => Err(Error::domain("a train is two or three parts", span)),
2829 }
2830 }
2831 Ar::Derived(word, ops) => {
2832 let frags: Result<Vec<Frag>> = ops.iter().map(|p| ar_frag(p, scope, span)).collect();
2833 let mut frags = frags?;
2834 if let Some(glyph) = adverb(word) {
2835 if frags.len() != 1 {
2836 return Err(Error::domain(format!("{glyph} takes one operand"), span));
2837 }
2838 let u = frags.pop().expect("one operand");
2839 return apply_adverb(u, Frag::Adverb(Modifier::Prim(glyph), span), scope);
2840 }
2841 if let Some(glyph) = conjunction(word) {
2842 if frags.len() != 2 {
2843 return Err(Error::domain(format!("{glyph} takes two operands"), span));
2844 }
2845 let v = frags.pop().expect("two operands");
2846 let u = frags.pop().expect("two operands");
2847 return apply_conj(u, Frag::Conj(Modifier::Prim(glyph), span), v, scope);
2848 }
2849 Err(Error::domain(
2850 format!("`{word}` is not a modifier an atomic representation may name"),
2851 span,
2852 ))
2853 }
2854 }
2855}
2856
2857fn train_of(vs: Vec<Verb>, span: Span) -> Result<Frag> {
2860 let mut frags: Vec<Frag> =
2861 vs.into_iter().map(|v| Frag::Verb(VerbFrag::V(v), span)).collect();
2862 while frags.len() > 3 {
2863 let h = frags.pop().expect("three or more");
2864 let g = frags.pop().expect("three or more");
2865 let f = frags.pop().expect("three or more");
2866 frags.push(apply_fork(f, g, h)?);
2867 }
2868 match frags.len() {
2869 1 => Ok(frags.pop().expect("one")),
2870 2 => {
2871 let b = frags.pop().expect("two");
2872 let a = frags.pop().expect("two");
2873 apply_bident(a, b, &HashSet::new())
2874 }
2875 _ => {
2876 let h = frags.pop().expect("three");
2877 let g = frags.pop().expect("three");
2878 let f = frags.pop().expect("three");
2879 apply_fork(f, g, h)
2880 }
2881 }
2882}
2883
2884fn apply_fork(f: Frag, g: Frag, h: Frag) -> Result<Frag> {
2885 let span = Span::merge(Span::merge(f.span(), g.span()), h.span());
2886 let (gv, _) = as_verb(g)?;
2887 let (hv, _) = as_verb(h)?;
2888 match f {
2889 Frag::Verb(VerbFrag::Cap, _) => {
2891 Ok(Frag::Verb(VerbFrag::V(Verb::Atop(Box::new(gv), Box::new(hv))), span))
2892 }
2893 Frag::Verb(VerbFrag::V(fv), _) => Ok(Frag::Verb(
2894 VerbFrag::V(Verb::Fork(Box::new(fv), Box::new(gv), Box::new(hv))),
2895 span,
2896 )),
2897 noun => {
2898 let Some(arr) = as_const(&noun) else {
2899 return Err(Error::not_yet("noun forks over a non-literal noun", span));
2900 };
2901 Ok(Frag::Verb(
2902 VerbFrag::V(Verb::NounFork(arr.clone(), Box::new(gv), Box::new(hv))),
2903 span,
2904 ))
2905 }
2906 }
2907}
2908
2909fn apply_bident(a: Frag, b: Frag, nouns: &HashSet<String>) -> Result<Frag> {
2910 let span = Span::merge(a.span(), b.span());
2911 if let Frag::Name(n, nspan) = &a && !nouns.contains(n) {
2915 return Err(Error::new(
2916 ErrorKind::Value,
2917 format!("undefined name: {n}"),
2918 Some(*nspan),
2919 ));
2920 }
2921 if a.is_real_verb() && b.is_real_verb() {
2922 let (f, _) = as_verb(a)?;
2923 let (g, _) = as_verb(b)?;
2924 return Ok(Frag::Verb(VerbFrag::V(Verb::Hook(Box::new(f), Box::new(g))), span));
2925 }
2926 if matches!(a, Frag::Verb(VerbFrag::Cap, _)) {
2931 return Err(Error::parse("`[:` caps a fork; it has no verb of its own", span));
2932 }
2933 Err(Error::parse("syntax error", span))
2934}
2935
2936fn apply_assign(target: Frag, value: Frag, scope: Scope) -> Result<Frag> {
2937 let span = Span::merge(target.span(), value.span());
2938 match target {
2939 Frag::Name(name, _) => match value {
2943 Frag::Verb(VerbFrag::V(verb), _) => Ok(Frag::VerbDef(name, verb, span)),
2946 Frag::Verb(VerbFrag::Cap, _) => Err(Error::not_yet("assigning [: on its own", span)),
2947 Frag::Adverb(m, _) => Ok(Frag::ModDef(name, false, m, span)),
2950 Frag::Conj(m, _) => Ok(Frag::ModDef(name, true, m, span)),
2951 v if v.is_noun() => {
2952 let value = as_noun(v)?;
2953 Ok(Frag::Noun(Expr::Assign { name, value: Box::new(value), scope, span }))
2954 }
2955 other => Err(Error::internal(format!("cannot assign {other:?}"))),
2956 },
2957 Frag::Noun(_) => Err(Error::not_yet("multiple assignment", span)),
2958 other => Err(Error::internal(format!("expected an assignment target, got {other:?}"))),
2959 }
2960}
2961
2962#[cfg(test)]
2963mod tests {
2964 use super::*;
2965 use crate::dtype::DType;
2966 use crate::error::ErrorKind;
2967 use rstest::rstest;
2968
2969 fn parse_str(src: &str) -> Result<Vec<Expr>> {
2970 parse(&SourceParts::from_source(src).expect("source parts"))
2971 }
2972
2973 fn one_literal(src: &str) -> Expr {
2977 let sp = SourceParts::from_parts(&[src], &[]);
2978 let mut s = parse(&sp).unwrap_or_else(|e| panic!("parse of {src:?} failed: {e}"));
2979 assert_eq!(s.len(), 1, "expected one sentence in {src:?}");
2980 s.pop().expect("one sentence")
2981 }
2982
2983 fn stmts(src: &str) -> Vec<Expr> {
2984 parse_str(src).unwrap_or_else(|e| panic!("parse of {src:?} failed: {e}"))
2985 }
2986
2987 fn one(src: &str) -> Expr {
2989 let mut s = stmts(src);
2990 assert_eq!(s.len(), 1, "expected one sentence in {src:?}");
2991 s.pop().expect("one sentence")
2992 }
2993
2994 fn err(src: &str) -> Error {
2995 match parse_str(src) {
2996 Ok(v) => panic!("expected an error for {src:?}, got {v:?}"),
2997 Err(e) => e,
2998 }
2999 }
3000
3001 fn konst(e: &Expr) -> Array {
3005 match e {
3006 Expr::Const(a, _) => a.clone(),
3007 other => panic!("expected a constant, got {other:?}"),
3008 }
3009 }
3010
3011 fn ints(e: &Expr) -> Vec<i64> {
3012 konst(e).as_i64_slice().expect("integer data").to_vec()
3013 }
3014
3015 fn prim_of(v: &Verb) -> Prim {
3016 match v {
3017 Verb::Prim(p) => *p,
3018 other => panic!("expected a primitive, got {other:?}"),
3019 }
3020 }
3021
3022 fn monad_of(e: &Expr) -> (Verb, Expr) {
3023 match e {
3024 Expr::Monad { verb, y, .. } => (verb.clone(), (**y).clone()),
3025 other => panic!("expected a monad, got {other:?}"),
3026 }
3027 }
3028
3029 fn dyad_of(e: &Expr) -> (Verb, Expr, Expr) {
3030 match e {
3031 Expr::Dyad { verb, x, y, .. } => (verb.clone(), (**x).clone(), (**y).clone()),
3032 other => panic!("expected a dyad, got {other:?}"),
3033 }
3034 }
3035
3036 #[test]
3039 fn single_number_is_an_atom() {
3040 let e = one("5");
3041 assert_eq!(konst(&e).shape, Vec::<usize>::new());
3042 assert_eq!(ints(&e), vec![5]);
3043 assert_eq!(e.span(), Span::new(0, 1));
3044 }
3045
3046 #[test]
3047 fn adjacent_numbers_merge_into_one_vector() {
3048 let e = one("1 2 3");
3049 assert_eq!(konst(&e).shape, vec![3]);
3050 assert_eq!(ints(&e), vec![1, 2, 3]);
3051 assert_eq!(e.span(), Span::new(0, 5));
3052 }
3053
3054 #[test]
3055 fn a_float_makes_the_whole_vector_float() {
3056 let a = konst(&one("1 2.5 3"));
3057 assert_eq!(a.dtype(), DType::F64);
3058 assert_eq!(a.as_f64_slice(), Some(&[1.0, 2.5, 3.0][..]));
3059 }
3060
3061 #[test]
3062 fn negatives_and_infinities() {
3063 let a = konst(&one("_3 1.5 _ __"));
3064 assert_eq!(a.shape, vec![4]);
3065 let v = a.as_f64_slice().expect("float vector");
3066 assert_eq!(v[0], -3.0);
3067 assert_eq!(v[1], 1.5);
3068 assert!(v[2].is_infinite() && v[2] > 0.0);
3069 assert!(v[3].is_infinite() && v[3] < 0.0);
3070 }
3071
3072 #[test]
3073 fn negative_integers_stay_integers() {
3074 let a = konst(&one("_3 _4"));
3075 assert_eq!(a.dtype(), DType::I64);
3076 assert_eq!(a.as_i64_slice(), Some(&[-3i64, -4][..]));
3077 }
3078
3079 #[rstest]
3080 #[case("1e3", 1000.0)]
3081 #[case("1e_3", 0.001)]
3082 #[case("2.5e2", 250.0)]
3083 #[case("_1.5", -1.5)]
3084 fn exponent_and_sign_forms(#[case] src: &str, #[case] want: f64) {
3085 let a = konst(&one(src));
3086 assert_eq!(a.dtype(), DType::F64);
3087 assert_eq!(a.to_f64_vec().expect("numeric"), vec![want]);
3088 }
3089
3090 #[test]
3091 fn adjacent_numbers_stop_at_a_non_number() {
3092 let (_, x, y) = dyad_of(&one("2 3 i. 4"));
3094 assert_eq!(konst(&x).shape, vec![2]);
3095 assert_eq!(konst(&y).shape, Vec::<usize>::new());
3096 }
3097
3098 #[test]
3099 fn string_of_several_characters_is_a_vector() {
3100 let e = one("'abc'");
3101 let a = konst(&e);
3102 assert_eq!(a.shape, vec![3]);
3103 assert_eq!(a.data, Data::Char(vec!['a', 'b', 'c'].into()));
3104 assert_eq!(e.span(), Span::new(0, 5));
3105 }
3106
3107 #[test]
3108 fn one_character_string_is_an_atom() {
3109 let a = konst(&one("'a'"));
3110 assert_eq!(a.shape, Vec::<usize>::new());
3111 assert_eq!(a.data, Data::Char(vec!['a'].into()));
3112 }
3113
3114 #[test]
3115 fn empty_string_is_an_empty_vector() {
3116 let a = konst(&one("''"));
3117 assert_eq!(a.shape, vec![0]);
3118 assert_eq!(a.dtype(), DType::Char);
3119 }
3120
3121 #[test]
3122 fn doubled_quote_is_an_escaped_quote() {
3123 let a = konst(&one("'it''s'"));
3124 assert_eq!(a.shape, vec![4]);
3125 assert_eq!(a.data, Data::Char(vec!['i', 't', '\'', 's'].into()));
3126 }
3127
3128 #[test]
3129 fn unterminated_string_is_a_parse_error() {
3130 let e = err("'abc");
3131 assert_eq!(e.kind, ErrorKind::Parse);
3132 assert!(e.msg.contains("unterminated"), "{}", e.msg);
3133 assert_eq!(e.span, Some(Span::new(0, 4)));
3134 }
3135
3136 #[test]
3139 fn comment_runs_to_end_of_line() {
3140 let e = one("1 2 NB. and the rest + - ' is ignored");
3141 assert_eq!(konst(&e).shape, vec![2]);
3142 }
3143
3144 #[test]
3145 fn comment_only_line_yields_no_sentence() {
3146 assert!(stmts("NB. nothing here").is_empty());
3147 let s = stmts("NB. header\n5");
3148 assert_eq!(s.len(), 1);
3149 assert_eq!(ints(&s[0]), vec![5]);
3150 }
3151
3152 #[test]
3153 fn nb_inside_a_name_is_not_a_comment() {
3154 match one("aNB") {
3156 Expr::Name(n, _) => assert_eq!(n, "aNB"),
3157 other => panic!("expected a name, got {other:?}"),
3158 }
3159 }
3160
3161 #[test]
3164 fn empty_program_has_no_sentences() {
3165 assert!(stmts("").is_empty());
3166 assert!(stmts("\n\n").is_empty());
3167 }
3168
3169 #[test]
3170 fn trains_of_dyads_are_right_associative() {
3171 let e = one("1 + 2 + 3");
3172 let (v, x, y) = dyad_of(&e);
3173 assert_eq!(prim_of(&v).name, "+");
3174 assert_eq!(ints(&x), vec![1]);
3175 let (v2, x2, y2) = dyad_of(&y);
3176 assert_eq!(prim_of(&v2).name, "+");
3177 assert_eq!(ints(&x2), vec![2]);
3178 assert_eq!(ints(&y2), vec![3]);
3179 assert_eq!(e.span(), Span::new(0, 9));
3180 }
3181
3182 #[test]
3183 fn a_verb_with_no_left_argument_is_a_monad() {
3184 let e = one("- 5");
3185 let (v, y) = monad_of(&e);
3186 assert_eq!(prim_of(&v).monad, MonadOp::Scalar(ScalarMonad::Neg));
3187 assert_eq!(ints(&y), vec![5]);
3188 assert_eq!(e.span(), Span::new(0, 3));
3189 }
3190
3191 #[test]
3192 fn a_verb_with_a_left_argument_is_a_dyad() {
3193 let (v, _, _) = dyad_of(&one("1 - 5"));
3194 assert_eq!(prim_of(&v).dyad, DyadOp::Scalar(ScalarDyad::Sub));
3195 }
3196
3197 #[test]
3198 fn a_monad_binds_to_the_right_inside_a_dyad() {
3199 let (v, x, y) = dyad_of(&one("2 * - 3"));
3200 assert_eq!(prim_of(&v).name, "*");
3201 assert_eq!(ints(&x), vec![2]);
3202 let (mv, my) = monad_of(&y);
3203 assert_eq!(prim_of(&mv).name, "-");
3204 assert_eq!(ints(&my), vec![3]);
3205 }
3206
3207 #[test]
3208 fn parentheses_group_the_left_argument() {
3209 let (v, x, y) = dyad_of(&one("(1 + 2) * 3"));
3210 assert_eq!(prim_of(&v).name, "*");
3211 let (iv, _, _) = dyad_of(&x);
3212 assert_eq!(prim_of(&iv).name, "+");
3213 assert_eq!(x.span(), Span::new(0, 7));
3216 assert_eq!(ints(&y), vec![3]);
3217 }
3218
3219 #[test]
3220 fn names_are_nouns() {
3221 match one("x") {
3222 Expr::Name(n, s) => {
3223 assert_eq!(n, "x");
3224 assert_eq!(s, Span::new(0, 1));
3225 }
3226 other => panic!("expected a name, got {other:?}"),
3227 }
3228 let (_, x, y) = dyad_of(&one("x + y"));
3229 assert!(matches!(x, Expr::Name(..)));
3230 assert!(matches!(y, Expr::Name(..)));
3231 }
3232
3233 #[test]
3234 fn echo_is_a_verb() {
3235 let (v, y) = monad_of(&one("echo 5"));
3236 assert_eq!(prim_of(&v).monad, MonadOp::Echo);
3237 assert_eq!(ints(&y), vec![5]);
3238 }
3239
3240 #[test]
3241 fn inflected_letter_words_are_primitives() {
3242 let (v, _) = monad_of(&one("i. 3"));
3243 let p = prim_of(&v);
3244 assert_eq!(p.monad, MonadOp::IotaJ);
3245 assert_eq!(p.ranks, [1, RANK_INF, RANK_INF]);
3246 }
3247
3248 #[rstest]
3249 #[case("|: 1 2 3", MonadOp::TransposeAxes)]
3250 #[case("$ 1 2 3", MonadOp::ShapeOf)]
3251 #[case("# 1 2 3", MonadOp::Tally)]
3252 #[case(", 1 2 3", MonadOp::Ravel)]
3253 #[case("%: 1 2 3", MonadOp::Scalar(ScalarMonad::Sqrt))]
3254 #[case("<. 1.5", MonadOp::Scalar(ScalarMonad::Floor))]
3255 fn inflected_symbol_words(#[case] src: &str, #[case] want: MonadOp) {
3256 let (v, _) = monad_of(&one(src));
3257 assert_eq!(prim_of(&v).monad, want);
3258 }
3259
3260 #[rstest]
3261 #[case("{. 1 2 3", MonadOp::Head, DyadOp::Take)]
3262 #[case("}. 1 2 3", MonadOp::Behead, DyadOp::Drop)]
3263 fn brace_words(#[case] src: &str, #[case] monad: MonadOp, #[case] dyad: DyadOp) {
3264 let (v, _) = monad_of(&one_literal(src));
3265 let p = prim_of(&v);
3266 assert_eq!(p.monad, monad);
3267 assert_eq!(p.dyad, dyad);
3268 assert_eq!(p.ranks, [RANK_INF, 1, RANK_INF]);
3269 }
3270
3271 #[test]
3272 fn a_brace_word_takes_a_left_argument() {
3273 let (v, x, y) = dyad_of(&one_literal("2 {. 1 2 3"));
3274 assert_eq!(prim_of(&v).dyad, DyadOp::Take);
3275 assert_eq!(ints(&x), vec![2]);
3276 assert_eq!(konst(&y).shape, vec![3]);
3277 }
3278
3279 #[rstest]
3280 #[case("2 $ 1 2 3", DyadOp::Reshape)]
3281 #[case("2 [ 3", DyadOp::Left)]
3282 #[case("2 ] 3", DyadOp::Right)]
3283 #[case("2 <. 3", DyadOp::Scalar(ScalarDyad::Min))]
3284 #[case("2 >: 3", DyadOp::Scalar(ScalarDyad::Ge))]
3285 fn dyadic_primitives(#[case] src: &str, #[case] want: DyadOp) {
3286 let (v, _, _) = dyad_of(&one(src));
3287 assert_eq!(prim_of(&v).dyad, want);
3288 }
3289
3290 #[test]
3291 fn unimplemented_meanings_reach_the_verb_not_the_parser() {
3292 let (v, _, _) = dyad_of(&one("2 s: 'a b'"));
3296 assert_eq!(prim_of(&v).dyad, DyadOp::SymbolForm);
3297 let (v, _, _) = dyad_of(&one("6 $. 'a b'"));
3298 assert_eq!(prim_of(&v).dyad, DyadOp::SparseForm);
3299 }
3300
3301 #[test]
3302 fn multiple_sentences_become_multiple_statements() {
3303 let s = stmts("a =. 1 2\n+/ a\n");
3304 assert_eq!(s.len(), 2);
3305 assert!(matches!(s[0], Expr::Assign { .. }));
3306 assert!(matches!(s[1], Expr::Monad { .. }));
3307 }
3308
3309 #[test]
3312 fn an_adverb_binds_before_the_verb_is_applied() {
3313 let e = one("+/ 1 2 3");
3314 let (v, y) = monad_of(&e);
3315 match &v {
3316 Verb::Reduce(inner) => assert_eq!(prim_of(inner).name, "+"),
3317 other => panic!("expected a reduction, got {other:?}"),
3318 }
3319 assert_eq!(konst(&y).shape, vec![3]);
3320 assert_eq!(e.span(), Span::new(0, 8));
3321 }
3322
3323 #[test]
3324 fn rank_applies_to_the_derived_verb() {
3325 let (v, _) = monad_of(&one("+/\"1 m"));
3326 match &v {
3327 Verb::Rank(inner, ranks) => {
3328 assert_eq!(*ranks, [1, 1, 1]);
3329 assert!(matches!(**inner, Verb::Reduce(_)), "got {inner:?}");
3330 }
3331 other => panic!("expected a ranked verb, got {other:?}"),
3332 }
3333 }
3334
3335 #[rstest]
3336 #[case("+\"1 m", [1, 1, 1])]
3337 #[case("+\"1 2 m", [2, 1, 2])]
3338 #[case("+\"0 1 2 m", [0, 1, 2])]
3339 #[case("+\"_ m", [RANK_INF, RANK_INF, RANK_INF])]
3340 #[case("+\"_1 m", [-1, -1, -1])]
3341 #[case("+\"2.0 m", [2, 2, 2])]
3342 fn rank_specifications(#[case] src: &str, #[case] want: [i64; 3]) {
3343 let (v, _) = monad_of(&one(src));
3344 assert_eq!(v.ranks(), want);
3345 }
3346
3347 #[test]
3348 fn rank_must_be_one_to_three_integer_atoms() {
3349 let e = err("+\"1 2 3 4 m");
3350 assert_eq!(e.kind, ErrorKind::Parse);
3351 assert!(e.msg.contains("1 to 3 atoms"), "{}", e.msg);
3352 let e = err("+\"1.5 m");
3353 assert_eq!(e.kind, ErrorKind::Parse);
3354 assert!(e.msg.contains("integer"), "{}", e.msg);
3355 let e = err("+\"'a' m");
3356 assert_eq!(e.kind, ErrorKind::Parse);
3357 assert!(e.msg.contains("numeric"), "{}", e.msg);
3358 }
3359
3360 #[test]
3361 fn verb_rank_is_not_supported_yet() {
3362 let e = err("+\"- m");
3363 assert_eq!(e.kind, ErrorKind::NotYet);
3364 assert!(e.msg.contains("verb rank"), "{}", e.msg);
3365 }
3366
3367 #[test]
3368 fn computed_rank_is_not_supported_yet() {
3369 let e = err("+\"{r} m");
3370 assert_eq!(e.kind, ErrorKind::NotYet);
3371 assert!(e.msg.contains("computed rank"), "{}", e.msg);
3372 }
3373
3374 #[test]
3375 fn atop_conjunction() {
3376 let (v, _) = monad_of(&one("+/ @: , y"));
3377 match &v {
3378 Verb::Atop(f, g) => {
3379 assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
3380 assert_eq!(prim_of(g).name, ",");
3381 }
3382 other => panic!("expected an atop, got {other:?}"),
3383 }
3384 }
3385
3386 #[rstest]
3387 #[case("+ ^: {n} y", "computed power")]
3388 #[case("(+/ % #) ^: _1 y", "the obverse of")]
3389 #[case("+: &. (+/ % #) y", "the obverse of")]
3392 #[case("(1 + 2) & , y", "bonds over a non-literal noun")]
3393 fn other_conjunctions_are_not_supported_yet(#[case] src: &str, #[case] msg: &str) {
3394 let e = err(src);
3395 assert_eq!(e.kind, ErrorKind::NotYet);
3396 assert!(e.msg.contains(msg), "{}", e.msg);
3397 }
3398
3399 #[test]
3400 fn atop_at_rank_and_compose() {
3401 let (v, _) = monad_of(&one("+/ @ (,\"1) y"));
3404 match &v {
3405 Verb::Rank(inner, ranks) => {
3406 assert_eq!(*ranks, [1, 1, 1]);
3407 assert!(matches!(**inner, Verb::Atop(..)), "got {inner:?}");
3408 }
3409 other => panic!("expected a ranked atop, got {other:?}"),
3410 }
3411 let (v, _) = monad_of(&one("+ & (*:\"0) y"));
3412 match &v {
3413 Verb::Rank(inner, ranks) => {
3414 assert_eq!(*ranks, [0, 0, 0]);
3415 assert!(matches!(**inner, Verb::Compose(..)), "got {inner:?}");
3416 }
3417 other => panic!("expected a ranked composition, got {other:?}"),
3418 }
3419 let (v, _) = monad_of(&one("+ &: *: y"));
3420 assert!(matches!(v, Verb::Compose(..)), "got {v:?}");
3421 }
3422
3423 #[test]
3424 fn a_noun_operand_bonds_the_conjunction() {
3425 let (v, _) = monad_of(&one("1 & + y"));
3429 match &v {
3430 Verb::BondLeft(a, g) => {
3431 assert_eq!(a.as_i64_slice(), Some(&[1i64][..]));
3432 assert_eq!(prim_of(g).name, "+");
3433 }
3434 other => panic!("expected a left bond, got {other:?}"),
3435 }
3436 assert_eq!(v.ranks(), [crate::verb::RANK_INF; 3]);
3437 let (v, _) = monad_of(&one("{. & 2 y"));
3438 assert!(matches!(v, Verb::BondRight(..)), "got {v:?}");
3439 assert_eq!(v.ranks(), [crate::verb::RANK_INF; 3]);
3440 }
3441
3442 #[test]
3443 fn window_scan_and_commute_adverbs() {
3444 let (v, _) = monad_of(&one("+/\\ 1 2 3"));
3445 match &v {
3446 Verb::Windowed(u, WindowKind::Prefix) => assert!(matches!(**u, Verb::Reduce(_))),
3447 other => panic!("expected a prefix application, got {other:?}"),
3448 }
3449 assert_eq!(v.ranks(), [RANK_INF, 0, RANK_INF]);
3452 let (v, _, _) = dyad_of(&one("2 +/\\ 1 2 3"));
3453 assert!(matches!(v, Verb::Windowed(_, WindowKind::Prefix)));
3454 let (v, _) = monad_of(&one("+/\\. 1 2 3"));
3455 assert!(matches!(v, Verb::Windowed(_, WindowKind::Suffix)));
3456 let (v, _) = monad_of(&one("+~ 1 2 3"));
3457 match &v {
3458 Verb::Commute(u) => assert_eq!(prim_of(u).name, "+"),
3459 other => panic!("expected a commute, got {other:?}"),
3460 }
3461 let (v, _) = monad_of(&one("+:^:3 (1)"));
3462 assert!(matches!(v, Verb::PowerN(_, Power::Times(3))));
3463 let (v, _) = monad_of(&one("%:^:_ (100)"));
3464 assert!(matches!(v, Verb::PowerN(_, Power::Converge)));
3465 }
3466
3467 #[test]
3468 fn the_key_adverb_derives_a_verb() {
3469 match one("+/. 1 2 3") {
3470 Expr::Monad { verb: Verb::Key(_), .. } => {}
3471 other => panic!("expected a key, got {other:?}"),
3472 }
3473 }
3474
3475 #[test]
3476 fn noun_operand_adverbs_are_not_supported_yet() {
3477 let e = err("1/ 2");
3478 assert_eq!(e.kind, ErrorKind::NotYet);
3479 assert!(e.msg.contains("noun-operand adverbs"), "{}", e.msg);
3480 }
3481
3482 #[test]
3483 fn noun_operand_conjunctions_are_not_supported_yet() {
3484 let e = err("1 @: + y");
3485 assert_eq!(e.kind, ErrorKind::NotYet);
3486 assert!(e.msg.contains("noun-operand conjunctions"), "{}", e.msg);
3487 }
3488
3489 #[test]
3492 fn three_verbs_in_parentheses_are_a_fork() {
3493 let (v, y) = monad_of(&one("(+/ % #) 1 2 3"));
3494 match &v {
3495 Verb::Fork(f, g, h) => {
3496 assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
3497 assert_eq!(prim_of(g).name, "%");
3498 assert_eq!(prim_of(h).name, "#");
3499 }
3500 other => panic!("expected a fork, got {other:?}"),
3501 }
3502 assert_eq!(konst(&y).shape, vec![3]);
3503 }
3504
3505 #[test]
3506 fn a_noun_left_tine_is_a_noun_fork() {
3507 let (v, _) = monad_of(&one("(2 + #) 1 2 3"));
3508 match &v {
3509 Verb::NounFork(a, g, h) => {
3510 assert_eq!(a.as_i64_slice(), Some(&[2i64][..]));
3511 assert_eq!(prim_of(g).name, "+");
3512 assert_eq!(prim_of(h).name, "#");
3513 }
3514 other => panic!("expected a noun fork, got {other:?}"),
3515 }
3516 }
3517
3518 #[test]
3519 fn two_verbs_in_parentheses_are_a_hook() {
3520 let (v, _) = monad_of(&one("(+ #) 1 2 3"));
3521 match &v {
3522 Verb::Hook(f, g) => {
3523 assert_eq!(prim_of(f).name, "+");
3524 assert_eq!(prim_of(g).name, "#");
3525 }
3526 other => panic!("expected a hook, got {other:?}"),
3527 }
3528 }
3529
3530 #[test]
3531 fn cap_makes_a_fork_an_atop() {
3532 let (v, _) = monad_of(&one("([: +/ ,) 1 2 3"));
3533 match &v {
3534 Verb::Atop(f, g) => {
3535 assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
3536 assert_eq!(prim_of(g).name, ",");
3537 }
3538 other => panic!("expected an atop, got {other:?}"),
3539 }
3540 }
3541
3542 #[test]
3543 fn a_five_verb_train_folds_from_the_right() {
3544 let (v, _) = monad_of(&one("(] , [ , ]) 1 2 3"));
3546 match &v {
3547 Verb::Fork(f, g, h) => {
3548 assert_eq!(prim_of(f).name, "]");
3549 assert_eq!(prim_of(g).name, ",");
3550 assert!(matches!(**h, Verb::Fork(..)), "got {h:?}");
3551 }
3552 other => panic!("expected a fork, got {other:?}"),
3553 }
3554 }
3555
3556 #[test]
3557 fn a_noun_fork_needs_a_literal_noun() {
3558 let e = err("({n} + #) 1 2 3");
3559 assert_eq!(e.kind, ErrorKind::NotYet);
3560 assert!(e.msg.contains("noun forks"), "{}", e.msg);
3561 }
3562
3563 #[test]
3564 fn cap_is_never_applied_as_a_verb() {
3565 let e = err("[: # 1 2 3");
3568 assert_eq!(e.kind, ErrorKind::Parse);
3569 assert!(e.msg.contains("caps a fork"), "{}", e.msg);
3570 }
3571
3572 #[test]
3573 fn two_nouns_side_by_side_are_a_syntax_error() {
3574 let e = err("'ab' 'cd'");
3576 assert_eq!(e.kind, ErrorKind::Parse);
3577 assert_eq!(e.msg, "syntax error");
3578 }
3579
3580 #[test]
3581 fn a_sentence_that_is_a_verb_is_not_supported_yet() {
3582 let e = err("+/ % #");
3583 assert_eq!(e.kind, ErrorKind::NotYet);
3584 assert!(e.msg.contains("tacit"), "{}", e.msg);
3585 }
3586
3587 #[rstest]
3590 #[case("x =. 5", Scope::Local)]
3591 #[case("x =: 5", Scope::Global)]
3592 fn assignment_yields_an_assign_node(#[case] src: &str, #[case] want: Scope) {
3593 match one(src) {
3594 Expr::Assign { name, value, scope, span } => {
3595 assert_eq!(name, "x");
3596 assert_eq!(ints(&value), vec![5]);
3597 assert_eq!(scope, want);
3598 assert_eq!(span, Span::new(0, 6));
3599 }
3600 other => panic!("expected an assignment, got {other:?}"),
3601 }
3602 }
3603
3604 #[test]
3605 fn assignment_in_expression_position() {
3606 let (v, x, y) = dyad_of(&one("y + x =. 3"));
3607 assert_eq!(prim_of(&v).name, "+");
3608 assert!(matches!(x, Expr::Name(..)));
3609 match y {
3610 Expr::Assign { name, span, .. } => {
3611 assert_eq!(name, "x");
3612 assert_eq!(span, Span::new(4, 10));
3613 }
3614 other => panic!("expected an assignment, got {other:?}"),
3615 }
3616 }
3617
3618 #[test]
3619 fn assignment_takes_the_whole_right_hand_sentence() {
3620 match one("x =. 1 + 2") {
3621 Expr::Assign { value, .. } => {
3622 let (v, _, _) = dyad_of(&value);
3623 assert_eq!(prim_of(&v).name, "+");
3624 }
3625 other => panic!("expected an assignment, got {other:?}"),
3626 }
3627 }
3628
3629 #[test]
3632 fn assigning_a_verb_names_it_and_runs_nothing() {
3633 let s = stmts("mean =. +/ % #");
3634 assert_eq!(s.len(), 1);
3635 match &s[0] {
3636 Expr::VerbDef { name, verb, span } => {
3637 assert_eq!(name, "mean");
3638 assert!(matches!(verb, Verb::Fork(..)), "got {verb:?}");
3639 assert_eq!(*span, Span::new(0, 14));
3640 }
3641 other => panic!("expected a verb definition, got {other:?}"),
3642 }
3643 }
3644
3645 #[test]
3646 fn a_named_verb_applies_in_a_later_sentence() {
3647 let s = stmts("mean =. +/ % #\nmean 1 2 3 4");
3648 assert_eq!(s.len(), 2);
3649 let (v, y) = monad_of(&s[1]);
3650 assert!(matches!(v, Verb::Fork(..)), "got {v:?}");
3651 assert_eq!(konst(&y).shape, vec![4]);
3652 }
3653
3654 #[test]
3655 fn a_named_verb_is_a_verb_inside_a_train_and_under_a_conjunction() {
3656 let (v, _) = monad_of(&stmts("mean =. +/ % #\n(mean - {.) 1 2 3 4").pop().expect("two"));
3657 match &v {
3658 Verb::Fork(f, g, h) => {
3659 assert!(matches!(**f, Verb::Fork(..)), "got {f:?}");
3660 assert_eq!(prim_of(g).name, "-");
3661 assert_eq!(prim_of(h).name, "{.");
3662 }
3663 other => panic!("expected a fork, got {other:?}"),
3664 }
3665 let (v, _) = monad_of(&stmts("mean =. +/ % #\nmean\"1 m").pop().expect("two"));
3666 match &v {
3667 Verb::Rank(inner, r) => {
3668 assert_eq!(*r, [1, 1, 1]);
3669 assert!(matches!(**inner, Verb::Fork(..)), "got {inner:?}");
3670 }
3671 other => panic!("expected a ranked verb, got {other:?}"),
3672 }
3673 }
3674
3675 #[test]
3676 fn redefinition_rebinds_from_that_sentence_on() {
3677 let s = stmts("f =. +/\nf 1 2 3\nf =. #\nf 1 2 3");
3678 assert_eq!(s.len(), 4);
3679 assert!(matches!(monad_of(&s[1]).0, Verb::Reduce(_)));
3680 assert_eq!(prim_of(&monad_of(&s[3]).0).name, "#");
3681 }
3682
3683 #[test]
3684 fn a_name_may_change_part_of_speech_in_either_direction() {
3685 let s = stmts("a =. 1 2 3\na =. +/\na 1 2 3");
3687 assert!(matches!(s[0], Expr::Assign { .. }));
3688 assert!(matches!(s[1], Expr::VerbDef { .. }));
3689 assert!(matches!(monad_of(&s[2]).0, Verb::Reduce(_)));
3690 let s = stmts("f =. +/\nf =. 10 20\nf");
3691 assert!(matches!(s[0], Expr::VerbDef { .. }));
3692 assert!(matches!(s[1], Expr::Assign { .. }));
3693 assert!(matches!(s[2], Expr::Name(..)));
3694 }
3695
3696 #[test]
3697 fn an_undefined_name_applied_as_a_verb_is_a_value_error() {
3698 let e = err("zz 1 2 3");
3700 assert_eq!(e.kind, ErrorKind::Value);
3701 assert_eq!(e.msg, "undefined name: zz");
3702 assert_eq!(e.span, Some(Span::new(0, 2)));
3703 let e = err("a =. 5\na 1 2 3");
3706 assert_eq!(e.kind, ErrorKind::Parse);
3707 assert_eq!(e.msg, "syntax error");
3708 }
3709
3710 #[test]
3711 fn assignment_names_an_adverb_or_a_conjunction() {
3712 match one("insert =. /") {
3713 Expr::ModDef { name, spelling, conjunction, .. } => {
3714 assert_eq!(name, "insert");
3715 assert_eq!(spelling, "/");
3716 assert!(!conjunction);
3717 }
3718 other => panic!("expected a modifier definition, got {other:?}"),
3719 }
3720 match one("atop =. @") {
3721 Expr::ModDef { spelling, conjunction, .. } => {
3722 assert_eq!(spelling, "@");
3723 assert!(conjunction);
3724 }
3725 other => panic!("expected a modifier definition, got {other:?}"),
3726 }
3727 let s = stmts("insert =. /\n+ insert 1 2 3");
3730 assert!(matches!(s[1], Expr::Monad { verb: Verb::Reduce(_), .. }), "{:?}", s[1]);
3731 }
3732
3733 #[test]
3734 fn a_sentence_that_is_a_modifier_is_a_named_gap() {
3735 let e = err("insert =. /\ninsert");
3736 assert_eq!(e.kind, ErrorKind::NotYet);
3737 assert!(e.msg.contains("displaying a modifier"), "{}", e.msg);
3738 }
3739
3740 #[rstest]
3741 #[case("f =. 3 : 'y + 1'", None)]
3742 #[case("f =. 4 : 'x + y'", Some("x"))]
3743 #[case("f =. {{ y + 1 }}", None)]
3744 #[case("f =. {{ x + y }}", Some("x"))]
3745 fn an_explicit_definition_names_a_verb(#[case] src: &str, #[case] left: Option<&str>) {
3746 match one(src) {
3747 Expr::VerbDef { name, verb: Verb::Explicit(d), .. } => {
3748 assert_eq!(name, "f");
3749 assert_eq!(d.left.as_deref(), left);
3750 assert_eq!(d.right, "y");
3751 assert_eq!(d.body.len(), 1);
3752 }
3753 other => panic!("expected an explicit verb definition, got {other:?}"),
3754 }
3755 }
3756
3757 #[rstest]
3758 #[case("f =. 13 : 'y + 1'", "tacit definitions")]
3759 fn definition_forms_libjay_has_not_are_named(#[case] src: &str, #[case] msg: &str) {
3760 let e = err(src);
3761 assert_eq!(e.kind, ErrorKind::NotYet);
3762 assert!(e.msg.contains(msg), "{}", e.msg);
3763 }
3764
3765 #[rstest]
3768 #[case("f =. 1 : 'y + 1'", Some(false))]
3769 #[case("f =. 2 : 'u v y'", Some(true))]
3770 #[case("f =. {{ y + 1 }}", None)]
3771 #[case("f =. {{ u y }}", Some(false))]
3772 #[case("f =. {{ m + y }}", Some(false))]
3773 #[case("f =. {{ u v y }}", Some(true))]
3774 #[case("f =. {{ v y }}", Some(true))]
3775 #[case("f =. {{ n + y }}", Some(true))]
3776 #[case("f =. {{ u n y }}", Some(true))]
3777 #[case("f =. {{)a\nu y\n}}", Some(false))]
3778 #[case("f =. {{)c\nu v y\n}}", Some(true))]
3779 #[case("f =. {{)v\ny\n}}", None)]
3780 fn an_explicit_definitions_part_of_speech(#[case] src: &str, #[case] want: Option<bool>) {
3781 match (one(src), want) {
3782 (Expr::ModDef { name, conjunction, .. }, Some(conj)) => {
3783 assert_eq!(name, "f");
3784 assert_eq!(conjunction, conj, "{src:?}");
3785 }
3786 (Expr::VerbDef { name, .. }, None) => assert_eq!(name, "f"),
3787 (other, _) => panic!("expected {want:?} for {src:?}, got {other:?}"),
3788 }
3789 }
3790
3791 #[test]
3792 fn a_control_word_outside_a_definition_is_a_parse_error() {
3793 let e = err("if. 1 do. 2 end.");
3794 assert_eq!(e.kind, ErrorKind::Parse);
3795 assert!(e.msg.contains("only meaningful inside an explicit definition"), "{}", e.msg);
3796 }
3797
3798 #[test]
3799 fn multiple_assignment_is_not_supported_yet() {
3800 let e = err("'a b' =. 1 2");
3801 assert_eq!(e.kind, ErrorKind::NotYet);
3802 assert!(e.msg.contains("multiple assignment"), "{}", e.msg);
3803 }
3804
3805 #[test]
3808 fn a_hole_is_a_noun() {
3809 let e = one("{a} + 1");
3810 let (_, x, y) = dyad_of(&e);
3811 match x {
3812 Expr::Param(i, s) => {
3813 assert_eq!(i, 0);
3814 assert_eq!(s, Span::new(0, 3));
3815 }
3816 other => panic!("expected a parameter, got {other:?}"),
3817 }
3818 assert_eq!(ints(&y), vec![1]);
3819 assert_eq!(e.span(), Span::new(0, 7));
3820 }
3821
3822 #[test]
3823 fn holes_are_numbered_and_shared_by_name() {
3824 let sp = SourceParts::from_source("{a} + {b} + {a}").expect("source parts");
3825 assert_eq!(sp.param_names, vec!["a".to_string(), "b".to_string()]);
3826 let e = parse(&sp).expect("parse").pop().expect("one sentence");
3827 let (_, x, y) = dyad_of(&e);
3828 assert!(matches!(x, Expr::Param(0, _)));
3829 let (_, x2, y2) = dyad_of(&y);
3830 assert!(matches!(x2, Expr::Param(1, _)));
3831 assert!(matches!(y2, Expr::Param(0, _)));
3832 }
3833
3834 #[rstest]
3835 #[case("3j4", 3.0, 4.0)]
3836 #[case("_1j_2", -1.0, -2.0)]
3837 #[case("1e1j2", 10.0, 2.0)]
3838 #[case("2ad90", 0.0, 2.0)]
3839 #[case("1ad180", -1.0, 0.0)]
3840 fn complex_literals(#[case] src: &str, #[case] re: f64, #[case] im: f64) {
3841 let a = konst(&one(src));
3842 assert_eq!(a.dtype(), DType::Complex);
3843 let z = a.as_complex_slice().expect("complex data")[0];
3844 assert!((z[0] - re).abs() < 1e-12 && (z[1] - im).abs() < 1e-12, "{z:?}");
3845 }
3846
3847 #[test]
3848 fn a_hole_takes_a_verb_like_any_noun() {
3849 let (v, y) = monad_of(&one("+/ {data}"));
3850 assert!(matches!(v, Verb::Reduce(_)));
3851 assert!(matches!(y, Expr::Param(0, _)));
3852 }
3853
3854 #[test]
3855 fn braces_inside_a_string_are_not_holes() {
3856 let sp = SourceParts::from_source("'{a}'").expect("source parts");
3857 assert!(sp.param_names.is_empty());
3858 let a = konst(&parse(&sp).expect("parse")[0]);
3859 assert_eq!(a.data, Data::Char(vec!['{', 'a', '}'].into()));
3860 }
3861
3862 #[test]
3863 fn parts_of_one_sentence_lex_across_a_hole() {
3864 let sp = SourceParts::from_parts(&["1 + ", " * 2"], &["v"]);
3866 assert_eq!(sp.display, "1 + {v} * 2");
3867 let e = parse(&sp).expect("parse").pop().expect("one sentence");
3868 let (_, x, y) = dyad_of(&e);
3869 assert_eq!(ints(&x), vec![1]);
3870 let (_, x2, y2) = dyad_of(&y);
3871 assert!(matches!(x2, Expr::Param(0, _)));
3872 assert_eq!(ints(&y2), vec![2]);
3873 }
3874
3875 #[test]
3876 fn spans_of_later_sentences_index_the_whole_source() {
3877 let src = "5\n1 + 2";
3878 let s = stmts(src);
3879 assert_eq!(s[1].span(), Span::new(2, 7));
3880 assert_eq!(&src[2..7], "1 + 2");
3881 }
3882
3883 #[test]
3886 fn unknown_word_reports_its_span() {
3887 let e = err("1 [. 2");
3888 assert_eq!(e.kind, ErrorKind::Parse);
3889 assert_eq!(e.msg, "unknown word: [.");
3890 assert_eq!(e.span, Some(Span::new(2, 4)));
3891 }
3892
3893 #[test]
3894 fn an_inflected_unknown_word_is_reported_whole() {
3895 let e = err("1 ]: 2");
3896 assert_eq!(e.msg, "unknown word: ]:");
3897 assert_eq!(e.span, Some(Span::new(2, 4)));
3898 }
3899
3900 #[rstest]
3902 #[case("1.5x", 0, 4)]
3903 #[case("1e10x", 0, 5)]
3904 fn a_fractional_extended_literal_is_ill_formed(
3905 #[case] src: &str,
3906 #[case] start: usize,
3907 #[case] end: usize,
3908 ) {
3909 let e = err(src);
3910 assert_eq!(e.kind, ErrorKind::Parse);
3911 assert!(e.msg.contains("invalid number"), "{}", e.msg);
3912 assert_eq!(e.span, Some(Span::new(start, end)));
3913 }
3914
3915 #[test]
3916 fn a_malformed_number_is_a_parse_error() {
3917 let e = err("1.2.3");
3918 assert_eq!(e.kind, ErrorKind::Parse);
3919 assert!(e.msg.contains("invalid number"), "{}", e.msg);
3920 }
3921
3922 #[test]
3923 fn an_unbalanced_sentence_is_a_syntax_error() {
3924 let e = err("(1 + 2");
3927 assert_eq!(e.kind, ErrorKind::Parse);
3928 assert!(e.msg.contains("no closing"), "{}", e.msg);
3929 assert_eq!(e.span, Some(Span::new(0, 1)));
3930 }
3931
3932 #[test]
3933 fn a_stray_right_parenthesis_is_a_syntax_error() {
3934 let e = err("1 + 2)");
3935 assert_eq!(e.kind, ErrorKind::Parse);
3936 assert!(e.msg.contains("no opening"), "{}", e.msg);
3937 assert_eq!(e.span, Some(Span::new(5, 6)));
3938 }
3939
3940 #[test]
3941 fn the_error_of_a_later_sentence_points_at_that_sentence() {
3942 let e = err("1 + 2\n3 [. 4");
3943 assert_eq!(e.span, Some(Span::new(8, 10)));
3944 }
3945}