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::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::NotYet("format with a specification"), [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::NotYet("sequential machine (dyadic ;:)"),
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::NotYet("numbers from text (dyadic \".)"),
1210 [1, INF, INF],
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(
1217 "s:",
1218 M::NotYet("symbols (s:)"),
1219 D::NotYet("symbols (s:)"),
1220 [INF, INF, INF],
1221 ),
1222 "]" => prim("]", M::Same, D::Right, [INF, INF, INF]),
1223 "[" => prim("[", M::Same, D::Left, [INF, INF, INF]),
1224 "echo" => prim("echo", M::Echo, D::None, [INF, INF, INF]),
1225 _ => return None,
1226 })
1227}
1228
1229fn noun_word(word: &str) -> Option<Array> {
1234 match word {
1235 "a." => Some(Array::from_chars(
1236 (0u32..256).map(|c| char::from_u32(c).expect("a Latin-1 codepoint")).collect(),
1237 )),
1238 "a:" => Some(Array::boxed(Array::empty(crate::dtype::DType::I64))),
1239 "_." => Some(Array::scalar_f64(f64::NAN)),
1240 _ => None,
1241 }
1242}
1243
1244fn verb_for(word: &str) -> Option<Verb> {
1247 let p = primitive(word)?;
1248 if word == ",." {
1249 return Some(Verb::Rank(Box::new(Verb::Prim(p)), [-1, -1, -1]));
1250 }
1251 Some(Verb::Prim(p))
1252}
1253
1254fn constant_verb(n: Array) -> Verb {
1257 Verb::NounFork(
1260 n,
1261 Box::new(verb_for("[").expect("`[` is a primitive")),
1262 Box::new(verb_for("]").expect("`]` is a primitive")),
1263 )
1264}
1265
1266fn constant_verb_word(cs: &[(usize, char)], i: usize) -> Option<(usize, Array)> {
1270 let at = |k: usize| cs.get(k).map(|&(_, c)| c);
1271 let (digits, value) = match (at(i), at(i + 1), at(i + 2)) {
1272 (Some('_'), Some(':'), _) => (2, f64::INFINITY),
1273 (Some('_'), Some(d), Some(':')) if d.is_ascii_digit() => {
1274 (3, -((d as u8 - b'0') as f64))
1275 }
1276 (Some(d), Some(':'), _) if d.is_ascii_digit() => (2, (d as u8 - b'0') as f64),
1277 _ => return None,
1278 };
1279 if at(i + digits) == Some(':') {
1280 return None;
1281 }
1282 let arr = if value.is_infinite() {
1283 Array::scalar_f64(value)
1284 } else {
1285 Array::scalar_i64(value as i64)
1286 };
1287 Some((digits, arr))
1288}
1289
1290pub(crate) fn verb_named(word: &str) -> Option<Verb> {
1293 verb_for(word)
1294}
1295
1296const ADVERBS: [&str; 9] = ["/", "\\", "/.", "\\.", "~", "}", "f.", "M.", "b."];
1297
1298const CONJUNCTIONS: [&str; 24] = [
1301 "\"", "@", "@.", "@:", "&", "&.", "&.:", "&:", "^:", ";.", "!.", "!:", "`", "`:", ".", ":",
1302 ":.", "::", "L:", "S:", "H.", "T.", "t.", "t:",
1303];
1304
1305fn adverb(word: &str) -> Option<&'static str> {
1306 ADVERBS.iter().copied().find(|&g| g == word)
1307}
1308
1309fn conjunction(word: &str) -> Option<&'static str> {
1310 CONJUNCTIONS.iter().copied().find(|&g| g == word)
1311}
1312
1313fn lex(src: &SourceParts) -> Result<Vec<Vec<Frag>>> {
1318 let mut sentences: Vec<Vec<Frag>> = Vec::new();
1319 let mut cur: Vec<Frag> = Vec::new();
1320 for seg in &src.segments {
1321 match seg {
1322 Segment::Text { text, offset } => {
1323 let mut pos = 0usize;
1324 for (n, line) in text.split('\n').enumerate() {
1325 if n > 0 && !cur.is_empty() {
1326 sentences.push(std::mem::take(&mut cur));
1327 }
1328 lex_line(line, offset + pos, &mut cur)?;
1329 pos += line.len() + 1;
1330 }
1331 }
1332 Segment::Param { index, offset, len } => {
1333 let span = Span::new(*offset, *offset + *len);
1334 cur.push(Frag::Noun(Expr::Param(*index, span)));
1335 }
1336 }
1337 }
1338 if !cur.is_empty() {
1339 sentences.push(cur);
1340 }
1341 Ok(sentences)
1342}
1343
1344#[derive(Clone, Debug)]
1347enum Num {
1348 I(i64),
1349 F(f64),
1350 X(crate::exact::Ext),
1352 R(crate::exact::Rat),
1354 C(crate::complex::Cx),
1355}
1356
1357fn lex_line(text: &str, base: usize, out: &mut Vec<Frag>) -> Result<()> {
1358 let cs: Vec<(usize, char)> = text.char_indices().collect();
1359 let at = |i: usize| cs.get(i).map(|&(_, c)| c);
1360 let off = |i: usize| cs.get(i).map(|&(o, _)| o).unwrap_or(text.len());
1361 let span = |a: usize, b: usize| Span::new(base + off(a), base + off(b));
1362 let mut i = 0usize;
1363 while i < cs.len() {
1364 let c = cs[i].1;
1365 if c.is_whitespace() {
1366 i += 1;
1367 continue;
1368 }
1369 if c == 'N' && at(i + 1) == Some('B') && at(i + 2) == Some('.') {
1372 break;
1373 }
1374 if c == '\'' {
1375 let start = i;
1376 i += 1;
1377 let mut chars: Vec<char> = Vec::new();
1378 loop {
1379 match at(i) {
1380 None => {
1381 return Err(Error::parse(
1382 "unterminated string literal",
1383 span(start, cs.len()),
1384 ));
1385 }
1386 Some('\'') if at(i + 1) == Some('\'') => {
1387 chars.push('\'');
1388 i += 2;
1389 }
1390 Some('\'') => {
1391 i += 1;
1392 break;
1393 }
1394 Some(ch) => {
1395 chars.push(ch);
1396 i += 1;
1397 }
1398 }
1399 }
1400 let shape = if chars.len() == 1 { vec![] } else { vec![chars.len()] };
1402 let arr = Array::new(shape, Data::Char(chars.into()));
1403 out.push(Frag::Noun(Expr::Const(arr, span(start, i))));
1404 continue;
1405 }
1406 if let Some((len, n)) = constant_verb_word(&cs, i) {
1407 out.push(Frag::Verb(VerbFrag::V(constant_verb(n)), span(i, i + len)));
1408 i += len;
1409 continue;
1410 }
1411 if starts_number(&cs, i) {
1412 let start = i;
1414 let mut nums: Vec<Num> = Vec::new();
1415 let mut end;
1416 loop {
1417 let ws = i;
1418 while at(i).is_some_and(|c| c.is_ascii_alphanumeric() || c == '.' || c == '_') {
1419 i += 1;
1420 }
1421 nums.push(parse_number(&text[off(ws)..off(i)], span(ws, i))?);
1422 end = i;
1423 let mut k = i;
1424 while at(k).is_some_and(char::is_whitespace) {
1425 k += 1;
1426 }
1427 if k < cs.len()
1430 && starts_number(&cs, k)
1431 && constant_verb_word(&cs, k).is_none()
1432 {
1433 i = k;
1434 } else {
1435 break;
1436 }
1437 }
1438 out.push(Frag::Noun(Expr::Const(num_array(&nums), span(start, end))));
1439 continue;
1440 }
1441 if c.is_ascii_alphabetic() {
1442 let start = i;
1443 i += 1;
1444 while at(i).is_some_and(|c| c.is_ascii_alphanumeric() || c == '_') {
1445 i += 1;
1446 }
1447 let mut inflected = None;
1452 if matches!(at(i), Some('.') | Some(':')) {
1453 let most = if matches!(at(i + 1), Some('.') | Some(':')) { 2 } else { 1 };
1454 for n in (1..=most).rev() {
1455 let word = &text[off(start)..off(i + n)];
1456 let sp = span(start, i + n);
1457 let frag = if let Some(v) = verb_for(word) {
1458 Frag::Verb(VerbFrag::V(v), sp)
1459 } else if let Some(value) = noun_word(word) {
1460 Frag::Noun(Expr::Const(value, sp))
1461 } else if let Some(g) = adverb(word) {
1462 Frag::Adverb(Modifier::Prim(g), sp)
1463 } else if let Some(g) = conjunction(word) {
1464 Frag::Conj(Modifier::Prim(g), sp)
1465 } else if let Some((cw, suffix)) = control_word(word) {
1466 Frag::Control(cw, suffix, sp)
1467 } else {
1468 continue;
1469 };
1470 inflected = Some((frag, n));
1471 break;
1472 }
1473 }
1474 if let Some((frag, n)) = inflected {
1475 i += n;
1476 out.push(frag);
1477 continue;
1478 }
1479 let word = &text[off(start)..off(i)];
1480 match verb_for(word) {
1481 Some(v) => out.push(Frag::Verb(VerbFrag::V(v), span(start, i))),
1482 None => out.push(Frag::Name(word.to_string(), span(start, i))),
1483 }
1484 continue;
1485 }
1486 if c == '{' && at(i + 1) == Some('{') {
1488 let marker = match (at(i + 2), at(i + 3)) {
1493 (Some(')'), Some(m)) if m.is_ascii_alphabetic() => Some(m),
1494 _ => None,
1495 };
1496 if let Some(m) = marker {
1497 if cs[i + 4..].iter().any(|&(_, c)| !c.is_whitespace()) {
1498 return Err(Error::parse(
1499 format!("`)`{m} names the part of speech of a direct definition, \
1500 and has to be the last thing on its line"),
1501 span(i, i + 4),
1502 ));
1503 }
1504 out.push(Frag::DdOpen(Some(m), span(i, i + 4)));
1505 i += 4;
1506 continue;
1507 }
1508 out.push(Frag::DdOpen(None, span(i, i + 2)));
1509 i += 2;
1510 continue;
1511 }
1512 if c == '}' && at(i + 1) == Some('}') {
1513 out.push(Frag::DdClose(span(i, i + 2)));
1514 i += 2;
1515 continue;
1516 }
1517 let inflectable = c != '(' && c != ')';
1521 let mut len =
1522 if inflectable && matches!(at(i + 1), Some('.') | Some(':')) { 2 } else { 1 };
1523 if len == 2 && at(i + 2) == Some(':') {
1526 let w = &text[off(i)..off(i + 3)];
1527 if conjunction(w).is_some() || verb_for(w).is_some() {
1528 len = 3;
1529 }
1530 }
1531 let word = &text[off(i)..off(i + len)];
1532 match symbol_frag(word, span(i, i + len)) {
1533 Some(frag) => {
1534 out.push(frag);
1535 i += len;
1536 }
1537 None => {
1538 return Err(Error::parse(format!("unknown word: {word}"), span(i, i + len)));
1539 }
1540 }
1541 }
1542 Ok(())
1543}
1544
1545fn symbol_frag(word: &str, span: Span) -> Option<Frag> {
1546 Some(match word {
1547 "(" => Frag::LParen(span),
1548 ")" => Frag::RParen(span),
1549 "=." => Frag::AssignLocal(span),
1550 "=:" => Frag::AssignGlobal(span),
1551 "[:" => Frag::Verb(VerbFrag::Cap, span),
1552 "$:" => Frag::Verb(VerbFrag::V(Verb::SelfRef), span),
1554 _ => {
1557 if let Some(v) = verb_for(word) {
1558 Frag::Verb(VerbFrag::V(v), span)
1559 } else if let Some(g) = adverb(word) {
1560 Frag::Adverb(Modifier::Prim(g), span)
1561 } else {
1562 Frag::Conj(Modifier::Prim(conjunction(word)?), span)
1563 }
1564 }
1565 })
1566}
1567
1568fn starts_number(cs: &[(usize, char)], i: usize) -> bool {
1571 let c = cs[i].1;
1572 if c.is_ascii_digit() {
1573 return true;
1574 }
1575 if c != '_' {
1576 return false;
1577 }
1578 match cs.get(i + 1).map(|&(_, c)| c) {
1579 None => true,
1580 Some(d) => d.is_ascii_digit() || d == '.' || !d.is_alphanumeric(),
1581 }
1582}
1583
1584fn parse_number(word: &str, span: Span) -> Result<Num> {
1585 if word == "_." {
1587 return Ok(Num::F(f64::NAN));
1588 }
1589 if let Some(k) = word.find(['p', 'x']) {
1593 if word[k + 1..].is_empty() {
1594 if word.as_bytes()[k] == b'x' {
1598 return extended_literal(&word[..k], word, span);
1599 }
1600 return Err(Error::parse(format!("invalid number: {word}"), span));
1601 }
1602 let base =
1603 if word.as_bytes()[k] == b'p' { std::f64::consts::PI } else { std::f64::consts::E };
1604 let mantissa = plain_number(&word[..k], word, span)?;
1605 let exponent = plain_number(&word[k + 1..], word, span)?;
1606 return Ok(scale(mantissa, base, exponent));
1607 }
1608 if let Some(k) = word.find('j') && !word[..k].contains('b') {
1611 let re = as_f64(plain_number(&word[..k], word, span)?);
1612 let im = as_f64(plain_number(&word[k + 1..], word, span)?);
1613 return Ok(Num::C([re, im]));
1614 }
1615 if let Some(k) = word.find("ad").or_else(|| word.find("ar")) && !word[..k].contains('b') {
1618 let magnitude = as_f64(plain_number(&word[..k], word, span)?);
1619 let angle = as_f64(plain_number(&word[k + 2..], word, span)?);
1620 return Ok(Num::C(if word.as_bytes()[k + 1] == b'd' {
1621 crate::complex::from_degrees(magnitude, angle)
1622 } else {
1623 crate::complex::from_radians(magnitude, angle)
1624 }));
1625 }
1626 if let Some(k) = word.find('r') && !word[..k].contains('b') {
1630 return rational_literal(&word[..k], &word[k + 1..], word, span);
1631 }
1632 if let Some(k) = word.find('b') {
1633 return base_literal(&word[..k], &word[k + 1..], word, span);
1634 }
1635 plain_number(word, word, span)
1636}
1637
1638fn extended_literal(digits: &str, word: &str, span: Span) -> Result<Num> {
1641 Ok(Num::X(whole_digits(digits, word, span)?))
1642}
1643
1644fn rational_literal(num: &str, den: &str, word: &str, span: Span) -> Result<Num> {
1647 use num_traits::Zero;
1648 let num = whole_digits(num, word, span)?;
1649 let den = whole_digits(den, word, span)?;
1650 if den.is_zero() {
1651 if num.is_zero() {
1652 return Ok(Num::I(0));
1653 }
1654 return Ok(Num::F(if num.sign() == num_bigint::Sign::Minus {
1655 f64::NEG_INFINITY
1656 } else {
1657 f64::INFINITY
1658 }));
1659 }
1660 Ok(Num::R(
1661 crate::exact::Rat::new(num, den).ok_or_else(|| Error::internal("a zero denominator"))?,
1662 ))
1663}
1664
1665fn whole_digits(word: &str, whole: &str, span: Span) -> Result<crate::exact::Ext> {
1667 let invalid = || Error::parse(format!("invalid number: {whole}"), span);
1668 let (digits, negative) = match word.strip_prefix('_') {
1669 Some(rest) => (rest, true),
1670 None => (word, false),
1671 };
1672 if digits.is_empty() || !digits.bytes().all(|b| b.is_ascii_digit()) {
1673 return Err(invalid());
1674 }
1675 let v: crate::exact::Ext = digits.parse().map_err(|_| invalid())?;
1676 Ok(if negative { -v } else { v })
1677}
1678
1679fn scale(mantissa: Num, base: f64, exponent: Num) -> Num {
1682 if matches!(mantissa, Num::C(_)) || matches!(exponent, Num::C(_)) {
1683 let m = as_cx(mantissa);
1684 let f = crate::complex::pow([base, 0.0], as_cx(exponent));
1685 return Num::C(crate::complex::mul(m, f));
1686 }
1687 Num::F(as_f64(mantissa) * base.powf(as_f64(exponent)))
1688}
1689
1690fn as_cx(n: Num) -> crate::complex::Cx {
1691 match n {
1692 Num::C(z) => z,
1693 other => [as_f64(other), 0.0],
1694 }
1695}
1696
1697fn as_f64(n: Num) -> f64 {
1698 match n {
1699 Num::I(v) => v as f64,
1700 Num::F(v) => v,
1701 Num::X(v) => crate::exact::ext_to_f64(&v),
1702 Num::R(v) => v.to_f64(),
1703 Num::C(z) => z[0],
1706 }
1707}
1708
1709fn base_literal(base: &str, digits: &str, word: &str, span: Span) -> Result<Num> {
1712 let invalid = || Error::parse(format!("invalid number: {word}"), span);
1713 let base = as_f64(plain_number(base, word, span)?);
1714 let (digits, negative) = match digits.strip_prefix('_') {
1715 Some(rest) => (rest, true),
1716 None => (digits, false),
1717 };
1718 if digits.is_empty() {
1719 return Err(invalid());
1720 }
1721 let mut value = 0.0f64;
1722 for ch in digits.chars() {
1723 let d = match ch {
1724 '0'..='9' => ch as u32 - '0' as u32,
1725 'a'..='z' => ch as u32 - 'a' as u32 + 10,
1726 _ => return Err(invalid()),
1727 };
1728 value = value * base + f64::from(d);
1729 }
1730 if negative {
1731 value = -value;
1732 }
1733 if value.fract() == 0.0 && value.abs() < 9.007_199_254_740_992e15 {
1735 return Ok(Num::I(value as i64));
1736 }
1737 Ok(Num::F(value))
1738}
1739
1740fn plain_number(word: &str, whole: &str, span: Span) -> Result<Num> {
1744 if word.is_empty() {
1745 return Err(Error::parse(format!("invalid number: {whole}"), span));
1746 }
1747 if word.contains(['j', 'p', 'x', 'b', 'r']) || word.contains("ad") || word.contains("ar") {
1748 return parse_number(word, span);
1749 }
1750 parse_plain(word, span)
1751}
1752
1753fn parse_plain(word: &str, span: Span) -> Result<Num> {
1754 if word == "_" {
1755 return Ok(Num::F(f64::INFINITY));
1756 }
1757 if word == "__" {
1758 return Ok(Num::F(f64::NEG_INFINITY));
1759 }
1760 let invalid = || Error::parse(format!("invalid number: {word}"), span);
1761 let mut norm = String::with_capacity(word.len());
1763 for (k, ch) in word.char_indices() {
1764 if ch == '_' {
1765 if k != 0 && !word[..k].ends_with('e') {
1766 return Err(invalid());
1767 }
1768 norm.push('-');
1769 } else {
1770 norm.push(ch);
1771 }
1772 }
1773 if norm.contains('.') || norm.contains('e') {
1775 return norm.parse::<f64>().map(Num::F).map_err(|_| invalid());
1776 }
1777 match norm.parse::<i64>() {
1780 Ok(v) => Ok(Num::I(v)),
1781 Err(_) => norm.parse::<f64>().map(Num::F).map_err(|_| invalid()),
1782 }
1783}
1784
1785fn num_array(nums: &[Num]) -> Array {
1789 use crate::exact::{Ext, Rat};
1790 let shape = if nums.len() == 1 { vec![] } else { vec![nums.len()] };
1791 let has = |f: fn(&Num) -> bool| nums.iter().any(f);
1792 if has(|n| matches!(n, Num::C(_))) {
1793 let data = nums.iter().map(|n| as_cx(n.clone())).collect();
1794 return Array::new(shape, Data::Complex(data));
1795 }
1796 if has(|n| matches!(n, Num::F(_))) {
1797 let data = nums.iter().map(|n| as_f64(n.clone())).collect();
1798 return Array::new(shape, Data::F64(data));
1799 }
1800 if has(|n| matches!(n, Num::R(_))) {
1801 let data = nums
1802 .iter()
1803 .map(|n| match n {
1804 Num::I(v) => Rat::from_int(Ext::from(*v)),
1805 Num::X(v) => Rat::from_int(v.clone()),
1806 Num::R(v) => v.clone(),
1807 Num::F(_) | Num::C(_) => Rat::zero(),
1808 })
1809 .collect();
1810 return Array::new(shape, Data::Rat(data));
1811 }
1812 if has(|n| matches!(n, Num::X(_))) {
1813 let data = nums
1814 .iter()
1815 .map(|n| match n {
1816 Num::I(v) => Ext::from(*v),
1817 Num::X(v) => v.clone(),
1818 _ => Ext::default(),
1819 })
1820 .collect();
1821 return Array::new(shape, Data::Ext(data));
1822 }
1823 let data = nums
1824 .iter()
1825 .map(|n| match n {
1826 Num::I(v) => *v,
1827 _ => 0,
1828 })
1829 .collect();
1830 Array::new(shape, Data::I64(data))
1831}
1832
1833#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1836enum Rule {
1837 Monad1,
1838 Monad2,
1839 Dyad3,
1840 Adverb4,
1841 Conj5,
1842 Fork6,
1843 Bident7,
1844 Assign8,
1845 Paren9,
1846}
1847
1848fn reduce_to_fragment(tokens: Vec<Frag>, scope: &Names) -> Result<Option<Frag>> {
1852 check_parens(&tokens)?;
1853 let mut stack: Vec<Frag> = Vec::new();
1854 for frag in tokens.into_iter().rev() {
1855 stack.insert(0, frag);
1856 reduce(&mut stack, scope)?;
1857 }
1858 stack.insert(0, Frag::Mark);
1859 reduce(&mut stack, scope)?;
1860 if stack.len() == 2 {
1861 return Ok(Some(stack.pop().expect("checked length")));
1862 }
1863 Ok(None)
1864}
1865
1866fn lower_sentence(frag: Option<Frag>, whole: Span) -> Result<Expr> {
1869 match frag {
1870 Some(f @ (Frag::Noun(_) | Frag::Name(..))) => as_noun(f),
1871 Some(Frag::VerbDef(name, verb, span)) => Ok(Expr::VerbDef { name, verb, span }),
1872 Some(Frag::ModDef(name, conjunction, m, span)) => {
1873 Ok(Expr::ModDef { name, spelling: m.spelling(), conjunction, span })
1874 }
1875 Some(Frag::Verb(VerbFrag::V(_), span)) => {
1876 Err(Error::not_yet("tacit verb definitions (a sentence that is a verb)", span))
1877 }
1878 Some(Frag::Adverb(_, span) | Frag::Conj(_, span)) => Err(Error::not_yet(
1879 "displaying a modifier (a sentence that is an adverb or a conjunction)",
1880 span,
1881 )),
1882 _ => Err(Error::parse("syntax error", whole)),
1883 }
1884}
1885
1886fn check_parens(tokens: &[Frag]) -> Result<()> {
1890 let mut open: Vec<Span> = Vec::new();
1891 for frag in tokens {
1892 match frag {
1893 Frag::LParen(s) => open.push(*s),
1894 Frag::RParen(s) => {
1895 if open.pop().is_none() {
1896 return Err(Error::parse("this `)` has no opening `(`", *s));
1897 }
1898 }
1899 _ => {}
1900 }
1901 }
1902 match open.pop() {
1903 None => Ok(()),
1904 Some(s) => Err(Error::parse("this `(` has no closing `)`", s)),
1905 }
1906}
1907
1908fn sentence_span(tokens: &[Frag]) -> Span {
1909 tokens
1910 .iter()
1911 .map(Frag::span)
1912 .reduce(Span::merge)
1913 .unwrap_or_else(|| Span::new(0, 0))
1914}
1915
1916fn reduce(stack: &mut Vec<Frag>, scope: &Names) -> Result<()> {
1917 while apply(stack, scope)? {}
1918 Ok(())
1919}
1920
1921fn match_rule(s: &[Frag]) -> Option<Rule> {
1924 let is = |i: usize, f: fn(&Frag) -> bool| s.get(i).is_some_and(f);
1925 let ctx = |i: usize| s.get(i).is_some_and(|f| f.is_edge() || f.is_avn());
1928 let verb_or_noun =
1929 |i: usize| s.get(i).is_some_and(|f| f.is_real_verb() || f.is_noun());
1930 if is(0, Frag::is_edge) && is(1, Frag::is_real_verb) && is(2, Frag::is_noun) {
1931 return Some(Rule::Monad1);
1932 }
1933 if ctx(0) && is(1, Frag::is_verb) && is(2, Frag::is_real_verb) && is(3, Frag::is_noun) {
1934 return Some(Rule::Monad2);
1935 }
1936 if ctx(0) && is(1, Frag::is_noun) && is(2, Frag::is_real_verb) && is(3, Frag::is_noun) {
1937 return Some(Rule::Dyad3);
1938 }
1939 if ctx(0) && verb_or_noun(1) && is(2, Frag::is_adverb) {
1940 return Some(Rule::Adverb4);
1941 }
1942 if ctx(0) && verb_or_noun(1) && is(2, Frag::is_conj) && verb_or_noun(3) {
1943 return Some(Rule::Conj5);
1944 }
1945 if ctx(0)
1946 && s.get(1).is_some_and(|f| f.is_verb() || f.is_noun())
1947 && is(2, Frag::is_real_verb)
1948 && is(3, Frag::is_real_verb)
1949 {
1950 return Some(Rule::Fork6);
1951 }
1952 if is(0, Frag::is_edge) && is(1, Frag::is_cavn) && is(2, Frag::is_cavn) {
1953 return Some(Rule::Bident7);
1954 }
1955 if is(0, Frag::is_noun) && is(1, Frag::is_assign) && is(2, Frag::is_cavn) {
1956 return Some(Rule::Assign8);
1957 }
1958 if matches!(s.first(), Some(Frag::LParen(_)))
1959 && is(1, Frag::is_cavn)
1960 && matches!(s.get(2), Some(Frag::RParen(_)))
1961 {
1962 return Some(Rule::Paren9);
1963 }
1964 None
1965}
1966
1967fn take(stack: &mut Vec<Frag>, range: Range<usize>) -> Vec<Frag> {
1968 stack.drain(range).collect()
1969}
1970
1971fn respan(f: Frag, to: Span) -> Frag {
1975 match f {
1976 Frag::Noun(mut e) => {
1977 e.set_span(to);
1978 Frag::Noun(e)
1979 }
1980 Frag::Name(n, _) => Frag::Name(n, to),
1981 Frag::Verb(v, _) => Frag::Verb(v, to),
1982 Frag::Adverb(a, _) => Frag::Adverb(a, to),
1983 Frag::Conj(c, _) => Frag::Conj(c, to),
1984 other => other,
1985 }
1986}
1987
1988fn apply(stack: &mut Vec<Frag>, scope: &Names) -> Result<bool> {
1989 let Some(rule) = match_rule(stack) else {
1990 return Ok(false);
1991 };
1992 match rule {
1993 Rule::Monad1 => {
1994 let mut t = take(stack, 1..3);
1995 let y = t.pop().expect("two slots");
1996 let v = t.pop().expect("two slots");
1997 let frag = monad(v, y)?;
1998 stack.insert(1, frag);
1999 }
2000 Rule::Monad2 => {
2001 let mut t = take(stack, 2..4);
2002 let y = t.pop().expect("two slots");
2003 let v = t.pop().expect("two slots");
2004 let frag = monad(v, y)?;
2005 stack.insert(2, frag);
2006 }
2007 Rule::Dyad3 => {
2008 let mut t = take(stack, 1..4);
2009 let y = t.pop().expect("three slots");
2010 let v = t.pop().expect("three slots");
2011 let x = t.pop().expect("three slots");
2012 let frag = dyad(x, v, y)?;
2013 stack.insert(1, frag);
2014 }
2015 Rule::Adverb4 => {
2016 let mut t = take(stack, 1..3);
2017 let a = t.pop().expect("two slots");
2018 let u = t.pop().expect("two slots");
2019 let frag = apply_adverb(u, a, scope)?;
2020 stack.insert(1, frag);
2021 }
2022 Rule::Conj5 => {
2023 let mut t = take(stack, 1..4);
2024 let v = t.pop().expect("three slots");
2025 let c = t.pop().expect("three slots");
2026 let u = t.pop().expect("three slots");
2027 let frag = apply_conj(u, c, v, scope)?;
2028 stack.insert(1, frag);
2029 }
2030 Rule::Fork6 => {
2031 let mut t = take(stack, 1..4);
2032 let h = t.pop().expect("three slots");
2033 let g = t.pop().expect("three slots");
2034 let f = t.pop().expect("three slots");
2035 let frag = apply_fork(f, g, h)?;
2036 stack.insert(1, frag);
2037 }
2038 Rule::Bident7 => {
2039 let mut t = take(stack, 1..3);
2040 let b = t.pop().expect("two slots");
2041 let a = t.pop().expect("two slots");
2042 let frag = apply_bident(a, b, &scope.nouns)?;
2043 stack.insert(1, frag);
2044 }
2045 Rule::Assign8 => {
2046 let mut t = take(stack, 0..3);
2047 let value = t.pop().expect("three slots");
2048 let assign = t.pop().expect("three slots");
2049 let target = t.pop().expect("three slots");
2050 let scope = match assign {
2051 Frag::AssignGlobal(_) => Scope::Global,
2052 _ => Scope::Local,
2053 };
2054 let frag = apply_assign(target, value, scope)?;
2055 stack.insert(0, frag);
2056 }
2057 Rule::Paren9 => {
2058 let mut t = take(stack, 0..3);
2059 let close = t.pop().expect("three slots");
2060 let inner = t.pop().expect("three slots");
2061 let open = t.pop().expect("three slots");
2062 let outer = Span::merge(open.span(), close.span());
2063 stack.insert(0, respan(inner, outer));
2064 }
2065 }
2066 Ok(true)
2067}
2068
2069fn as_noun(f: Frag) -> Result<Expr> {
2072 match f {
2073 Frag::Noun(e) => Ok(e),
2074 Frag::Name(n, s) => Ok(Expr::Name(n, s)),
2075 other => Err(Error::internal(format!("expected a noun fragment, got {other:?}"))),
2076 }
2077}
2078
2079fn as_verb(f: Frag) -> Result<(Verb, Span)> {
2080 match f {
2081 Frag::Verb(VerbFrag::V(v), s) => Ok((v, s)),
2082 other => Err(Error::internal(format!("expected a verb fragment, got {other:?}"))),
2083 }
2084}
2085
2086fn as_const(f: &Frag) -> Option<&Array> {
2089 match f {
2090 Frag::Noun(Expr::Const(a, _)) => Some(a),
2091 _ => None,
2092 }
2093}
2094
2095fn noun_value(f: &Frag) -> Option<Array> {
2100 if let Some(a) = as_const(f) {
2101 return Some(a.clone());
2102 }
2103 let Frag::Noun(e) = f else { return None };
2104 let cfg = crate::verb::EvalCfg {
2105 agreement: crate::verb::Agreement::LeadingPrefix,
2106 fmt: crate::fmt::FmtOpts::J,
2107 tol: crate::verb::Tol::J,
2108 rules: crate::frontend::Rules::default(),
2109 };
2110 crate::ir::fold_const(e, cfg)
2111}
2112
2113fn monad(v: Frag, y: Frag) -> Result<Frag> {
2114 let (verb, vspan) = as_verb(v)?;
2115 let y = as_noun(y)?;
2116 let span = Span::merge(vspan, y.span());
2117 Ok(Frag::Noun(Expr::Monad { verb, y: Box::new(y), span }))
2118}
2119
2120fn dyad(x: Frag, v: Frag, y: Frag) -> Result<Frag> {
2121 let x = as_noun(x)?;
2122 let (verb, vspan) = as_verb(v)?;
2123 let y = as_noun(y)?;
2124 let span = Span::merge(Span::merge(x.span(), vspan), y.span());
2125 Ok(Frag::Noun(Expr::Dyad { verb, x: Box::new(x), y: Box::new(y), span }))
2126}
2127
2128fn apply_adverb(u: Frag, a: Frag, scope: &Names) -> Result<Frag> {
2129 let Frag::Adverb(m, aspan) = a else {
2130 return Err(Error::internal("expected an adverb fragment"));
2131 };
2132 let span = Span::merge(u.span(), aspan);
2133 let glyph = match m {
2134 Modifier::Prim(g) => g,
2135 Modifier::Explicit(src) => return derive_explicit(&src, u, None, scope, span),
2136 };
2137 if glyph == "}" {
2140 if !u.is_real_verb() {
2141 let m = noun_value(&u)
2142 .ok_or_else(|| Error::not_yet("amend over a computed index", span))?;
2143 return Ok(Frag::Verb(VerbFrag::V(Verb::Amend(m)), span));
2144 }
2145 let (v, _) = as_verb(u)?;
2146 return Ok(Frag::Verb(VerbFrag::V(Verb::AmendVerb(Box::new(v))), span));
2147 }
2148 if glyph == "b." && !u.is_real_verb() {
2151 let m = as_const(&u)
2152 .and_then(Array::to_i64_vec)
2153 .and_then(|v| v.first().copied())
2154 .filter(|&m| (0..32).contains(&m))
2155 .ok_or_else(|| {
2156 Error::not_yet("a boolean function outside `0 b.` … `31 b.`", span)
2157 })?;
2158 let p = crate::verb::Prim {
2159 name: "b.",
2160 monad: MonadOp::None,
2161 dyad: DyadOp::TruthTable(m as u8),
2162 ranks: [crate::verb::RANK_INF, 0, 0],
2163 };
2164 return Ok(Frag::Verb(VerbFrag::V(Verb::Prim(p)), span));
2165 }
2166 if !u.is_real_verb() {
2167 return Err(Error::not_yet("noun-operand adverbs", span));
2168 }
2169 let (v, _) = as_verb(u)?;
2170 let derived = match glyph {
2171 "/" => Verb::Reduce(Box::new(v)),
2172 "\\" => Verb::Windowed(Box::new(v), WindowKind::Prefix),
2173 "\\." => Verb::Windowed(Box::new(v), WindowKind::Suffix),
2174 "~" => Verb::Commute(Box::new(v)),
2175 "/." => Verb::Key(Box::new(v)),
2176 "f." => v,
2179 "M." => Verb::Memo(Box::new(v), Default::default()),
2180 "b." => Verb::Characteristics(Box::new(v)),
2181 _ => return Err(Error::not_yet(format!("adverb ({glyph})"), span)),
2182 };
2183 Ok(Frag::Verb(VerbFrag::V(derived), span))
2184}
2185
2186fn apply_conj(u: Frag, c: Frag, v: Frag, scope: &Names) -> Result<Frag> {
2187 let Frag::Conj(m, cspan) = c else {
2188 return Err(Error::internal("expected a conjunction fragment"));
2189 };
2190 let span = Span::merge(Span::merge(u.span(), cspan), v.span());
2191 let glyph = match m {
2192 Modifier::Prim(g) => g,
2193 Modifier::Explicit(src) => return derive_explicit(&src, u, Some(v), scope, span),
2194 };
2195 match glyph {
2196 "\"" => {
2197 let f = verb_operand(u, span)?;
2198 if v.is_verb() {
2199 return Err(Error::not_yet("verb rank (u\"v)", span));
2200 }
2201 let ranks = rank_spec(&v, span)?;
2202 Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(f), ranks)), span))
2203 }
2204 "@:" => {
2205 let f = verb_operand(u, span)?;
2206 let g = verb_operand(v, span)?;
2207 Ok(Frag::Verb(VerbFrag::V(Verb::Atop(Box::new(f), Box::new(g))), span))
2208 }
2209 "@" => {
2213 let f = verb_operand(u, span)?;
2214 let g = verb_operand(v, span)?;
2215 let ranks = g.ranks();
2216 let atop = Verb::Atop(Box::new(f), Box::new(g));
2217 Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(atop), ranks)), span))
2218 }
2219 "&" => compose(u, v, false, span),
2220 "&:" => compose(u, v, true, span),
2221 "&." if is_open(&v) => {
2224 let f = verb_operand(u, span)?;
2225 Ok(Frag::Verb(VerbFrag::V(Verb::Each(Box::new(f), Enclose::Always)), span))
2226 }
2227 "&." | "&.:" => {
2232 let f = verb_operand(u, span)?;
2233 let g = verb_operand(v, span)?;
2234 let back = obverse_of(&g, span)?;
2235 let composed = Verb::Compose(Box::new(f), Box::new(g.clone()));
2236 let under = Verb::Atop(Box::new(back), Box::new(composed));
2237 if glyph == "&.:" {
2238 return Ok(Frag::Verb(VerbFrag::V(under), span));
2239 }
2240 let rank = g.ranks()[0];
2241 Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(under), [rank; 3])), span))
2242 }
2243 "^:" => {
2244 let f = verb_operand(u, span)?;
2245 if v.is_verb() {
2246 let g = verb_operand(v, span)?;
2249 let p = Verb::PowerV(Box::new(f), Box::new(g));
2250 return Ok(Frag::Verb(VerbFrag::V(p), span));
2251 }
2252 let negative = noun_value(&v).is_some_and(|a| {
2257 let inner = match a.as_boxes() {
2258 Some([b]) => b.clone(),
2259 _ => a,
2260 };
2261 inner.to_f64_vec().is_some_and(|n| n.len() == 1 && n[0] < 0.0)
2262 });
2263 let p = power_spec(&v, span)?;
2264 let f = if negative { obverse_of(&f, span)? } else { f };
2265 Ok(Frag::Verb(VerbFrag::V(Verb::PowerN(Box::new(f), p)), span))
2266 }
2267 ";." => {
2268 let f = verb_operand(u, span)?;
2269 let n = one_atom(&v, "cut", span)?;
2270 if n.fract() != 0.0 || !matches!(n as i64, -3..=3) {
2271 return Err(Error::not_yet(format!("cut (u;.{n})"), span));
2272 }
2273 Ok(Frag::Verb(VerbFrag::V(Verb::Cut(Box::new(f), n as i64)), span))
2274 }
2275 "!." => {
2279 let f = verb_operand(u, span)?;
2280 if matches!(&f, Verb::Prim(p) if p.name == "|.") {
2283 let fill = as_const(&v)
2284 .cloned()
2285 .ok_or_else(|| Error::not_yet("a computed fill (|.!.n)", span))?;
2286 return Ok(Frag::Verb(VerbFrag::V(Verb::ShiftFill(fill)), span));
2287 }
2288 let n = one_atom(&v, "fit", span)?;
2289 if !f.uses_tolerance() {
2290 return Err(Error::not_yet(
2291 format!("fill specification ({}!.n)", f.name()),
2292 span,
2293 ));
2294 }
2295 if !(0.0..=LARGEST_TOLERANCE).contains(&n) {
2297 return Err(Error::domain(
2298 format!("a comparison tolerance must be between 0 and {LARGEST_TOLERANCE}"),
2299 span,
2300 ));
2301 }
2302 Ok(Frag::Verb(VerbFrag::V(Verb::Fit(Box::new(f), n)), span))
2303 }
2304 ":." => {
2307 let f = verb_operand(u, span)?;
2308 let g = verb_operand(v, span)?;
2309 Ok(Frag::Verb(
2310 VerbFrag::V(Verb::WithObverse(Box::new(f), Box::new(g))),
2311 span,
2312 ))
2313 }
2314 "@." => {
2317 let vs = gerund_verbs(&u, scope, span)?;
2318 if v.is_verb() {
2319 let w = verb_operand(v, span)?;
2320 return Ok(Frag::Verb(VerbFrag::V(Verb::Agenda(vs, Box::new(w))), span));
2321 }
2322 let at = one_atom(&v, "agenda", span)?;
2323 if at.fract() != 0.0 {
2324 return Err(Error::parse("an agenda index must be a whole number", span));
2325 }
2326 let picked = crate::verb::pick_gerund(&vs, at as i64, span)?;
2327 Ok(Frag::Verb(VerbFrag::V(picked), span))
2328 }
2329 "`" => {
2332 let left = tie_side(&u, scope, span)?;
2333 let right = tie_side(&v, scope, span)?;
2334 let tied = crate::verb::catenate(&left, &right, true, true, span)?;
2335 Ok(Frag::Noun(Expr::Const(tied, span)))
2336 }
2337 "::" => {
2340 let f = verb_operand(u, span)?;
2341 let g = if v.is_noun() {
2342 constant_verb(bond_noun(&v, span)?)
2343 } else {
2344 verb_operand(v, span)?
2345 };
2346 Ok(Frag::Verb(VerbFrag::V(Verb::Adverse(Box::new(f), Box::new(g))), span))
2347 }
2348 "L:" | "S:" => {
2352 let f = verb_operand(u, span)?;
2353 let n = one_atom(&v, "level", span)?;
2354 if n.fract() != 0.0 || !n.is_finite() {
2355 return Err(Error::not_yet(format!("a level of {n} ({glyph})"), span));
2356 }
2357 let level = Verb::Level {
2358 u: Box::new(f),
2359 level: n as i64,
2360 spread: glyph == "S:",
2361 };
2362 Ok(Frag::Verb(VerbFrag::V(level), span))
2363 }
2364 "`:" => {
2368 if u.is_verb() {
2369 return Err(Error::domain(
2370 "`: reads a gerund, which is boxed data, not a verb",
2371 span,
2372 ));
2373 }
2374 let vs = gerund_verbs(&u, scope, span)?;
2375 let n = one_atom(&v, "evoke gerund", span)?;
2376 if vs.is_empty() {
2377 return Err(Error::domain("an evoked gerund is empty", span));
2378 }
2379 match n {
2380 0.0 | 3.0 => {
2381 Ok(Frag::Verb(VerbFrag::V(Verb::Evoke(vs, n as i64)), span))
2382 }
2383 6.0 => train_of(vs, span),
2384 _ => Err(Error::domain(
2385 format!("`:{n} is not one of the evoke forms 0, 3 and 6"),
2386 span,
2387 )),
2388 }
2389 }
2390 "H." => {
2394 let num = series_parameters(&u, span)?;
2395 let den = series_parameters(&v, span)?;
2396 Ok(Frag::Verb(VerbFrag::V(Verb::Hypergeometric { num, den }), span))
2397 }
2398 "T." => Err(Error::sandbox(
2402 "T. starts J's own threads, which libjay does not open",
2403 span,
2404 )),
2405 "t:" => Err(Error::new(
2411 ErrorKind::Language,
2412 "t: is not a J inflection; the reference rejects the spelling",
2413 Some(span),
2414 )),
2415 "t." => Err(Error::sandbox(
2416 "t. runs a verb in one of J's thread pools, which libjay does not open",
2417 span,
2418 )),
2419 "." => Err(Error::not_yet("the inner product (u . v)", span)),
2420 "!:" => foreign(&u, &v, span),
2421 ":" => Err(Error::not_yet("the monad-dyad conjunction (u : v)", span)),
2425 _ => Err(Error::not_yet(format!("the conjunction {glyph}"), span)),
2426 }
2427}
2428
2429fn compose(u: Frag, v: Frag, infinite: bool, span: Span) -> Result<Frag> {
2437 let verb = |v: Verb| Ok(Frag::Verb(VerbFrag::V(v), span));
2438 if infinite || (!u.is_noun() && !v.is_noun()) {
2439 let f = verb_operand(u, span)?;
2440 let g = verb_operand(v, span)?;
2441 let monadic_rank = g.ranks()[0];
2442 let composed = Verb::Compose(Box::new(f), Box::new(g));
2443 if infinite {
2444 return verb(composed);
2445 }
2446 return verb(Verb::Rank(Box::new(composed), [monadic_rank; 3]));
2447 }
2448 if u.is_noun() && v.is_noun() {
2449 return Err(Error::not_yet("noun-operand conjunctions", span));
2450 }
2451 if u.is_noun() {
2456 let m = bond_noun(&u, span)?;
2457 let g = as_verb(v)?.0;
2458 return verb(Verb::BondLeft(m, Box::new(g)));
2459 }
2460 let f = as_verb(u)?.0;
2461 let n = bond_noun(&v, span)?;
2462 verb(Verb::BondRight(Box::new(f), n))
2463}
2464
2465const LARGEST_TOLERANCE: f64 = 5.820_766_091_346_741e-11;
2467
2468fn series_parameters(f: &Frag, span: Span) -> Result<Vec<crate::complex::Cx>> {
2471 let Some(arr) = as_const(f) else {
2472 return Err(Error::not_yet("computed hypergeometric parameters (m H. n)", span));
2473 };
2474 if arr.count() == 0 {
2475 return Ok(Vec::new());
2476 }
2477 if arr.rank() > 1 {
2478 return Err(Error::parse("a hypergeometric parameter list is a vector", span));
2479 }
2480 match arr.data.cast(crate::dtype::DType::Complex) {
2481 Some(Data::Complex(v)) => Ok(v.as_slice().to_vec()),
2482 _ => Err(Error::parse("hypergeometric parameters are numbers", span)),
2483 }
2484}
2485
2486fn foreign(u: &Frag, v: &Frag, span: Span) -> Result<Frag> {
2498 let family = foreign_number(u, span)?;
2499 let member = foreign_number(v, span)?;
2500 let prim = |name, monad, dyad| {
2501 Ok(Frag::Verb(
2502 VerbFrag::V(Verb::Prim(Prim { name, monad, dyad, ranks: [RANK_INF; 3] })),
2503 span,
2504 ))
2505 };
2506 let closed = |what: &str| {
2507 Err(Error::sandbox(format!("{family}!:{member} {what}, which is outside the program"), span))
2508 };
2509 match (family, member) {
2510 (1, 1) => prim("1!:1", MonadOp::ReadStream, DyadOp::None),
2511 (1, 2) => prim("1!:2", MonadOp::None, DyadOp::WriteStream),
2512 (3, 0) => prim("3!:0", MonadOp::TypeCode, DyadOp::None),
2513 (5, 1) => prim("5!:1", MonadOp::AtomicRep, DyadOp::None),
2516 (0, _) => closed("runs a script file"),
2517 (1, _) => closed("reaches the filesystem"),
2520 (2, _) => closed("reaches the host — its environment, its shell, its processes"),
2521 (6, _) => closed("reads the clock"),
2522 (15, _) => closed("calls into a shared library"),
2523 _ => Err(Error::not_yet(format!("the foreign {family}!:{member}"), span)),
2524 }
2525}
2526
2527fn foreign_number(f: &Frag, span: Span) -> Result<i64> {
2530 if f.is_verb() {
2531 return Err(Error::parse("a foreign is spelled m!:n, with two numbers", span));
2532 }
2533 let Some(arr) = as_const(f) else {
2534 return Err(Error::not_yet("a computed foreign number (m!:n)", span));
2535 };
2536 match arr.to_i64_vec().as_deref() {
2537 Some([n]) if *n >= 0 => Ok(*n),
2538 _ => Err(Error::parse("a foreign is spelled m!:n, with two whole numbers", span)),
2539 }
2540}
2541
2542fn one_atom(f: &Frag, what: &str, span: Span) -> Result<f64> {
2543 let Some(arr) = as_const(f) else {
2544 return Err(Error::not_yet(format!("a computed {what} specification"), span));
2545 };
2546 let Some(vals) = arr.to_f64_vec() else {
2547 return Err(Error::parse(format!("{what} takes a numeric operand"), span));
2548 };
2549 match vals[..] {
2550 [n] => Ok(n),
2551 _ => Err(Error::parse(format!("{what} takes one atom"), span)),
2552 }
2553}
2554
2555fn bond_noun(f: &Frag, span: Span) -> Result<Array> {
2557 as_const(f)
2558 .cloned()
2559 .ok_or_else(|| Error::not_yet("bonds over a non-literal noun", span))
2560}
2561
2562fn is_open(f: &Frag) -> bool {
2565 matches!(f, Frag::Verb(VerbFrag::V(Verb::Prim(p)), _) if p.monad == MonadOp::Open)
2566}
2567
2568fn verb_operand(f: Frag, span: Span) -> Result<Verb> {
2569 if f.is_noun() {
2570 return Err(Error::not_yet("noun-operand conjunctions", span));
2571 }
2572 Ok(as_verb(f)?.0)
2573}
2574
2575fn rank_spec(f: &Frag, span: Span) -> Result<[i64; 3]> {
2578 let Some(arr) = as_const(f) else {
2579 return Err(Error::not_yet("computed rank specifications", span));
2580 };
2581 let Some(vals) = arr.to_f64_vec() else {
2582 return Err(Error::parse("rank must be numeric", span));
2583 };
2584 if vals.is_empty() || vals.len() > 3 {
2585 return Err(Error::parse("rank takes 1 to 3 atoms", span));
2586 }
2587 let mut r = Vec::with_capacity(vals.len());
2588 for x in vals {
2589 if x == f64::INFINITY {
2590 r.push(RANK_INF);
2591 } else if x == f64::NEG_INFINITY {
2592 r.push(-RANK_INF);
2593 } else if x.fract() != 0.0 {
2594 return Err(Error::parse("rank must be an integer", span));
2595 } else {
2596 r.push(x as i64);
2597 }
2598 }
2599 Ok(match r.len() {
2600 1 => [r[0], r[0], r[0]],
2601 2 => [r[1], r[0], r[1]],
2602 _ => [r[0], r[1], r[2]],
2603 })
2604}
2605
2606fn power_spec(f: &Frag, span: Span) -> Result<Power> {
2609 let Some(arr) = noun_value(f) else {
2610 return Err(Error::not_yet("computed power (u^:n)", span));
2611 };
2612 let arr = &arr;
2613 if let Some(boxes) = arr.as_boxes() {
2616 let [inner] = boxes else {
2617 return Err(Error::parse("a boxed power takes one box", span));
2618 };
2619 if inner.count() == 0 {
2620 return Ok(Power::ConvergeTrace);
2621 }
2622 let Some(vals) = inner.to_f64_vec() else {
2623 return Err(Error::parse("power must be numeric", span));
2624 };
2625 let [n] = vals[..] else {
2626 return Err(Error::not_yet("a boxed list of power counts (u^:(<n))", span));
2627 };
2628 if n.fract() != 0.0 || n.abs() > 1e6 {
2629 return Err(Error::parse("a boxed power must be a whole count", span));
2630 }
2631 if n == 0.0 {
2633 return Err(Error::domain("a boxed power traces at least one application", span));
2634 }
2635 return Ok(Power::Each((0..n.abs() as u64).collect()));
2638 }
2639 let Some(vals) = arr.to_f64_vec() else {
2640 return Err(Error::parse("power must be numeric", span));
2641 };
2642 if vals.len() > 1 {
2643 let mut counts = Vec::with_capacity(vals.len());
2645 for n in &vals {
2646 if n.fract() != 0.0 || *n < 0.0 || *n > 1e6 {
2647 return Err(Error::not_yet("a power count outside 0 … 1e6", span));
2648 }
2649 counts.push(*n as u64);
2650 }
2651 return Ok(Power::Each(counts));
2652 }
2653 let [n] = vals[..] else {
2654 return Err(Error::not_yet("power over a list of counts (u^:n)", span));
2655 };
2656 if n == f64::INFINITY {
2657 return Ok(Power::Converge);
2658 }
2659 if n.fract() != 0.0 {
2660 return Err(Error::parse("power must be a whole number", span));
2661 }
2662 if n < 0.0 {
2663 return Ok(Power::Times((-n) as u64));
2666 }
2667 Ok(Power::Times(n as u64))
2668}
2669
2670pub(crate) fn obverse_of(v: &Verb, span: Span) -> Result<Verb> {
2672 crate::verb::obverse(v).ok_or_else(|| {
2673 Error::not_yet(format!("the obverse of {} (no inverse is known)", v.name()), span)
2674 })
2675}
2676
2677fn tie_side(f: &Frag, scope: &Names, span: Span) -> Result<Array> {
2681 if f.is_real_verb() {
2682 let (v, _) = as_verb(f.clone())?;
2683 return Ok(Array::boxed(verb_ar(&v, span)?.to_array()));
2684 }
2685 noun_in_scope(f, scope)
2686 .ok_or_else(|| Error::not_yet("a tie over a computed noun", span))
2687}
2688
2689fn verb_ar(v: &Verb, span: Span) -> Result<crate::gerund::Ar> {
2692 crate::gerund::verb_ar(v).ok_or_else(|| {
2693 Error::not_yet(format!("the atomic representation of {}", v.name()), span)
2694 })
2695}
2696
2697fn noun_in_scope(f: &Frag, scope: &Names) -> Option<Array> {
2700 if let Frag::Name(n, _) = f {
2701 return scope.consts.get(n).cloned();
2702 }
2703 noun_value(f)
2704}
2705
2706fn gerund_verbs(f: &Frag, scope: &Names, span: Span) -> Result<Vec<Verb>> {
2709 if f.is_real_verb() {
2710 return Ok(vec![as_verb(f.clone())?.0]);
2711 }
2712 let arr = noun_in_scope(f, scope)
2713 .ok_or_else(|| Error::not_yet("a gerund computed at run time", span))?;
2714 let Some(items) = arr.as_boxes() else {
2715 return Err(Error::domain("a gerund is boxed data", span));
2716 };
2717 items.iter().map(|a| ar_verb(a, scope, span)).collect()
2718}
2719
2720fn ar_verb(a: &Array, scope: &Names, span: Span) -> Result<Verb> {
2722 let ar = crate::gerund::Ar::from_array(a)
2723 .ok_or_else(|| Error::domain("this is not an atomic representation", span))?;
2724 let (v, _) = as_verb(ar_frag(&ar, scope, span)?)?;
2725 Ok(v)
2726}
2727
2728fn ar_frag(ar: &crate::gerund::Ar, scope: &Names, span: Span) -> Result<Frag> {
2731 use crate::gerund::Ar;
2732 match ar {
2733 Ar::Noun(a) => Ok(Frag::Noun(Expr::Const(a.clone(), span))),
2734 Ar::Prim(word) => {
2735 if word == "[:" {
2736 return Ok(Frag::Verb(VerbFrag::Cap, span));
2737 }
2738 match verb_for(word) {
2739 Some(v) => Ok(Frag::Verb(VerbFrag::V(v), span)),
2740 None => Err(Error::domain(
2741 format!("`{word}` is not a verb an atomic representation may name"),
2742 span,
2743 )),
2744 }
2745 }
2746 Ar::Train(parts) => {
2747 let frags: Result<Vec<Frag>> =
2748 parts.iter().map(|p| ar_frag(p, scope, span)).collect();
2749 let mut frags = frags?;
2750 match frags.len() {
2751 2 => {
2752 let b = frags.pop().expect("two parts");
2753 let a = frags.pop().expect("two parts");
2754 apply_bident(a, b, &scope.nouns)
2755 }
2756 3 => {
2757 let h = frags.pop().expect("three parts");
2758 let g = frags.pop().expect("three parts");
2759 let f = frags.pop().expect("three parts");
2760 apply_fork(f, g, h)
2761 }
2762 _ => Err(Error::domain("a train is two or three parts", span)),
2763 }
2764 }
2765 Ar::Derived(word, ops) => {
2766 let frags: Result<Vec<Frag>> = ops.iter().map(|p| ar_frag(p, scope, span)).collect();
2767 let mut frags = frags?;
2768 if let Some(glyph) = adverb(word) {
2769 if frags.len() != 1 {
2770 return Err(Error::domain(format!("{glyph} takes one operand"), span));
2771 }
2772 let u = frags.pop().expect("one operand");
2773 return apply_adverb(u, Frag::Adverb(Modifier::Prim(glyph), span), scope);
2774 }
2775 if let Some(glyph) = conjunction(word) {
2776 if frags.len() != 2 {
2777 return Err(Error::domain(format!("{glyph} takes two operands"), span));
2778 }
2779 let v = frags.pop().expect("two operands");
2780 let u = frags.pop().expect("two operands");
2781 return apply_conj(u, Frag::Conj(Modifier::Prim(glyph), span), v, scope);
2782 }
2783 Err(Error::domain(
2784 format!("`{word}` is not a modifier an atomic representation may name"),
2785 span,
2786 ))
2787 }
2788 }
2789}
2790
2791fn train_of(vs: Vec<Verb>, span: Span) -> Result<Frag> {
2794 let mut frags: Vec<Frag> =
2795 vs.into_iter().map(|v| Frag::Verb(VerbFrag::V(v), span)).collect();
2796 while frags.len() > 3 {
2797 let h = frags.pop().expect("three or more");
2798 let g = frags.pop().expect("three or more");
2799 let f = frags.pop().expect("three or more");
2800 frags.push(apply_fork(f, g, h)?);
2801 }
2802 match frags.len() {
2803 1 => Ok(frags.pop().expect("one")),
2804 2 => {
2805 let b = frags.pop().expect("two");
2806 let a = frags.pop().expect("two");
2807 apply_bident(a, b, &HashSet::new())
2808 }
2809 _ => {
2810 let h = frags.pop().expect("three");
2811 let g = frags.pop().expect("three");
2812 let f = frags.pop().expect("three");
2813 apply_fork(f, g, h)
2814 }
2815 }
2816}
2817
2818fn apply_fork(f: Frag, g: Frag, h: Frag) -> Result<Frag> {
2819 let span = Span::merge(Span::merge(f.span(), g.span()), h.span());
2820 let (gv, _) = as_verb(g)?;
2821 let (hv, _) = as_verb(h)?;
2822 match f {
2823 Frag::Verb(VerbFrag::Cap, _) => {
2825 Ok(Frag::Verb(VerbFrag::V(Verb::Atop(Box::new(gv), Box::new(hv))), span))
2826 }
2827 Frag::Verb(VerbFrag::V(fv), _) => Ok(Frag::Verb(
2828 VerbFrag::V(Verb::Fork(Box::new(fv), Box::new(gv), Box::new(hv))),
2829 span,
2830 )),
2831 noun => {
2832 let Some(arr) = as_const(&noun) else {
2833 return Err(Error::not_yet("noun forks over a non-literal noun", span));
2834 };
2835 Ok(Frag::Verb(
2836 VerbFrag::V(Verb::NounFork(arr.clone(), Box::new(gv), Box::new(hv))),
2837 span,
2838 ))
2839 }
2840 }
2841}
2842
2843fn apply_bident(a: Frag, b: Frag, nouns: &HashSet<String>) -> Result<Frag> {
2844 let span = Span::merge(a.span(), b.span());
2845 if let Frag::Name(n, nspan) = &a && !nouns.contains(n) {
2849 return Err(Error::new(
2850 ErrorKind::Value,
2851 format!("undefined name: {n}"),
2852 Some(*nspan),
2853 ));
2854 }
2855 if a.is_real_verb() && b.is_real_verb() {
2856 let (f, _) = as_verb(a)?;
2857 let (g, _) = as_verb(b)?;
2858 return Ok(Frag::Verb(VerbFrag::V(Verb::Hook(Box::new(f), Box::new(g))), span));
2859 }
2860 if matches!(a, Frag::Verb(VerbFrag::Cap, _)) {
2865 return Err(Error::parse("`[:` caps a fork; it has no verb of its own", span));
2866 }
2867 Err(Error::parse("syntax error", span))
2868}
2869
2870fn apply_assign(target: Frag, value: Frag, scope: Scope) -> Result<Frag> {
2871 let span = Span::merge(target.span(), value.span());
2872 match target {
2873 Frag::Name(name, _) => match value {
2877 Frag::Verb(VerbFrag::V(verb), _) => Ok(Frag::VerbDef(name, verb, span)),
2880 Frag::Verb(VerbFrag::Cap, _) => Err(Error::not_yet("assigning [: on its own", span)),
2881 Frag::Adverb(m, _) => Ok(Frag::ModDef(name, false, m, span)),
2884 Frag::Conj(m, _) => Ok(Frag::ModDef(name, true, m, span)),
2885 v if v.is_noun() => {
2886 let value = as_noun(v)?;
2887 Ok(Frag::Noun(Expr::Assign { name, value: Box::new(value), scope, span }))
2888 }
2889 other => Err(Error::internal(format!("cannot assign {other:?}"))),
2890 },
2891 Frag::Noun(_) => Err(Error::not_yet("multiple assignment", span)),
2892 other => Err(Error::internal(format!("expected an assignment target, got {other:?}"))),
2893 }
2894}
2895
2896#[cfg(test)]
2897mod tests {
2898 use super::*;
2899 use crate::dtype::DType;
2900 use crate::error::ErrorKind;
2901 use rstest::rstest;
2902
2903 fn parse_str(src: &str) -> Result<Vec<Expr>> {
2904 parse(&SourceParts::from_source(src).expect("source parts"))
2905 }
2906
2907 fn one_literal(src: &str) -> Expr {
2911 let sp = SourceParts::from_parts(&[src], &[]);
2912 let mut s = parse(&sp).unwrap_or_else(|e| panic!("parse of {src:?} failed: {e}"));
2913 assert_eq!(s.len(), 1, "expected one sentence in {src:?}");
2914 s.pop().expect("one sentence")
2915 }
2916
2917 fn stmts(src: &str) -> Vec<Expr> {
2918 parse_str(src).unwrap_or_else(|e| panic!("parse of {src:?} failed: {e}"))
2919 }
2920
2921 fn one(src: &str) -> Expr {
2923 let mut s = stmts(src);
2924 assert_eq!(s.len(), 1, "expected one sentence in {src:?}");
2925 s.pop().expect("one sentence")
2926 }
2927
2928 fn err(src: &str) -> Error {
2929 match parse_str(src) {
2930 Ok(v) => panic!("expected an error for {src:?}, got {v:?}"),
2931 Err(e) => e,
2932 }
2933 }
2934
2935 fn konst(e: &Expr) -> Array {
2939 match e {
2940 Expr::Const(a, _) => a.clone(),
2941 other => panic!("expected a constant, got {other:?}"),
2942 }
2943 }
2944
2945 fn ints(e: &Expr) -> Vec<i64> {
2946 konst(e).as_i64_slice().expect("integer data").to_vec()
2947 }
2948
2949 fn prim_of(v: &Verb) -> Prim {
2950 match v {
2951 Verb::Prim(p) => *p,
2952 other => panic!("expected a primitive, got {other:?}"),
2953 }
2954 }
2955
2956 fn monad_of(e: &Expr) -> (Verb, Expr) {
2957 match e {
2958 Expr::Monad { verb, y, .. } => (verb.clone(), (**y).clone()),
2959 other => panic!("expected a monad, got {other:?}"),
2960 }
2961 }
2962
2963 fn dyad_of(e: &Expr) -> (Verb, Expr, Expr) {
2964 match e {
2965 Expr::Dyad { verb, x, y, .. } => (verb.clone(), (**x).clone(), (**y).clone()),
2966 other => panic!("expected a dyad, got {other:?}"),
2967 }
2968 }
2969
2970 #[test]
2973 fn single_number_is_an_atom() {
2974 let e = one("5");
2975 assert_eq!(konst(&e).shape, Vec::<usize>::new());
2976 assert_eq!(ints(&e), vec![5]);
2977 assert_eq!(e.span(), Span::new(0, 1));
2978 }
2979
2980 #[test]
2981 fn adjacent_numbers_merge_into_one_vector() {
2982 let e = one("1 2 3");
2983 assert_eq!(konst(&e).shape, vec![3]);
2984 assert_eq!(ints(&e), vec![1, 2, 3]);
2985 assert_eq!(e.span(), Span::new(0, 5));
2986 }
2987
2988 #[test]
2989 fn a_float_makes_the_whole_vector_float() {
2990 let a = konst(&one("1 2.5 3"));
2991 assert_eq!(a.dtype(), DType::F64);
2992 assert_eq!(a.as_f64_slice(), Some(&[1.0, 2.5, 3.0][..]));
2993 }
2994
2995 #[test]
2996 fn negatives_and_infinities() {
2997 let a = konst(&one("_3 1.5 _ __"));
2998 assert_eq!(a.shape, vec![4]);
2999 let v = a.as_f64_slice().expect("float vector");
3000 assert_eq!(v[0], -3.0);
3001 assert_eq!(v[1], 1.5);
3002 assert!(v[2].is_infinite() && v[2] > 0.0);
3003 assert!(v[3].is_infinite() && v[3] < 0.0);
3004 }
3005
3006 #[test]
3007 fn negative_integers_stay_integers() {
3008 let a = konst(&one("_3 _4"));
3009 assert_eq!(a.dtype(), DType::I64);
3010 assert_eq!(a.as_i64_slice(), Some(&[-3i64, -4][..]));
3011 }
3012
3013 #[rstest]
3014 #[case("1e3", 1000.0)]
3015 #[case("1e_3", 0.001)]
3016 #[case("2.5e2", 250.0)]
3017 #[case("_1.5", -1.5)]
3018 fn exponent_and_sign_forms(#[case] src: &str, #[case] want: f64) {
3019 let a = konst(&one(src));
3020 assert_eq!(a.dtype(), DType::F64);
3021 assert_eq!(a.to_f64_vec().expect("numeric"), vec![want]);
3022 }
3023
3024 #[test]
3025 fn adjacent_numbers_stop_at_a_non_number() {
3026 let (_, x, y) = dyad_of(&one("2 3 i. 4"));
3028 assert_eq!(konst(&x).shape, vec![2]);
3029 assert_eq!(konst(&y).shape, Vec::<usize>::new());
3030 }
3031
3032 #[test]
3033 fn string_of_several_characters_is_a_vector() {
3034 let e = one("'abc'");
3035 let a = konst(&e);
3036 assert_eq!(a.shape, vec![3]);
3037 assert_eq!(a.data, Data::Char(vec!['a', 'b', 'c'].into()));
3038 assert_eq!(e.span(), Span::new(0, 5));
3039 }
3040
3041 #[test]
3042 fn one_character_string_is_an_atom() {
3043 let a = konst(&one("'a'"));
3044 assert_eq!(a.shape, Vec::<usize>::new());
3045 assert_eq!(a.data, Data::Char(vec!['a'].into()));
3046 }
3047
3048 #[test]
3049 fn empty_string_is_an_empty_vector() {
3050 let a = konst(&one("''"));
3051 assert_eq!(a.shape, vec![0]);
3052 assert_eq!(a.dtype(), DType::Char);
3053 }
3054
3055 #[test]
3056 fn doubled_quote_is_an_escaped_quote() {
3057 let a = konst(&one("'it''s'"));
3058 assert_eq!(a.shape, vec![4]);
3059 assert_eq!(a.data, Data::Char(vec!['i', 't', '\'', 's'].into()));
3060 }
3061
3062 #[test]
3063 fn unterminated_string_is_a_parse_error() {
3064 let e = err("'abc");
3065 assert_eq!(e.kind, ErrorKind::Parse);
3066 assert!(e.msg.contains("unterminated"), "{}", e.msg);
3067 assert_eq!(e.span, Some(Span::new(0, 4)));
3068 }
3069
3070 #[test]
3073 fn comment_runs_to_end_of_line() {
3074 let e = one("1 2 NB. and the rest + - ' is ignored");
3075 assert_eq!(konst(&e).shape, vec![2]);
3076 }
3077
3078 #[test]
3079 fn comment_only_line_yields_no_sentence() {
3080 assert!(stmts("NB. nothing here").is_empty());
3081 let s = stmts("NB. header\n5");
3082 assert_eq!(s.len(), 1);
3083 assert_eq!(ints(&s[0]), vec![5]);
3084 }
3085
3086 #[test]
3087 fn nb_inside_a_name_is_not_a_comment() {
3088 match one("aNB") {
3090 Expr::Name(n, _) => assert_eq!(n, "aNB"),
3091 other => panic!("expected a name, got {other:?}"),
3092 }
3093 }
3094
3095 #[test]
3098 fn empty_program_has_no_sentences() {
3099 assert!(stmts("").is_empty());
3100 assert!(stmts("\n\n").is_empty());
3101 }
3102
3103 #[test]
3104 fn trains_of_dyads_are_right_associative() {
3105 let e = one("1 + 2 + 3");
3106 let (v, x, y) = dyad_of(&e);
3107 assert_eq!(prim_of(&v).name, "+");
3108 assert_eq!(ints(&x), vec![1]);
3109 let (v2, x2, y2) = dyad_of(&y);
3110 assert_eq!(prim_of(&v2).name, "+");
3111 assert_eq!(ints(&x2), vec![2]);
3112 assert_eq!(ints(&y2), vec![3]);
3113 assert_eq!(e.span(), Span::new(0, 9));
3114 }
3115
3116 #[test]
3117 fn a_verb_with_no_left_argument_is_a_monad() {
3118 let e = one("- 5");
3119 let (v, y) = monad_of(&e);
3120 assert_eq!(prim_of(&v).monad, MonadOp::Scalar(ScalarMonad::Neg));
3121 assert_eq!(ints(&y), vec![5]);
3122 assert_eq!(e.span(), Span::new(0, 3));
3123 }
3124
3125 #[test]
3126 fn a_verb_with_a_left_argument_is_a_dyad() {
3127 let (v, _, _) = dyad_of(&one("1 - 5"));
3128 assert_eq!(prim_of(&v).dyad, DyadOp::Scalar(ScalarDyad::Sub));
3129 }
3130
3131 #[test]
3132 fn a_monad_binds_to_the_right_inside_a_dyad() {
3133 let (v, x, y) = dyad_of(&one("2 * - 3"));
3134 assert_eq!(prim_of(&v).name, "*");
3135 assert_eq!(ints(&x), vec![2]);
3136 let (mv, my) = monad_of(&y);
3137 assert_eq!(prim_of(&mv).name, "-");
3138 assert_eq!(ints(&my), vec![3]);
3139 }
3140
3141 #[test]
3142 fn parentheses_group_the_left_argument() {
3143 let (v, x, y) = dyad_of(&one("(1 + 2) * 3"));
3144 assert_eq!(prim_of(&v).name, "*");
3145 let (iv, _, _) = dyad_of(&x);
3146 assert_eq!(prim_of(&iv).name, "+");
3147 assert_eq!(x.span(), Span::new(0, 7));
3150 assert_eq!(ints(&y), vec![3]);
3151 }
3152
3153 #[test]
3154 fn names_are_nouns() {
3155 match one("x") {
3156 Expr::Name(n, s) => {
3157 assert_eq!(n, "x");
3158 assert_eq!(s, Span::new(0, 1));
3159 }
3160 other => panic!("expected a name, got {other:?}"),
3161 }
3162 let (_, x, y) = dyad_of(&one("x + y"));
3163 assert!(matches!(x, Expr::Name(..)));
3164 assert!(matches!(y, Expr::Name(..)));
3165 }
3166
3167 #[test]
3168 fn echo_is_a_verb() {
3169 let (v, y) = monad_of(&one("echo 5"));
3170 assert_eq!(prim_of(&v).monad, MonadOp::Echo);
3171 assert_eq!(ints(&y), vec![5]);
3172 }
3173
3174 #[test]
3175 fn inflected_letter_words_are_primitives() {
3176 let (v, _) = monad_of(&one("i. 3"));
3177 let p = prim_of(&v);
3178 assert_eq!(p.monad, MonadOp::IotaJ);
3179 assert_eq!(p.ranks, [1, RANK_INF, RANK_INF]);
3180 }
3181
3182 #[rstest]
3183 #[case("|: 1 2 3", MonadOp::TransposeAxes)]
3184 #[case("$ 1 2 3", MonadOp::ShapeOf)]
3185 #[case("# 1 2 3", MonadOp::Tally)]
3186 #[case(", 1 2 3", MonadOp::Ravel)]
3187 #[case("%: 1 2 3", MonadOp::Scalar(ScalarMonad::Sqrt))]
3188 #[case("<. 1.5", MonadOp::Scalar(ScalarMonad::Floor))]
3189 fn inflected_symbol_words(#[case] src: &str, #[case] want: MonadOp) {
3190 let (v, _) = monad_of(&one(src));
3191 assert_eq!(prim_of(&v).monad, want);
3192 }
3193
3194 #[rstest]
3195 #[case("{. 1 2 3", MonadOp::Head, DyadOp::Take)]
3196 #[case("}. 1 2 3", MonadOp::Behead, DyadOp::Drop)]
3197 fn brace_words(#[case] src: &str, #[case] monad: MonadOp, #[case] dyad: DyadOp) {
3198 let (v, _) = monad_of(&one_literal(src));
3199 let p = prim_of(&v);
3200 assert_eq!(p.monad, monad);
3201 assert_eq!(p.dyad, dyad);
3202 assert_eq!(p.ranks, [RANK_INF, 1, RANK_INF]);
3203 }
3204
3205 #[test]
3206 fn a_brace_word_takes_a_left_argument() {
3207 let (v, x, y) = dyad_of(&one_literal("2 {. 1 2 3"));
3208 assert_eq!(prim_of(&v).dyad, DyadOp::Take);
3209 assert_eq!(ints(&x), vec![2]);
3210 assert_eq!(konst(&y).shape, vec![3]);
3211 }
3212
3213 #[rstest]
3214 #[case("2 $ 1 2 3", DyadOp::Reshape)]
3215 #[case("2 [ 3", DyadOp::Left)]
3216 #[case("2 ] 3", DyadOp::Right)]
3217 #[case("2 <. 3", DyadOp::Scalar(ScalarDyad::Min))]
3218 #[case("2 >: 3", DyadOp::Scalar(ScalarDyad::Ge))]
3219 fn dyadic_primitives(#[case] src: &str, #[case] want: DyadOp) {
3220 let (v, _, _) = dyad_of(&one(src));
3221 assert_eq!(prim_of(&v).dyad, want);
3222 }
3223
3224 #[test]
3225 fn unimplemented_meanings_reach_the_verb_not_the_parser() {
3226 let (v, _, _) = dyad_of(&one("2 ;: 'a b'"));
3227 assert_eq!(prim_of(&v).dyad, DyadOp::NotYet("sequential machine (dyadic ;:)"));
3228 let (v, _) = monad_of(&one("\": 1 2"));
3229 assert_eq!(prim_of(&v).dyad, DyadOp::NotYet("format with a specification"));
3230 }
3231
3232 #[test]
3233 fn multiple_sentences_become_multiple_statements() {
3234 let s = stmts("a =. 1 2\n+/ a\n");
3235 assert_eq!(s.len(), 2);
3236 assert!(matches!(s[0], Expr::Assign { .. }));
3237 assert!(matches!(s[1], Expr::Monad { .. }));
3238 }
3239
3240 #[test]
3243 fn an_adverb_binds_before_the_verb_is_applied() {
3244 let e = one("+/ 1 2 3");
3245 let (v, y) = monad_of(&e);
3246 match &v {
3247 Verb::Reduce(inner) => assert_eq!(prim_of(inner).name, "+"),
3248 other => panic!("expected a reduction, got {other:?}"),
3249 }
3250 assert_eq!(konst(&y).shape, vec![3]);
3251 assert_eq!(e.span(), Span::new(0, 8));
3252 }
3253
3254 #[test]
3255 fn rank_applies_to_the_derived_verb() {
3256 let (v, _) = monad_of(&one("+/\"1 m"));
3257 match &v {
3258 Verb::Rank(inner, ranks) => {
3259 assert_eq!(*ranks, [1, 1, 1]);
3260 assert!(matches!(**inner, Verb::Reduce(_)), "got {inner:?}");
3261 }
3262 other => panic!("expected a ranked verb, got {other:?}"),
3263 }
3264 }
3265
3266 #[rstest]
3267 #[case("+\"1 m", [1, 1, 1])]
3268 #[case("+\"1 2 m", [2, 1, 2])]
3269 #[case("+\"0 1 2 m", [0, 1, 2])]
3270 #[case("+\"_ m", [RANK_INF, RANK_INF, RANK_INF])]
3271 #[case("+\"_1 m", [-1, -1, -1])]
3272 #[case("+\"2.0 m", [2, 2, 2])]
3273 fn rank_specifications(#[case] src: &str, #[case] want: [i64; 3]) {
3274 let (v, _) = monad_of(&one(src));
3275 assert_eq!(v.ranks(), want);
3276 }
3277
3278 #[test]
3279 fn rank_must_be_one_to_three_integer_atoms() {
3280 let e = err("+\"1 2 3 4 m");
3281 assert_eq!(e.kind, ErrorKind::Parse);
3282 assert!(e.msg.contains("1 to 3 atoms"), "{}", e.msg);
3283 let e = err("+\"1.5 m");
3284 assert_eq!(e.kind, ErrorKind::Parse);
3285 assert!(e.msg.contains("integer"), "{}", e.msg);
3286 let e = err("+\"'a' m");
3287 assert_eq!(e.kind, ErrorKind::Parse);
3288 assert!(e.msg.contains("numeric"), "{}", e.msg);
3289 }
3290
3291 #[test]
3292 fn verb_rank_is_not_supported_yet() {
3293 let e = err("+\"- m");
3294 assert_eq!(e.kind, ErrorKind::NotYet);
3295 assert!(e.msg.contains("verb rank"), "{}", e.msg);
3296 }
3297
3298 #[test]
3299 fn computed_rank_is_not_supported_yet() {
3300 let e = err("+\"{r} m");
3301 assert_eq!(e.kind, ErrorKind::NotYet);
3302 assert!(e.msg.contains("computed rank"), "{}", e.msg);
3303 }
3304
3305 #[test]
3306 fn atop_conjunction() {
3307 let (v, _) = monad_of(&one("+/ @: , y"));
3308 match &v {
3309 Verb::Atop(f, g) => {
3310 assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
3311 assert_eq!(prim_of(g).name, ",");
3312 }
3313 other => panic!("expected an atop, got {other:?}"),
3314 }
3315 }
3316
3317 #[rstest]
3318 #[case("+ ^: {n} y", "computed power")]
3319 #[case("(+/ % #) ^: _1 y", "the obverse of")]
3320 #[case("(+/ % #) &. , y", "the obverse of")]
3321 #[case("(1 + 2) & , y", "bonds over a non-literal noun")]
3322 fn other_conjunctions_are_not_supported_yet(#[case] src: &str, #[case] msg: &str) {
3323 let e = err(src);
3324 assert_eq!(e.kind, ErrorKind::NotYet);
3325 assert!(e.msg.contains(msg), "{}", e.msg);
3326 }
3327
3328 #[test]
3329 fn atop_at_rank_and_compose() {
3330 let (v, _) = monad_of(&one("+/ @ (,\"1) y"));
3333 match &v {
3334 Verb::Rank(inner, ranks) => {
3335 assert_eq!(*ranks, [1, 1, 1]);
3336 assert!(matches!(**inner, Verb::Atop(..)), "got {inner:?}");
3337 }
3338 other => panic!("expected a ranked atop, got {other:?}"),
3339 }
3340 let (v, _) = monad_of(&one("+ & (*:\"0) y"));
3341 match &v {
3342 Verb::Rank(inner, ranks) => {
3343 assert_eq!(*ranks, [0, 0, 0]);
3344 assert!(matches!(**inner, Verb::Compose(..)), "got {inner:?}");
3345 }
3346 other => panic!("expected a ranked composition, got {other:?}"),
3347 }
3348 let (v, _) = monad_of(&one("+ &: *: y"));
3349 assert!(matches!(v, Verb::Compose(..)), "got {v:?}");
3350 }
3351
3352 #[test]
3353 fn a_noun_operand_bonds_the_conjunction() {
3354 let (v, _) = monad_of(&one("1 & + y"));
3358 match &v {
3359 Verb::BondLeft(a, g) => {
3360 assert_eq!(a.as_i64_slice(), Some(&[1i64][..]));
3361 assert_eq!(prim_of(g).name, "+");
3362 }
3363 other => panic!("expected a left bond, got {other:?}"),
3364 }
3365 assert_eq!(v.ranks(), [crate::verb::RANK_INF; 3]);
3366 let (v, _) = monad_of(&one("{. & 2 y"));
3367 assert!(matches!(v, Verb::BondRight(..)), "got {v:?}");
3368 assert_eq!(v.ranks(), [crate::verb::RANK_INF; 3]);
3369 }
3370
3371 #[test]
3372 fn window_scan_and_commute_adverbs() {
3373 let (v, _) = monad_of(&one("+/\\ 1 2 3"));
3374 match &v {
3375 Verb::Windowed(u, WindowKind::Prefix) => assert!(matches!(**u, Verb::Reduce(_))),
3376 other => panic!("expected a prefix application, got {other:?}"),
3377 }
3378 assert_eq!(v.ranks(), [RANK_INF, 0, RANK_INF]);
3381 let (v, _, _) = dyad_of(&one("2 +/\\ 1 2 3"));
3382 assert!(matches!(v, Verb::Windowed(_, WindowKind::Prefix)));
3383 let (v, _) = monad_of(&one("+/\\. 1 2 3"));
3384 assert!(matches!(v, Verb::Windowed(_, WindowKind::Suffix)));
3385 let (v, _) = monad_of(&one("+~ 1 2 3"));
3386 match &v {
3387 Verb::Commute(u) => assert_eq!(prim_of(u).name, "+"),
3388 other => panic!("expected a commute, got {other:?}"),
3389 }
3390 let (v, _) = monad_of(&one("+:^:3 (1)"));
3391 assert!(matches!(v, Verb::PowerN(_, Power::Times(3))));
3392 let (v, _) = monad_of(&one("%:^:_ (100)"));
3393 assert!(matches!(v, Verb::PowerN(_, Power::Converge)));
3394 }
3395
3396 #[test]
3397 fn the_key_adverb_derives_a_verb() {
3398 match one("+/. 1 2 3") {
3399 Expr::Monad { verb: Verb::Key(_), .. } => {}
3400 other => panic!("expected a key, got {other:?}"),
3401 }
3402 }
3403
3404 #[test]
3405 fn noun_operand_adverbs_are_not_supported_yet() {
3406 let e = err("1/ 2");
3407 assert_eq!(e.kind, ErrorKind::NotYet);
3408 assert!(e.msg.contains("noun-operand adverbs"), "{}", e.msg);
3409 }
3410
3411 #[test]
3412 fn noun_operand_conjunctions_are_not_supported_yet() {
3413 let e = err("1 @: + y");
3414 assert_eq!(e.kind, ErrorKind::NotYet);
3415 assert!(e.msg.contains("noun-operand conjunctions"), "{}", e.msg);
3416 }
3417
3418 #[test]
3421 fn three_verbs_in_parentheses_are_a_fork() {
3422 let (v, y) = monad_of(&one("(+/ % #) 1 2 3"));
3423 match &v {
3424 Verb::Fork(f, g, h) => {
3425 assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
3426 assert_eq!(prim_of(g).name, "%");
3427 assert_eq!(prim_of(h).name, "#");
3428 }
3429 other => panic!("expected a fork, got {other:?}"),
3430 }
3431 assert_eq!(konst(&y).shape, vec![3]);
3432 }
3433
3434 #[test]
3435 fn a_noun_left_tine_is_a_noun_fork() {
3436 let (v, _) = monad_of(&one("(2 + #) 1 2 3"));
3437 match &v {
3438 Verb::NounFork(a, g, h) => {
3439 assert_eq!(a.as_i64_slice(), Some(&[2i64][..]));
3440 assert_eq!(prim_of(g).name, "+");
3441 assert_eq!(prim_of(h).name, "#");
3442 }
3443 other => panic!("expected a noun fork, got {other:?}"),
3444 }
3445 }
3446
3447 #[test]
3448 fn two_verbs_in_parentheses_are_a_hook() {
3449 let (v, _) = monad_of(&one("(+ #) 1 2 3"));
3450 match &v {
3451 Verb::Hook(f, g) => {
3452 assert_eq!(prim_of(f).name, "+");
3453 assert_eq!(prim_of(g).name, "#");
3454 }
3455 other => panic!("expected a hook, got {other:?}"),
3456 }
3457 }
3458
3459 #[test]
3460 fn cap_makes_a_fork_an_atop() {
3461 let (v, _) = monad_of(&one("([: +/ ,) 1 2 3"));
3462 match &v {
3463 Verb::Atop(f, g) => {
3464 assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
3465 assert_eq!(prim_of(g).name, ",");
3466 }
3467 other => panic!("expected an atop, got {other:?}"),
3468 }
3469 }
3470
3471 #[test]
3472 fn a_five_verb_train_folds_from_the_right() {
3473 let (v, _) = monad_of(&one("(] , [ , ]) 1 2 3"));
3475 match &v {
3476 Verb::Fork(f, g, h) => {
3477 assert_eq!(prim_of(f).name, "]");
3478 assert_eq!(prim_of(g).name, ",");
3479 assert!(matches!(**h, Verb::Fork(..)), "got {h:?}");
3480 }
3481 other => panic!("expected a fork, got {other:?}"),
3482 }
3483 }
3484
3485 #[test]
3486 fn a_noun_fork_needs_a_literal_noun() {
3487 let e = err("({n} + #) 1 2 3");
3488 assert_eq!(e.kind, ErrorKind::NotYet);
3489 assert!(e.msg.contains("noun forks"), "{}", e.msg);
3490 }
3491
3492 #[test]
3493 fn cap_is_never_applied_as_a_verb() {
3494 let e = err("[: # 1 2 3");
3497 assert_eq!(e.kind, ErrorKind::Parse);
3498 assert!(e.msg.contains("caps a fork"), "{}", e.msg);
3499 }
3500
3501 #[test]
3502 fn two_nouns_side_by_side_are_a_syntax_error() {
3503 let e = err("'ab' 'cd'");
3505 assert_eq!(e.kind, ErrorKind::Parse);
3506 assert_eq!(e.msg, "syntax error");
3507 }
3508
3509 #[test]
3510 fn a_sentence_that_is_a_verb_is_not_supported_yet() {
3511 let e = err("+/ % #");
3512 assert_eq!(e.kind, ErrorKind::NotYet);
3513 assert!(e.msg.contains("tacit"), "{}", e.msg);
3514 }
3515
3516 #[rstest]
3519 #[case("x =. 5", Scope::Local)]
3520 #[case("x =: 5", Scope::Global)]
3521 fn assignment_yields_an_assign_node(#[case] src: &str, #[case] want: Scope) {
3522 match one(src) {
3523 Expr::Assign { name, value, scope, span } => {
3524 assert_eq!(name, "x");
3525 assert_eq!(ints(&value), vec![5]);
3526 assert_eq!(scope, want);
3527 assert_eq!(span, Span::new(0, 6));
3528 }
3529 other => panic!("expected an assignment, got {other:?}"),
3530 }
3531 }
3532
3533 #[test]
3534 fn assignment_in_expression_position() {
3535 let (v, x, y) = dyad_of(&one("y + x =. 3"));
3536 assert_eq!(prim_of(&v).name, "+");
3537 assert!(matches!(x, Expr::Name(..)));
3538 match y {
3539 Expr::Assign { name, span, .. } => {
3540 assert_eq!(name, "x");
3541 assert_eq!(span, Span::new(4, 10));
3542 }
3543 other => panic!("expected an assignment, got {other:?}"),
3544 }
3545 }
3546
3547 #[test]
3548 fn assignment_takes_the_whole_right_hand_sentence() {
3549 match one("x =. 1 + 2") {
3550 Expr::Assign { value, .. } => {
3551 let (v, _, _) = dyad_of(&value);
3552 assert_eq!(prim_of(&v).name, "+");
3553 }
3554 other => panic!("expected an assignment, got {other:?}"),
3555 }
3556 }
3557
3558 #[test]
3561 fn assigning_a_verb_names_it_and_runs_nothing() {
3562 let s = stmts("mean =. +/ % #");
3563 assert_eq!(s.len(), 1);
3564 match &s[0] {
3565 Expr::VerbDef { name, verb, span } => {
3566 assert_eq!(name, "mean");
3567 assert!(matches!(verb, Verb::Fork(..)), "got {verb:?}");
3568 assert_eq!(*span, Span::new(0, 14));
3569 }
3570 other => panic!("expected a verb definition, got {other:?}"),
3571 }
3572 }
3573
3574 #[test]
3575 fn a_named_verb_applies_in_a_later_sentence() {
3576 let s = stmts("mean =. +/ % #\nmean 1 2 3 4");
3577 assert_eq!(s.len(), 2);
3578 let (v, y) = monad_of(&s[1]);
3579 assert!(matches!(v, Verb::Fork(..)), "got {v:?}");
3580 assert_eq!(konst(&y).shape, vec![4]);
3581 }
3582
3583 #[test]
3584 fn a_named_verb_is_a_verb_inside_a_train_and_under_a_conjunction() {
3585 let (v, _) = monad_of(&stmts("mean =. +/ % #\n(mean - {.) 1 2 3 4").pop().expect("two"));
3586 match &v {
3587 Verb::Fork(f, g, h) => {
3588 assert!(matches!(**f, Verb::Fork(..)), "got {f:?}");
3589 assert_eq!(prim_of(g).name, "-");
3590 assert_eq!(prim_of(h).name, "{.");
3591 }
3592 other => panic!("expected a fork, got {other:?}"),
3593 }
3594 let (v, _) = monad_of(&stmts("mean =. +/ % #\nmean\"1 m").pop().expect("two"));
3595 match &v {
3596 Verb::Rank(inner, r) => {
3597 assert_eq!(*r, [1, 1, 1]);
3598 assert!(matches!(**inner, Verb::Fork(..)), "got {inner:?}");
3599 }
3600 other => panic!("expected a ranked verb, got {other:?}"),
3601 }
3602 }
3603
3604 #[test]
3605 fn redefinition_rebinds_from_that_sentence_on() {
3606 let s = stmts("f =. +/\nf 1 2 3\nf =. #\nf 1 2 3");
3607 assert_eq!(s.len(), 4);
3608 assert!(matches!(monad_of(&s[1]).0, Verb::Reduce(_)));
3609 assert_eq!(prim_of(&monad_of(&s[3]).0).name, "#");
3610 }
3611
3612 #[test]
3613 fn a_name_may_change_part_of_speech_in_either_direction() {
3614 let s = stmts("a =. 1 2 3\na =. +/\na 1 2 3");
3616 assert!(matches!(s[0], Expr::Assign { .. }));
3617 assert!(matches!(s[1], Expr::VerbDef { .. }));
3618 assert!(matches!(monad_of(&s[2]).0, Verb::Reduce(_)));
3619 let s = stmts("f =. +/\nf =. 10 20\nf");
3620 assert!(matches!(s[0], Expr::VerbDef { .. }));
3621 assert!(matches!(s[1], Expr::Assign { .. }));
3622 assert!(matches!(s[2], Expr::Name(..)));
3623 }
3624
3625 #[test]
3626 fn an_undefined_name_applied_as_a_verb_is_a_value_error() {
3627 let e = err("zz 1 2 3");
3629 assert_eq!(e.kind, ErrorKind::Value);
3630 assert_eq!(e.msg, "undefined name: zz");
3631 assert_eq!(e.span, Some(Span::new(0, 2)));
3632 let e = err("a =. 5\na 1 2 3");
3635 assert_eq!(e.kind, ErrorKind::Parse);
3636 assert_eq!(e.msg, "syntax error");
3637 }
3638
3639 #[test]
3640 fn assignment_names_an_adverb_or_a_conjunction() {
3641 match one("insert =. /") {
3642 Expr::ModDef { name, spelling, conjunction, .. } => {
3643 assert_eq!(name, "insert");
3644 assert_eq!(spelling, "/");
3645 assert!(!conjunction);
3646 }
3647 other => panic!("expected a modifier definition, got {other:?}"),
3648 }
3649 match one("atop =. @") {
3650 Expr::ModDef { spelling, conjunction, .. } => {
3651 assert_eq!(spelling, "@");
3652 assert!(conjunction);
3653 }
3654 other => panic!("expected a modifier definition, got {other:?}"),
3655 }
3656 let s = stmts("insert =. /\n+ insert 1 2 3");
3659 assert!(matches!(s[1], Expr::Monad { verb: Verb::Reduce(_), .. }), "{:?}", s[1]);
3660 }
3661
3662 #[test]
3663 fn a_sentence_that_is_a_modifier_is_a_named_gap() {
3664 let e = err("insert =. /\ninsert");
3665 assert_eq!(e.kind, ErrorKind::NotYet);
3666 assert!(e.msg.contains("displaying a modifier"), "{}", e.msg);
3667 }
3668
3669 #[rstest]
3670 #[case("f =. 3 : 'y + 1'", None)]
3671 #[case("f =. 4 : 'x + y'", Some("x"))]
3672 #[case("f =. {{ y + 1 }}", None)]
3673 #[case("f =. {{ x + y }}", Some("x"))]
3674 fn an_explicit_definition_names_a_verb(#[case] src: &str, #[case] left: Option<&str>) {
3675 match one(src) {
3676 Expr::VerbDef { name, verb: Verb::Explicit(d), .. } => {
3677 assert_eq!(name, "f");
3678 assert_eq!(d.left.as_deref(), left);
3679 assert_eq!(d.right, "y");
3680 assert_eq!(d.body.len(), 1);
3681 }
3682 other => panic!("expected an explicit verb definition, got {other:?}"),
3683 }
3684 }
3685
3686 #[rstest]
3687 #[case("f =. 13 : 'y + 1'", "tacit definitions")]
3688 fn definition_forms_libjay_has_not_are_named(#[case] src: &str, #[case] msg: &str) {
3689 let e = err(src);
3690 assert_eq!(e.kind, ErrorKind::NotYet);
3691 assert!(e.msg.contains(msg), "{}", e.msg);
3692 }
3693
3694 #[rstest]
3697 #[case("f =. 1 : 'y + 1'", Some(false))]
3698 #[case("f =. 2 : 'u v y'", Some(true))]
3699 #[case("f =. {{ y + 1 }}", None)]
3700 #[case("f =. {{ u y }}", Some(false))]
3701 #[case("f =. {{ m + y }}", Some(false))]
3702 #[case("f =. {{ u v y }}", Some(true))]
3703 #[case("f =. {{ v y }}", Some(true))]
3704 #[case("f =. {{ n + y }}", Some(true))]
3705 #[case("f =. {{ u n y }}", Some(true))]
3706 #[case("f =. {{)a\nu y\n}}", Some(false))]
3707 #[case("f =. {{)c\nu v y\n}}", Some(true))]
3708 #[case("f =. {{)v\ny\n}}", None)]
3709 fn an_explicit_definitions_part_of_speech(#[case] src: &str, #[case] want: Option<bool>) {
3710 match (one(src), want) {
3711 (Expr::ModDef { name, conjunction, .. }, Some(conj)) => {
3712 assert_eq!(name, "f");
3713 assert_eq!(conjunction, conj, "{src:?}");
3714 }
3715 (Expr::VerbDef { name, .. }, None) => assert_eq!(name, "f"),
3716 (other, _) => panic!("expected {want:?} for {src:?}, got {other:?}"),
3717 }
3718 }
3719
3720 #[test]
3721 fn a_control_word_outside_a_definition_is_a_parse_error() {
3722 let e = err("if. 1 do. 2 end.");
3723 assert_eq!(e.kind, ErrorKind::Parse);
3724 assert!(e.msg.contains("only meaningful inside an explicit definition"), "{}", e.msg);
3725 }
3726
3727 #[test]
3728 fn multiple_assignment_is_not_supported_yet() {
3729 let e = err("'a b' =. 1 2");
3730 assert_eq!(e.kind, ErrorKind::NotYet);
3731 assert!(e.msg.contains("multiple assignment"), "{}", e.msg);
3732 }
3733
3734 #[test]
3737 fn a_hole_is_a_noun() {
3738 let e = one("{a} + 1");
3739 let (_, x, y) = dyad_of(&e);
3740 match x {
3741 Expr::Param(i, s) => {
3742 assert_eq!(i, 0);
3743 assert_eq!(s, Span::new(0, 3));
3744 }
3745 other => panic!("expected a parameter, got {other:?}"),
3746 }
3747 assert_eq!(ints(&y), vec![1]);
3748 assert_eq!(e.span(), Span::new(0, 7));
3749 }
3750
3751 #[test]
3752 fn holes_are_numbered_and_shared_by_name() {
3753 let sp = SourceParts::from_source("{a} + {b} + {a}").expect("source parts");
3754 assert_eq!(sp.param_names, vec!["a".to_string(), "b".to_string()]);
3755 let e = parse(&sp).expect("parse").pop().expect("one sentence");
3756 let (_, x, y) = dyad_of(&e);
3757 assert!(matches!(x, Expr::Param(0, _)));
3758 let (_, x2, y2) = dyad_of(&y);
3759 assert!(matches!(x2, Expr::Param(1, _)));
3760 assert!(matches!(y2, Expr::Param(0, _)));
3761 }
3762
3763 #[rstest]
3764 #[case("3j4", 3.0, 4.0)]
3765 #[case("_1j_2", -1.0, -2.0)]
3766 #[case("1e1j2", 10.0, 2.0)]
3767 #[case("2ad90", 0.0, 2.0)]
3768 #[case("1ad180", -1.0, 0.0)]
3769 fn complex_literals(#[case] src: &str, #[case] re: f64, #[case] im: f64) {
3770 let a = konst(&one(src));
3771 assert_eq!(a.dtype(), DType::Complex);
3772 let z = a.as_complex_slice().expect("complex data")[0];
3773 assert!((z[0] - re).abs() < 1e-12 && (z[1] - im).abs() < 1e-12, "{z:?}");
3774 }
3775
3776 #[test]
3777 fn a_hole_takes_a_verb_like_any_noun() {
3778 let (v, y) = monad_of(&one("+/ {data}"));
3779 assert!(matches!(v, Verb::Reduce(_)));
3780 assert!(matches!(y, Expr::Param(0, _)));
3781 }
3782
3783 #[test]
3784 fn braces_inside_a_string_are_not_holes() {
3785 let sp = SourceParts::from_source("'{a}'").expect("source parts");
3786 assert!(sp.param_names.is_empty());
3787 let a = konst(&parse(&sp).expect("parse")[0]);
3788 assert_eq!(a.data, Data::Char(vec!['{', 'a', '}'].into()));
3789 }
3790
3791 #[test]
3792 fn parts_of_one_sentence_lex_across_a_hole() {
3793 let sp = SourceParts::from_parts(&["1 + ", " * 2"], &["v"]);
3795 assert_eq!(sp.display, "1 + {v} * 2");
3796 let e = parse(&sp).expect("parse").pop().expect("one sentence");
3797 let (_, x, y) = dyad_of(&e);
3798 assert_eq!(ints(&x), vec![1]);
3799 let (_, x2, y2) = dyad_of(&y);
3800 assert!(matches!(x2, Expr::Param(0, _)));
3801 assert_eq!(ints(&y2), vec![2]);
3802 }
3803
3804 #[test]
3805 fn spans_of_later_sentences_index_the_whole_source() {
3806 let src = "5\n1 + 2";
3807 let s = stmts(src);
3808 assert_eq!(s[1].span(), Span::new(2, 7));
3809 assert_eq!(&src[2..7], "1 + 2");
3810 }
3811
3812 #[test]
3815 fn unknown_word_reports_its_span() {
3816 let e = err("1 [. 2");
3817 assert_eq!(e.kind, ErrorKind::Parse);
3818 assert_eq!(e.msg, "unknown word: [.");
3819 assert_eq!(e.span, Some(Span::new(2, 4)));
3820 }
3821
3822 #[test]
3823 fn an_inflected_unknown_word_is_reported_whole() {
3824 let e = err("1 ]: 2");
3825 assert_eq!(e.msg, "unknown word: ]:");
3826 assert_eq!(e.span, Some(Span::new(2, 4)));
3827 }
3828
3829 #[rstest]
3831 #[case("1.5x", 0, 4)]
3832 #[case("1e10x", 0, 5)]
3833 fn a_fractional_extended_literal_is_ill_formed(
3834 #[case] src: &str,
3835 #[case] start: usize,
3836 #[case] end: usize,
3837 ) {
3838 let e = err(src);
3839 assert_eq!(e.kind, ErrorKind::Parse);
3840 assert!(e.msg.contains("invalid number"), "{}", e.msg);
3841 assert_eq!(e.span, Some(Span::new(start, end)));
3842 }
3843
3844 #[test]
3845 fn a_malformed_number_is_a_parse_error() {
3846 let e = err("1.2.3");
3847 assert_eq!(e.kind, ErrorKind::Parse);
3848 assert!(e.msg.contains("invalid number"), "{}", e.msg);
3849 }
3850
3851 #[test]
3852 fn an_unbalanced_sentence_is_a_syntax_error() {
3853 let e = err("(1 + 2");
3856 assert_eq!(e.kind, ErrorKind::Parse);
3857 assert!(e.msg.contains("no closing"), "{}", e.msg);
3858 assert_eq!(e.span, Some(Span::new(0, 1)));
3859 }
3860
3861 #[test]
3862 fn a_stray_right_parenthesis_is_a_syntax_error() {
3863 let e = err("1 + 2)");
3864 assert_eq!(e.kind, ErrorKind::Parse);
3865 assert!(e.msg.contains("no opening"), "{}", e.msg);
3866 assert_eq!(e.span, Some(Span::new(5, 6)));
3867 }
3868
3869 #[test]
3870 fn the_error_of_a_later_sentence_points_at_that_sentence() {
3871 let e = err("1 + 2\n3 [. 4");
3872 assert_eq!(e.span, Some(Span::new(8, 10)));
3873 }
3874}