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 result: None,
506 locals: Vec::new(),
507 body: stmts,
508 labels: Vec::new(),
510 empty: Some(crate::ir::empty_result()),
511 pure,
512 })))
513}
514
515#[derive(Debug)]
525struct ModSource {
526 name: String,
528 conjunction: bool,
530 body: Vec<Vec<Frag>>,
531 deferred: bool,
535 dyadic: bool,
537 self_name: Option<String>,
540}
541
542fn mod_source(
543 name: &str,
544 conjunction: bool,
545 body: Vec<Vec<Frag>>,
546 self_name: Option<&str>,
547) -> ModSource {
548 let dyadic = mentions(&body, "x");
549 ModSource {
550 name: name.to_string(),
551 conjunction,
552 deferred: dyadic || mentions(&body, "y"),
553 dyadic,
554 self_name: self_name.map(str::to_string),
555 body,
556 }
557}
558
559thread_local! {
560 static DERIVING: std::cell::RefCell<Vec<usize>> = const { std::cell::RefCell::new(Vec::new()) };
564}
565
566struct Deriving;
569
570impl Drop for Deriving {
571 fn drop(&mut self) {
572 DERIVING.with(|d| {
573 d.borrow_mut().pop();
574 });
575 }
576}
577
578fn derive_explicit(
586 src: &Arc<ModSource>,
587 u: Frag,
588 v: Option<Frag>,
589 scope: &Names,
590 span: Span,
591) -> Result<Frag> {
592 let addr = Arc::as_ptr(src) as usize;
593 let recursive = DERIVING.with(|d| {
594 let mut d = d.borrow_mut();
595 if d.contains(&addr) {
596 return true;
597 }
598 d.push(addr);
599 false
600 });
601 if recursive {
602 return Err(Error::not_yet(
603 "an explicit modifier whose body derives the modifier itself",
604 span,
605 ));
606 }
607 let _guard = Deriving;
608 let mut body = src.body.clone();
609 bind_operand(&mut body, "u", "m", &u);
610 if let Some(v) = &v {
611 bind_operand(&mut body, "v", "n", v);
612 }
613 let mut inner = scope.clone();
617 if let Some(n) = &src.self_name {
618 inner.verbs.remove(n);
619 inner.nouns.remove(n);
620 inner.consts.remove(n);
621 inner.mods.insert(n.clone(), (src.conjunction, Modifier::Explicit(Arc::clone(src))));
622 }
623 if src.deferred {
624 let verb = build_definition(body, src.dyadic, &src.name, &inner, None)?;
625 return Ok(Frag::Verb(VerbFrag::V(verb), span));
626 }
627 let mut lines: Vec<Vec<Frag>> = Vec::new();
630 let mut k = 0usize;
631 while k < body.len() {
632 let line = collect_definitions(&body, &mut k, &mut inner, false)?;
633 if !line.is_empty() {
634 lines.push(line);
635 }
636 }
637 if lines.len() != 1 {
638 return Err(Error::not_yet(
639 "an explicit modifier that names no argument and is more than one sentence",
640 span,
641 ));
642 }
643 let mut sentence = lines.pop().expect("checked length");
644 substitute_names(&mut sentence, &inner.verbs, &inner.mods);
645 match reduce_to_fragment(sentence, &inner)? {
646 Some(f) if f.is_real_verb() || f.is_noun() => Ok(respan(f, span)),
647 Some(f) => Err(Error::not_yet(
648 format!("an explicit modifier that produces {}", part_of_speech(&f)),
649 span,
650 )),
651 None => Err(Error::parse("syntax error", span)),
652 }
653}
654
655fn part_of_speech(f: &Frag) -> &'static str {
657 match f {
658 Frag::Adverb(..) => "an adverb",
659 Frag::Conj(..) => "a conjunction",
660 _ => "no value",
661 }
662}
663
664fn bind_operand(body: &mut [Vec<Frag>], verb_name: &str, noun_name: &str, operand: &Frag) {
669 let wanted = if operand.is_real_verb() { verb_name } else { noun_name };
670 for line in body.iter_mut() {
671 for i in 0..line.len() {
672 let Frag::Name(n, span) = &line[i] else { continue };
673 if n != wanted {
674 continue;
675 }
676 let span = *span;
677 if line.get(i + 1).is_some_and(Frag::is_assign) {
679 continue;
680 }
681 line[i] = respan(operand.clone(), span);
682 }
683 }
684}
685
686fn block_is_pure(e: &Expr) -> bool {
688 match e {
689 Expr::Const(..) | Expr::Param(..) | Expr::Name(..) => true,
690 Expr::Monad { verb, y, .. } => verb.is_pure() && block_is_pure(y),
691 Expr::Dyad { verb, x, y, .. } => {
692 verb.is_pure() && block_is_pure(x) && block_is_pure(y)
693 }
694 Expr::Assign { value, .. } => block_is_pure(value),
695 Expr::Control(c, _) => control_is_pure(c),
696 _ => false,
697 }
698}
699
700fn control_is_pure(c: &Control) -> bool {
701 let all = |b: &Vec<Expr>| b.iter().all(block_is_pure);
702 match c {
703 Control::Return | Control::Break | Control::Continue => true,
704 Control::Branch(target) => block_is_pure(target),
707 Control::If { arms, otherwise } => {
708 arms.iter().all(|a| {
709 a.test.as_ref().is_none_or(all) && all(&a.body)
710 }) && otherwise.as_ref().is_none_or(all)
711 }
712 Control::While { test, body, .. } => all(test) && all(body),
713 Control::For { source, body, .. } => block_is_pure(source) && all(body),
714 Control::Select { subject, cases } => {
715 block_is_pure(subject)
716 && cases.iter().all(|c| c.test.as_ref().is_none_or(all) && all(&c.body))
717 }
718 Control::Try { body, catch } => all(body) && all(catch),
719 }
720}
721
722fn split_items(lines: &[Vec<Frag>]) -> Vec<Item> {
724 let mut items = Vec::new();
725 for line in lines {
726 let mut run: Vec<Frag> = Vec::new();
727 for f in line {
728 match f {
729 Frag::Control(word, suffix, span) => {
730 if !run.is_empty() {
731 items.push(Item::Sentence(std::mem::take(&mut run)));
732 }
733 items.push(Item::Word {
734 word,
735 suffix: suffix.clone(),
736 span: *span,
737 });
738 }
739 _ => run.push(f.clone()),
740 }
741 }
742 if !run.is_empty() {
743 items.push(Item::Sentence(run));
744 }
745 }
746 items
747}
748
749struct Cursor<'a> {
750 items: &'a [Item],
751 at: usize,
752}
753
754impl<'a> Cursor<'a> {
755 fn peek(&self) -> Option<&'a Item> {
756 self.items.get(self.at)
757 }
758
759 fn peek_word(&self) -> Option<&'static str> {
760 self.peek().and_then(Item::word)
761 }
762
763 fn next(&mut self) -> Option<&'a Item> {
764 let it = self.items.get(self.at);
765 if it.is_some() {
766 self.at += 1;
767 }
768 it
769 }
770
771 fn last_span(&self) -> Span {
772 self.items
773 .get(self.at.saturating_sub(1))
774 .map_or_else(|| Span::new(0, 0), Item::span)
775 }
776
777 fn expect(&mut self, want: &str) -> Result<Span> {
779 match self.peek() {
780 Some(Item::Word { word, span, .. }) if *word == want => {
781 self.at += 1;
782 Ok(*span)
783 }
784 Some(other) => {
785 Err(Error::parse(format!("expected `{want}` here"), other.span()))
786 }
787 None => Err(Error::parse(format!("this block needs a `{want}`"), self.last_span())),
788 }
789 }
790}
791
792fn parse_block(cur: &mut Cursor<'_>, scope: &mut Names, stop: &[&str]) -> Result<Vec<Expr>> {
794 let mut out = Vec::new();
795 loop {
796 match cur.peek() {
797 None => return Ok(out),
798 Some(Item::Word { word, .. }) if stop.contains(word) => return Ok(out),
799 Some(Item::Sentence(frags)) => {
800 cur.at += 1;
801 out.push(scope.parse_sentence(frags.clone())?);
802 }
803 Some(Item::Word { .. }) => out.push(parse_control(cur, scope)?),
804 }
805 }
806}
807
808fn parse_control(cur: &mut Cursor<'_>, scope: &mut Names) -> Result<Expr> {
809 let Some(Item::Word { word, suffix, span }) = cur.next() else {
810 return Err(Error::internal("expected a control word"));
811 };
812 let start = *span;
813 let control = match *word {
814 "if." => parse_if(cur, scope)?,
815 "while." | "whilst." => {
816 let body_first = *word == "whilst.";
817 let test = parse_block(cur, scope, &["do."])?;
818 cur.expect("do.")?;
819 let body = parse_block(cur, scope, &["end."])?;
820 cur.expect("end.")?;
821 Control::While { test, body, body_first, until: false }
822 }
823 "for." => {
824 if let Some(name) = suffix {
825 scope.nouns.insert(name.clone());
826 scope.nouns.insert(format!("{name}_index"));
827 scope.verbs.remove(name);
828 scope.consts.remove(name);
829 }
830 let source = parse_block(cur, scope, &["do."])?;
831 cur.expect("do.")?;
832 let body = parse_block(cur, scope, &["end."])?;
833 let end = cur.expect("end.")?;
834 let source = one_expr(source, Span::merge(start, end))?;
835 Control::For { name: suffix.clone(), source: Box::new(source), body }
836 }
837 "select." => parse_select(cur, scope, start)?,
838 "try." => {
839 let body = parse_block(cur, scope, &["catch.", "catcht.", "end."])?;
840 if cur.peek_word() == Some("catcht.") {
841 return Err(Error::not_yet("throw. and catcht.", cur.last_span()));
842 }
843 let catch = if cur.peek_word() == Some("catch.") {
844 cur.expect("catch.")?;
845 parse_block(cur, scope, &["end."])?
846 } else {
847 Vec::new()
848 };
849 cur.expect("end.")?;
850 Control::Try { body, catch }
851 }
852 "return." => Control::Return,
853 "break." => Control::Break,
854 "continue." => Control::Continue,
855 "throw." | "catcht." => return Err(Error::not_yet("throw. and catcht.", start)),
856 "goto." | "label." => {
857 return Err(Error::not_yet("goto_name. and label_name.", start))
858 }
859 other => {
860 return Err(Error::parse(
861 format!("`{other}` has no matching opening word"),
862 start,
863 ))
864 }
865 };
866 let span = Span::merge(start, cur.last_span());
867 Ok(Expr::Control(Box::new(control), span))
868}
869
870fn parse_if(cur: &mut Cursor<'_>, scope: &mut Names) -> Result<Control> {
871 let mut arms = Vec::new();
872 let mut otherwise = None;
873 loop {
874 let test = parse_block(cur, scope, &["do."])?;
875 cur.expect("do.")?;
876 let body = parse_block(cur, scope, &["elseif.", "else.", "end."])?;
877 arms.push(Branch { test: Some(test), body, fall_through: false });
878 match cur.peek_word() {
879 Some("elseif.") => {
880 cur.at += 1;
881 }
882 Some("else.") => {
883 cur.at += 1;
884 otherwise = Some(parse_block(cur, scope, &["end."])?);
885 cur.expect("end.")?;
886 break;
887 }
888 _ => {
889 cur.expect("end.")?;
890 break;
891 }
892 }
893 }
894 if let Some(last) = arms.last_mut() && last.test.as_ref().is_some_and(Vec::is_empty) {
897 last.test = None;
898 }
899 Ok(Control::If { arms, otherwise })
900}
901
902fn parse_select(cur: &mut Cursor<'_>, scope: &mut Names, start: Span) -> Result<Control> {
903 let subject = parse_block(cur, scope, &["case.", "fcase.", "end."])?;
904 let subject = one_expr(subject, start)?;
905 let mut cases = Vec::new();
906 loop {
907 let fall_through = match cur.peek_word() {
908 Some("case.") => false,
909 Some("fcase.") => true,
910 _ => {
911 cur.expect("end.")?;
912 break;
913 }
914 };
915 cur.at += 1;
916 let test = parse_block(cur, scope, &["do."])?;
917 cur.expect("do.")?;
918 let body = parse_block(cur, scope, &["case.", "fcase.", "end."])?;
919 let test = (!test.is_empty()).then_some(test);
921 cases.push(Branch { test, body, fall_through });
922 }
923 Ok(Control::Select { subject: Box::new(subject), cases })
924}
925
926fn one_expr(mut stmts: Vec<Expr>, span: Span) -> Result<Expr> {
929 match stmts.pop() {
930 Some(e) if stmts.is_empty() => Ok(e),
931 Some(_) => Err(Error::not_yet("several sentences where one value is needed", span)),
932 None => Err(Error::parse("this control word needs a value", span)),
933 }
934}
935
936fn substitute_names(
940 sentence: &mut [Frag],
941 verbs: &HashMap<String, Verb>,
942 mods: &HashMap<String, (bool, Modifier)>,
943) {
944 for i in 0..sentence.len() {
945 let Frag::Name(name, span) = &sentence[i] else { continue };
946 let (name, span) = (name.clone(), *span);
947 if sentence.get(i + 1).is_some_and(Frag::is_assign) {
948 continue;
949 }
950 if let Some(v) = verbs.get(&name) {
951 sentence[i] = Frag::Verb(VerbFrag::V(v.clone()), span);
952 } else if let Some((conj, m)) = mods.get(&name) {
953 sentence[i] = if *conj {
954 Frag::Conj(m.clone(), span)
955 } else {
956 Frag::Adverb(m.clone(), span)
957 };
958 }
959 }
960}
961
962fn assigned_names(e: &Expr, out: &mut Vec<String>) {
964 match e {
965 Expr::Assign { name, value, .. } => {
966 out.push(name.clone());
967 assigned_names(value, out);
968 }
969 Expr::Monad { y, .. } => assigned_names(y, out),
970 Expr::Dyad { x, y, .. } => {
971 assigned_names(x, out);
972 assigned_names(y, out);
973 }
974 Expr::PrintPass { value, .. } => assigned_names(value, out),
975 _ => {}
976 }
977}
978
979#[derive(Clone, Debug)]
985enum Frag {
986 Mark,
988 Noun(Expr),
989 Name(String, Span),
991 Verb(VerbFrag, Span),
992 Adverb(Modifier, Span),
993 Conj(Modifier, Span),
994 LParen(Span),
995 RParen(Span),
996 AssignLocal(Span),
997 AssignGlobal(Span),
998 VerbDef(String, Verb, Span),
1001 ModDef(String, bool, Modifier, Span),
1005 Control(&'static str, Option<String>, Span),
1008 DdOpen(Option<char>, Span),
1011 DdClose(Span),
1012}
1013
1014#[derive(Clone, Debug)]
1017enum VerbFrag {
1018 V(Verb),
1019 Cap,
1020}
1021
1022impl Frag {
1023 fn span(&self) -> Span {
1024 match self {
1025 Frag::Mark => Span::new(0, 0),
1026 Frag::Noun(e) => e.span(),
1027 Frag::Name(_, s)
1028 | Frag::Verb(_, s)
1029 | Frag::Adverb(_, s)
1030 | Frag::Conj(_, s)
1031 | Frag::LParen(s)
1032 | Frag::RParen(s)
1033 | Frag::AssignLocal(s)
1034 | Frag::AssignGlobal(s)
1035 | Frag::DdClose(s)
1036 | Frag::VerbDef(_, _, s)
1037 | Frag::ModDef(_, _, _, s) => *s,
1038 Frag::DdOpen(_, s) => *s,
1039 Frag::Control(_, _, s) => *s,
1040 }
1041 }
1042
1043 fn is_edge(&self) -> bool {
1044 matches!(self, Frag::Mark | Frag::AssignLocal(_) | Frag::AssignGlobal(_) | Frag::LParen(_))
1045 }
1046
1047 fn is_verb(&self) -> bool {
1049 matches!(self, Frag::Verb(..))
1050 }
1051
1052 fn is_real_verb(&self) -> bool {
1054 matches!(self, Frag::Verb(VerbFrag::V(_), _))
1055 }
1056
1057 fn is_noun(&self) -> bool {
1059 matches!(self, Frag::Noun(_) | Frag::Name(..))
1060 }
1061
1062 fn is_adverb(&self) -> bool {
1063 matches!(self, Frag::Adverb(..))
1064 }
1065
1066 fn is_conj(&self) -> bool {
1067 matches!(self, Frag::Conj(..))
1068 }
1069
1070 fn is_avn(&self) -> bool {
1071 self.is_adverb() || self.is_verb() || self.is_noun()
1072 }
1073
1074 fn is_cavn(&self) -> bool {
1075 self.is_conj() || self.is_avn()
1076 }
1077
1078 fn is_assign(&self) -> bool {
1079 matches!(self, Frag::AssignLocal(_) | Frag::AssignGlobal(_))
1080 }
1081}
1082
1083const fn prim(name: &'static str, monad: MonadOp, dyad: DyadOp, ranks: [i64; 3]) -> Prim {
1086 Prim { name, monad, dyad, ranks }
1087}
1088
1089fn primitive(word: &str) -> Option<Prim> {
1093 use DyadOp as D;
1094 use MonadOp as M;
1095 use ScalarDyad as SD;
1096 use ScalarMonad as SM;
1097 const INF: i64 = RANK_INF;
1098 Some(match word {
1099 "+" => prim("+", M::Scalar(SM::Conj), D::Scalar(SD::Add), [0, 0, 0]),
1100 "-" => prim("-", M::Scalar(SM::Neg), D::Scalar(SD::Sub), [0, 0, 0]),
1101 "*" => prim("*", M::Scalar(SM::Signum), D::Scalar(SD::Mul), [0, 0, 0]),
1102 "%" => prim("%", M::Scalar(SM::Recip), D::Scalar(SD::DivJ), [0, 0, 0]),
1103 "^" => prim("^", M::Scalar(SM::Exp), D::Scalar(SD::Pow), [0, 0, 0]),
1104 "%:" => prim("%:", M::Scalar(SM::Sqrt), D::Scalar(SD::Root), [0, 0, 0]),
1105 "^." => prim("^.", M::Scalar(SM::Ln), D::Scalar(SD::Log), [0, 0, 0]),
1106 "|" => prim("|", M::Scalar(SM::Abs), D::Scalar(SD::Residue), [0, 0, 0]),
1107 "<." => prim("<.", M::Scalar(SM::Floor), D::Scalar(SD::Min), [0, 0, 0]),
1108 ">." => prim(">.", M::Scalar(SM::Ceil), D::Scalar(SD::Max), [0, 0, 0]),
1109 "=" => prim("=", M::SelfClassify, D::Scalar(SD::Eq), [INF, 0, 0]),
1110 "<" => prim("<", M::Enclose(Enclose::Always), D::Scalar(SD::Lt), [INF, 0, 0]),
1111 ">" => prim(">", M::Open, D::Scalar(SD::Gt), [0, 0, 0]),
1112 "<:" => prim("<:", M::Scalar(SM::Dec), D::Scalar(SD::Le), [0, 0, 0]),
1113 ">:" => prim(">:", M::Scalar(SM::Inc), D::Scalar(SD::Ge), [0, 0, 0]),
1114 "+:" => prim("+:", M::Scalar(SM::Double), D::Boolean(BoolDyad::Nor), [0, 0, 0]),
1115 "*:" => prim("*:", M::Scalar(SM::Square), D::Boolean(BoolDyad::Nand), [0, 0, 0]),
1116 "-:" => prim("-:", M::Scalar(SM::Halve), D::Match, [0, INF, INF]),
1117 "-." => prim("-.", M::Scalar(SM::OneMinus), D::Less, [0, INF, INF]),
1118 "*." => prim("*.", M::ComplexParts { polar: true }, D::Scalar(SD::Lcm), [0, 0, 0]),
1119 "+." => prim("+.", M::ComplexParts { polar: false }, D::Scalar(SD::Gcd), [0, 0, 0]),
1120 "~:" => prim("~:", M::NubSieve, D::Scalar(SD::Ne), [INF, 0, 0]),
1121 "~." => prim("~.", M::Nub, D::None, [INF, INF, INF]),
1122 "$" => prim("$", M::ShapeOf, D::Reshape, [INF, 1, INF]),
1123 "," => prim(",", M::Ravel, D::AppendLeading, [INF, INF, INF]),
1124 ",." => prim(",.", M::Ravel, D::AppendLeading, [INF, INF, INF]),
1126 ",:" => prim(",:", M::Itemize, D::Laminate, [INF, INF, INF]),
1127 "#" => prim("#", M::Tally, D::Copy, [INF, 1, INF]),
1128 "#." => prim("#.", M::DecodeBits, D::Decode, [1, 1, 1]),
1129 "#:" => prim("#:", M::EncodeBits, D::Encode, [INF, 1, 0]),
1132 "!" => prim("!", M::Scalar(SM::Factorial), D::Scalar(SD::Binomial), [0, 0, 0]),
1133 "\":" => {
1134 prim("\":", M::Format, D::FormatSpecJ, [INF, 1, INF])
1135 }
1136 "o." => prim("o.", M::Scalar(SM::Pi), D::Scalar(SD::Circle), [0, 0, 0]),
1137 "j." => prim("j.", M::Scalar(SM::Imaginary), D::Scalar(SD::MakeComplex), [0, 0, 0]),
1138 "r." => prim("r.", M::Scalar(SM::Polar), D::Scalar(SD::PolarBy), [0, 0, 0]),
1139 "{" => prim("{", M::Catalogue, D::From, [INF, 0, INF]),
1140 "{." => prim("{.", M::Head, D::Take, [INF, 1, INF]),
1141 "}." => prim("}.", M::Behead, D::Drop, [INF, 1, INF]),
1142 "{:" => prim("{:", M::Tail, D::None, [INF, INF, INF]),
1143 "}:" => prim("}:", M::Curtail, D::None, [INF, INF, INF]),
1144 "|." => prim("|.", M::Reverse, D::Rotate, [INF, 1, INF]),
1145 "|:" => prim("|:", M::TransposeAxes, D::TransposeJ, [INF, 1, INF]),
1146 "i." => prim("i.", M::IotaJ, D::IndexOf { origin: 0 }, [1, INF, INF]),
1147 "i:" => prim("i:", M::Steps, D::IndexOfLast { origin: 0 }, [0, INF, INF]),
1148 "I." => prim(
1149 "I.",
1150 M::Indices { origin: 0, boxed_coords: false },
1151 D::IntervalIndex { offset: 0, closed: false },
1152 [1, 1, INF],
1153 ),
1154 "x:" => prim("x:", M::ToExact, D::ExactForm, [INF, 0, INF]),
1157 "p:" => prim("p:", M::NthPrime, D::PrimeMeta, [0, 0, 0]),
1158 "p." => prim("p.", M::PolyRoots, D::PolyEval, [1, 1, 0]),
1161 "p.." => prim("p..", M::PolyDeriv, D::PolyIntegral, [1, 0, 1]),
1162 "$." => prim(
1163 "$.",
1164 M::NotYet("sparse arrays ($.)"),
1165 D::NotYet("sparse arrays ($.)"),
1166 [INF, INF, INF],
1167 ),
1168 "q:" => prim("q:", M::PrimeFactors, D::PrimeExponents, [0, 0, 0]),
1169 "%." => prim("%.", M::MatrixInverse, D::MatrixDivide, [2, INF, 2]),
1170 "?" => prim(
1173 "?",
1174 M::Roll { origin: 0, fixed: false, float_at_zero: true },
1175 D::Deal { origin: 0, fixed: false },
1176 [INF, 0, 0],
1177 ),
1178 "?." => prim(
1179 "?.",
1180 M::Roll { origin: 0, fixed: true, float_at_zero: true },
1181 D::Deal { origin: 0, fixed: true },
1182 [INF, 0, 0],
1183 ),
1184 "{::" => prim("{::", M::MapPaths, D::Fetch, [INF, INF, INF]),
1185 "e." => prim("e.", M::RazeIn, D::MemberJ, [INF, INF, INF]),
1186 "/:" => prim(
1187 "/:",
1188 M::GradeUp { origin: 0 },
1189 D::GradeSelect { down: false },
1190 [INF, INF, INF],
1191 ),
1192 "\\:" => prim(
1193 "\\:",
1194 M::GradeDown { origin: 0 },
1195 D::GradeSelect { down: true },
1196 [INF, INF, INF],
1197 ),
1198 ";" => prim(";", M::Raze, D::Link, [INF, INF, INF]),
1199 ";:" => prim(
1200 ";:",
1201 M::Words,
1202 D::SequentialMachine,
1203 [INF, INF, INF],
1204 ),
1205 "L." => prim("L.", M::LevelOf, D::None, [INF, INF, INF]),
1206 "\"." => prim(
1207 "\".",
1208 M::Execute { apl: false },
1209 D::ParseNumbers,
1210 [1, INF, 1],
1211 ),
1212 "A." => prim("A.", M::AnagramIndex, D::AnagramFrom, [1, 0, INF]),
1213 "C." => prim("C.", M::CycleForm, D::Permute, [INF, INF, INF]),
1214 "E." => prim("E.", M::None, D::FindSeq, [INF, INF, INF]),
1215 "u:" => prim("u:", M::Unicode { pass_chars: true }, D::UnicodeForm, [INF, 0, INF]),
1216 "s:" => prim("s:", M::Symbols, D::SymbolForm, [INF, 0, INF]),
1219 "]" => prim("]", M::Same, D::Right, [INF, INF, INF]),
1220 "[" => prim("[", M::Same, D::Left, [INF, INF, INF]),
1221 "echo" => prim("echo", M::Echo, D::None, [INF, INF, INF]),
1222 _ => return None,
1223 })
1224}
1225
1226fn noun_word(word: &str) -> Option<Array> {
1231 match word {
1232 "a." => Some(Array::from_chars(
1233 (0u32..256).map(|c| char::from_u32(c).expect("a Latin-1 codepoint")).collect(),
1234 )),
1235 "a:" => Some(Array::boxed(Array::empty(crate::dtype::DType::I64))),
1236 "_." => Some(Array::scalar_f64(f64::NAN)),
1237 _ => None,
1238 }
1239}
1240
1241fn verb_for(word: &str) -> Option<Verb> {
1244 let p = primitive(word)?;
1245 if word == ",." {
1246 return Some(Verb::Rank(Box::new(Verb::Prim(p)), [-1, -1, -1]));
1247 }
1248 Some(Verb::Prim(p))
1249}
1250
1251fn constant_verb(n: Array) -> Verb {
1254 Verb::NounFork(
1257 n,
1258 Box::new(verb_for("[").expect("`[` is a primitive")),
1259 Box::new(verb_for("]").expect("`]` is a primitive")),
1260 )
1261}
1262
1263fn constant_verb_word(cs: &[(usize, char)], i: usize) -> Option<(usize, Array)> {
1267 let at = |k: usize| cs.get(k).map(|&(_, c)| c);
1268 let (digits, value) = match (at(i), at(i + 1), at(i + 2)) {
1269 (Some('_'), Some(':'), _) => (2, f64::INFINITY),
1270 (Some('_'), Some(d), Some(':')) if d.is_ascii_digit() => {
1271 (3, -((d as u8 - b'0') as f64))
1272 }
1273 (Some(d), Some(':'), _) if d.is_ascii_digit() => (2, (d as u8 - b'0') as f64),
1274 _ => return None,
1275 };
1276 if at(i + digits) == Some(':') {
1277 return None;
1278 }
1279 let arr = if value.is_infinite() {
1280 Array::scalar_f64(value)
1281 } else {
1282 Array::scalar_i64(value as i64)
1283 };
1284 Some((digits, arr))
1285}
1286
1287pub(crate) fn verb_named(word: &str) -> Option<Verb> {
1290 verb_for(word)
1291}
1292
1293const ADVERBS: [&str; 9] = ["/", "\\", "/.", "\\.", "~", "}", "f.", "M.", "b."];
1294
1295const CONJUNCTIONS: [&str; 24] = [
1298 "\"", "@", "@.", "@:", "&", "&.", "&.:", "&:", "^:", ";.", "!.", "!:", "`", "`:", ".", ":",
1299 ":.", "::", "L:", "S:", "H.", "T.", "t.", "t:",
1300];
1301
1302fn adverb(word: &str) -> Option<&'static str> {
1303 ADVERBS.iter().copied().find(|&g| g == word)
1304}
1305
1306fn conjunction(word: &str) -> Option<&'static str> {
1307 CONJUNCTIONS.iter().copied().find(|&g| g == word)
1308}
1309
1310fn lex(src: &SourceParts) -> Result<Vec<Vec<Frag>>> {
1315 let mut sentences: Vec<Vec<Frag>> = Vec::new();
1316 let mut cur: Vec<Frag> = Vec::new();
1317 for seg in &src.segments {
1318 match seg {
1319 Segment::Text { text, offset } => {
1320 let mut pos = 0usize;
1321 for (n, line) in text.split('\n').enumerate() {
1322 if n > 0 && !cur.is_empty() {
1323 sentences.push(std::mem::take(&mut cur));
1324 }
1325 lex_line(line, offset + pos, &mut cur)?;
1326 pos += line.len() + 1;
1327 }
1328 }
1329 Segment::Param { index, offset, len } => {
1330 let span = Span::new(*offset, *offset + *len);
1331 cur.push(Frag::Noun(Expr::Param(*index, span)));
1332 }
1333 }
1334 }
1335 if !cur.is_empty() {
1336 sentences.push(cur);
1337 }
1338 Ok(sentences)
1339}
1340
1341#[derive(Clone, Debug)]
1344enum Num {
1345 I(i64),
1346 F(f64),
1347 X(crate::exact::Ext),
1349 R(crate::exact::Rat),
1351 C(crate::complex::Cx),
1352}
1353
1354fn lex_line(text: &str, base: usize, out: &mut Vec<Frag>) -> Result<()> {
1355 let cs: Vec<(usize, char)> = text.char_indices().collect();
1356 let at = |i: usize| cs.get(i).map(|&(_, c)| c);
1357 let off = |i: usize| cs.get(i).map(|&(o, _)| o).unwrap_or(text.len());
1358 let span = |a: usize, b: usize| Span::new(base + off(a), base + off(b));
1359 let mut i = 0usize;
1360 while i < cs.len() {
1361 let c = cs[i].1;
1362 if c.is_whitespace() {
1363 i += 1;
1364 continue;
1365 }
1366 if c == 'N' && at(i + 1) == Some('B') && at(i + 2) == Some('.') {
1369 break;
1370 }
1371 if c == '\'' {
1372 let start = i;
1373 i += 1;
1374 let mut chars: Vec<char> = Vec::new();
1375 loop {
1376 match at(i) {
1377 None => {
1378 return Err(Error::parse(
1379 "unterminated string literal",
1380 span(start, cs.len()),
1381 ));
1382 }
1383 Some('\'') if at(i + 1) == Some('\'') => {
1384 chars.push('\'');
1385 i += 2;
1386 }
1387 Some('\'') => {
1388 i += 1;
1389 break;
1390 }
1391 Some(ch) => {
1392 chars.push(ch);
1393 i += 1;
1394 }
1395 }
1396 }
1397 let shape = if chars.len() == 1 { vec![] } else { vec![chars.len()] };
1399 let arr = Array::new(shape, Data::Char(chars.into()));
1400 out.push(Frag::Noun(Expr::Const(arr, span(start, i))));
1401 continue;
1402 }
1403 if let Some((len, n)) = constant_verb_word(&cs, i) {
1404 out.push(Frag::Verb(VerbFrag::V(constant_verb(n)), span(i, i + len)));
1405 i += len;
1406 continue;
1407 }
1408 if starts_number(&cs, i) {
1409 let start = i;
1411 let mut nums: Vec<Num> = Vec::new();
1412 let mut end;
1413 loop {
1414 let ws = i;
1415 while at(i).is_some_and(|c| c.is_ascii_alphanumeric() || c == '.' || c == '_') {
1416 i += 1;
1417 }
1418 nums.push(parse_number(&text[off(ws)..off(i)], span(ws, i))?);
1419 end = i;
1420 let mut k = i;
1421 while at(k).is_some_and(char::is_whitespace) {
1422 k += 1;
1423 }
1424 if k < cs.len()
1427 && starts_number(&cs, k)
1428 && constant_verb_word(&cs, k).is_none()
1429 {
1430 i = k;
1431 } else {
1432 break;
1433 }
1434 }
1435 out.push(Frag::Noun(Expr::Const(num_array(&nums), span(start, end))));
1436 continue;
1437 }
1438 if c.is_ascii_alphabetic() {
1439 let start = i;
1440 i += 1;
1441 while at(i).is_some_and(|c| c.is_ascii_alphanumeric() || c == '_') {
1442 i += 1;
1443 }
1444 let mut inflected = None;
1449 if matches!(at(i), Some('.') | Some(':')) {
1450 let most = if matches!(at(i + 1), Some('.') | Some(':')) { 2 } else { 1 };
1451 for n in (1..=most).rev() {
1452 let word = &text[off(start)..off(i + n)];
1453 let sp = span(start, i + n);
1454 let frag = if let Some(v) = verb_for(word) {
1455 Frag::Verb(VerbFrag::V(v), sp)
1456 } else if let Some(value) = noun_word(word) {
1457 Frag::Noun(Expr::Const(value, sp))
1458 } else if let Some(g) = adverb(word) {
1459 Frag::Adverb(Modifier::Prim(g), sp)
1460 } else if let Some(g) = conjunction(word) {
1461 Frag::Conj(Modifier::Prim(g), sp)
1462 } else if let Some((cw, suffix)) = control_word(word) {
1463 Frag::Control(cw, suffix, sp)
1464 } else {
1465 continue;
1466 };
1467 inflected = Some((frag, n));
1468 break;
1469 }
1470 }
1471 if let Some((frag, n)) = inflected {
1472 i += n;
1473 out.push(frag);
1474 continue;
1475 }
1476 let word = &text[off(start)..off(i)];
1477 match verb_for(word) {
1478 Some(v) => out.push(Frag::Verb(VerbFrag::V(v), span(start, i))),
1479 None => out.push(Frag::Name(word.to_string(), span(start, i))),
1480 }
1481 continue;
1482 }
1483 if c == '{' && at(i + 1) == Some('{') {
1485 let marker = match (at(i + 2), at(i + 3)) {
1490 (Some(')'), Some(m)) if m.is_ascii_alphabetic() => Some(m),
1491 _ => None,
1492 };
1493 if let Some(m) = marker {
1494 if cs[i + 4..].iter().any(|&(_, c)| !c.is_whitespace()) {
1495 return Err(Error::parse(
1496 format!("`)`{m} names the part of speech of a direct definition, \
1497 and has to be the last thing on its line"),
1498 span(i, i + 4),
1499 ));
1500 }
1501 out.push(Frag::DdOpen(Some(m), span(i, i + 4)));
1502 i += 4;
1503 continue;
1504 }
1505 out.push(Frag::DdOpen(None, span(i, i + 2)));
1506 i += 2;
1507 continue;
1508 }
1509 if c == '}' && at(i + 1) == Some('}') {
1510 out.push(Frag::DdClose(span(i, i + 2)));
1511 i += 2;
1512 continue;
1513 }
1514 let inflectable = c != '(' && c != ')';
1518 let mut len =
1519 if inflectable && matches!(at(i + 1), Some('.') | Some(':')) { 2 } else { 1 };
1520 if len == 2 && at(i + 2) == Some(':') {
1523 let w = &text[off(i)..off(i + 3)];
1524 if conjunction(w).is_some() || verb_for(w).is_some() {
1525 len = 3;
1526 }
1527 }
1528 let word = &text[off(i)..off(i + len)];
1529 match symbol_frag(word, span(i, i + len)) {
1530 Some(frag) => {
1531 out.push(frag);
1532 i += len;
1533 }
1534 None => {
1535 return Err(Error::parse(format!("unknown word: {word}"), span(i, i + len)));
1536 }
1537 }
1538 }
1539 Ok(())
1540}
1541
1542fn symbol_frag(word: &str, span: Span) -> Option<Frag> {
1543 Some(match word {
1544 "(" => Frag::LParen(span),
1545 ")" => Frag::RParen(span),
1546 "=." => Frag::AssignLocal(span),
1547 "=:" => Frag::AssignGlobal(span),
1548 "[:" => Frag::Verb(VerbFrag::Cap, span),
1549 "$:" => Frag::Verb(VerbFrag::V(Verb::SelfRef), span),
1551 _ => {
1554 if let Some(v) = verb_for(word) {
1555 Frag::Verb(VerbFrag::V(v), span)
1556 } else if let Some(g) = adverb(word) {
1557 Frag::Adverb(Modifier::Prim(g), span)
1558 } else {
1559 Frag::Conj(Modifier::Prim(conjunction(word)?), span)
1560 }
1561 }
1562 })
1563}
1564
1565fn starts_number(cs: &[(usize, char)], i: usize) -> bool {
1568 let c = cs[i].1;
1569 if c.is_ascii_digit() {
1570 return true;
1571 }
1572 if c != '_' {
1573 return false;
1574 }
1575 match cs.get(i + 1).map(|&(_, c)| c) {
1576 None => true,
1577 Some(d) => d.is_ascii_digit() || d == '.' || !d.is_alphanumeric(),
1578 }
1579}
1580
1581fn parse_number(word: &str, span: Span) -> Result<Num> {
1582 if word == "_." {
1584 return Ok(Num::F(f64::NAN));
1585 }
1586 if let Some(k) = word.find(['p', 'x']) {
1590 if word[k + 1..].is_empty() {
1591 if word.as_bytes()[k] == b'x' {
1595 return extended_literal(&word[..k], word, span);
1596 }
1597 return Err(Error::parse(format!("invalid number: {word}"), span));
1598 }
1599 let base =
1600 if word.as_bytes()[k] == b'p' { std::f64::consts::PI } else { std::f64::consts::E };
1601 let mantissa = plain_number(&word[..k], word, span)?;
1602 let exponent = plain_number(&word[k + 1..], word, span)?;
1603 return Ok(scale(mantissa, base, exponent));
1604 }
1605 if let Some(k) = word.find('j') && !word[..k].contains('b') {
1608 let re = as_f64(plain_number(&word[..k], word, span)?);
1609 let im = as_f64(plain_number(&word[k + 1..], word, span)?);
1610 return Ok(Num::C([re, im]));
1611 }
1612 if let Some(k) = word.find("ad").or_else(|| word.find("ar")) && !word[..k].contains('b') {
1615 let magnitude = as_f64(plain_number(&word[..k], word, span)?);
1616 let angle = as_f64(plain_number(&word[k + 2..], word, span)?);
1617 return Ok(Num::C(if word.as_bytes()[k + 1] == b'd' {
1618 crate::complex::from_degrees(magnitude, angle)
1619 } else {
1620 crate::complex::from_radians(magnitude, angle)
1621 }));
1622 }
1623 if let Some(k) = word.find('r') && !word[..k].contains('b') {
1627 return rational_literal(&word[..k], &word[k + 1..], word, span);
1628 }
1629 if let Some(k) = word.find('b') {
1630 return base_literal(&word[..k], &word[k + 1..], word, span);
1631 }
1632 plain_number(word, word, span)
1633}
1634
1635fn extended_literal(digits: &str, word: &str, span: Span) -> Result<Num> {
1638 Ok(Num::X(whole_digits(digits, word, span)?))
1639}
1640
1641fn rational_literal(num: &str, den: &str, word: &str, span: Span) -> Result<Num> {
1644 use num_traits::Zero;
1645 let num = whole_digits(num, word, span)?;
1646 let den = whole_digits(den, word, span)?;
1647 if den.is_zero() {
1648 if num.is_zero() {
1649 return Ok(Num::I(0));
1650 }
1651 return Ok(Num::F(if num.sign() == num_bigint::Sign::Minus {
1652 f64::NEG_INFINITY
1653 } else {
1654 f64::INFINITY
1655 }));
1656 }
1657 Ok(Num::R(
1658 crate::exact::Rat::new(num, den).ok_or_else(|| Error::internal("a zero denominator"))?,
1659 ))
1660}
1661
1662fn whole_digits(word: &str, whole: &str, span: Span) -> Result<crate::exact::Ext> {
1664 let invalid = || Error::parse(format!("invalid number: {whole}"), span);
1665 let (digits, negative) = match word.strip_prefix('_') {
1666 Some(rest) => (rest, true),
1667 None => (word, false),
1668 };
1669 if digits.is_empty() || !digits.bytes().all(|b| b.is_ascii_digit()) {
1670 return Err(invalid());
1671 }
1672 let v: crate::exact::Ext = digits.parse().map_err(|_| invalid())?;
1673 Ok(if negative { -v } else { v })
1674}
1675
1676fn scale(mantissa: Num, base: f64, exponent: Num) -> Num {
1679 if matches!(mantissa, Num::C(_)) || matches!(exponent, Num::C(_)) {
1680 let m = as_cx(mantissa);
1681 let f = crate::complex::pow([base, 0.0], as_cx(exponent));
1682 return Num::C(crate::complex::mul(m, f));
1683 }
1684 Num::F(as_f64(mantissa) * base.powf(as_f64(exponent)))
1685}
1686
1687fn as_cx(n: Num) -> crate::complex::Cx {
1688 match n {
1689 Num::C(z) => z,
1690 other => [as_f64(other), 0.0],
1691 }
1692}
1693
1694fn as_f64(n: Num) -> f64 {
1695 match n {
1696 Num::I(v) => v as f64,
1697 Num::F(v) => v,
1698 Num::X(v) => crate::exact::ext_to_f64(&v),
1699 Num::R(v) => v.to_f64(),
1700 Num::C(z) => z[0],
1703 }
1704}
1705
1706fn base_literal(base: &str, digits: &str, word: &str, span: Span) -> Result<Num> {
1709 let invalid = || Error::parse(format!("invalid number: {word}"), span);
1710 let base = as_f64(plain_number(base, word, span)?);
1711 let (digits, negative) = match digits.strip_prefix('_') {
1712 Some(rest) => (rest, true),
1713 None => (digits, false),
1714 };
1715 if digits.is_empty() {
1716 return Err(invalid());
1717 }
1718 let mut value = 0.0f64;
1719 for ch in digits.chars() {
1720 let d = match ch {
1721 '0'..='9' => ch as u32 - '0' as u32,
1722 'a'..='z' => ch as u32 - 'a' as u32 + 10,
1723 _ => return Err(invalid()),
1724 };
1725 value = value * base + f64::from(d);
1726 }
1727 if negative {
1728 value = -value;
1729 }
1730 if value.fract() == 0.0 && value.abs() < 9.007_199_254_740_992e15 {
1732 return Ok(Num::I(value as i64));
1733 }
1734 Ok(Num::F(value))
1735}
1736
1737fn plain_number(word: &str, whole: &str, span: Span) -> Result<Num> {
1741 if word.is_empty() {
1742 return Err(Error::parse(format!("invalid number: {whole}"), span));
1743 }
1744 if word.contains(['j', 'p', 'x', 'b', 'r']) || word.contains("ad") || word.contains("ar") {
1745 return parse_number(word, span);
1746 }
1747 parse_plain(word, span)
1748}
1749
1750fn parse_plain(word: &str, span: Span) -> Result<Num> {
1751 if word == "_" {
1752 return Ok(Num::F(f64::INFINITY));
1753 }
1754 if word == "__" {
1755 return Ok(Num::F(f64::NEG_INFINITY));
1756 }
1757 let invalid = || Error::parse(format!("invalid number: {word}"), span);
1758 let mut norm = String::with_capacity(word.len());
1760 for (k, ch) in word.char_indices() {
1761 if ch == '_' {
1762 if k != 0 && !word[..k].ends_with('e') {
1763 return Err(invalid());
1764 }
1765 norm.push('-');
1766 } else {
1767 norm.push(ch);
1768 }
1769 }
1770 if norm.contains('.') || norm.contains('e') {
1772 return norm.parse::<f64>().map(Num::F).map_err(|_| invalid());
1773 }
1774 match norm.parse::<i64>() {
1777 Ok(v) => Ok(Num::I(v)),
1778 Err(_) => norm.parse::<f64>().map(Num::F).map_err(|_| invalid()),
1779 }
1780}
1781
1782pub(crate) fn numbers_from_text(line: &str, fallback: &Array) -> Option<Array> {
1796 let stand_in = match &fallback.data {
1797 Data::Bool(v) => Num::I(i64::from(*v.as_slice().first()?)),
1798 Data::I64(v) => Num::I(*v.as_slice().first()?),
1799 Data::F64(v) => Num::F(*v.as_slice().first()?),
1800 Data::Ext(v) => Num::X(v.as_slice().first()?.clone()),
1801 Data::Rat(v) => Num::R(v.as_slice().first()?.clone()),
1802 Data::Complex(v) => Num::C(*v.as_slice().first()?),
1803 Data::Char(_) | Data::Symbol(_) | Data::Box(_) => return None,
1804 };
1805 let nums: Vec<Num> = line
1806 .split_whitespace()
1807 .map(|w| parse_number(w, Span::new(0, 0)).unwrap_or_else(|_| stand_in.clone()))
1808 .collect();
1809 Some(num_array(&nums))
1810}
1811
1812fn num_array(nums: &[Num]) -> Array {
1813 use crate::exact::{Ext, Rat};
1814 let shape = if nums.len() == 1 { vec![] } else { vec![nums.len()] };
1815 let has = |f: fn(&Num) -> bool| nums.iter().any(f);
1816 if has(|n| matches!(n, Num::C(_))) {
1817 let data = nums.iter().map(|n| as_cx(n.clone())).collect();
1818 return Array::new(shape, Data::Complex(data));
1819 }
1820 if has(|n| matches!(n, Num::F(_))) {
1821 let data = nums.iter().map(|n| as_f64(n.clone())).collect();
1822 return Array::new(shape, Data::F64(data));
1823 }
1824 if has(|n| matches!(n, Num::R(_))) {
1825 let data = nums
1826 .iter()
1827 .map(|n| match n {
1828 Num::I(v) => Rat::from_int(Ext::from(*v)),
1829 Num::X(v) => Rat::from_int(v.clone()),
1830 Num::R(v) => v.clone(),
1831 Num::F(_) | Num::C(_) => Rat::zero(),
1832 })
1833 .collect();
1834 return Array::new(shape, Data::Rat(data));
1835 }
1836 if has(|n| matches!(n, Num::X(_))) {
1837 let data = nums
1838 .iter()
1839 .map(|n| match n {
1840 Num::I(v) => Ext::from(*v),
1841 Num::X(v) => v.clone(),
1842 _ => Ext::default(),
1843 })
1844 .collect();
1845 return Array::new(shape, Data::Ext(data));
1846 }
1847 let data = nums
1848 .iter()
1849 .map(|n| match n {
1850 Num::I(v) => *v,
1851 _ => 0,
1852 })
1853 .collect();
1854 Array::new(shape, Data::I64(data))
1855}
1856
1857#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1860enum Rule {
1861 Monad1,
1862 Monad2,
1863 Dyad3,
1864 Adverb4,
1865 Conj5,
1866 Fork6,
1867 Bident7,
1868 Assign8,
1869 Paren9,
1870}
1871
1872fn reduce_to_fragment(tokens: Vec<Frag>, scope: &Names) -> Result<Option<Frag>> {
1876 check_parens(&tokens)?;
1877 let mut stack: Vec<Frag> = Vec::new();
1878 for frag in tokens.into_iter().rev() {
1879 stack.insert(0, frag);
1880 reduce(&mut stack, scope)?;
1881 }
1882 stack.insert(0, Frag::Mark);
1883 reduce(&mut stack, scope)?;
1884 if stack.len() == 2 {
1885 return Ok(Some(stack.pop().expect("checked length")));
1886 }
1887 Ok(None)
1888}
1889
1890fn lower_sentence(frag: Option<Frag>, whole: Span) -> Result<Expr> {
1893 match frag {
1894 Some(f @ (Frag::Noun(_) | Frag::Name(..))) => as_noun(f),
1895 Some(Frag::VerbDef(name, verb, span)) => Ok(Expr::VerbDef { name, verb, span }),
1896 Some(Frag::ModDef(name, conjunction, m, span)) => {
1897 Ok(Expr::ModDef { name, spelling: m.spelling(), conjunction, span })
1898 }
1899 Some(Frag::Verb(VerbFrag::V(_), span)) => {
1900 Err(Error::not_yet("tacit verb definitions (a sentence that is a verb)", span))
1901 }
1902 Some(Frag::Adverb(_, span) | Frag::Conj(_, span)) => Err(Error::not_yet(
1903 "displaying a modifier (a sentence that is an adverb or a conjunction)",
1904 span,
1905 )),
1906 _ => Err(Error::parse("syntax error", whole)),
1907 }
1908}
1909
1910fn check_parens(tokens: &[Frag]) -> Result<()> {
1914 let mut open: Vec<Span> = Vec::new();
1915 for frag in tokens {
1916 match frag {
1917 Frag::LParen(s) => open.push(*s),
1918 Frag::RParen(s) => {
1919 if open.pop().is_none() {
1920 return Err(Error::parse("this `)` has no opening `(`", *s));
1921 }
1922 }
1923 _ => {}
1924 }
1925 }
1926 match open.pop() {
1927 None => Ok(()),
1928 Some(s) => Err(Error::parse("this `(` has no closing `)`", s)),
1929 }
1930}
1931
1932fn sentence_span(tokens: &[Frag]) -> Span {
1933 tokens
1934 .iter()
1935 .map(Frag::span)
1936 .reduce(Span::merge)
1937 .unwrap_or_else(|| Span::new(0, 0))
1938}
1939
1940fn reduce(stack: &mut Vec<Frag>, scope: &Names) -> Result<()> {
1941 while apply(stack, scope)? {}
1942 Ok(())
1943}
1944
1945fn match_rule(s: &[Frag]) -> Option<Rule> {
1948 let is = |i: usize, f: fn(&Frag) -> bool| s.get(i).is_some_and(f);
1949 let ctx = |i: usize| s.get(i).is_some_and(|f| f.is_edge() || f.is_avn());
1952 let verb_or_noun =
1953 |i: usize| s.get(i).is_some_and(|f| f.is_real_verb() || f.is_noun());
1954 if is(0, Frag::is_edge) && is(1, Frag::is_real_verb) && is(2, Frag::is_noun) {
1955 return Some(Rule::Monad1);
1956 }
1957 if ctx(0) && is(1, Frag::is_verb) && is(2, Frag::is_real_verb) && is(3, Frag::is_noun) {
1958 return Some(Rule::Monad2);
1959 }
1960 if ctx(0) && is(1, Frag::is_noun) && is(2, Frag::is_real_verb) && is(3, Frag::is_noun) {
1961 return Some(Rule::Dyad3);
1962 }
1963 if ctx(0) && verb_or_noun(1) && is(2, Frag::is_adverb) {
1964 return Some(Rule::Adverb4);
1965 }
1966 if ctx(0) && verb_or_noun(1) && is(2, Frag::is_conj) && verb_or_noun(3) {
1967 return Some(Rule::Conj5);
1968 }
1969 if ctx(0)
1970 && s.get(1).is_some_and(|f| f.is_verb() || f.is_noun())
1971 && is(2, Frag::is_real_verb)
1972 && is(3, Frag::is_real_verb)
1973 {
1974 return Some(Rule::Fork6);
1975 }
1976 if is(0, Frag::is_edge) && is(1, Frag::is_cavn) && is(2, Frag::is_cavn) {
1977 return Some(Rule::Bident7);
1978 }
1979 if is(0, Frag::is_noun) && is(1, Frag::is_assign) && is(2, Frag::is_cavn) {
1980 return Some(Rule::Assign8);
1981 }
1982 if matches!(s.first(), Some(Frag::LParen(_)))
1983 && is(1, Frag::is_cavn)
1984 && matches!(s.get(2), Some(Frag::RParen(_)))
1985 {
1986 return Some(Rule::Paren9);
1987 }
1988 None
1989}
1990
1991fn take(stack: &mut Vec<Frag>, range: Range<usize>) -> Vec<Frag> {
1992 stack.drain(range).collect()
1993}
1994
1995fn respan(f: Frag, to: Span) -> Frag {
1999 match f {
2000 Frag::Noun(mut e) => {
2001 e.set_span(to);
2002 Frag::Noun(e)
2003 }
2004 Frag::Name(n, _) => Frag::Name(n, to),
2005 Frag::Verb(v, _) => Frag::Verb(v, to),
2006 Frag::Adverb(a, _) => Frag::Adverb(a, to),
2007 Frag::Conj(c, _) => Frag::Conj(c, to),
2008 other => other,
2009 }
2010}
2011
2012fn apply(stack: &mut Vec<Frag>, scope: &Names) -> Result<bool> {
2013 let Some(rule) = match_rule(stack) else {
2014 return Ok(false);
2015 };
2016 match rule {
2017 Rule::Monad1 => {
2018 let mut t = take(stack, 1..3);
2019 let y = t.pop().expect("two slots");
2020 let v = t.pop().expect("two slots");
2021 let frag = monad(v, y)?;
2022 stack.insert(1, frag);
2023 }
2024 Rule::Monad2 => {
2025 let mut t = take(stack, 2..4);
2026 let y = t.pop().expect("two slots");
2027 let v = t.pop().expect("two slots");
2028 let frag = monad(v, y)?;
2029 stack.insert(2, frag);
2030 }
2031 Rule::Dyad3 => {
2032 let mut t = take(stack, 1..4);
2033 let y = t.pop().expect("three slots");
2034 let v = t.pop().expect("three slots");
2035 let x = t.pop().expect("three slots");
2036 let frag = dyad(x, v, y)?;
2037 stack.insert(1, frag);
2038 }
2039 Rule::Adverb4 => {
2040 let mut t = take(stack, 1..3);
2041 let a = t.pop().expect("two slots");
2042 let u = t.pop().expect("two slots");
2043 let frag = apply_adverb(u, a, scope)?;
2044 stack.insert(1, frag);
2045 }
2046 Rule::Conj5 => {
2047 let mut t = take(stack, 1..4);
2048 let v = t.pop().expect("three slots");
2049 let c = t.pop().expect("three slots");
2050 let u = t.pop().expect("three slots");
2051 let frag = apply_conj(u, c, v, scope)?;
2052 stack.insert(1, frag);
2053 }
2054 Rule::Fork6 => {
2055 let mut t = take(stack, 1..4);
2056 let h = t.pop().expect("three slots");
2057 let g = t.pop().expect("three slots");
2058 let f = t.pop().expect("three slots");
2059 let frag = apply_fork(f, g, h)?;
2060 stack.insert(1, frag);
2061 }
2062 Rule::Bident7 => {
2063 let mut t = take(stack, 1..3);
2064 let b = t.pop().expect("two slots");
2065 let a = t.pop().expect("two slots");
2066 let frag = apply_bident(a, b, &scope.nouns)?;
2067 stack.insert(1, frag);
2068 }
2069 Rule::Assign8 => {
2070 let mut t = take(stack, 0..3);
2071 let value = t.pop().expect("three slots");
2072 let assign = t.pop().expect("three slots");
2073 let target = t.pop().expect("three slots");
2074 let scope = match assign {
2075 Frag::AssignGlobal(_) => Scope::Global,
2076 _ => Scope::Local,
2077 };
2078 let frag = apply_assign(target, value, scope)?;
2079 stack.insert(0, frag);
2080 }
2081 Rule::Paren9 => {
2082 let mut t = take(stack, 0..3);
2083 let close = t.pop().expect("three slots");
2084 let inner = t.pop().expect("three slots");
2085 let open = t.pop().expect("three slots");
2086 let outer = Span::merge(open.span(), close.span());
2087 stack.insert(0, respan(inner, outer));
2088 }
2089 }
2090 Ok(true)
2091}
2092
2093fn as_noun(f: Frag) -> Result<Expr> {
2096 match f {
2097 Frag::Noun(e) => Ok(e),
2098 Frag::Name(n, s) => Ok(Expr::Name(n, s)),
2099 other => Err(Error::internal(format!("expected a noun fragment, got {other:?}"))),
2100 }
2101}
2102
2103fn as_verb(f: Frag) -> Result<(Verb, Span)> {
2104 match f {
2105 Frag::Verb(VerbFrag::V(v), s) => Ok((v, s)),
2106 other => Err(Error::internal(format!("expected a verb fragment, got {other:?}"))),
2107 }
2108}
2109
2110fn as_const(f: &Frag) -> Option<&Array> {
2113 match f {
2114 Frag::Noun(Expr::Const(a, _)) => Some(a),
2115 _ => None,
2116 }
2117}
2118
2119fn noun_value(f: &Frag) -> Option<Array> {
2124 if let Some(a) = as_const(f) {
2125 return Some(a.clone());
2126 }
2127 let Frag::Noun(e) = f else { return None };
2128 let cfg = crate::verb::EvalCfg {
2129 agreement: crate::verb::Agreement::LeadingPrefix,
2130 fmt: crate::fmt::FmtOpts::J,
2131 tol: crate::verb::Tol::J,
2132 rules: crate::frontend::Rules::default(),
2133 };
2134 crate::ir::fold_const(e, cfg)
2135}
2136
2137fn monad(v: Frag, y: Frag) -> Result<Frag> {
2138 let (verb, vspan) = as_verb(v)?;
2139 let y = as_noun(y)?;
2140 let span = Span::merge(vspan, y.span());
2141 Ok(Frag::Noun(Expr::Monad { verb, y: Box::new(y), span }))
2142}
2143
2144fn dyad(x: Frag, v: Frag, y: Frag) -> Result<Frag> {
2145 let x = as_noun(x)?;
2146 let (verb, vspan) = as_verb(v)?;
2147 let y = as_noun(y)?;
2148 let span = Span::merge(Span::merge(x.span(), vspan), y.span());
2149 Ok(Frag::Noun(Expr::Dyad { verb, x: Box::new(x), y: Box::new(y), span }))
2150}
2151
2152fn apply_adverb(u: Frag, a: Frag, scope: &Names) -> Result<Frag> {
2153 let Frag::Adverb(m, aspan) = a else {
2154 return Err(Error::internal("expected an adverb fragment"));
2155 };
2156 let span = Span::merge(u.span(), aspan);
2157 let glyph = match m {
2158 Modifier::Prim(g) => g,
2159 Modifier::Explicit(src) => return derive_explicit(&src, u, None, scope, span),
2160 };
2161 if glyph == "}" {
2164 if !u.is_real_verb() {
2165 let m = noun_value(&u)
2166 .ok_or_else(|| Error::not_yet("amend over a computed index", span))?;
2167 return Ok(Frag::Verb(VerbFrag::V(Verb::Amend(m)), span));
2168 }
2169 let (v, _) = as_verb(u)?;
2170 return Ok(Frag::Verb(VerbFrag::V(Verb::AmendVerb(Box::new(v))), span));
2171 }
2172 if glyph == "b." && !u.is_real_verb() {
2175 let m = as_const(&u)
2176 .and_then(Array::to_i64_vec)
2177 .and_then(|v| v.first().copied())
2178 .filter(|&m| (0..32).contains(&m))
2179 .ok_or_else(|| {
2180 Error::not_yet("a boolean function outside `0 b.` … `31 b.`", span)
2181 })?;
2182 let p = crate::verb::Prim {
2183 name: "b.",
2184 monad: MonadOp::None,
2185 dyad: DyadOp::TruthTable(m as u8),
2186 ranks: [crate::verb::RANK_INF, 0, 0],
2187 };
2188 return Ok(Frag::Verb(VerbFrag::V(Verb::Prim(p)), span));
2189 }
2190 if !u.is_real_verb() {
2191 return Err(Error::not_yet("noun-operand adverbs", span));
2192 }
2193 let (v, _) = as_verb(u)?;
2194 let derived = match glyph {
2195 "/" => Verb::Reduce(Box::new(v)),
2196 "\\" => Verb::Windowed(Box::new(v), WindowKind::Prefix),
2197 "\\." => Verb::Windowed(Box::new(v), WindowKind::Suffix),
2198 "~" => Verb::Commute(Box::new(v)),
2199 "/." => Verb::Key(Box::new(v)),
2200 "f." => v,
2203 "M." => Verb::Memo(Box::new(v), Default::default()),
2204 "b." => Verb::Characteristics(Box::new(v)),
2205 _ => return Err(Error::not_yet(format!("adverb ({glyph})"), span)),
2206 };
2207 Ok(Frag::Verb(VerbFrag::V(derived), span))
2208}
2209
2210fn apply_conj(u: Frag, c: Frag, v: Frag, scope: &Names) -> Result<Frag> {
2211 let Frag::Conj(m, cspan) = c else {
2212 return Err(Error::internal("expected a conjunction fragment"));
2213 };
2214 let span = Span::merge(Span::merge(u.span(), cspan), v.span());
2215 let glyph = match m {
2216 Modifier::Prim(g) => g,
2217 Modifier::Explicit(src) => return derive_explicit(&src, u, Some(v), scope, span),
2218 };
2219 match glyph {
2220 "\"" => {
2221 let f = verb_operand(u, span)?;
2222 if v.is_verb() {
2223 return Err(Error::not_yet("verb rank (u\"v)", span));
2224 }
2225 let ranks = rank_spec(&v, span)?;
2226 Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(f), ranks)), span))
2227 }
2228 "@:" => {
2229 let f = verb_operand(u, span)?;
2230 let g = verb_operand(v, span)?;
2231 Ok(Frag::Verb(VerbFrag::V(Verb::Atop(Box::new(f), Box::new(g))), span))
2232 }
2233 "@" => {
2237 let f = verb_operand(u, span)?;
2238 let g = verb_operand(v, span)?;
2239 let ranks = g.ranks();
2240 let atop = Verb::Atop(Box::new(f), Box::new(g));
2241 Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(atop), ranks)), span))
2242 }
2243 "&" => compose(u, v, false, span),
2244 "&:" => compose(u, v, true, span),
2245 "&." if is_open(&v) => {
2248 let f = verb_operand(u, span)?;
2249 Ok(Frag::Verb(VerbFrag::V(Verb::Each(Box::new(f), Enclose::Always)), span))
2250 }
2251 "&." | "&.:" => {
2256 let f = verb_operand(u, span)?;
2257 let g = verb_operand(v, span)?;
2258 let back = obverse_of(&g, span)?;
2259 let composed = Verb::Compose(Box::new(f), Box::new(g.clone()));
2260 let under = Verb::Atop(Box::new(back), Box::new(composed));
2261 if glyph == "&.:" {
2262 return Ok(Frag::Verb(VerbFrag::V(under), span));
2263 }
2264 let rank = g.ranks()[0];
2265 Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(under), [rank; 3])), span))
2266 }
2267 "^:" => {
2268 let f = verb_operand(u, span)?;
2269 if v.is_verb() {
2270 let g = verb_operand(v, span)?;
2273 let p = Verb::PowerV(Box::new(f), Box::new(g));
2274 return Ok(Frag::Verb(VerbFrag::V(p), span));
2275 }
2276 let negative = noun_value(&v).is_some_and(|a| {
2281 let inner = match a.as_boxes() {
2282 Some([b]) => b.clone(),
2283 _ => a,
2284 };
2285 inner.to_f64_vec().is_some_and(|n| n.len() == 1 && n[0] < 0.0)
2286 });
2287 let p = power_spec(&v, span)?;
2288 let f = if negative { obverse_of(&f, span)? } else { f };
2289 Ok(Frag::Verb(VerbFrag::V(Verb::PowerN(Box::new(f), p)), span))
2290 }
2291 ";." => {
2292 let f = verb_operand(u, span)?;
2293 let n = one_atom(&v, "cut", span)?;
2294 if n.fract() != 0.0 || !matches!(n as i64, -3..=3) {
2295 return Err(Error::not_yet(format!("cut (u;.{n})"), span));
2296 }
2297 Ok(Frag::Verb(VerbFrag::V(Verb::Cut(Box::new(f), n as i64)), span))
2298 }
2299 "!." => {
2303 let f = verb_operand(u, span)?;
2304 if matches!(&f, Verb::Prim(p) if p.name == "|.") {
2307 let fill = as_const(&v)
2308 .cloned()
2309 .ok_or_else(|| Error::not_yet("a computed fill (|.!.n)", span))?;
2310 return Ok(Frag::Verb(VerbFrag::V(Verb::ShiftFill(fill)), span));
2311 }
2312 let n = one_atom(&v, "fit", span)?;
2313 if !f.uses_tolerance() {
2314 return Err(Error::not_yet(
2315 format!("fill specification ({}!.n)", f.name()),
2316 span,
2317 ));
2318 }
2319 if !(0.0..=LARGEST_TOLERANCE).contains(&n) {
2321 return Err(Error::domain(
2322 format!("a comparison tolerance must be between 0 and {LARGEST_TOLERANCE}"),
2323 span,
2324 ));
2325 }
2326 Ok(Frag::Verb(VerbFrag::V(Verb::Fit(Box::new(f), n)), span))
2327 }
2328 ":." => {
2331 let f = verb_operand(u, span)?;
2332 let g = verb_operand(v, span)?;
2333 Ok(Frag::Verb(
2334 VerbFrag::V(Verb::WithObverse(Box::new(f), Box::new(g))),
2335 span,
2336 ))
2337 }
2338 "@." => {
2341 let vs = gerund_verbs(&u, scope, span)?;
2342 if v.is_verb() {
2343 let w = verb_operand(v, span)?;
2344 return Ok(Frag::Verb(VerbFrag::V(Verb::Agenda(vs, Box::new(w))), span));
2345 }
2346 let at = one_atom(&v, "agenda", span)?;
2347 if at.fract() != 0.0 {
2348 return Err(Error::parse("an agenda index must be a whole number", span));
2349 }
2350 let picked = crate::verb::pick_gerund(&vs, at as i64, span)?;
2351 Ok(Frag::Verb(VerbFrag::V(picked), span))
2352 }
2353 "`" => {
2356 let left = tie_side(&u, scope, span)?;
2357 let right = tie_side(&v, scope, span)?;
2358 let tied = crate::verb::catenate(&left, &right, true, true, span)?;
2359 Ok(Frag::Noun(Expr::Const(tied, span)))
2360 }
2361 "::" => {
2364 let f = verb_operand(u, span)?;
2365 let g = if v.is_noun() {
2366 constant_verb(bond_noun(&v, span)?)
2367 } else {
2368 verb_operand(v, span)?
2369 };
2370 Ok(Frag::Verb(VerbFrag::V(Verb::Adverse(Box::new(f), Box::new(g))), span))
2371 }
2372 "L:" | "S:" => {
2376 let f = verb_operand(u, span)?;
2377 let n = one_atom(&v, "level", span)?;
2378 if n.fract() != 0.0 || !n.is_finite() {
2379 return Err(Error::not_yet(format!("a level of {n} ({glyph})"), span));
2380 }
2381 let level = Verb::Level {
2382 u: Box::new(f),
2383 level: n as i64,
2384 spread: glyph == "S:",
2385 };
2386 Ok(Frag::Verb(VerbFrag::V(level), span))
2387 }
2388 "`:" => {
2392 if u.is_verb() {
2393 return Err(Error::domain(
2394 "`: reads a gerund, which is boxed data, not a verb",
2395 span,
2396 ));
2397 }
2398 let vs = gerund_verbs(&u, scope, span)?;
2399 let n = one_atom(&v, "evoke gerund", span)?;
2400 if vs.is_empty() {
2401 return Err(Error::domain("an evoked gerund is empty", span));
2402 }
2403 match n {
2404 0.0 | 3.0 => {
2405 Ok(Frag::Verb(VerbFrag::V(Verb::Evoke(vs, n as i64)), span))
2406 }
2407 6.0 => train_of(vs, span),
2408 _ => Err(Error::domain(
2409 format!("`:{n} is not one of the evoke forms 0, 3 and 6"),
2410 span,
2411 )),
2412 }
2413 }
2414 "H." => {
2418 let num = series_parameters(&u, span)?;
2419 let den = series_parameters(&v, span)?;
2420 Ok(Frag::Verb(VerbFrag::V(Verb::Hypergeometric { num, den }), span))
2421 }
2422 "T." => Err(Error::sandbox(
2426 "T. starts J's own threads, which libjay does not open",
2427 span,
2428 )),
2429 "t:" => Err(Error::new(
2435 ErrorKind::Language,
2436 "t: is not a J inflection; the reference rejects the spelling",
2437 Some(span),
2438 )),
2439 "t." => Err(Error::sandbox(
2440 "t. runs a verb in one of J's thread pools, which libjay does not open",
2441 span,
2442 )),
2443 "." => {
2446 let f = verb_operand(u, span)?;
2447 let g = verb_operand(v, span)?;
2448 Ok(Frag::Verb(VerbFrag::V(Verb::InnerProduct {
2449 u: Box::new(f),
2450 v: Box::new(g),
2451 apl: false,
2452 }), span))
2453 }
2454 "!:" => foreign(&u, &v, span),
2455 ":" => Err(Error::not_yet("the monad-dyad conjunction (u : v)", span)),
2459 _ => Err(Error::not_yet(format!("the conjunction {glyph}"), span)),
2460 }
2461}
2462
2463fn compose(u: Frag, v: Frag, infinite: bool, span: Span) -> Result<Frag> {
2471 let verb = |v: Verb| Ok(Frag::Verb(VerbFrag::V(v), span));
2472 if infinite || (!u.is_noun() && !v.is_noun()) {
2473 let f = verb_operand(u, span)?;
2474 let g = verb_operand(v, span)?;
2475 let monadic_rank = g.ranks()[0];
2476 let composed = Verb::Compose(Box::new(f), Box::new(g));
2477 if infinite {
2478 return verb(composed);
2479 }
2480 return verb(Verb::Rank(Box::new(composed), [monadic_rank; 3]));
2481 }
2482 if u.is_noun() && v.is_noun() {
2483 return Err(Error::not_yet("noun-operand conjunctions", span));
2484 }
2485 if u.is_noun() {
2490 let m = bond_noun(&u, span)?;
2491 let g = as_verb(v)?.0;
2492 return verb(Verb::BondLeft(m, Box::new(g)));
2493 }
2494 let f = as_verb(u)?.0;
2495 let n = bond_noun(&v, span)?;
2496 verb(Verb::BondRight(Box::new(f), n))
2497}
2498
2499const LARGEST_TOLERANCE: f64 = 5.820_766_091_346_741e-11;
2501
2502fn series_parameters(f: &Frag, span: Span) -> Result<Vec<crate::complex::Cx>> {
2505 let Some(arr) = as_const(f) else {
2506 return Err(Error::not_yet("computed hypergeometric parameters (m H. n)", span));
2507 };
2508 if arr.count() == 0 {
2509 return Ok(Vec::new());
2510 }
2511 if arr.rank() > 1 {
2512 return Err(Error::parse("a hypergeometric parameter list is a vector", span));
2513 }
2514 match arr.data.cast(crate::dtype::DType::Complex) {
2515 Some(Data::Complex(v)) => Ok(v.as_slice().to_vec()),
2516 _ => Err(Error::parse("hypergeometric parameters are numbers", span)),
2517 }
2518}
2519
2520fn foreign(u: &Frag, v: &Frag, span: Span) -> Result<Frag> {
2532 let family = foreign_number(u, span)?;
2533 let member = foreign_number(v, span)?;
2534 let prim = |name, monad, dyad| {
2535 Ok(Frag::Verb(
2536 VerbFrag::V(Verb::Prim(Prim { name, monad, dyad, ranks: [RANK_INF; 3] })),
2537 span,
2538 ))
2539 };
2540 let closed = |what: &str| {
2541 Err(Error::sandbox(format!("{family}!:{member} {what}, which is outside the program"), span))
2542 };
2543 match (family, member) {
2544 (1, 1) => prim("1!:1", MonadOp::ReadStream, DyadOp::None),
2545 (1, 2) => prim("1!:2", MonadOp::None, DyadOp::WriteStream),
2546 (3, 0) => prim("3!:0", MonadOp::TypeCode, DyadOp::None),
2547 (5, 1) => prim("5!:1", MonadOp::AtomicRep, DyadOp::None),
2550 (0, _) => closed("runs a script file"),
2551 (1, _) => closed("reaches the filesystem"),
2554 (2, _) => closed("reaches the host — its environment, its shell, its processes"),
2555 (6, _) => closed("reads the clock"),
2556 (15, _) => closed("calls into a shared library"),
2557 _ => Err(Error::not_yet(format!("the foreign {family}!:{member}"), span)),
2558 }
2559}
2560
2561fn foreign_number(f: &Frag, span: Span) -> Result<i64> {
2564 if f.is_verb() {
2565 return Err(Error::parse("a foreign is spelled m!:n, with two numbers", span));
2566 }
2567 let Some(arr) = as_const(f) else {
2568 return Err(Error::not_yet("a computed foreign number (m!:n)", span));
2569 };
2570 match arr.to_i64_vec().as_deref() {
2571 Some([n]) if *n >= 0 => Ok(*n),
2572 _ => Err(Error::parse("a foreign is spelled m!:n, with two whole numbers", span)),
2573 }
2574}
2575
2576fn one_atom(f: &Frag, what: &str, span: Span) -> Result<f64> {
2577 let Some(arr) = as_const(f) else {
2578 return Err(Error::not_yet(format!("a computed {what} specification"), span));
2579 };
2580 let Some(vals) = arr.to_f64_vec() else {
2581 return Err(Error::parse(format!("{what} takes a numeric operand"), span));
2582 };
2583 match vals[..] {
2584 [n] => Ok(n),
2585 _ => Err(Error::parse(format!("{what} takes one atom"), span)),
2586 }
2587}
2588
2589fn bond_noun(f: &Frag, span: Span) -> Result<Array> {
2591 as_const(f)
2592 .cloned()
2593 .ok_or_else(|| Error::not_yet("bonds over a non-literal noun", span))
2594}
2595
2596fn is_open(f: &Frag) -> bool {
2599 matches!(f, Frag::Verb(VerbFrag::V(Verb::Prim(p)), _) if p.monad == MonadOp::Open)
2600}
2601
2602fn verb_operand(f: Frag, span: Span) -> Result<Verb> {
2603 if f.is_noun() {
2604 return Err(Error::not_yet("noun-operand conjunctions", span));
2605 }
2606 Ok(as_verb(f)?.0)
2607}
2608
2609fn rank_spec(f: &Frag, span: Span) -> Result<[i64; 3]> {
2612 let Some(arr) = as_const(f) else {
2613 return Err(Error::not_yet("computed rank specifications", span));
2614 };
2615 let Some(vals) = arr.to_f64_vec() else {
2616 return Err(Error::parse("rank must be numeric", span));
2617 };
2618 if vals.is_empty() || vals.len() > 3 {
2619 return Err(Error::parse("rank takes 1 to 3 atoms", span));
2620 }
2621 let mut r = Vec::with_capacity(vals.len());
2622 for x in vals {
2623 if x == f64::INFINITY {
2624 r.push(RANK_INF);
2625 } else if x == f64::NEG_INFINITY {
2626 r.push(-RANK_INF);
2627 } else if x.fract() != 0.0 {
2628 return Err(Error::parse("rank must be an integer", span));
2629 } else {
2630 r.push(x as i64);
2631 }
2632 }
2633 Ok(match r.len() {
2634 1 => [r[0], r[0], r[0]],
2635 2 => [r[1], r[0], r[1]],
2636 _ => [r[0], r[1], r[2]],
2637 })
2638}
2639
2640fn power_spec(f: &Frag, span: Span) -> Result<Power> {
2643 let Some(arr) = noun_value(f) else {
2644 return Err(Error::not_yet("computed power (u^:n)", span));
2645 };
2646 let arr = &arr;
2647 if let Some(boxes) = arr.as_boxes() {
2650 let [inner] = boxes else {
2651 return Err(Error::parse("a boxed power takes one box", span));
2652 };
2653 if inner.count() == 0 {
2654 return Ok(Power::ConvergeTrace);
2655 }
2656 let Some(vals) = inner.to_f64_vec() else {
2657 return Err(Error::parse("power must be numeric", span));
2658 };
2659 let [n] = vals[..] else {
2660 return Err(Error::not_yet("a boxed list of power counts (u^:(<n))", span));
2661 };
2662 if n.fract() != 0.0 || n.abs() > 1e6 {
2663 return Err(Error::parse("a boxed power must be a whole count", span));
2664 }
2665 if n == 0.0 {
2667 return Err(Error::domain("a boxed power traces at least one application", span));
2668 }
2669 return Ok(Power::Each((0..n.abs() as u64).collect()));
2672 }
2673 let Some(vals) = arr.to_f64_vec() else {
2674 return Err(Error::parse("power must be numeric", span));
2675 };
2676 if vals.len() > 1 {
2677 let mut counts = Vec::with_capacity(vals.len());
2679 for n in &vals {
2680 if n.fract() != 0.0 || *n < 0.0 || *n > 1e6 {
2681 return Err(Error::not_yet("a power count outside 0 … 1e6", span));
2682 }
2683 counts.push(*n as u64);
2684 }
2685 return Ok(Power::Each(counts));
2686 }
2687 let [n] = vals[..] else {
2688 return Err(Error::not_yet("power over a list of counts (u^:n)", span));
2689 };
2690 if n == f64::INFINITY {
2691 return Ok(Power::Converge);
2692 }
2693 if n.fract() != 0.0 {
2694 return Err(Error::parse("power must be a whole number", span));
2695 }
2696 if n < 0.0 {
2697 return Ok(Power::Times((-n) as u64));
2700 }
2701 Ok(Power::Times(n as u64))
2702}
2703
2704pub(crate) fn obverse_of(v: &Verb, span: Span) -> Result<Verb> {
2706 crate::verb::obverse(v).ok_or_else(|| {
2707 Error::not_yet(format!("the obverse of {} (no inverse is known)", v.name()), span)
2708 })
2709}
2710
2711fn tie_side(f: &Frag, scope: &Names, span: Span) -> Result<Array> {
2715 if f.is_real_verb() {
2716 let (v, _) = as_verb(f.clone())?;
2717 return Ok(Array::boxed(verb_ar(&v, span)?.to_array()));
2718 }
2719 noun_in_scope(f, scope)
2720 .ok_or_else(|| Error::not_yet("a tie over a computed noun", span))
2721}
2722
2723fn verb_ar(v: &Verb, span: Span) -> Result<crate::gerund::Ar> {
2726 crate::gerund::verb_ar(v).ok_or_else(|| {
2727 Error::not_yet(format!("the atomic representation of {}", v.name()), span)
2728 })
2729}
2730
2731fn noun_in_scope(f: &Frag, scope: &Names) -> Option<Array> {
2734 if let Frag::Name(n, _) = f {
2735 return scope.consts.get(n).cloned();
2736 }
2737 noun_value(f)
2738}
2739
2740fn gerund_verbs(f: &Frag, scope: &Names, span: Span) -> Result<Vec<Verb>> {
2743 if f.is_real_verb() {
2744 return Ok(vec![as_verb(f.clone())?.0]);
2745 }
2746 let arr = noun_in_scope(f, scope)
2747 .ok_or_else(|| Error::not_yet("a gerund computed at run time", span))?;
2748 let Some(items) = arr.as_boxes() else {
2749 return Err(Error::domain("a gerund is boxed data", span));
2750 };
2751 items.iter().map(|a| ar_verb(a, scope, span)).collect()
2752}
2753
2754fn ar_verb(a: &Array, scope: &Names, span: Span) -> Result<Verb> {
2756 let ar = crate::gerund::Ar::from_array(a)
2757 .ok_or_else(|| Error::domain("this is not an atomic representation", span))?;
2758 let (v, _) = as_verb(ar_frag(&ar, scope, span)?)?;
2759 Ok(v)
2760}
2761
2762fn ar_frag(ar: &crate::gerund::Ar, scope: &Names, span: Span) -> Result<Frag> {
2765 use crate::gerund::Ar;
2766 match ar {
2767 Ar::Noun(a) => Ok(Frag::Noun(Expr::Const(a.clone(), span))),
2768 Ar::Prim(word) => {
2769 if word == "[:" {
2770 return Ok(Frag::Verb(VerbFrag::Cap, span));
2771 }
2772 match verb_for(word) {
2773 Some(v) => Ok(Frag::Verb(VerbFrag::V(v), span)),
2774 None => Err(Error::domain(
2775 format!("`{word}` is not a verb an atomic representation may name"),
2776 span,
2777 )),
2778 }
2779 }
2780 Ar::Train(parts) => {
2781 let frags: Result<Vec<Frag>> =
2782 parts.iter().map(|p| ar_frag(p, scope, span)).collect();
2783 let mut frags = frags?;
2784 match frags.len() {
2785 2 => {
2786 let b = frags.pop().expect("two parts");
2787 let a = frags.pop().expect("two parts");
2788 apply_bident(a, b, &scope.nouns)
2789 }
2790 3 => {
2791 let h = frags.pop().expect("three parts");
2792 let g = frags.pop().expect("three parts");
2793 let f = frags.pop().expect("three parts");
2794 apply_fork(f, g, h)
2795 }
2796 _ => Err(Error::domain("a train is two or three parts", span)),
2797 }
2798 }
2799 Ar::Derived(word, ops) => {
2800 let frags: Result<Vec<Frag>> = ops.iter().map(|p| ar_frag(p, scope, span)).collect();
2801 let mut frags = frags?;
2802 if let Some(glyph) = adverb(word) {
2803 if frags.len() != 1 {
2804 return Err(Error::domain(format!("{glyph} takes one operand"), span));
2805 }
2806 let u = frags.pop().expect("one operand");
2807 return apply_adverb(u, Frag::Adverb(Modifier::Prim(glyph), span), scope);
2808 }
2809 if let Some(glyph) = conjunction(word) {
2810 if frags.len() != 2 {
2811 return Err(Error::domain(format!("{glyph} takes two operands"), span));
2812 }
2813 let v = frags.pop().expect("two operands");
2814 let u = frags.pop().expect("two operands");
2815 return apply_conj(u, Frag::Conj(Modifier::Prim(glyph), span), v, scope);
2816 }
2817 Err(Error::domain(
2818 format!("`{word}` is not a modifier an atomic representation may name"),
2819 span,
2820 ))
2821 }
2822 }
2823}
2824
2825fn train_of(vs: Vec<Verb>, span: Span) -> Result<Frag> {
2828 let mut frags: Vec<Frag> =
2829 vs.into_iter().map(|v| Frag::Verb(VerbFrag::V(v), span)).collect();
2830 while frags.len() > 3 {
2831 let h = frags.pop().expect("three or more");
2832 let g = frags.pop().expect("three or more");
2833 let f = frags.pop().expect("three or more");
2834 frags.push(apply_fork(f, g, h)?);
2835 }
2836 match frags.len() {
2837 1 => Ok(frags.pop().expect("one")),
2838 2 => {
2839 let b = frags.pop().expect("two");
2840 let a = frags.pop().expect("two");
2841 apply_bident(a, b, &HashSet::new())
2842 }
2843 _ => {
2844 let h = frags.pop().expect("three");
2845 let g = frags.pop().expect("three");
2846 let f = frags.pop().expect("three");
2847 apply_fork(f, g, h)
2848 }
2849 }
2850}
2851
2852fn apply_fork(f: Frag, g: Frag, h: Frag) -> Result<Frag> {
2853 let span = Span::merge(Span::merge(f.span(), g.span()), h.span());
2854 let (gv, _) = as_verb(g)?;
2855 let (hv, _) = as_verb(h)?;
2856 match f {
2857 Frag::Verb(VerbFrag::Cap, _) => {
2859 Ok(Frag::Verb(VerbFrag::V(Verb::Atop(Box::new(gv), Box::new(hv))), span))
2860 }
2861 Frag::Verb(VerbFrag::V(fv), _) => Ok(Frag::Verb(
2862 VerbFrag::V(Verb::Fork(Box::new(fv), Box::new(gv), Box::new(hv))),
2863 span,
2864 )),
2865 noun => {
2866 let Some(arr) = as_const(&noun) else {
2867 return Err(Error::not_yet("noun forks over a non-literal noun", span));
2868 };
2869 Ok(Frag::Verb(
2870 VerbFrag::V(Verb::NounFork(arr.clone(), Box::new(gv), Box::new(hv))),
2871 span,
2872 ))
2873 }
2874 }
2875}
2876
2877fn apply_bident(a: Frag, b: Frag, nouns: &HashSet<String>) -> Result<Frag> {
2878 let span = Span::merge(a.span(), b.span());
2879 if let Frag::Name(n, nspan) = &a && !nouns.contains(n) {
2883 return Err(Error::new(
2884 ErrorKind::Value,
2885 format!("undefined name: {n}"),
2886 Some(*nspan),
2887 ));
2888 }
2889 if a.is_real_verb() && b.is_real_verb() {
2890 let (f, _) = as_verb(a)?;
2891 let (g, _) = as_verb(b)?;
2892 return Ok(Frag::Verb(VerbFrag::V(Verb::Hook(Box::new(f), Box::new(g))), span));
2893 }
2894 if matches!(a, Frag::Verb(VerbFrag::Cap, _)) {
2899 return Err(Error::parse("`[:` caps a fork; it has no verb of its own", span));
2900 }
2901 Err(Error::parse("syntax error", span))
2902}
2903
2904fn apply_assign(target: Frag, value: Frag, scope: Scope) -> Result<Frag> {
2905 let span = Span::merge(target.span(), value.span());
2906 match target {
2907 Frag::Name(name, _) => match value {
2911 Frag::Verb(VerbFrag::V(verb), _) => Ok(Frag::VerbDef(name, verb, span)),
2914 Frag::Verb(VerbFrag::Cap, _) => Err(Error::not_yet("assigning [: on its own", span)),
2915 Frag::Adverb(m, _) => Ok(Frag::ModDef(name, false, m, span)),
2918 Frag::Conj(m, _) => Ok(Frag::ModDef(name, true, m, span)),
2919 v if v.is_noun() => {
2920 let value = as_noun(v)?;
2921 Ok(Frag::Noun(Expr::Assign { name, value: Box::new(value), scope, span }))
2922 }
2923 other => Err(Error::internal(format!("cannot assign {other:?}"))),
2924 },
2925 Frag::Noun(_) => Err(Error::not_yet("multiple assignment", span)),
2926 other => Err(Error::internal(format!("expected an assignment target, got {other:?}"))),
2927 }
2928}
2929
2930#[cfg(test)]
2931mod tests {
2932 use super::*;
2933 use crate::dtype::DType;
2934 use crate::error::ErrorKind;
2935 use rstest::rstest;
2936
2937 fn parse_str(src: &str) -> Result<Vec<Expr>> {
2938 parse(&SourceParts::from_source(src).expect("source parts"))
2939 }
2940
2941 fn one_literal(src: &str) -> Expr {
2945 let sp = SourceParts::from_parts(&[src], &[]);
2946 let mut s = parse(&sp).unwrap_or_else(|e| panic!("parse of {src:?} failed: {e}"));
2947 assert_eq!(s.len(), 1, "expected one sentence in {src:?}");
2948 s.pop().expect("one sentence")
2949 }
2950
2951 fn stmts(src: &str) -> Vec<Expr> {
2952 parse_str(src).unwrap_or_else(|e| panic!("parse of {src:?} failed: {e}"))
2953 }
2954
2955 fn one(src: &str) -> Expr {
2957 let mut s = stmts(src);
2958 assert_eq!(s.len(), 1, "expected one sentence in {src:?}");
2959 s.pop().expect("one sentence")
2960 }
2961
2962 fn err(src: &str) -> Error {
2963 match parse_str(src) {
2964 Ok(v) => panic!("expected an error for {src:?}, got {v:?}"),
2965 Err(e) => e,
2966 }
2967 }
2968
2969 fn konst(e: &Expr) -> Array {
2973 match e {
2974 Expr::Const(a, _) => a.clone(),
2975 other => panic!("expected a constant, got {other:?}"),
2976 }
2977 }
2978
2979 fn ints(e: &Expr) -> Vec<i64> {
2980 konst(e).as_i64_slice().expect("integer data").to_vec()
2981 }
2982
2983 fn prim_of(v: &Verb) -> Prim {
2984 match v {
2985 Verb::Prim(p) => *p,
2986 other => panic!("expected a primitive, got {other:?}"),
2987 }
2988 }
2989
2990 fn monad_of(e: &Expr) -> (Verb, Expr) {
2991 match e {
2992 Expr::Monad { verb, y, .. } => (verb.clone(), (**y).clone()),
2993 other => panic!("expected a monad, got {other:?}"),
2994 }
2995 }
2996
2997 fn dyad_of(e: &Expr) -> (Verb, Expr, Expr) {
2998 match e {
2999 Expr::Dyad { verb, x, y, .. } => (verb.clone(), (**x).clone(), (**y).clone()),
3000 other => panic!("expected a dyad, got {other:?}"),
3001 }
3002 }
3003
3004 #[test]
3007 fn single_number_is_an_atom() {
3008 let e = one("5");
3009 assert_eq!(konst(&e).shape, Vec::<usize>::new());
3010 assert_eq!(ints(&e), vec![5]);
3011 assert_eq!(e.span(), Span::new(0, 1));
3012 }
3013
3014 #[test]
3015 fn adjacent_numbers_merge_into_one_vector() {
3016 let e = one("1 2 3");
3017 assert_eq!(konst(&e).shape, vec![3]);
3018 assert_eq!(ints(&e), vec![1, 2, 3]);
3019 assert_eq!(e.span(), Span::new(0, 5));
3020 }
3021
3022 #[test]
3023 fn a_float_makes_the_whole_vector_float() {
3024 let a = konst(&one("1 2.5 3"));
3025 assert_eq!(a.dtype(), DType::F64);
3026 assert_eq!(a.as_f64_slice(), Some(&[1.0, 2.5, 3.0][..]));
3027 }
3028
3029 #[test]
3030 fn negatives_and_infinities() {
3031 let a = konst(&one("_3 1.5 _ __"));
3032 assert_eq!(a.shape, vec![4]);
3033 let v = a.as_f64_slice().expect("float vector");
3034 assert_eq!(v[0], -3.0);
3035 assert_eq!(v[1], 1.5);
3036 assert!(v[2].is_infinite() && v[2] > 0.0);
3037 assert!(v[3].is_infinite() && v[3] < 0.0);
3038 }
3039
3040 #[test]
3041 fn negative_integers_stay_integers() {
3042 let a = konst(&one("_3 _4"));
3043 assert_eq!(a.dtype(), DType::I64);
3044 assert_eq!(a.as_i64_slice(), Some(&[-3i64, -4][..]));
3045 }
3046
3047 #[rstest]
3048 #[case("1e3", 1000.0)]
3049 #[case("1e_3", 0.001)]
3050 #[case("2.5e2", 250.0)]
3051 #[case("_1.5", -1.5)]
3052 fn exponent_and_sign_forms(#[case] src: &str, #[case] want: f64) {
3053 let a = konst(&one(src));
3054 assert_eq!(a.dtype(), DType::F64);
3055 assert_eq!(a.to_f64_vec().expect("numeric"), vec![want]);
3056 }
3057
3058 #[test]
3059 fn adjacent_numbers_stop_at_a_non_number() {
3060 let (_, x, y) = dyad_of(&one("2 3 i. 4"));
3062 assert_eq!(konst(&x).shape, vec![2]);
3063 assert_eq!(konst(&y).shape, Vec::<usize>::new());
3064 }
3065
3066 #[test]
3067 fn string_of_several_characters_is_a_vector() {
3068 let e = one("'abc'");
3069 let a = konst(&e);
3070 assert_eq!(a.shape, vec![3]);
3071 assert_eq!(a.data, Data::Char(vec!['a', 'b', 'c'].into()));
3072 assert_eq!(e.span(), Span::new(0, 5));
3073 }
3074
3075 #[test]
3076 fn one_character_string_is_an_atom() {
3077 let a = konst(&one("'a'"));
3078 assert_eq!(a.shape, Vec::<usize>::new());
3079 assert_eq!(a.data, Data::Char(vec!['a'].into()));
3080 }
3081
3082 #[test]
3083 fn empty_string_is_an_empty_vector() {
3084 let a = konst(&one("''"));
3085 assert_eq!(a.shape, vec![0]);
3086 assert_eq!(a.dtype(), DType::Char);
3087 }
3088
3089 #[test]
3090 fn doubled_quote_is_an_escaped_quote() {
3091 let a = konst(&one("'it''s'"));
3092 assert_eq!(a.shape, vec![4]);
3093 assert_eq!(a.data, Data::Char(vec!['i', 't', '\'', 's'].into()));
3094 }
3095
3096 #[test]
3097 fn unterminated_string_is_a_parse_error() {
3098 let e = err("'abc");
3099 assert_eq!(e.kind, ErrorKind::Parse);
3100 assert!(e.msg.contains("unterminated"), "{}", e.msg);
3101 assert_eq!(e.span, Some(Span::new(0, 4)));
3102 }
3103
3104 #[test]
3107 fn comment_runs_to_end_of_line() {
3108 let e = one("1 2 NB. and the rest + - ' is ignored");
3109 assert_eq!(konst(&e).shape, vec![2]);
3110 }
3111
3112 #[test]
3113 fn comment_only_line_yields_no_sentence() {
3114 assert!(stmts("NB. nothing here").is_empty());
3115 let s = stmts("NB. header\n5");
3116 assert_eq!(s.len(), 1);
3117 assert_eq!(ints(&s[0]), vec![5]);
3118 }
3119
3120 #[test]
3121 fn nb_inside_a_name_is_not_a_comment() {
3122 match one("aNB") {
3124 Expr::Name(n, _) => assert_eq!(n, "aNB"),
3125 other => panic!("expected a name, got {other:?}"),
3126 }
3127 }
3128
3129 #[test]
3132 fn empty_program_has_no_sentences() {
3133 assert!(stmts("").is_empty());
3134 assert!(stmts("\n\n").is_empty());
3135 }
3136
3137 #[test]
3138 fn trains_of_dyads_are_right_associative() {
3139 let e = one("1 + 2 + 3");
3140 let (v, x, y) = dyad_of(&e);
3141 assert_eq!(prim_of(&v).name, "+");
3142 assert_eq!(ints(&x), vec![1]);
3143 let (v2, x2, y2) = dyad_of(&y);
3144 assert_eq!(prim_of(&v2).name, "+");
3145 assert_eq!(ints(&x2), vec![2]);
3146 assert_eq!(ints(&y2), vec![3]);
3147 assert_eq!(e.span(), Span::new(0, 9));
3148 }
3149
3150 #[test]
3151 fn a_verb_with_no_left_argument_is_a_monad() {
3152 let e = one("- 5");
3153 let (v, y) = monad_of(&e);
3154 assert_eq!(prim_of(&v).monad, MonadOp::Scalar(ScalarMonad::Neg));
3155 assert_eq!(ints(&y), vec![5]);
3156 assert_eq!(e.span(), Span::new(0, 3));
3157 }
3158
3159 #[test]
3160 fn a_verb_with_a_left_argument_is_a_dyad() {
3161 let (v, _, _) = dyad_of(&one("1 - 5"));
3162 assert_eq!(prim_of(&v).dyad, DyadOp::Scalar(ScalarDyad::Sub));
3163 }
3164
3165 #[test]
3166 fn a_monad_binds_to_the_right_inside_a_dyad() {
3167 let (v, x, y) = dyad_of(&one("2 * - 3"));
3168 assert_eq!(prim_of(&v).name, "*");
3169 assert_eq!(ints(&x), vec![2]);
3170 let (mv, my) = monad_of(&y);
3171 assert_eq!(prim_of(&mv).name, "-");
3172 assert_eq!(ints(&my), vec![3]);
3173 }
3174
3175 #[test]
3176 fn parentheses_group_the_left_argument() {
3177 let (v, x, y) = dyad_of(&one("(1 + 2) * 3"));
3178 assert_eq!(prim_of(&v).name, "*");
3179 let (iv, _, _) = dyad_of(&x);
3180 assert_eq!(prim_of(&iv).name, "+");
3181 assert_eq!(x.span(), Span::new(0, 7));
3184 assert_eq!(ints(&y), vec![3]);
3185 }
3186
3187 #[test]
3188 fn names_are_nouns() {
3189 match one("x") {
3190 Expr::Name(n, s) => {
3191 assert_eq!(n, "x");
3192 assert_eq!(s, Span::new(0, 1));
3193 }
3194 other => panic!("expected a name, got {other:?}"),
3195 }
3196 let (_, x, y) = dyad_of(&one("x + y"));
3197 assert!(matches!(x, Expr::Name(..)));
3198 assert!(matches!(y, Expr::Name(..)));
3199 }
3200
3201 #[test]
3202 fn echo_is_a_verb() {
3203 let (v, y) = monad_of(&one("echo 5"));
3204 assert_eq!(prim_of(&v).monad, MonadOp::Echo);
3205 assert_eq!(ints(&y), vec![5]);
3206 }
3207
3208 #[test]
3209 fn inflected_letter_words_are_primitives() {
3210 let (v, _) = monad_of(&one("i. 3"));
3211 let p = prim_of(&v);
3212 assert_eq!(p.monad, MonadOp::IotaJ);
3213 assert_eq!(p.ranks, [1, RANK_INF, RANK_INF]);
3214 }
3215
3216 #[rstest]
3217 #[case("|: 1 2 3", MonadOp::TransposeAxes)]
3218 #[case("$ 1 2 3", MonadOp::ShapeOf)]
3219 #[case("# 1 2 3", MonadOp::Tally)]
3220 #[case(", 1 2 3", MonadOp::Ravel)]
3221 #[case("%: 1 2 3", MonadOp::Scalar(ScalarMonad::Sqrt))]
3222 #[case("<. 1.5", MonadOp::Scalar(ScalarMonad::Floor))]
3223 fn inflected_symbol_words(#[case] src: &str, #[case] want: MonadOp) {
3224 let (v, _) = monad_of(&one(src));
3225 assert_eq!(prim_of(&v).monad, want);
3226 }
3227
3228 #[rstest]
3229 #[case("{. 1 2 3", MonadOp::Head, DyadOp::Take)]
3230 #[case("}. 1 2 3", MonadOp::Behead, DyadOp::Drop)]
3231 fn brace_words(#[case] src: &str, #[case] monad: MonadOp, #[case] dyad: DyadOp) {
3232 let (v, _) = monad_of(&one_literal(src));
3233 let p = prim_of(&v);
3234 assert_eq!(p.monad, monad);
3235 assert_eq!(p.dyad, dyad);
3236 assert_eq!(p.ranks, [RANK_INF, 1, RANK_INF]);
3237 }
3238
3239 #[test]
3240 fn a_brace_word_takes_a_left_argument() {
3241 let (v, x, y) = dyad_of(&one_literal("2 {. 1 2 3"));
3242 assert_eq!(prim_of(&v).dyad, DyadOp::Take);
3243 assert_eq!(ints(&x), vec![2]);
3244 assert_eq!(konst(&y).shape, vec![3]);
3245 }
3246
3247 #[rstest]
3248 #[case("2 $ 1 2 3", DyadOp::Reshape)]
3249 #[case("2 [ 3", DyadOp::Left)]
3250 #[case("2 ] 3", DyadOp::Right)]
3251 #[case("2 <. 3", DyadOp::Scalar(ScalarDyad::Min))]
3252 #[case("2 >: 3", DyadOp::Scalar(ScalarDyad::Ge))]
3253 fn dyadic_primitives(#[case] src: &str, #[case] want: DyadOp) {
3254 let (v, _, _) = dyad_of(&one(src));
3255 assert_eq!(prim_of(&v).dyad, want);
3256 }
3257
3258 #[test]
3259 fn unimplemented_meanings_reach_the_verb_not_the_parser() {
3260 let (v, _, _) = dyad_of(&one("2 $. 'a b'"));
3261 assert_eq!(prim_of(&v).dyad, DyadOp::NotYet("sparse arrays ($.)"));
3262 let (v, _, _) = dyad_of(&one("2 s: 'a b'"));
3265 assert_eq!(prim_of(&v).dyad, DyadOp::SymbolForm);
3266 }
3267
3268 #[test]
3269 fn multiple_sentences_become_multiple_statements() {
3270 let s = stmts("a =. 1 2\n+/ a\n");
3271 assert_eq!(s.len(), 2);
3272 assert!(matches!(s[0], Expr::Assign { .. }));
3273 assert!(matches!(s[1], Expr::Monad { .. }));
3274 }
3275
3276 #[test]
3279 fn an_adverb_binds_before_the_verb_is_applied() {
3280 let e = one("+/ 1 2 3");
3281 let (v, y) = monad_of(&e);
3282 match &v {
3283 Verb::Reduce(inner) => assert_eq!(prim_of(inner).name, "+"),
3284 other => panic!("expected a reduction, got {other:?}"),
3285 }
3286 assert_eq!(konst(&y).shape, vec![3]);
3287 assert_eq!(e.span(), Span::new(0, 8));
3288 }
3289
3290 #[test]
3291 fn rank_applies_to_the_derived_verb() {
3292 let (v, _) = monad_of(&one("+/\"1 m"));
3293 match &v {
3294 Verb::Rank(inner, ranks) => {
3295 assert_eq!(*ranks, [1, 1, 1]);
3296 assert!(matches!(**inner, Verb::Reduce(_)), "got {inner:?}");
3297 }
3298 other => panic!("expected a ranked verb, got {other:?}"),
3299 }
3300 }
3301
3302 #[rstest]
3303 #[case("+\"1 m", [1, 1, 1])]
3304 #[case("+\"1 2 m", [2, 1, 2])]
3305 #[case("+\"0 1 2 m", [0, 1, 2])]
3306 #[case("+\"_ m", [RANK_INF, RANK_INF, RANK_INF])]
3307 #[case("+\"_1 m", [-1, -1, -1])]
3308 #[case("+\"2.0 m", [2, 2, 2])]
3309 fn rank_specifications(#[case] src: &str, #[case] want: [i64; 3]) {
3310 let (v, _) = monad_of(&one(src));
3311 assert_eq!(v.ranks(), want);
3312 }
3313
3314 #[test]
3315 fn rank_must_be_one_to_three_integer_atoms() {
3316 let e = err("+\"1 2 3 4 m");
3317 assert_eq!(e.kind, ErrorKind::Parse);
3318 assert!(e.msg.contains("1 to 3 atoms"), "{}", e.msg);
3319 let e = err("+\"1.5 m");
3320 assert_eq!(e.kind, ErrorKind::Parse);
3321 assert!(e.msg.contains("integer"), "{}", e.msg);
3322 let e = err("+\"'a' m");
3323 assert_eq!(e.kind, ErrorKind::Parse);
3324 assert!(e.msg.contains("numeric"), "{}", e.msg);
3325 }
3326
3327 #[test]
3328 fn verb_rank_is_not_supported_yet() {
3329 let e = err("+\"- m");
3330 assert_eq!(e.kind, ErrorKind::NotYet);
3331 assert!(e.msg.contains("verb rank"), "{}", e.msg);
3332 }
3333
3334 #[test]
3335 fn computed_rank_is_not_supported_yet() {
3336 let e = err("+\"{r} m");
3337 assert_eq!(e.kind, ErrorKind::NotYet);
3338 assert!(e.msg.contains("computed rank"), "{}", e.msg);
3339 }
3340
3341 #[test]
3342 fn atop_conjunction() {
3343 let (v, _) = monad_of(&one("+/ @: , y"));
3344 match &v {
3345 Verb::Atop(f, g) => {
3346 assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
3347 assert_eq!(prim_of(g).name, ",");
3348 }
3349 other => panic!("expected an atop, got {other:?}"),
3350 }
3351 }
3352
3353 #[rstest]
3354 #[case("+ ^: {n} y", "computed power")]
3355 #[case("(+/ % #) ^: _1 y", "the obverse of")]
3356 #[case("(+/ % #) &. , y", "the obverse of")]
3357 #[case("(1 + 2) & , y", "bonds over a non-literal noun")]
3358 fn other_conjunctions_are_not_supported_yet(#[case] src: &str, #[case] msg: &str) {
3359 let e = err(src);
3360 assert_eq!(e.kind, ErrorKind::NotYet);
3361 assert!(e.msg.contains(msg), "{}", e.msg);
3362 }
3363
3364 #[test]
3365 fn atop_at_rank_and_compose() {
3366 let (v, _) = monad_of(&one("+/ @ (,\"1) y"));
3369 match &v {
3370 Verb::Rank(inner, ranks) => {
3371 assert_eq!(*ranks, [1, 1, 1]);
3372 assert!(matches!(**inner, Verb::Atop(..)), "got {inner:?}");
3373 }
3374 other => panic!("expected a ranked atop, got {other:?}"),
3375 }
3376 let (v, _) = monad_of(&one("+ & (*:\"0) y"));
3377 match &v {
3378 Verb::Rank(inner, ranks) => {
3379 assert_eq!(*ranks, [0, 0, 0]);
3380 assert!(matches!(**inner, Verb::Compose(..)), "got {inner:?}");
3381 }
3382 other => panic!("expected a ranked composition, got {other:?}"),
3383 }
3384 let (v, _) = monad_of(&one("+ &: *: y"));
3385 assert!(matches!(v, Verb::Compose(..)), "got {v:?}");
3386 }
3387
3388 #[test]
3389 fn a_noun_operand_bonds_the_conjunction() {
3390 let (v, _) = monad_of(&one("1 & + y"));
3394 match &v {
3395 Verb::BondLeft(a, g) => {
3396 assert_eq!(a.as_i64_slice(), Some(&[1i64][..]));
3397 assert_eq!(prim_of(g).name, "+");
3398 }
3399 other => panic!("expected a left bond, got {other:?}"),
3400 }
3401 assert_eq!(v.ranks(), [crate::verb::RANK_INF; 3]);
3402 let (v, _) = monad_of(&one("{. & 2 y"));
3403 assert!(matches!(v, Verb::BondRight(..)), "got {v:?}");
3404 assert_eq!(v.ranks(), [crate::verb::RANK_INF; 3]);
3405 }
3406
3407 #[test]
3408 fn window_scan_and_commute_adverbs() {
3409 let (v, _) = monad_of(&one("+/\\ 1 2 3"));
3410 match &v {
3411 Verb::Windowed(u, WindowKind::Prefix) => assert!(matches!(**u, Verb::Reduce(_))),
3412 other => panic!("expected a prefix application, got {other:?}"),
3413 }
3414 assert_eq!(v.ranks(), [RANK_INF, 0, RANK_INF]);
3417 let (v, _, _) = dyad_of(&one("2 +/\\ 1 2 3"));
3418 assert!(matches!(v, Verb::Windowed(_, WindowKind::Prefix)));
3419 let (v, _) = monad_of(&one("+/\\. 1 2 3"));
3420 assert!(matches!(v, Verb::Windowed(_, WindowKind::Suffix)));
3421 let (v, _) = monad_of(&one("+~ 1 2 3"));
3422 match &v {
3423 Verb::Commute(u) => assert_eq!(prim_of(u).name, "+"),
3424 other => panic!("expected a commute, got {other:?}"),
3425 }
3426 let (v, _) = monad_of(&one("+:^:3 (1)"));
3427 assert!(matches!(v, Verb::PowerN(_, Power::Times(3))));
3428 let (v, _) = monad_of(&one("%:^:_ (100)"));
3429 assert!(matches!(v, Verb::PowerN(_, Power::Converge)));
3430 }
3431
3432 #[test]
3433 fn the_key_adverb_derives_a_verb() {
3434 match one("+/. 1 2 3") {
3435 Expr::Monad { verb: Verb::Key(_), .. } => {}
3436 other => panic!("expected a key, got {other:?}"),
3437 }
3438 }
3439
3440 #[test]
3441 fn noun_operand_adverbs_are_not_supported_yet() {
3442 let e = err("1/ 2");
3443 assert_eq!(e.kind, ErrorKind::NotYet);
3444 assert!(e.msg.contains("noun-operand adverbs"), "{}", e.msg);
3445 }
3446
3447 #[test]
3448 fn noun_operand_conjunctions_are_not_supported_yet() {
3449 let e = err("1 @: + y");
3450 assert_eq!(e.kind, ErrorKind::NotYet);
3451 assert!(e.msg.contains("noun-operand conjunctions"), "{}", e.msg);
3452 }
3453
3454 #[test]
3457 fn three_verbs_in_parentheses_are_a_fork() {
3458 let (v, y) = monad_of(&one("(+/ % #) 1 2 3"));
3459 match &v {
3460 Verb::Fork(f, g, h) => {
3461 assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
3462 assert_eq!(prim_of(g).name, "%");
3463 assert_eq!(prim_of(h).name, "#");
3464 }
3465 other => panic!("expected a fork, got {other:?}"),
3466 }
3467 assert_eq!(konst(&y).shape, vec![3]);
3468 }
3469
3470 #[test]
3471 fn a_noun_left_tine_is_a_noun_fork() {
3472 let (v, _) = monad_of(&one("(2 + #) 1 2 3"));
3473 match &v {
3474 Verb::NounFork(a, g, h) => {
3475 assert_eq!(a.as_i64_slice(), Some(&[2i64][..]));
3476 assert_eq!(prim_of(g).name, "+");
3477 assert_eq!(prim_of(h).name, "#");
3478 }
3479 other => panic!("expected a noun fork, got {other:?}"),
3480 }
3481 }
3482
3483 #[test]
3484 fn two_verbs_in_parentheses_are_a_hook() {
3485 let (v, _) = monad_of(&one("(+ #) 1 2 3"));
3486 match &v {
3487 Verb::Hook(f, g) => {
3488 assert_eq!(prim_of(f).name, "+");
3489 assert_eq!(prim_of(g).name, "#");
3490 }
3491 other => panic!("expected a hook, got {other:?}"),
3492 }
3493 }
3494
3495 #[test]
3496 fn cap_makes_a_fork_an_atop() {
3497 let (v, _) = monad_of(&one("([: +/ ,) 1 2 3"));
3498 match &v {
3499 Verb::Atop(f, g) => {
3500 assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
3501 assert_eq!(prim_of(g).name, ",");
3502 }
3503 other => panic!("expected an atop, got {other:?}"),
3504 }
3505 }
3506
3507 #[test]
3508 fn a_five_verb_train_folds_from_the_right() {
3509 let (v, _) = monad_of(&one("(] , [ , ]) 1 2 3"));
3511 match &v {
3512 Verb::Fork(f, g, h) => {
3513 assert_eq!(prim_of(f).name, "]");
3514 assert_eq!(prim_of(g).name, ",");
3515 assert!(matches!(**h, Verb::Fork(..)), "got {h:?}");
3516 }
3517 other => panic!("expected a fork, got {other:?}"),
3518 }
3519 }
3520
3521 #[test]
3522 fn a_noun_fork_needs_a_literal_noun() {
3523 let e = err("({n} + #) 1 2 3");
3524 assert_eq!(e.kind, ErrorKind::NotYet);
3525 assert!(e.msg.contains("noun forks"), "{}", e.msg);
3526 }
3527
3528 #[test]
3529 fn cap_is_never_applied_as_a_verb() {
3530 let e = err("[: # 1 2 3");
3533 assert_eq!(e.kind, ErrorKind::Parse);
3534 assert!(e.msg.contains("caps a fork"), "{}", e.msg);
3535 }
3536
3537 #[test]
3538 fn two_nouns_side_by_side_are_a_syntax_error() {
3539 let e = err("'ab' 'cd'");
3541 assert_eq!(e.kind, ErrorKind::Parse);
3542 assert_eq!(e.msg, "syntax error");
3543 }
3544
3545 #[test]
3546 fn a_sentence_that_is_a_verb_is_not_supported_yet() {
3547 let e = err("+/ % #");
3548 assert_eq!(e.kind, ErrorKind::NotYet);
3549 assert!(e.msg.contains("tacit"), "{}", e.msg);
3550 }
3551
3552 #[rstest]
3555 #[case("x =. 5", Scope::Local)]
3556 #[case("x =: 5", Scope::Global)]
3557 fn assignment_yields_an_assign_node(#[case] src: &str, #[case] want: Scope) {
3558 match one(src) {
3559 Expr::Assign { name, value, scope, span } => {
3560 assert_eq!(name, "x");
3561 assert_eq!(ints(&value), vec![5]);
3562 assert_eq!(scope, want);
3563 assert_eq!(span, Span::new(0, 6));
3564 }
3565 other => panic!("expected an assignment, got {other:?}"),
3566 }
3567 }
3568
3569 #[test]
3570 fn assignment_in_expression_position() {
3571 let (v, x, y) = dyad_of(&one("y + x =. 3"));
3572 assert_eq!(prim_of(&v).name, "+");
3573 assert!(matches!(x, Expr::Name(..)));
3574 match y {
3575 Expr::Assign { name, span, .. } => {
3576 assert_eq!(name, "x");
3577 assert_eq!(span, Span::new(4, 10));
3578 }
3579 other => panic!("expected an assignment, got {other:?}"),
3580 }
3581 }
3582
3583 #[test]
3584 fn assignment_takes_the_whole_right_hand_sentence() {
3585 match one("x =. 1 + 2") {
3586 Expr::Assign { value, .. } => {
3587 let (v, _, _) = dyad_of(&value);
3588 assert_eq!(prim_of(&v).name, "+");
3589 }
3590 other => panic!("expected an assignment, got {other:?}"),
3591 }
3592 }
3593
3594 #[test]
3597 fn assigning_a_verb_names_it_and_runs_nothing() {
3598 let s = stmts("mean =. +/ % #");
3599 assert_eq!(s.len(), 1);
3600 match &s[0] {
3601 Expr::VerbDef { name, verb, span } => {
3602 assert_eq!(name, "mean");
3603 assert!(matches!(verb, Verb::Fork(..)), "got {verb:?}");
3604 assert_eq!(*span, Span::new(0, 14));
3605 }
3606 other => panic!("expected a verb definition, got {other:?}"),
3607 }
3608 }
3609
3610 #[test]
3611 fn a_named_verb_applies_in_a_later_sentence() {
3612 let s = stmts("mean =. +/ % #\nmean 1 2 3 4");
3613 assert_eq!(s.len(), 2);
3614 let (v, y) = monad_of(&s[1]);
3615 assert!(matches!(v, Verb::Fork(..)), "got {v:?}");
3616 assert_eq!(konst(&y).shape, vec![4]);
3617 }
3618
3619 #[test]
3620 fn a_named_verb_is_a_verb_inside_a_train_and_under_a_conjunction() {
3621 let (v, _) = monad_of(&stmts("mean =. +/ % #\n(mean - {.) 1 2 3 4").pop().expect("two"));
3622 match &v {
3623 Verb::Fork(f, g, h) => {
3624 assert!(matches!(**f, Verb::Fork(..)), "got {f:?}");
3625 assert_eq!(prim_of(g).name, "-");
3626 assert_eq!(prim_of(h).name, "{.");
3627 }
3628 other => panic!("expected a fork, got {other:?}"),
3629 }
3630 let (v, _) = monad_of(&stmts("mean =. +/ % #\nmean\"1 m").pop().expect("two"));
3631 match &v {
3632 Verb::Rank(inner, r) => {
3633 assert_eq!(*r, [1, 1, 1]);
3634 assert!(matches!(**inner, Verb::Fork(..)), "got {inner:?}");
3635 }
3636 other => panic!("expected a ranked verb, got {other:?}"),
3637 }
3638 }
3639
3640 #[test]
3641 fn redefinition_rebinds_from_that_sentence_on() {
3642 let s = stmts("f =. +/\nf 1 2 3\nf =. #\nf 1 2 3");
3643 assert_eq!(s.len(), 4);
3644 assert!(matches!(monad_of(&s[1]).0, Verb::Reduce(_)));
3645 assert_eq!(prim_of(&monad_of(&s[3]).0).name, "#");
3646 }
3647
3648 #[test]
3649 fn a_name_may_change_part_of_speech_in_either_direction() {
3650 let s = stmts("a =. 1 2 3\na =. +/\na 1 2 3");
3652 assert!(matches!(s[0], Expr::Assign { .. }));
3653 assert!(matches!(s[1], Expr::VerbDef { .. }));
3654 assert!(matches!(monad_of(&s[2]).0, Verb::Reduce(_)));
3655 let s = stmts("f =. +/\nf =. 10 20\nf");
3656 assert!(matches!(s[0], Expr::VerbDef { .. }));
3657 assert!(matches!(s[1], Expr::Assign { .. }));
3658 assert!(matches!(s[2], Expr::Name(..)));
3659 }
3660
3661 #[test]
3662 fn an_undefined_name_applied_as_a_verb_is_a_value_error() {
3663 let e = err("zz 1 2 3");
3665 assert_eq!(e.kind, ErrorKind::Value);
3666 assert_eq!(e.msg, "undefined name: zz");
3667 assert_eq!(e.span, Some(Span::new(0, 2)));
3668 let e = err("a =. 5\na 1 2 3");
3671 assert_eq!(e.kind, ErrorKind::Parse);
3672 assert_eq!(e.msg, "syntax error");
3673 }
3674
3675 #[test]
3676 fn assignment_names_an_adverb_or_a_conjunction() {
3677 match one("insert =. /") {
3678 Expr::ModDef { name, spelling, conjunction, .. } => {
3679 assert_eq!(name, "insert");
3680 assert_eq!(spelling, "/");
3681 assert!(!conjunction);
3682 }
3683 other => panic!("expected a modifier definition, got {other:?}"),
3684 }
3685 match one("atop =. @") {
3686 Expr::ModDef { spelling, conjunction, .. } => {
3687 assert_eq!(spelling, "@");
3688 assert!(conjunction);
3689 }
3690 other => panic!("expected a modifier definition, got {other:?}"),
3691 }
3692 let s = stmts("insert =. /\n+ insert 1 2 3");
3695 assert!(matches!(s[1], Expr::Monad { verb: Verb::Reduce(_), .. }), "{:?}", s[1]);
3696 }
3697
3698 #[test]
3699 fn a_sentence_that_is_a_modifier_is_a_named_gap() {
3700 let e = err("insert =. /\ninsert");
3701 assert_eq!(e.kind, ErrorKind::NotYet);
3702 assert!(e.msg.contains("displaying a modifier"), "{}", e.msg);
3703 }
3704
3705 #[rstest]
3706 #[case("f =. 3 : 'y + 1'", None)]
3707 #[case("f =. 4 : 'x + y'", Some("x"))]
3708 #[case("f =. {{ y + 1 }}", None)]
3709 #[case("f =. {{ x + y }}", Some("x"))]
3710 fn an_explicit_definition_names_a_verb(#[case] src: &str, #[case] left: Option<&str>) {
3711 match one(src) {
3712 Expr::VerbDef { name, verb: Verb::Explicit(d), .. } => {
3713 assert_eq!(name, "f");
3714 assert_eq!(d.left.as_deref(), left);
3715 assert_eq!(d.right, "y");
3716 assert_eq!(d.body.len(), 1);
3717 }
3718 other => panic!("expected an explicit verb definition, got {other:?}"),
3719 }
3720 }
3721
3722 #[rstest]
3723 #[case("f =. 13 : 'y + 1'", "tacit definitions")]
3724 fn definition_forms_libjay_has_not_are_named(#[case] src: &str, #[case] msg: &str) {
3725 let e = err(src);
3726 assert_eq!(e.kind, ErrorKind::NotYet);
3727 assert!(e.msg.contains(msg), "{}", e.msg);
3728 }
3729
3730 #[rstest]
3733 #[case("f =. 1 : 'y + 1'", Some(false))]
3734 #[case("f =. 2 : 'u v y'", Some(true))]
3735 #[case("f =. {{ y + 1 }}", None)]
3736 #[case("f =. {{ u y }}", Some(false))]
3737 #[case("f =. {{ m + y }}", Some(false))]
3738 #[case("f =. {{ u v y }}", Some(true))]
3739 #[case("f =. {{ v y }}", Some(true))]
3740 #[case("f =. {{ n + y }}", Some(true))]
3741 #[case("f =. {{ u n y }}", Some(true))]
3742 #[case("f =. {{)a\nu y\n}}", Some(false))]
3743 #[case("f =. {{)c\nu v y\n}}", Some(true))]
3744 #[case("f =. {{)v\ny\n}}", None)]
3745 fn an_explicit_definitions_part_of_speech(#[case] src: &str, #[case] want: Option<bool>) {
3746 match (one(src), want) {
3747 (Expr::ModDef { name, conjunction, .. }, Some(conj)) => {
3748 assert_eq!(name, "f");
3749 assert_eq!(conjunction, conj, "{src:?}");
3750 }
3751 (Expr::VerbDef { name, .. }, None) => assert_eq!(name, "f"),
3752 (other, _) => panic!("expected {want:?} for {src:?}, got {other:?}"),
3753 }
3754 }
3755
3756 #[test]
3757 fn a_control_word_outside_a_definition_is_a_parse_error() {
3758 let e = err("if. 1 do. 2 end.");
3759 assert_eq!(e.kind, ErrorKind::Parse);
3760 assert!(e.msg.contains("only meaningful inside an explicit definition"), "{}", e.msg);
3761 }
3762
3763 #[test]
3764 fn multiple_assignment_is_not_supported_yet() {
3765 let e = err("'a b' =. 1 2");
3766 assert_eq!(e.kind, ErrorKind::NotYet);
3767 assert!(e.msg.contains("multiple assignment"), "{}", e.msg);
3768 }
3769
3770 #[test]
3773 fn a_hole_is_a_noun() {
3774 let e = one("{a} + 1");
3775 let (_, x, y) = dyad_of(&e);
3776 match x {
3777 Expr::Param(i, s) => {
3778 assert_eq!(i, 0);
3779 assert_eq!(s, Span::new(0, 3));
3780 }
3781 other => panic!("expected a parameter, got {other:?}"),
3782 }
3783 assert_eq!(ints(&y), vec![1]);
3784 assert_eq!(e.span(), Span::new(0, 7));
3785 }
3786
3787 #[test]
3788 fn holes_are_numbered_and_shared_by_name() {
3789 let sp = SourceParts::from_source("{a} + {b} + {a}").expect("source parts");
3790 assert_eq!(sp.param_names, vec!["a".to_string(), "b".to_string()]);
3791 let e = parse(&sp).expect("parse").pop().expect("one sentence");
3792 let (_, x, y) = dyad_of(&e);
3793 assert!(matches!(x, Expr::Param(0, _)));
3794 let (_, x2, y2) = dyad_of(&y);
3795 assert!(matches!(x2, Expr::Param(1, _)));
3796 assert!(matches!(y2, Expr::Param(0, _)));
3797 }
3798
3799 #[rstest]
3800 #[case("3j4", 3.0, 4.0)]
3801 #[case("_1j_2", -1.0, -2.0)]
3802 #[case("1e1j2", 10.0, 2.0)]
3803 #[case("2ad90", 0.0, 2.0)]
3804 #[case("1ad180", -1.0, 0.0)]
3805 fn complex_literals(#[case] src: &str, #[case] re: f64, #[case] im: f64) {
3806 let a = konst(&one(src));
3807 assert_eq!(a.dtype(), DType::Complex);
3808 let z = a.as_complex_slice().expect("complex data")[0];
3809 assert!((z[0] - re).abs() < 1e-12 && (z[1] - im).abs() < 1e-12, "{z:?}");
3810 }
3811
3812 #[test]
3813 fn a_hole_takes_a_verb_like_any_noun() {
3814 let (v, y) = monad_of(&one("+/ {data}"));
3815 assert!(matches!(v, Verb::Reduce(_)));
3816 assert!(matches!(y, Expr::Param(0, _)));
3817 }
3818
3819 #[test]
3820 fn braces_inside_a_string_are_not_holes() {
3821 let sp = SourceParts::from_source("'{a}'").expect("source parts");
3822 assert!(sp.param_names.is_empty());
3823 let a = konst(&parse(&sp).expect("parse")[0]);
3824 assert_eq!(a.data, Data::Char(vec!['{', 'a', '}'].into()));
3825 }
3826
3827 #[test]
3828 fn parts_of_one_sentence_lex_across_a_hole() {
3829 let sp = SourceParts::from_parts(&["1 + ", " * 2"], &["v"]);
3831 assert_eq!(sp.display, "1 + {v} * 2");
3832 let e = parse(&sp).expect("parse").pop().expect("one sentence");
3833 let (_, x, y) = dyad_of(&e);
3834 assert_eq!(ints(&x), vec![1]);
3835 let (_, x2, y2) = dyad_of(&y);
3836 assert!(matches!(x2, Expr::Param(0, _)));
3837 assert_eq!(ints(&y2), vec![2]);
3838 }
3839
3840 #[test]
3841 fn spans_of_later_sentences_index_the_whole_source() {
3842 let src = "5\n1 + 2";
3843 let s = stmts(src);
3844 assert_eq!(s[1].span(), Span::new(2, 7));
3845 assert_eq!(&src[2..7], "1 + 2");
3846 }
3847
3848 #[test]
3851 fn unknown_word_reports_its_span() {
3852 let e = err("1 [. 2");
3853 assert_eq!(e.kind, ErrorKind::Parse);
3854 assert_eq!(e.msg, "unknown word: [.");
3855 assert_eq!(e.span, Some(Span::new(2, 4)));
3856 }
3857
3858 #[test]
3859 fn an_inflected_unknown_word_is_reported_whole() {
3860 let e = err("1 ]: 2");
3861 assert_eq!(e.msg, "unknown word: ]:");
3862 assert_eq!(e.span, Some(Span::new(2, 4)));
3863 }
3864
3865 #[rstest]
3867 #[case("1.5x", 0, 4)]
3868 #[case("1e10x", 0, 5)]
3869 fn a_fractional_extended_literal_is_ill_formed(
3870 #[case] src: &str,
3871 #[case] start: usize,
3872 #[case] end: usize,
3873 ) {
3874 let e = err(src);
3875 assert_eq!(e.kind, ErrorKind::Parse);
3876 assert!(e.msg.contains("invalid number"), "{}", e.msg);
3877 assert_eq!(e.span, Some(Span::new(start, end)));
3878 }
3879
3880 #[test]
3881 fn a_malformed_number_is_a_parse_error() {
3882 let e = err("1.2.3");
3883 assert_eq!(e.kind, ErrorKind::Parse);
3884 assert!(e.msg.contains("invalid number"), "{}", e.msg);
3885 }
3886
3887 #[test]
3888 fn an_unbalanced_sentence_is_a_syntax_error() {
3889 let e = err("(1 + 2");
3892 assert_eq!(e.kind, ErrorKind::Parse);
3893 assert!(e.msg.contains("no closing"), "{}", e.msg);
3894 assert_eq!(e.span, Some(Span::new(0, 1)));
3895 }
3896
3897 #[test]
3898 fn a_stray_right_parenthesis_is_a_syntax_error() {
3899 let e = err("1 + 2)");
3900 assert_eq!(e.kind, ErrorKind::Parse);
3901 assert!(e.msg.contains("no opening"), "{}", e.msg);
3902 assert_eq!(e.span, Some(Span::new(5, 6)));
3903 }
3904
3905 #[test]
3906 fn the_error_of_a_later_sentence_points_at_that_sentence() {
3907 let e = err("1 + 2\n3 [. 4");
3908 assert_eq!(e.span, Some(Span::new(8, 10)));
3909 }
3910}