Skip to main content

jay/frontend/
j.rs

1//! J frontend: lexer and the sentence parser, lowering to the shared IR.
2//!
3//! Word formation and sentence parsing follow the model published in the J
4//! Dictionary. Words are formed left to right; a sentence is then executed
5//! right to left by pushing words onto a stack and matching the leftmost four
6//! stack slots against the parse table after every push.
7
8use 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
21/// Parse a J program (one sentence per line) into IR statements.
22///
23/// Sentences are parsed in order over a table of the names that have been
24/// given verbs, because a name's part of speech decides how the sentence
25/// around it parses. A sentence that names a verb records it and produces
26/// no work; a later sentence that reads the name gets the verb substituted
27/// into it. That is enough for the straight-line programs this frontend
28/// compiles: there is no control flow for a definition to reach backwards
29/// through, and reassigning the name simply rebinds it from there on.
30pub 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        // A definition whose body is written on the lines below swallows
37        // them, so the sentence that comes out may span several of them.
38        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/// What a name of modifier class stands for.
48#[derive(Clone, Debug)]
49enum Modifier {
50    /// A primitive modifier, by the spelling it is written with.
51    Prim(&'static str),
52    /// An explicit adverb or conjunction, by the body it was written with.
53    Explicit(Arc<ModSource>),
54}
55
56impl Modifier {
57    /// How the modifier names itself in `explain` and in diagnostics.
58    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/// The parts of speech a sentence is read against. A name's part of speech
67/// decides how the sentence around it parses, so the table is carried from
68/// sentence to sentence and into every definition body.
69#[derive(Clone, Default)]
70struct Names {
71    verbs: HashMap<String, Verb>,
72    /// Names given an adverb or a conjunction (`m =. /`), by what they
73    /// stand for and whether it is a conjunction. A modifier is applied
74    /// when a sentence is parsed, so the name has to be resolved then too,
75    /// exactly as a verb name is.
76    mods: HashMap<String, (bool, Modifier)>,
77    /// Names that hold a value by the time a sentence is read. Only the
78    /// diagnostics need this: a name that is neither a verb nor a value is
79    /// an undefined name, not a sentence the parser has yet to learn.
80    nouns: HashSet<String>,
81    /// The value of a name given a literal, for the operands that have to
82    /// be known while the sentence is read. A gerund is data, so
83    /// `` g =. +`- `` and then `g@.1` needs what g holds; an assignment
84    /// whose value is not settled at parse time takes the name back out.
85    consts: HashMap<String, Array>,
86}
87
88impl Names {
89    /// Parse one sentence against the table and note what it did to the
90    /// names it mentions.
91    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        // A sentence that names a modifier is settled here rather than in
96        // the IR: what the name stands for is a parser object, and the
97        // node the sentence lowers to carries only its spelling.
98        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    /// Note what a parsed sentence did to the names it mentions.
111    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            // A name given a noun stops being a verb, at any depth: J lets
119            // a name change part of speech, and the oracle agrees.
120            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
137/// The literal a sentence gave a name, where the whole sentence is that one
138/// assignment and its value is settled already.
139fn 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
149// ------------------------------------------------------- explicit definitions
150
151/// J's control words. `for_i.` and its relatives carry the name they bind,
152/// which is why the suffix is kept apart from the word.
153const 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
158/// A control word and, for `for_i.`, the name it binds.
159fn 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/// One piece of a definition body: a run of ordinary words, or a control
181/// word. A line break ends a sentence, and so does every control word.
182#[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
204/// Collapse every explicit definition in one line into a verb fragment.
205///
206/// `lines[*i]` is the line to read; `*i` advances past it and past any lines
207/// a definition took for its body. At the top level a control word is a
208/// spelling error, which is what the reference calls it.
209fn 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    // `f =. 3 : '… f …'` calls itself by name, so the body has to be parsed
218    // with `f` already a verb. The name is resolved when it is applied.
219    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                // Every definition on the line is now one verb fragment, so
231                // a control word still standing is one nothing encloses.
232                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
250/// The index of the `:` of a `m : n` definition, if the line has one.
251fn 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
259/// `m : n` — the definition whose body is a string, or the lines below when
260/// the right operand is `0`.
261fn 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        // `3 : 0`: the body is written on the lines below, ending with `)`.
286        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            // The body sits one character past the opening quote; a doubled
301            // quote inside it shifts what follows by one column.
302            lex_line(&text, body_span.start + 1, &mut frags)?;
303            vec![frags]
304        }
305        Data::Symbol(_) | Data::Box(_) => {
306            return Err(Error::parse("an explicit definition takes 0 or a string", body_span))
307        }
308    };
309    if let Some(conjunction) = modifier {
310        let name = if conjunction { "2 : '...'" } else { "1 : '...'" };
311        let src = mod_source(name, conjunction, body, self_name);
312        let frag = if conjunction {
313            Frag::Conj(Modifier::Explicit(Arc::new(src)), span)
314        } else {
315            Frag::Adverb(Modifier::Explicit(Arc::new(src)), span)
316        };
317        sentence.splice(at - 1..at + 2, [frag]);
318        return Ok(());
319    }
320    let name = if dyadic { "4 : '...'" } else { "3 : '...'" };
321    let verb = build_definition(body, dyadic, name, scope, self_name)?;
322    sentence.splice(at - 1..at + 2, [Frag::Verb(VerbFrag::V(verb), span)]);
323    Ok(())
324}
325
326/// The lines of a `3 : 0` body: everything up to a line that is a lone `)`.
327fn 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
345/// `{{ … }}` — the body is the words between the braces, on this line or on
346/// the lines below.
347fn 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    // The body's own words decide the part of speech, as they do in the
400    // reference: an operand name of the second position makes a
401    // conjunction, one of the first an adverb, and neither a verb. A
402    // `{{)a` marker says it outright instead.
403    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            // `)d` and `)m` fix the valence; otherwise a body that names
431            // `x` is a dyad and nothing else.
432            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
448/// True where a definition's words include this name.
449fn 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
453/// Parse a definition's body and wrap it in a verb.
454fn 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    // The body reads the names the program has already given, and binds its
462    // own arguments over them.
463    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    // A body may hold definitions of its own, and one of them may run past
478    // the end of its line, so the lines are collected before they are split
479    // into sentences.
480    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        // J decides a definition's valence from its header (or, for a
503        // `{{ }}`, from its words): one that takes `x` is a dyad only.
504        dyad_only: dyadic,
505        result: None,
506        locals: Vec::new(),
507        body: stmts,
508        // A branch that runs nothing yields J's empty result, `i. 0 0`.
509        labels: Vec::new(),
510        empty: Some(crate::ir::empty_result()),
511        pure,
512    })))
513}
514
515// ------------------------------------------------------- explicit modifiers
516
517/// An explicit adverb or conjunction: `1 : '…'`, `2 : '…'` and the `{{ … }}`
518/// whose body names an operand.
519///
520/// The body is kept as words rather than as a parsed tree. Applying the
521/// modifier substitutes the operands into those words and parses them
522/// afresh, which is what J's own substitution rule says happens, and what
523/// lets a body that mentions no argument yield a verb of its own.
524#[derive(Debug)]
525struct ModSource {
526    /// How the definition names itself in diagnostics.
527    name: String,
528    /// Two operands rather than one.
529    conjunction: bool,
530    body: Vec<Vec<Frag>>,
531    /// The body names `x` or `y`, so it is the body of the derived VERB and
532    /// runs when that verb is applied. A body that names neither runs at
533    /// derivation instead, and what it makes is what the modifier produced.
534    deferred: bool,
535    /// The body names `x`: the derived verb is a dyad only.
536    dyadic: bool,
537    /// The name this definition is being given, so that its body can
538    /// mention it.
539    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    /// The explicit modifiers whose bodies are being parsed right now, by
561    /// address. A body that derives the modifier it belongs to would parse
562    /// for ever, so the nesting is what catches it.
563    static DERIVING: std::cell::RefCell<Vec<usize>> = const { std::cell::RefCell::new(Vec::new()) };
564}
565
566/// Removes the innermost derivation from the in-progress list however it
567/// ends.
568struct Deriving;
569
570impl Drop for Deriving {
571    fn drop(&mut self) {
572        DERIVING.with(|d| {
573            d.borrow_mut().pop();
574        });
575    }
576}
577
578/// Apply an explicit modifier to its operands.
579///
580/// The operands are substituted into the body under the names J gives them
581/// — `u` and `v` for verbs, `m` and `n` for nouns — and the body is parsed
582/// with those substitutions in place. A body that names an argument becomes
583/// the derived verb's body; one that does not is a sentence, and its value
584/// (usually a tacit verb) is what the derivation produced.
585fn 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    // The body reads the names the program has given so far; the name this
614    // definition is being given is one of them, and it stands for the
615    // modifier rather than for a verb.
616    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    // The derivation-time phase: the body is a sentence, parsed here and
628    // now, and what it reduces to is what the modifier made.
629    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
655/// What part of speech a fragment belongs to, for a diagnostic.
656fn 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
664/// Put an operand in the place of the name it arrives under. A verb operand
665/// answers to `u` (or `v`), a noun one to `m` (or `n`); the other name is
666/// left alone, so a body that reaches for it reports an undefined name, as
667/// the reference does.
668fn 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            // An assignment to the name is a definition of it, not a use.
678            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
686/// True when nothing in this sentence can have an effect beyond its value.
687fn 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        // J has no branch; the variant only reaches this frontend through
705        // the shared IR, and reading its target is as pure as any read.
706        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
722/// Split a definition's lines into sentences and control words.
723fn 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    /// Consume the word that must come next.
778    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
792/// Parse sentences and control structures until one of `stop` is next.
793fn 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    // `elseif. do.` with no test is the reference's other spelling of
895    // `else.`: a final arm that always runs.
896    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        // `case. do.` with no test is the default arm.
920        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
926/// A block that has to be one sentence — a `for.` source, a `select.`
927/// subject. The value is the last sentence's, so the rest run for effect.
928fn 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
936/// Replace every name known to be a verb or a modifier by what it stands
937/// for, except where the name is the target of an assignment, which is a
938/// definition of the name rather than a use of it.
939fn 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
962/// Every name this sentence assigns a value to, inline assignments included.
963fn 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// ---------------------------------------------------------------- fragments
980
981/// A stack fragment. The lexer emits these directly: a token and a parser
982/// fragment are the same thing in J, which is why the parse table can be
983/// stated over four adjacent stack slots.
984#[derive(Clone, Debug)]
985enum Frag {
986    /// Left edge of the sentence.
987    Mark,
988    Noun(Expr),
989    /// A name used as a value, or an assignment target.
990    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    /// A finished verb definition: `mean =. +/ % #`. It belongs to no part
999    /// of speech, so no rule reaches it and it can only end a sentence.
1000    VerbDef(String, Verb, Span),
1001    /// A finished modifier definition: `m =. /`. Like `VerbDef`, it belongs
1002    /// to no part of speech and can only end a sentence. The flag says
1003    /// whether it is a conjunction.
1004    ModDef(String, bool, Modifier, Span),
1005    /// A control word, with the name `for_i.` binds when it has one. Only a
1006    /// definition's body may hold one.
1007    Control(&'static str, Option<String>, Span),
1008    /// `{{` and `}}`, the direct definition's brackets. The opening one
1009    /// carries the letter of a `{{)a` marker where the source wrote one.
1010    DdOpen(Option<char>, Span),
1011    DdClose(Span),
1012}
1013
1014/// `[:` has the verb category but no verb of its own: it is only meaningful
1015/// as the left tine of a fork, where it caps the fork into an atop.
1016#[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    /// Verb category, `[:` included.
1048    fn is_verb(&self) -> bool {
1049        matches!(self, Frag::Verb(..))
1050    }
1051
1052    /// A verb that can actually be applied or bound to a modifier.
1053    fn is_real_verb(&self) -> bool {
1054        matches!(self, Frag::Verb(VerbFrag::V(_), _))
1055    }
1056
1057    /// Names are nouns in this subset; only assignment treats them apart.
1058    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
1083// -------------------------------------------------------------- primitives
1084
1085const fn prim(name: &'static str, monad: MonadOp, dyad: DyadOp, ranks: [i64; 3]) -> Prim {
1086    Prim { name, monad, dyad, ranks }
1087}
1088
1089/// The primitive verbs this frontend knows, by their J spelling. Verbs whose
1090/// meaning exists in J but not here carry `NotYet` so the diagnostic arrives
1091/// at evaluation, pointing at the verb.
1092fn 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        // `,.` is J's `,"_1`; `verb_for` wraps it in that rank.
1125        ",." => 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        // The width of `#: y` comes from the largest value in the whole
1130        // argument, which is why the monad has infinite rank.
1131        "#:" => prim("#:", M::EncodeBits, D::Encode, [INF, 1, 0]),
1132        "!" => prim("!", M::Scalar(SM::Factorial), D::Scalar(SD::Binomial), [0, 0, 0]),
1133        "\":" => {
1134            prim("\":", M::Format, D::FormatSpecJ, [INF, 1, INF])
1135        }
1136        "o." => prim("o.", M::Scalar(SM::Pi), D::Scalar(SD::Circle), [0, 0, 0]),
1137        "j." => prim("j.", M::Scalar(SM::Imaginary), D::Scalar(SD::MakeComplex), [0, 0, 0]),
1138        "r." => prim("r.", M::Scalar(SM::Polar), D::Scalar(SD::PolarBy), [0, 0, 0]),
1139        "{" => prim("{", M::Catalogue, D::From, [INF, 0, INF]),
1140        "{." => prim("{.", M::Head, D::Take, [INF, 1, INF]),
1141        "}." => prim("}.", M::Behead, D::Drop, [INF, 1, INF]),
1142        "{:" => prim("{:", M::Tail, D::None, [INF, INF, INF]),
1143        "}:" => prim("}:", M::Curtail, D::None, [INF, INF, INF]),
1144        "|." => prim("|.", M::Reverse, D::Rotate, [INF, 1, INF]),
1145        "|:" => prim("|:", M::TransposeAxes, D::TransposeJ, [INF, 1, INF]),
1146        "i." => prim("i.", M::IotaJ, D::IndexOf { origin: 0 }, [1, INF, INF]),
1147        "i:" => prim("i:", M::Steps, D::IndexOfLast { origin: 0 }, [0, INF, INF]),
1148        "I." => prim(
1149            "I.",
1150            M::Indices { origin: 0, boxed_coords: false },
1151            D::IntervalIndex { offset: 0, closed: false },
1152            [1, 1, INF],
1153        ),
1154        // The dyad reads the whole argument: `2 x: y` gives every value a
1155        // numerator and a denominator, which becomes a trailing axis.
1156        "x:" => prim("x:", M::ToExact, D::ExactForm, [INF, 0, INF]),
1157        "p:" => prim("p:", M::NthPrime, D::PrimeMeta, [0, 0, 0]),
1158        // The coefficients are one vector and the point one atom, so the
1159        // rank machinery evaluates a whole array of points at once.
1160        "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        // The monad takes the whole argument: one invocation is one run of
1171        // the generator, consumed in ravel order.
1172        "?" => prim(
1173            "?",
1174            M::Roll { origin: 0, fixed: false, float_at_zero: true },
1175            D::Deal { origin: 0, fixed: false },
1176            [INF, 0, 0],
1177        ),
1178        "?." => prim(
1179            "?.",
1180            M::Roll { origin: 0, fixed: true, float_at_zero: true },
1181            D::Deal { origin: 0, fixed: true },
1182            [INF, 0, 0],
1183        ),
1184        "{::" => prim("{::", M::MapPaths, D::Fetch, [INF, INF, INF]),
1185        "e." => prim("e.", M::RazeIn, D::MemberJ, [INF, INF, INF]),
1186        "/:" => prim(
1187            "/:",
1188            M::GradeUp { origin: 0 },
1189            D::GradeSelect { down: false },
1190            [INF, INF, INF],
1191        ),
1192        "\\:" => prim(
1193            "\\:",
1194            M::GradeDown { origin: 0 },
1195            D::GradeSelect { down: true },
1196            [INF, INF, INF],
1197        ),
1198        ";" => prim(";", M::Raze, D::Link, [INF, INF, INF]),
1199        ";:" => prim(
1200            ";:",
1201            M::Words,
1202            D::SequentialMachine,
1203            [INF, INF, INF],
1204        ),
1205        "L." => prim("L.", M::LevelOf, D::None, [INF, INF, INF]),
1206        "\"." => prim(
1207            "\".",
1208            M::Execute { apl: false },
1209            D::ParseNumbers,
1210            [1, INF, 1],
1211        ),
1212        "A." => prim("A.", M::AnagramIndex, D::AnagramFrom, [1, 0, INF]),
1213        "C." => prim("C.", M::CycleForm, D::Permute, [INF, INF, INF]),
1214        "E." => prim("E.", M::None, D::FindSeq, [INF, INF, INF]),
1215        "u:" => prim("u:", M::Unicode { pass_chars: true }, D::UnicodeForm, [INF, 0, INF]),
1216        // The monad reads the whole argument: one delimiter governs the
1217        // whole list. The dyad takes the form as an atom.
1218        "s:" => prim("s:", M::Symbols, D::SymbolForm, [INF, 0, INF]),
1219        "]" => prim("]", M::Same, D::Right, [INF, INF, INF]),
1220        "[" => prim("[", M::Same, D::Left, [INF, INF, INF]),
1221        "echo" => prim("echo", M::Echo, D::None, [INF, INF, INF]),
1222        _ => return None,
1223    })
1224}
1225
1226/// The constant nouns J spells as inflected words. `a.` is the 256
1227/// characters of J's alphabet in codepoint order; `a:` is the ace, the box
1228/// holding an empty numeric list; `_.` is the indeterminate value, which is
1229/// a NaN and prints as itself.
1230fn noun_word(word: &str) -> Option<Array> {
1231    match word {
1232        "a." => Some(Array::from_chars(
1233            (0u32..256).map(|c| char::from_u32(c).expect("a Latin-1 codepoint")).collect(),
1234        )),
1235        "a:" => Some(Array::boxed(Array::empty(crate::dtype::DType::I64))),
1236        "_." => Some(Array::scalar_f64(f64::NAN)),
1237        _ => None,
1238    }
1239}
1240
1241/// The verb a word denotes. Every word but `,.` is a bare primitive; J's
1242/// `,.` is `,"_1`, so it carries that rank.
1243fn verb_for(word: &str) -> Option<Verb> {
1244    let p = primitive(word)?;
1245    if word == ",." {
1246        return Some(Verb::Rank(Box::new(Verb::Prim(p)), [-1, -1, -1]));
1247    }
1248    Some(Verb::Prim(p))
1249}
1250
1251/// A constant verb: the noun itself, whatever the arguments are. `3:` and
1252/// the noun operand of `::` both need one.
1253fn constant_verb(n: Array) -> Verb {
1254    // `n [ (x ] y)` is n whatever the arguments are, and the noun fork has
1255    // both valences, which a bond does not.
1256    Verb::NounFork(
1257        n,
1258        Box::new(verb_for("[").expect("`[` is a primitive")),
1259        Box::new(verb_for("]").expect("`]` is a primitive")),
1260    )
1261}
1262
1263/// The spelling of a constant verb: `_9:` … `9:`, and `_:` for infinity.
1264/// The word must be complete — `3::` is the adverse conjunction after a
1265/// number, not a constant verb.
1266fn constant_verb_word(cs: &[(usize, char)], i: usize) -> Option<(usize, Array)> {
1267    let at = |k: usize| cs.get(k).map(|&(_, c)| c);
1268    let (digits, value) = match (at(i), at(i + 1), at(i + 2)) {
1269        (Some('_'), Some(':'), _) => (2, f64::INFINITY),
1270        (Some('_'), Some(d), Some(':')) if d.is_ascii_digit() => {
1271            (3, -((d as u8 - b'0') as f64))
1272        }
1273        (Some(d), Some(':'), _) if d.is_ascii_digit() => (2, (d as u8 - b'0') as f64),
1274        _ => return None,
1275    };
1276    if at(i + digits) == Some(':') {
1277        return None;
1278    }
1279    let arr = if value.is_infinite() {
1280        Array::scalar_f64(value)
1281    } else {
1282        Array::scalar_i64(value as i64)
1283    };
1284    Some((digits, arr))
1285}
1286
1287/// The verb one J spelling denotes, for the parts of the evaluator that
1288/// need to name a verb rather than parse one — the obverse table above all.
1289pub(crate) fn verb_named(word: &str) -> Option<Verb> {
1290    verb_for(word)
1291}
1292
1293const ADVERBS: [&str; 9] = ["/", "\\", "/.", "\\.", "~", "}", "f.", "M.", "b."];
1294
1295/// Conjunction spellings. The ones without a meaning here are recognised so
1296/// that their diagnostic names the conjunction rather than the word.
1297const CONJUNCTIONS: [&str; 24] = [
1298    "\"", "@", "@.", "@:", "&", "&.", "&.:", "&:", "^:", ";.", "!.", "!:", "`", "`:", ".", ":",
1299    ":.", "::", "L:", "S:", "H.", "T.", "t.", "t:",
1300];
1301
1302fn adverb(word: &str) -> Option<&'static str> {
1303    ADVERBS.iter().copied().find(|&g| g == word)
1304}
1305
1306fn conjunction(word: &str) -> Option<&'static str> {
1307    CONJUNCTIONS.iter().copied().find(|&g| g == word)
1308}
1309
1310// ------------------------------------------------------------------- lexer
1311
1312/// Split the source into sentences of fragments. Text segments are lexed;
1313/// each interpolation hole becomes a noun fragment holding its parameter.
1314fn lex(src: &SourceParts) -> Result<Vec<Vec<Frag>>> {
1315    let mut sentences: Vec<Vec<Frag>> = Vec::new();
1316    let mut cur: Vec<Frag> = Vec::new();
1317    for seg in &src.segments {
1318        match seg {
1319            Segment::Text { text, offset } => {
1320                let mut pos = 0usize;
1321                for (n, line) in text.split('\n').enumerate() {
1322                    if n > 0 && !cur.is_empty() {
1323                        sentences.push(std::mem::take(&mut cur));
1324                    }
1325                    lex_line(line, offset + pos, &mut cur)?;
1326                    pos += line.len() + 1;
1327                }
1328            }
1329            Segment::Param { index, offset, len } => {
1330                let span = Span::new(*offset, *offset + *len);
1331                cur.push(Frag::Noun(Expr::Param(*index, span)));
1332            }
1333        }
1334    }
1335    if !cur.is_empty() {
1336        sentences.push(cur);
1337    }
1338    Ok(sentences)
1339}
1340
1341/// A numeric word's value. Kept apart from `Array` so that a list of words
1342/// can pick one element type for the whole vector.
1343#[derive(Clone, Debug)]
1344enum Num {
1345    I(i64),
1346    F(f64),
1347    /// An extended-precision integer: `123x`.
1348    X(crate::exact::Ext),
1349    /// A rational: `1r3`.
1350    R(crate::exact::Rat),
1351    C(crate::complex::Cx),
1352}
1353
1354fn lex_line(text: &str, base: usize, out: &mut Vec<Frag>) -> Result<()> {
1355    let cs: Vec<(usize, char)> = text.char_indices().collect();
1356    let at = |i: usize| cs.get(i).map(|&(_, c)| c);
1357    let off = |i: usize| cs.get(i).map(|&(o, _)| o).unwrap_or(text.len());
1358    let span = |a: usize, b: usize| Span::new(base + off(a), base + off(b));
1359    let mut i = 0usize;
1360    while i < cs.len() {
1361        let c = cs[i].1;
1362        if c.is_whitespace() {
1363            i += 1;
1364            continue;
1365        }
1366        // `NB.` is only a comment at the start of a word, which is where
1367        // this loop always stands.
1368        if c == 'N' && at(i + 1) == Some('B') && at(i + 2) == Some('.') {
1369            break;
1370        }
1371        if c == '\'' {
1372            let start = i;
1373            i += 1;
1374            let mut chars: Vec<char> = Vec::new();
1375            loop {
1376                match at(i) {
1377                    None => {
1378                        return Err(Error::parse(
1379                            "unterminated string literal",
1380                            span(start, cs.len()),
1381                        ));
1382                    }
1383                    Some('\'') if at(i + 1) == Some('\'') => {
1384                        chars.push('\'');
1385                        i += 2;
1386                    }
1387                    Some('\'') => {
1388                        i += 1;
1389                        break;
1390                    }
1391                    Some(ch) => {
1392                        chars.push(ch);
1393                        i += 1;
1394                    }
1395                }
1396            }
1397            // One character is an atom; anything else is a vector.
1398            let shape = if chars.len() == 1 { vec![] } else { vec![chars.len()] };
1399            let arr = Array::new(shape, Data::Char(chars.into()));
1400            out.push(Frag::Noun(Expr::Const(arr, span(start, i))));
1401            continue;
1402        }
1403        if let Some((len, n)) = constant_verb_word(&cs, i) {
1404            out.push(Frag::Verb(VerbFrag::V(constant_verb(n)), span(i, i + len)));
1405            i += len;
1406            continue;
1407        }
1408        if starts_number(&cs, i) {
1409            // Numeric words separated only by blanks form one vector.
1410            let start = i;
1411            let mut nums: Vec<Num> = Vec::new();
1412            let mut end;
1413            loop {
1414                let ws = i;
1415                while at(i).is_some_and(|c| c.is_ascii_alphanumeric() || c == '.' || c == '_') {
1416                    i += 1;
1417                }
1418                nums.push(parse_number(&text[off(ws)..off(i)], span(ws, i))?);
1419                end = i;
1420                let mut k = i;
1421                while at(k).is_some_and(char::is_whitespace) {
1422                    k += 1;
1423                }
1424                // A constant verb (`3:`) ends the numeric word rather than
1425                // joining it: `2 3: 4` is 2, the verb `3:`, and 4.
1426                if k < cs.len()
1427                    && starts_number(&cs, k)
1428                    && constant_verb_word(&cs, k).is_none()
1429                {
1430                    i = k;
1431                } else {
1432                    break;
1433                }
1434            }
1435            out.push(Frag::Noun(Expr::Const(num_array(&nums), span(start, end))));
1436            continue;
1437        }
1438        if c.is_ascii_alphabetic() {
1439            let start = i;
1440            i += 1;
1441            while at(i).is_some_and(|c| c.is_ascii_alphanumeric() || c == '_') {
1442                i += 1;
1443            }
1444            // An alphabetic word may be inflected into a primitive (`i.`,
1445            // `p..`), a modifier (`f.`, `L:`) or a control word (`if.`,
1446            // `for_i.`). The longer inflection wins where it names
1447            // something: `p..` is one word, not `p.` and the dot.
1448            let mut inflected = None;
1449            if matches!(at(i), Some('.') | Some(':')) {
1450                let most = if matches!(at(i + 1), Some('.') | Some(':')) { 2 } else { 1 };
1451                for n in (1..=most).rev() {
1452                    let word = &text[off(start)..off(i + n)];
1453                    let sp = span(start, i + n);
1454                    let frag = if let Some(v) = verb_for(word) {
1455                        Frag::Verb(VerbFrag::V(v), sp)
1456                    } else if let Some(value) = noun_word(word) {
1457                        Frag::Noun(Expr::Const(value, sp))
1458                    } else if let Some(g) = adverb(word) {
1459                        Frag::Adverb(Modifier::Prim(g), sp)
1460                    } else if let Some(g) = conjunction(word) {
1461                        Frag::Conj(Modifier::Prim(g), sp)
1462                    } else if let Some((cw, suffix)) = control_word(word) {
1463                        Frag::Control(cw, suffix, sp)
1464                    } else {
1465                        continue;
1466                    };
1467                    inflected = Some((frag, n));
1468                    break;
1469                }
1470            }
1471            if let Some((frag, n)) = inflected {
1472                i += n;
1473                out.push(frag);
1474                continue;
1475            }
1476            let word = &text[off(start)..off(i)];
1477            match verb_for(word) {
1478                Some(v) => out.push(Frag::Verb(VerbFrag::V(v), span(start, i))),
1479                None => out.push(Frag::Name(word.to_string(), span(start, i))),
1480            }
1481            continue;
1482        }
1483        // `{{` and `}}` bracket J's direct definition; neither is two words.
1484        if c == '{' && at(i + 1) == Some('{') {
1485            // `{{)a` and its relatives state the definition's part of
1486            // speech instead of leaving it to the words of the body. The
1487            // reference takes the marker only where nothing follows it on
1488            // the line, and reads `{{)a u y }}` as a domain error.
1489            let marker = match (at(i + 2), at(i + 3)) {
1490                (Some(')'), Some(m)) if m.is_ascii_alphabetic() => Some(m),
1491                _ => None,
1492            };
1493            if let Some(m) = marker {
1494                if cs[i + 4..].iter().any(|&(_, c)| !c.is_whitespace()) {
1495                    return Err(Error::parse(
1496                        format!("`)`{m} names the part of speech of a direct definition, \
1497                                 and has to be the last thing on its line"),
1498                        span(i, i + 4),
1499                    ));
1500                }
1501                out.push(Frag::DdOpen(Some(m), span(i, i + 4)));
1502                i += 4;
1503                continue;
1504            }
1505            out.push(Frag::DdOpen(None, span(i, i + 2)));
1506            i += 2;
1507            continue;
1508        }
1509        if c == '}' && at(i + 1) == Some('}') {
1510            out.push(Frag::DdClose(span(i, i + 2)));
1511            i += 2;
1512            continue;
1513        }
1514        // A symbol word is one character plus a trailing inflection, which
1515        // always binds: `~:` is one word, never `~` followed by `:`. The
1516        // parentheses are the exception; they are never inflected.
1517        let inflectable = c != '(' && c != ')';
1518        let mut len =
1519            if inflectable && matches!(at(i + 1), Some('.') | Some(':')) { 2 } else { 1 };
1520        // A doubly inflected word (`&.:`) exists only where the table says
1521        // it does; everything else stops at one inflection.
1522        if len == 2 && at(i + 2) == Some(':') {
1523            let w = &text[off(i)..off(i + 3)];
1524            if conjunction(w).is_some() || verb_for(w).is_some() {
1525                len = 3;
1526            }
1527        }
1528        let word = &text[off(i)..off(i + len)];
1529        match symbol_frag(word, span(i, i + len)) {
1530            Some(frag) => {
1531                out.push(frag);
1532                i += len;
1533            }
1534            None => {
1535                return Err(Error::parse(format!("unknown word: {word}"), span(i, i + len)));
1536            }
1537        }
1538    }
1539    Ok(())
1540}
1541
1542fn symbol_frag(word: &str, span: Span) -> Option<Frag> {
1543    Some(match word {
1544        "(" => Frag::LParen(span),
1545        ")" => Frag::RParen(span),
1546        "=." => Frag::AssignLocal(span),
1547        "=:" => Frag::AssignGlobal(span),
1548        "[:" => Frag::Verb(VerbFrag::Cap, span),
1549        // `$:` stands for the explicit definition it is written in.
1550        "$:" => Frag::Verb(VerbFrag::V(Verb::SelfRef), span),
1551        // An inflected verb wins over the adverb its stem spells: `~.` is
1552        // the nub, never `~` followed by an inflection.
1553        _ => {
1554            if let Some(v) = verb_for(word) {
1555                Frag::Verb(VerbFrag::V(v), span)
1556            } else if let Some(g) = adverb(word) {
1557                Frag::Adverb(Modifier::Prim(g), span)
1558            } else {
1559                Frag::Conj(Modifier::Prim(conjunction(word)?), span)
1560            }
1561        }
1562    })
1563}
1564
1565/// A numeric word starts with a digit, or with `_` used as a negative sign
1566/// or as infinity (`_`, `__`) — but not as the start of a name.
1567fn starts_number(cs: &[(usize, char)], i: usize) -> bool {
1568    let c = cs[i].1;
1569    if c.is_ascii_digit() {
1570        return true;
1571    }
1572    if c != '_' {
1573        return false;
1574    }
1575    match cs.get(i + 1).map(|&(_, c)| c) {
1576        None => true,
1577        Some(d) => d.is_ascii_digit() || d == '.' || !d.is_alphanumeric(),
1578    }
1579}
1580
1581fn parse_number(word: &str, span: Span) -> Result<Num> {
1582    // `_.` is the indeterminate value, not a number with a decimal point.
1583    if word == "_." {
1584        return Ok(Num::F(f64::NAN));
1585    }
1586    // `1x` is an extended-precision integer; `1x1` is a multiple of e, and
1587    // `1p1` a multiple of π. The letter is the separator in both, and it
1588    // binds LOOSEST: `1ar1p1` is the polar value `1ar1` scaled by π.
1589    if let Some(k) = word.find(['p', 'x']) {
1590        if word[k + 1..].is_empty() {
1591            // A trailing `x` is the extended-precision suffix, and only a
1592            // whole decimal number carries it: `1.5x` and `1e10x` are
1593            // ill-formed, as they are in the reference.
1594            if word.as_bytes()[k] == b'x' {
1595                return extended_literal(&word[..k], word, span);
1596            }
1597            return Err(Error::parse(format!("invalid number: {word}"), span));
1598        }
1599        let base =
1600            if word.as_bytes()[k] == b'p' { std::f64::consts::PI } else { std::f64::consts::E };
1601        let mantissa = plain_number(&word[..k], word, span)?;
1602        let exponent = plain_number(&word[k + 1..], word, span)?;
1603        return Ok(scale(mantissa, base, exponent));
1604    }
1605    // `3j4` is the rectangular form. A `b` earlier in the word makes the
1606    // `j` a base-literal digit instead (`36bj` is 19).
1607    if let Some(k) = word.find('j') && !word[..k].contains('b') {
1608        let re = as_f64(plain_number(&word[..k], word, span)?);
1609        let im = as_f64(plain_number(&word[k + 1..], word, span)?);
1610        return Ok(Num::C([re, im]));
1611    }
1612    // `1ad45` and `1ar1` are the polar forms: a magnitude, then the angle
1613    // in degrees or in radians.
1614    if let Some(k) = word.find("ad").or_else(|| word.find("ar")) && !word[..k].contains('b') {
1615        let magnitude = as_f64(plain_number(&word[..k], word, span)?);
1616        let angle = as_f64(plain_number(&word[k + 2..], word, span)?);
1617        return Ok(Num::C(if word.as_bytes()[k + 1] == b'd' {
1618            crate::complex::from_degrees(magnitude, angle)
1619        } else {
1620            crate::complex::from_radians(magnitude, angle)
1621        }));
1622    }
1623    // `3r4` is a rational, and `1r_2` spells its negative denominator with
1624    // J's own negative sign. A `b` earlier in the word makes the `r` a
1625    // base-literal digit instead.
1626    if let Some(k) = word.find('r') && !word[..k].contains('b') {
1627        return rational_literal(&word[..k], &word[k + 1..], word, span);
1628    }
1629    if let Some(k) = word.find('b') {
1630        return base_literal(&word[..k], &word[k + 1..], word, span);
1631    }
1632    plain_number(word, word, span)
1633}
1634
1635/// `123x`: the digits as an extended-precision integer. The value is exact
1636/// however many digits it has, which is the whole point of the suffix.
1637fn extended_literal(digits: &str, word: &str, span: Span) -> Result<Num> {
1638    Ok(Num::X(whole_digits(digits, word, span)?))
1639}
1640
1641/// `3r4`: a rational. A zero denominator is J's infinity rather than a
1642/// number — the only spelling that leaves the exact types on sight.
1643fn rational_literal(num: &str, den: &str, word: &str, span: Span) -> Result<Num> {
1644    use num_traits::Zero;
1645    let num = whole_digits(num, word, span)?;
1646    let den = whole_digits(den, word, span)?;
1647    if den.is_zero() {
1648        if num.is_zero() {
1649            return Ok(Num::I(0));
1650        }
1651        return Ok(Num::F(if num.sign() == num_bigint::Sign::Minus {
1652            f64::NEG_INFINITY
1653        } else {
1654            f64::INFINITY
1655        }));
1656    }
1657    Ok(Num::R(
1658        crate::exact::Rat::new(num, den).ok_or_else(|| Error::internal("a zero denominator"))?,
1659    ))
1660}
1661
1662/// One run of decimal digits, with J's `_` as the negative sign.
1663fn whole_digits(word: &str, whole: &str, span: Span) -> Result<crate::exact::Ext> {
1664    let invalid = || Error::parse(format!("invalid number: {whole}"), span);
1665    let (digits, negative) = match word.strip_prefix('_') {
1666        Some(rest) => (rest, true),
1667        None => (word, false),
1668    };
1669    if digits.is_empty() || !digits.bytes().all(|b| b.is_ascii_digit()) {
1670        return Err(invalid());
1671    }
1672    let v: crate::exact::Ext = digits.parse().map_err(|_| invalid())?;
1673    Ok(if negative { -v } else { v })
1674}
1675
1676/// A mantissa scaled by a power of π or e. Either half may be complex —
1677/// `1p1j1` is π to the power `1j1`.
1678fn scale(mantissa: Num, base: f64, exponent: Num) -> Num {
1679    if matches!(mantissa, Num::C(_)) || matches!(exponent, Num::C(_)) {
1680        let m = as_cx(mantissa);
1681        let f = crate::complex::pow([base, 0.0], as_cx(exponent));
1682        return Num::C(crate::complex::mul(m, f));
1683    }
1684    Num::F(as_f64(mantissa) * base.powf(as_f64(exponent)))
1685}
1686
1687fn as_cx(n: Num) -> crate::complex::Cx {
1688    match n {
1689        Num::C(z) => z,
1690        other => [as_f64(other), 0.0],
1691    }
1692}
1693
1694fn as_f64(n: Num) -> f64 {
1695    match n {
1696        Num::I(v) => v as f64,
1697        Num::F(v) => v,
1698        Num::X(v) => crate::exact::ext_to_f64(&v),
1699        Num::R(v) => v.to_f64(),
1700        // A complex part is itself written as a plain number, so this is
1701        // never reached from a well-formed literal.
1702        Num::C(z) => z[0],
1703    }
1704}
1705
1706/// `mBd…`: the digits `d…` read in base `m`. Digits run `0`–`9` then `a`–`z`,
1707/// and a `_` in front of them negates the value, as the reference does.
1708fn base_literal(base: &str, digits: &str, word: &str, span: Span) -> Result<Num> {
1709    let invalid = || Error::parse(format!("invalid number: {word}"), span);
1710    let base = as_f64(plain_number(base, word, span)?);
1711    let (digits, negative) = match digits.strip_prefix('_') {
1712        Some(rest) => (rest, true),
1713        None => (digits, false),
1714    };
1715    if digits.is_empty() {
1716        return Err(invalid());
1717    }
1718    let mut value = 0.0f64;
1719    for ch in digits.chars() {
1720        let d = match ch {
1721            '0'..='9' => ch as u32 - '0' as u32,
1722            'a'..='z' => ch as u32 - 'a' as u32 + 10,
1723            _ => return Err(invalid()),
1724        };
1725        value = value * base + f64::from(d);
1726    }
1727    if negative {
1728        value = -value;
1729    }
1730    // An exact whole number stays an integer, as the reference prints it.
1731    if value.fract() == 0.0 && value.abs() < 9.007_199_254_740_992e15 {
1732        return Ok(Num::I(value as i64));
1733    }
1734    Ok(Num::F(value))
1735}
1736
1737/// One constituent of a literal — a whole one, a mantissa, an exponent, or
1738/// half of a complex or polar form. Every part is itself a number in the
1739/// same grammar, which is what makes `1ar1p1` and `1p1j1` read.
1740fn plain_number(word: &str, whole: &str, span: Span) -> Result<Num> {
1741    if word.is_empty() {
1742        return Err(Error::parse(format!("invalid number: {whole}"), span));
1743    }
1744    if word.contains(['j', 'p', 'x', 'b', 'r']) || word.contains("ad") || word.contains("ar") {
1745        return parse_number(word, span);
1746    }
1747    parse_plain(word, span)
1748}
1749
1750fn parse_plain(word: &str, span: Span) -> Result<Num> {
1751    if word == "_" {
1752        return Ok(Num::F(f64::INFINITY));
1753    }
1754    if word == "__" {
1755        return Ok(Num::F(f64::NEG_INFINITY));
1756    }
1757    let invalid = || Error::parse(format!("invalid number: {word}"), span);
1758    // `_` is J's negative sign, in the mantissa and after `e`.
1759    let mut norm = String::with_capacity(word.len());
1760    for (k, ch) in word.char_indices() {
1761        if ch == '_' {
1762            if k != 0 && !word[..k].ends_with('e') {
1763                return Err(invalid());
1764            }
1765            norm.push('-');
1766        } else {
1767            norm.push(ch);
1768        }
1769    }
1770    // Exponent notation yields a float, as a fractional part does.
1771    if norm.contains('.') || norm.contains('e') {
1772        return norm.parse::<f64>().map(Num::F).map_err(|_| invalid());
1773    }
1774    // Digits that overflow a machine word are a float, as they are in J;
1775    // the `x` suffix is what asks for an exact value instead.
1776    match norm.parse::<i64>() {
1777        Ok(v) => Ok(Num::I(v)),
1778        Err(_) => norm.parse::<f64>().map(Num::F).map_err(|_| invalid()),
1779    }
1780}
1781
1782/// One numeric word list as an array. The widest type any word reached
1783/// carries the whole vector: `1 2 3x` is extended throughout, and one
1784/// rational or float among the words pulls its neighbours up with it.
1785/// J `x ". y`: the numbers one line of text spells.
1786///
1787/// The line is split at blanks and every word read as a J numeric literal;
1788/// a word that is not one takes the value `fallback` instead, which is what
1789/// separates this from `".` the monad — a line that does not parse is
1790/// answered rather than refused. One word gives a scalar, as reading that
1791/// line as a noun would; several give a vector of that many.
1792///
1793/// None where the fallback is not a number: there is nothing to stand in
1794/// with.
1795pub(crate) fn numbers_from_text(line: &str, fallback: &Array) -> Option<Array> {
1796    let stand_in = match &fallback.data {
1797        Data::Bool(v) => Num::I(i64::from(*v.as_slice().first()?)),
1798        Data::I64(v) => Num::I(*v.as_slice().first()?),
1799        Data::F64(v) => Num::F(*v.as_slice().first()?),
1800        Data::Ext(v) => Num::X(v.as_slice().first()?.clone()),
1801        Data::Rat(v) => Num::R(v.as_slice().first()?.clone()),
1802        Data::Complex(v) => Num::C(*v.as_slice().first()?),
1803        Data::Char(_) | Data::Symbol(_) | Data::Box(_) => return None,
1804    };
1805    let nums: Vec<Num> = line
1806        .split_whitespace()
1807        .map(|w| parse_number(w, Span::new(0, 0)).unwrap_or_else(|_| stand_in.clone()))
1808        .collect();
1809    Some(num_array(&nums))
1810}
1811
1812fn num_array(nums: &[Num]) -> Array {
1813    use crate::exact::{Ext, Rat};
1814    let shape = if nums.len() == 1 { vec![] } else { vec![nums.len()] };
1815    let has = |f: fn(&Num) -> bool| nums.iter().any(f);
1816    if has(|n| matches!(n, Num::C(_))) {
1817        let data = nums.iter().map(|n| as_cx(n.clone())).collect();
1818        return Array::new(shape, Data::Complex(data));
1819    }
1820    if has(|n| matches!(n, Num::F(_))) {
1821        let data = nums.iter().map(|n| as_f64(n.clone())).collect();
1822        return Array::new(shape, Data::F64(data));
1823    }
1824    if has(|n| matches!(n, Num::R(_))) {
1825        let data = nums
1826            .iter()
1827            .map(|n| match n {
1828                Num::I(v) => Rat::from_int(Ext::from(*v)),
1829                Num::X(v) => Rat::from_int(v.clone()),
1830                Num::R(v) => v.clone(),
1831                Num::F(_) | Num::C(_) => Rat::zero(),
1832            })
1833            .collect();
1834        return Array::new(shape, Data::Rat(data));
1835    }
1836    if has(|n| matches!(n, Num::X(_))) {
1837        let data = nums
1838            .iter()
1839            .map(|n| match n {
1840                Num::I(v) => Ext::from(*v),
1841                Num::X(v) => v.clone(),
1842                _ => Ext::default(),
1843            })
1844            .collect();
1845        return Array::new(shape, Data::Ext(data));
1846    }
1847    let data = nums
1848        .iter()
1849        .map(|n| match n {
1850            Num::I(v) => *v,
1851            _ => 0,
1852        })
1853        .collect();
1854    Array::new(shape, Data::I64(data))
1855}
1856
1857// ------------------------------------------------------------------ parser
1858
1859#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1860enum Rule {
1861    Monad1,
1862    Monad2,
1863    Dyad3,
1864    Adverb4,
1865    Conj5,
1866    Fork6,
1867    Bident7,
1868    Assign8,
1869    Paren9,
1870}
1871
1872/// Run the parse table over a sentence's words. The result is the one
1873/// fragment left standing, or None where the sentence did not reduce to
1874/// one — which is the reference's syntax error.
1875fn reduce_to_fragment(tokens: Vec<Frag>, scope: &Names) -> Result<Option<Frag>> {
1876    check_parens(&tokens)?;
1877    let mut stack: Vec<Frag> = Vec::new();
1878    for frag in tokens.into_iter().rev() {
1879        stack.insert(0, frag);
1880        reduce(&mut stack, scope)?;
1881    }
1882    stack.insert(0, Frag::Mark);
1883    reduce(&mut stack, scope)?;
1884    if stack.len() == 2 {
1885        return Ok(Some(stack.pop().expect("checked length")));
1886    }
1887    Ok(None)
1888}
1889
1890/// The IR statement a finished sentence stands for. `whole` is the span of
1891/// the sentence, for the complaint that it has no reading at all.
1892fn lower_sentence(frag: Option<Frag>, whole: Span) -> Result<Expr> {
1893    match frag {
1894        Some(f @ (Frag::Noun(_) | Frag::Name(..))) => as_noun(f),
1895        Some(Frag::VerbDef(name, verb, span)) => Ok(Expr::VerbDef { name, verb, span }),
1896        Some(Frag::ModDef(name, conjunction, m, span)) => {
1897            Ok(Expr::ModDef { name, spelling: m.spelling(), conjunction, span })
1898        }
1899        Some(Frag::Verb(VerbFrag::V(_), span)) => {
1900            Err(Error::not_yet("tacit verb definitions (a sentence that is a verb)", span))
1901        }
1902        Some(Frag::Adverb(_, span) | Frag::Conj(_, span)) => Err(Error::not_yet(
1903            "displaying a modifier (a sentence that is an adverb or a conjunction)",
1904            span,
1905        )),
1906        _ => Err(Error::parse("syntax error", whole)),
1907    }
1908}
1909
1910/// Report an unbalanced parenthesis at the parenthesis itself, before the
1911/// sentence is reduced: the reduction would otherwise blame whatever
1912/// fragments the stray one left stranded beside each other.
1913fn check_parens(tokens: &[Frag]) -> Result<()> {
1914    let mut open: Vec<Span> = Vec::new();
1915    for frag in tokens {
1916        match frag {
1917            Frag::LParen(s) => open.push(*s),
1918            Frag::RParen(s) => {
1919                if open.pop().is_none() {
1920                    return Err(Error::parse("this `)` has no opening `(`", *s));
1921                }
1922            }
1923            _ => {}
1924        }
1925    }
1926    match open.pop() {
1927        None => Ok(()),
1928        Some(s) => Err(Error::parse("this `(` has no closing `)`", s)),
1929    }
1930}
1931
1932fn sentence_span(tokens: &[Frag]) -> Span {
1933    tokens
1934        .iter()
1935        .map(Frag::span)
1936        .reduce(Span::merge)
1937        .unwrap_or_else(|| Span::new(0, 0))
1938}
1939
1940fn reduce(stack: &mut Vec<Frag>, scope: &Names) -> Result<()> {
1941    while apply(stack, scope)? {}
1942    Ok(())
1943}
1944
1945/// The parse table: the first matching row wins, and matching restarts after
1946/// every reduction. Slot 0 is the leftmost (most recently pushed) fragment.
1947fn match_rule(s: &[Frag]) -> Option<Rule> {
1948    let is = |i: usize, f: fn(&Frag) -> bool| s.get(i).is_some_and(f);
1949    // Slot 0 is only ever context: an edge, or a fragment that keeps the
1950    // reduction from reaching further left than it should.
1951    let ctx = |i: usize| s.get(i).is_some_and(|f| f.is_edge() || f.is_avn());
1952    let verb_or_noun =
1953        |i: usize| s.get(i).is_some_and(|f| f.is_real_verb() || f.is_noun());
1954    if is(0, Frag::is_edge) && is(1, Frag::is_real_verb) && is(2, Frag::is_noun) {
1955        return Some(Rule::Monad1);
1956    }
1957    if ctx(0) && is(1, Frag::is_verb) && is(2, Frag::is_real_verb) && is(3, Frag::is_noun) {
1958        return Some(Rule::Monad2);
1959    }
1960    if ctx(0) && is(1, Frag::is_noun) && is(2, Frag::is_real_verb) && is(3, Frag::is_noun) {
1961        return Some(Rule::Dyad3);
1962    }
1963    if ctx(0) && verb_or_noun(1) && is(2, Frag::is_adverb) {
1964        return Some(Rule::Adverb4);
1965    }
1966    if ctx(0) && verb_or_noun(1) && is(2, Frag::is_conj) && verb_or_noun(3) {
1967        return Some(Rule::Conj5);
1968    }
1969    if ctx(0)
1970        && s.get(1).is_some_and(|f| f.is_verb() || f.is_noun())
1971        && is(2, Frag::is_real_verb)
1972        && is(3, Frag::is_real_verb)
1973    {
1974        return Some(Rule::Fork6);
1975    }
1976    if is(0, Frag::is_edge) && is(1, Frag::is_cavn) && is(2, Frag::is_cavn) {
1977        return Some(Rule::Bident7);
1978    }
1979    if is(0, Frag::is_noun) && is(1, Frag::is_assign) && is(2, Frag::is_cavn) {
1980        return Some(Rule::Assign8);
1981    }
1982    if matches!(s.first(), Some(Frag::LParen(_)))
1983        && is(1, Frag::is_cavn)
1984        && matches!(s.get(2), Some(Frag::RParen(_)))
1985    {
1986        return Some(Rule::Paren9);
1987    }
1988    None
1989}
1990
1991fn take(stack: &mut Vec<Frag>, range: Range<usize>) -> Vec<Frag> {
1992    stack.drain(range).collect()
1993}
1994
1995/// The fragment, pointing at `to` instead of at its own words. Removing a
1996/// pair of parentheses uses it so that the fragment left behind still
1997/// covers the brackets it was written in.
1998fn respan(f: Frag, to: Span) -> Frag {
1999    match f {
2000        Frag::Noun(mut e) => {
2001            e.set_span(to);
2002            Frag::Noun(e)
2003        }
2004        Frag::Name(n, _) => Frag::Name(n, to),
2005        Frag::Verb(v, _) => Frag::Verb(v, to),
2006        Frag::Adverb(a, _) => Frag::Adverb(a, to),
2007        Frag::Conj(c, _) => Frag::Conj(c, to),
2008        other => other,
2009    }
2010}
2011
2012fn apply(stack: &mut Vec<Frag>, scope: &Names) -> Result<bool> {
2013    let Some(rule) = match_rule(stack) else {
2014        return Ok(false);
2015    };
2016    match rule {
2017        Rule::Monad1 => {
2018            let mut t = take(stack, 1..3);
2019            let y = t.pop().expect("two slots");
2020            let v = t.pop().expect("two slots");
2021            let frag = monad(v, y)?;
2022            stack.insert(1, frag);
2023        }
2024        Rule::Monad2 => {
2025            let mut t = take(stack, 2..4);
2026            let y = t.pop().expect("two slots");
2027            let v = t.pop().expect("two slots");
2028            let frag = monad(v, y)?;
2029            stack.insert(2, frag);
2030        }
2031        Rule::Dyad3 => {
2032            let mut t = take(stack, 1..4);
2033            let y = t.pop().expect("three slots");
2034            let v = t.pop().expect("three slots");
2035            let x = t.pop().expect("three slots");
2036            let frag = dyad(x, v, y)?;
2037            stack.insert(1, frag);
2038        }
2039        Rule::Adverb4 => {
2040            let mut t = take(stack, 1..3);
2041            let a = t.pop().expect("two slots");
2042            let u = t.pop().expect("two slots");
2043            let frag = apply_adverb(u, a, scope)?;
2044            stack.insert(1, frag);
2045        }
2046        Rule::Conj5 => {
2047            let mut t = take(stack, 1..4);
2048            let v = t.pop().expect("three slots");
2049            let c = t.pop().expect("three slots");
2050            let u = t.pop().expect("three slots");
2051            let frag = apply_conj(u, c, v, scope)?;
2052            stack.insert(1, frag);
2053        }
2054        Rule::Fork6 => {
2055            let mut t = take(stack, 1..4);
2056            let h = t.pop().expect("three slots");
2057            let g = t.pop().expect("three slots");
2058            let f = t.pop().expect("three slots");
2059            let frag = apply_fork(f, g, h)?;
2060            stack.insert(1, frag);
2061        }
2062        Rule::Bident7 => {
2063            let mut t = take(stack, 1..3);
2064            let b = t.pop().expect("two slots");
2065            let a = t.pop().expect("two slots");
2066            let frag = apply_bident(a, b, &scope.nouns)?;
2067            stack.insert(1, frag);
2068        }
2069        Rule::Assign8 => {
2070            let mut t = take(stack, 0..3);
2071            let value = t.pop().expect("three slots");
2072            let assign = t.pop().expect("three slots");
2073            let target = t.pop().expect("three slots");
2074            let scope = match assign {
2075                Frag::AssignGlobal(_) => Scope::Global,
2076                _ => Scope::Local,
2077            };
2078            let frag = apply_assign(target, value, scope)?;
2079            stack.insert(0, frag);
2080        }
2081        Rule::Paren9 => {
2082            let mut t = take(stack, 0..3);
2083            let close = t.pop().expect("three slots");
2084            let inner = t.pop().expect("three slots");
2085            let open = t.pop().expect("three slots");
2086            let outer = Span::merge(open.span(), close.span());
2087            stack.insert(0, respan(inner, outer));
2088        }
2089    }
2090    Ok(true)
2091}
2092
2093// --------------------------------------------------------------- lowering
2094
2095fn as_noun(f: Frag) -> Result<Expr> {
2096    match f {
2097        Frag::Noun(e) => Ok(e),
2098        Frag::Name(n, s) => Ok(Expr::Name(n, s)),
2099        other => Err(Error::internal(format!("expected a noun fragment, got {other:?}"))),
2100    }
2101}
2102
2103fn as_verb(f: Frag) -> Result<(Verb, Span)> {
2104    match f {
2105        Frag::Verb(VerbFrag::V(v), s) => Ok((v, s)),
2106        other => Err(Error::internal(format!("expected a verb fragment, got {other:?}"))),
2107    }
2108}
2109
2110/// The literal array behind a noun fragment, if it is one. Derived verbs that
2111/// capture a noun (rank specifications, noun forks) need the value now.
2112fn as_const(f: &Frag) -> Option<&Array> {
2113    match f {
2114        Frag::Noun(Expr::Const(a, _)) => Some(a),
2115        _ => None,
2116    }
2117}
2118
2119/// A noun fragment's value, where it is a literal or an expression over
2120/// literals that settles at compile time. An index specification such as
2121/// `(<a:;1)` is written out rather than typed in, so a modifier capturing
2122/// one has to fold it.
2123fn noun_value(f: &Frag) -> Option<Array> {
2124    if let Some(a) = as_const(f) {
2125        return Some(a.clone());
2126    }
2127    let Frag::Noun(e) = f else { return None };
2128    let cfg = crate::verb::EvalCfg {
2129        agreement: crate::verb::Agreement::LeadingPrefix,
2130        fmt: crate::fmt::FmtOpts::J,
2131        tol: crate::verb::Tol::J,
2132        rules: crate::frontend::Rules::default(),
2133    };
2134    crate::ir::fold_const(e, cfg)
2135}
2136
2137fn monad(v: Frag, y: Frag) -> Result<Frag> {
2138    let (verb, vspan) = as_verb(v)?;
2139    let y = as_noun(y)?;
2140    let span = Span::merge(vspan, y.span());
2141    Ok(Frag::Noun(Expr::Monad { verb, y: Box::new(y), span }))
2142}
2143
2144fn dyad(x: Frag, v: Frag, y: Frag) -> Result<Frag> {
2145    let x = as_noun(x)?;
2146    let (verb, vspan) = as_verb(v)?;
2147    let y = as_noun(y)?;
2148    let span = Span::merge(Span::merge(x.span(), vspan), y.span());
2149    Ok(Frag::Noun(Expr::Dyad { verb, x: Box::new(x), y: Box::new(y), span }))
2150}
2151
2152fn apply_adverb(u: Frag, a: Frag, scope: &Names) -> Result<Frag> {
2153    let Frag::Adverb(m, aspan) = a else {
2154        return Err(Error::internal("expected an adverb fragment"));
2155    };
2156    let span = Span::merge(u.span(), aspan);
2157    let glyph = match m {
2158        Modifier::Prim(g) => g,
2159        Modifier::Explicit(src) => return derive_explicit(&src, u, None, scope, span),
2160    };
2161    // `}` takes either operand: `m}` amends at the indices m, and `u}`
2162    // computes them from the arguments instead.
2163    if glyph == "}" {
2164        if !u.is_real_verb() {
2165            let m = noun_value(&u)
2166                .ok_or_else(|| Error::not_yet("amend over a computed index", span))?;
2167            return Ok(Frag::Verb(VerbFrag::V(Verb::Amend(m)), span));
2168        }
2169        let (v, _) = as_verb(u)?;
2170        return Ok(Frag::Verb(VerbFrag::V(Verb::AmendVerb(Box::new(v))), span));
2171    }
2172    // `b.` takes either operand too: a noun names one of the thirty-two
2173    // boolean functions, a verb asks after the verb's own characteristics.
2174    if glyph == "b." && !u.is_real_verb() {
2175        let m = as_const(&u)
2176            .and_then(Array::to_i64_vec)
2177            .and_then(|v| v.first().copied())
2178            .filter(|&m| (0..32).contains(&m))
2179            .ok_or_else(|| {
2180                Error::not_yet("a boolean function outside `0 b.` … `31 b.`", span)
2181            })?;
2182        let p = crate::verb::Prim {
2183            name: "b.",
2184            monad: MonadOp::None,
2185            dyad: DyadOp::TruthTable(m as u8),
2186            ranks: [crate::verb::RANK_INF, 0, 0],
2187        };
2188        return Ok(Frag::Verb(VerbFrag::V(Verb::Prim(p)), span));
2189    }
2190    if !u.is_real_verb() {
2191        return Err(Error::not_yet("noun-operand adverbs", span));
2192    }
2193    let (v, _) = as_verb(u)?;
2194    let derived = match glyph {
2195        "/" => Verb::Reduce(Box::new(v)),
2196        "\\" => Verb::Windowed(Box::new(v), WindowKind::Prefix),
2197        "\\." => Verb::Windowed(Box::new(v), WindowKind::Suffix),
2198        "~" => Verb::Commute(Box::new(v)),
2199        "/." => Verb::Key(Box::new(v)),
2200        // Names are already substituted where they were used, so a fixed
2201        // verb is the verb itself.
2202        "f." => v,
2203        "M." => Verb::Memo(Box::new(v), Default::default()),
2204        "b." => Verb::Characteristics(Box::new(v)),
2205        _ => return Err(Error::not_yet(format!("adverb ({glyph})"), span)),
2206    };
2207    Ok(Frag::Verb(VerbFrag::V(derived), span))
2208}
2209
2210fn apply_conj(u: Frag, c: Frag, v: Frag, scope: &Names) -> Result<Frag> {
2211    let Frag::Conj(m, cspan) = c else {
2212        return Err(Error::internal("expected a conjunction fragment"));
2213    };
2214    let span = Span::merge(Span::merge(u.span(), cspan), v.span());
2215    let glyph = match m {
2216        Modifier::Prim(g) => g,
2217        Modifier::Explicit(src) => return derive_explicit(&src, u, Some(v), scope, span),
2218    };
2219    match glyph {
2220        "\"" => {
2221            let f = verb_operand(u, span)?;
2222            if v.is_verb() {
2223                return Err(Error::not_yet("verb rank (u\"v)", span));
2224            }
2225            let ranks = rank_spec(&v, span)?;
2226            Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(f), ranks)), span))
2227        }
2228        "@:" => {
2229            let f = verb_operand(u, span)?;
2230            let g = verb_operand(v, span)?;
2231            Ok(Frag::Verb(VerbFrag::V(Verb::Atop(Box::new(f), Box::new(g))), span))
2232        }
2233        // `u@v` is `u@:v` applied at v's own ranks: one v-cell at a time,
2234        // with u run on each result. That difference in rank is all that
2235        // separates the two spellings.
2236        "@" => {
2237            let f = verb_operand(u, span)?;
2238            let g = verb_operand(v, span)?;
2239            let ranks = g.ranks();
2240            let atop = Verb::Atop(Box::new(f), Box::new(g));
2241            Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(atop), ranks)), span))
2242        }
2243        "&" => compose(u, v, false, span),
2244        "&:" => compose(u, v, true, span),
2245        // `u&.>` is the one under that is not built out of an inverse:
2246        // opening each box and boxing the result again is J's each.
2247        "&." if is_open(&v) => {
2248            let f = verb_operand(u, span)?;
2249            Ok(Frag::Verb(VerbFrag::V(Verb::Each(Box::new(f), Enclose::Always)), span))
2250        }
2251        // `u&.v` is `v^:_1 @: u &: v`: v prepares both arguments, u runs on
2252        // what it made, and v's obverse puts the answer back. `&.` does it
2253        // at v's monadic rank, `&.:` on the arguments whole — the same
2254        // difference `&` and `&:` have.
2255        "&." | "&.:" => {
2256            let f = verb_operand(u, span)?;
2257            let g = verb_operand(v, span)?;
2258            let back = obverse_of(&g, span)?;
2259            let composed = Verb::Compose(Box::new(f), Box::new(g.clone()));
2260            let under = Verb::Atop(Box::new(back), Box::new(composed));
2261            if glyph == "&.:" {
2262                return Ok(Frag::Verb(VerbFrag::V(under), span));
2263            }
2264            let rank = g.ranks()[0];
2265            Ok(Frag::Verb(VerbFrag::V(Verb::Rank(Box::new(under), [rank; 3])), span))
2266        }
2267        "^:" => {
2268            let f = verb_operand(u, span)?;
2269            if v.is_verb() {
2270                // `u^:v` asks v for the number of applications; the while
2271                // loop is that verb under `^:_`.
2272                let g = verb_operand(v, span)?;
2273                let p = Verb::PowerV(Box::new(f), Box::new(g));
2274                return Ok(Frag::Verb(VerbFrag::V(p), span));
2275            }
2276            // A negative power runs the obverse that many times, which is
2277            // what makes `u^:_1` the inverse.
2278            // A negative count runs the obverse that many times, whether it
2279            // was written plainly or in a box (`u^:(<_3)`).
2280            let negative = noun_value(&v).is_some_and(|a| {
2281                let inner = match a.as_boxes() {
2282                    Some([b]) => b.clone(),
2283                    _ => a,
2284                };
2285                inner.to_f64_vec().is_some_and(|n| n.len() == 1 && n[0] < 0.0)
2286            });
2287            let p = power_spec(&v, span)?;
2288            let f = if negative { obverse_of(&f, span)? } else { f };
2289            Ok(Frag::Verb(VerbFrag::V(Verb::PowerN(Box::new(f), p)), span))
2290        }
2291        ";." => {
2292            let f = verb_operand(u, span)?;
2293            let n = one_atom(&v, "cut", span)?;
2294            if n.fract() != 0.0 || !matches!(n as i64, -3..=3) {
2295                return Err(Error::not_yet(format!("cut (u;.{n})"), span));
2296            }
2297            Ok(Frag::Verb(VerbFrag::V(Verb::Cut(Box::new(f), n as i64)), span))
2298        }
2299        // `u!.n` is the tolerance for the verbs whose meaning uses one; on
2300        // any other verb J's `!.` specifies a fill, which is its own
2301        // feature and not this one.
2302        "!." => {
2303            let f = verb_operand(u, span)?;
2304            // `|.!.f` is the fill shift: the fit specifies what the places
2305            // an item left behind are filled with, not a tolerance.
2306            if matches!(&f, Verb::Prim(p) if p.name == "|.") {
2307                let fill = as_const(&v)
2308                    .cloned()
2309                    .ok_or_else(|| Error::not_yet("a computed fill (|.!.n)", span))?;
2310                return Ok(Frag::Verb(VerbFrag::V(Verb::ShiftFill(fill)), span));
2311            }
2312            let n = one_atom(&v, "fit", span)?;
2313            if !f.uses_tolerance() {
2314                return Err(Error::not_yet(
2315                    format!("fill specification ({}!.n)", f.name()),
2316                    span,
2317                ));
2318            }
2319            // J refuses a tolerance above 2^-34, and so does libjay.
2320            if !(0.0..=LARGEST_TOLERANCE).contains(&n) {
2321                return Err(Error::domain(
2322                    format!("a comparison tolerance must be between 0 and {LARGEST_TOLERANCE}"),
2323                    span,
2324                ));
2325            }
2326            Ok(Frag::Verb(VerbFrag::V(Verb::Fit(Box::new(f), n)), span))
2327        }
2328        // `u :. v` declares v to be u's obverse; it changes nothing about
2329        // how u applies, only what `^:_1` and `&.` may then do with it.
2330        ":." => {
2331            let f = verb_operand(u, span)?;
2332            let g = verb_operand(v, span)?;
2333            Ok(Frag::Verb(
2334                VerbFrag::V(Verb::WithObverse(Box::new(f), Box::new(g))),
2335                span,
2336            ))
2337        }
2338        // `u@.v` picks one verb of the gerund u by v's value at the
2339        // arguments; a noun on the right picks one now and for good.
2340        "@." => {
2341            let vs = gerund_verbs(&u, scope, span)?;
2342            if v.is_verb() {
2343                let w = verb_operand(v, span)?;
2344                return Ok(Frag::Verb(VerbFrag::V(Verb::Agenda(vs, Box::new(w))), span));
2345            }
2346            let at = one_atom(&v, "agenda", span)?;
2347            if at.fract() != 0.0 {
2348                return Err(Error::parse("an agenda index must be a whole number", span));
2349            }
2350            let picked = crate::verb::pick_gerund(&vs, at as i64, span)?;
2351            Ok(Frag::Verb(VerbFrag::V(picked), span))
2352        }
2353        // `u`v` ties two entities into a gerund, which is ordinary boxed
2354        // data: one box per atomic representation, catenated.
2355        "`" => {
2356            let left = tie_side(&u, scope, span)?;
2357            let right = tie_side(&v, scope, span)?;
2358            let tied = crate::verb::catenate(&left, &right, true, true, span)?;
2359            Ok(Frag::Noun(Expr::Const(tied, span)))
2360        }
2361        // `u :: v` answers a refusal of u by running v instead. A noun on
2362        // the right is the constant verb yielding it, as J reads it.
2363        "::" => {
2364            let f = verb_operand(u, span)?;
2365            let g = if v.is_noun() {
2366                constant_verb(bond_noun(&v, span)?)
2367            } else {
2368                verb_operand(v, span)?
2369            };
2370            Ok(Frag::Verb(VerbFrag::V(Verb::Adverse(Box::new(f), Box::new(g))), span))
2371        }
2372        // `u L: n` and `u S: n` apply u at a boxing level: `L:` puts each
2373        // answer back in the box its operand came from, `S:` spreads them
2374        // into one array.
2375        "L:" | "S:" => {
2376            let f = verb_operand(u, span)?;
2377            let n = one_atom(&v, "level", span)?;
2378            if n.fract() != 0.0 || !n.is_finite() {
2379                return Err(Error::not_yet(format!("a level of {n} ({glyph})"), span));
2380            }
2381            let level = Verb::Level {
2382                u: Box::new(f),
2383                level: n as i64,
2384                spread: glyph == "S:",
2385            };
2386            Ok(Frag::Verb(VerbFrag::V(level), span))
2387        }
2388        // `` m`:n ``: 0 applies every verb of the gerund to the arguments
2389        // and frames the answers, 3 inserts them between the items of y,
2390        // and 6 is the train the gerund spells, which is built here.
2391        "`:" => {
2392            if u.is_verb() {
2393                return Err(Error::domain(
2394                    "`: reads a gerund, which is boxed data, not a verb",
2395                    span,
2396                ));
2397            }
2398            let vs = gerund_verbs(&u, scope, span)?;
2399            let n = one_atom(&v, "evoke gerund", span)?;
2400            if vs.is_empty() {
2401                return Err(Error::domain("an evoked gerund is empty", span));
2402            }
2403            match n {
2404                0.0 | 3.0 => {
2405                    Ok(Frag::Verb(VerbFrag::V(Verb::Evoke(vs, n as i64)), span))
2406                }
2407                6.0 => train_of(vs, span),
2408                _ => Err(Error::domain(
2409                    format!("`:{n} is not one of the evoke forms 0, 3 and 6"),
2410                    span,
2411                )),
2412            }
2413        }
2414        // `m H. n`: the generalised hypergeometric function, m the
2415        // numerator parameters and n the denominator ones. Both are nouns,
2416        // and an empty list on either side is the ordinary case of none.
2417        "H." => {
2418            let num = series_parameters(&u, span)?;
2419            let den = series_parameters(&v, span)?;
2420            Ok(Frag::Verb(VerbFrag::V(Verb::Hypergeometric { num, den }), span))
2421        }
2422        // Threads reach outside the expression, which the sandbox closes;
2423        // libjay's own parallelism is not something a sentence asks for.
2424        // That is a property of libjay, not a queue position.
2425        "T." => Err(Error::sandbox(
2426            "T. starts J's own threads, which libjay does not open",
2427            span,
2428        )),
2429        // `u t. n` schedules u in one of J's thread pools and answers with
2430        // a pyx — a task, not a value. The sandbox does not open those
2431        // threads, which is libjay's own policy and not a queue position.
2432        // The reference rejects `t:` outright — an invalid inflection, as
2433        // it does `d.`, `D.` and `D:`. There is nothing here to implement.
2434        "t:" => Err(Error::new(
2435            ErrorKind::Language,
2436            "t: is not a J inflection; the reference rejects the spelling",
2437            Some(span),
2438        )),
2439        "t." => Err(Error::sandbox(
2440            "t. runs a verb in one of J's thread pools, which libjay does not open",
2441            span,
2442        )),
2443        // `u . v`: the inner product, of which `+/ . *` is the matrix
2444        // product and `-/ . *` the determinant.
2445        "." => {
2446            let f = verb_operand(u, span)?;
2447            let g = verb_operand(v, span)?;
2448            Ok(Frag::Verb(VerbFrag::V(Verb::InnerProduct {
2449                u: Box::new(f),
2450                v: Box::new(g),
2451                apl: false,
2452            }), span))
2453        }
2454        "!:" => foreign(&u, &v, span),
2455        // `u : v` is J's monad/dyad conjunction. The explicit definitions
2456        // spelled `3 : '…'` and `4 : '…'` are read by the lexer and never
2457        // reach here.
2458        ":" => Err(Error::not_yet("the monad-dyad conjunction (u : v)", span)),
2459        _ => Err(Error::not_yet(format!("the conjunction {glyph}"), span)),
2460    }
2461}
2462
2463/// `u&v` and `u&:v`, in all three shapes the conjunction takes.
2464///
2465/// With two verbs it composes: monadically `u v y`, dyadically
2466/// `(v x) u (v y)` — and `&` runs that at v's monadic rank on both sides
2467/// while `&:` runs it on the arguments whole. With a noun on either side it
2468/// bonds that noun into the dyad, giving a verb with a monadic valence only;
2469/// `&:` takes no noun at all.
2470fn compose(u: Frag, v: Frag, infinite: bool, span: Span) -> Result<Frag> {
2471    let verb = |v: Verb| Ok(Frag::Verb(VerbFrag::V(v), span));
2472    if infinite || (!u.is_noun() && !v.is_noun()) {
2473        let f = verb_operand(u, span)?;
2474        let g = verb_operand(v, span)?;
2475        let monadic_rank = g.ranks()[0];
2476        let composed = Verb::Compose(Box::new(f), Box::new(g));
2477        if infinite {
2478            return verb(composed);
2479        }
2480        return verb(Verb::Rank(Box::new(composed), [monadic_rank; 3]));
2481    }
2482    if u.is_noun() && v.is_noun() {
2483        return Err(Error::not_yet("noun-operand conjunctions", span));
2484    }
2485    // A bond applies its verb dyadically to the WHOLE argument: `m&v y` is
2486    // `m v y`, and its rank is infinite whatever v's is — `1 2&+ b. 0`
2487    // reports `_ _ _`, and `1 2&+ i. 2 2` agrees row by row rather than
2488    // pairing the noun with every atom.
2489    if u.is_noun() {
2490        let m = bond_noun(&u, span)?;
2491        let g = as_verb(v)?.0;
2492        return verb(Verb::BondLeft(m, Box::new(g)));
2493    }
2494    let f = as_verb(u)?.0;
2495    let n = bond_noun(&v, span)?;
2496    verb(Verb::BondRight(Box::new(f), n))
2497}
2498
2499/// The largest comparison tolerance `!.` accepts, as J's does: 2^-34.
2500const LARGEST_TOLERANCE: f64 = 5.820_766_091_346_741e-11;
2501
2502/// A conjunction's single numeric noun operand.
2503/// One side's parameter list for `m H. n`: a numeric list, known now.
2504fn series_parameters(f: &Frag, span: Span) -> Result<Vec<crate::complex::Cx>> {
2505    let Some(arr) = as_const(f) else {
2506        return Err(Error::not_yet("computed hypergeometric parameters (m H. n)", span));
2507    };
2508    if arr.count() == 0 {
2509        return Ok(Vec::new());
2510    }
2511    if arr.rank() > 1 {
2512        return Err(Error::parse("a hypergeometric parameter list is a vector", span));
2513    }
2514    match arr.data.cast(crate::dtype::DType::Complex) {
2515        Some(Data::Complex(v)) => Ok(v.as_slice().to_vec()),
2516        _ => Err(Error::parse("hypergeometric parameters are numbers", span)),
2517    }
2518}
2519
2520/// `m !: n`: J's foreigns, the family that reaches outside the language.
2521///
2522/// Three of them are libjay's. `1!:1` reads a line from the input source
2523/// and `1!:2` writes one to the output sink — the two halves of the stdio
2524/// the sandbox opens — and `3!:0` names an element type, which computes
2525/// and touches nothing.
2526///
2527/// The rest divide in two, and the division is the whole point of the
2528/// dispatcher. A foreign that would reach a file, a directory, the host or
2529/// a script is closed by the sandbox and no release will open it; one that
2530/// only computes is a queue position, and names itself as one.
2531fn foreign(u: &Frag, v: &Frag, span: Span) -> Result<Frag> {
2532    let family = foreign_number(u, span)?;
2533    let member = foreign_number(v, span)?;
2534    let prim = |name, monad, dyad| {
2535        Ok(Frag::Verb(
2536            VerbFrag::V(Verb::Prim(Prim { name, monad, dyad, ranks: [RANK_INF; 3] })),
2537            span,
2538        ))
2539    };
2540    let closed = |what: &str| {
2541        Err(Error::sandbox(format!("{family}!:{member} {what}, which is outside the program"), span))
2542    };
2543    match (family, member) {
2544        (1, 1) => prim("1!:1", MonadOp::ReadStream, DyadOp::None),
2545        (1, 2) => prim("1!:2", MonadOp::None, DyadOp::WriteStream),
2546        (3, 0) => prim("3!:0", MonadOp::TypeCode, DyadOp::None),
2547        // `5!:1 <'name'` is the atomic representation of what the name
2548        // stands for — the same boxed data a gerund is made of.
2549        (5, 1) => prim("5!:1", MonadOp::AtomicRep, DyadOp::None),
2550        (0, _) => closed("runs a script file"),
2551        // The rest of the file family: stdin and stdout are the streams the
2552        // sandbox opens, and every other member of it is the filesystem.
2553        (1, _) => closed("reaches the filesystem"),
2554        (2, _) => closed("reaches the host — its environment, its shell, its processes"),
2555        (6, _) => closed("reads the clock"),
2556        (15, _) => closed("calls into a shared library"),
2557        _ => Err(Error::not_yet(format!("the foreign {family}!:{member}"), span)),
2558    }
2559}
2560
2561/// One side of `m !: n`: a whole number, known now. A foreign is chosen by
2562/// its two numbers, so neither may be computed.
2563fn foreign_number(f: &Frag, span: Span) -> Result<i64> {
2564    if f.is_verb() {
2565        return Err(Error::parse("a foreign is spelled m!:n, with two numbers", span));
2566    }
2567    let Some(arr) = as_const(f) else {
2568        return Err(Error::not_yet("a computed foreign number (m!:n)", span));
2569    };
2570    match arr.to_i64_vec().as_deref() {
2571        Some([n]) if *n >= 0 => Ok(*n),
2572        _ => Err(Error::parse("a foreign is spelled m!:n, with two whole numbers", span)),
2573    }
2574}
2575
2576fn one_atom(f: &Frag, what: &str, span: Span) -> Result<f64> {
2577    let Some(arr) = as_const(f) else {
2578        return Err(Error::not_yet(format!("a computed {what} specification"), span));
2579    };
2580    let Some(vals) = arr.to_f64_vec() else {
2581        return Err(Error::parse(format!("{what} takes a numeric operand"), span));
2582    };
2583    match vals[..] {
2584        [n] => Ok(n),
2585        _ => Err(Error::parse(format!("{what} takes one atom"), span)),
2586    }
2587}
2588
2589/// The array a bonded noun operand holds; it has to be known now.
2590fn bond_noun(f: &Frag, span: Span) -> Result<Array> {
2591    as_const(f)
2592        .cloned()
2593        .ok_or_else(|| Error::not_yet("bonds over a non-literal noun", span))
2594}
2595
2596/// True for the fragment holding the primitive `>`, the only right operand
2597/// `&.` accepts.
2598fn is_open(f: &Frag) -> bool {
2599    matches!(f, Frag::Verb(VerbFrag::V(Verb::Prim(p)), _) if p.monad == MonadOp::Open)
2600}
2601
2602fn verb_operand(f: Frag, span: Span) -> Result<Verb> {
2603    if f.is_noun() {
2604        return Err(Error::not_yet("noun-operand conjunctions", span));
2605    }
2606    Ok(as_verb(f)?.0)
2607}
2608
2609/// `u"n`: 1 atom applies to every valence, 2 atoms are `left right` with the
2610/// monadic rank taken from the right, 3 atoms are given in full.
2611fn rank_spec(f: &Frag, span: Span) -> Result<[i64; 3]> {
2612    let Some(arr) = as_const(f) else {
2613        return Err(Error::not_yet("computed rank specifications", span));
2614    };
2615    let Some(vals) = arr.to_f64_vec() else {
2616        return Err(Error::parse("rank must be numeric", span));
2617    };
2618    if vals.is_empty() || vals.len() > 3 {
2619        return Err(Error::parse("rank takes 1 to 3 atoms", span));
2620    }
2621    let mut r = Vec::with_capacity(vals.len());
2622    for x in vals {
2623        if x == f64::INFINITY {
2624            r.push(RANK_INF);
2625        } else if x == f64::NEG_INFINITY {
2626            r.push(-RANK_INF);
2627        } else if x.fract() != 0.0 {
2628            return Err(Error::parse("rank must be an integer", span));
2629        } else {
2630            r.push(x as i64);
2631        }
2632    }
2633    Ok(match r.len() {
2634        1 => [r[0], r[0], r[0]],
2635        2 => [r[1], r[0], r[1]],
2636        _ => [r[0], r[1], r[2]],
2637    })
2638}
2639
2640/// `u^:n`: one nonnegative integer atom, or `_` for "iterate until the
2641/// result stops changing".
2642fn power_spec(f: &Frag, span: Span) -> Result<Power> {
2643    let Some(arr) = noun_value(f) else {
2644        return Err(Error::not_yet("computed power (u^:n)", span));
2645    };
2646    let arr = &arr;
2647    // A boxed count traces the applications rather than taking one of
2648    // them: `u^:(<n)` is `u^:(i.n)`, and `u^:a:` traces to convergence.
2649    if let Some(boxes) = arr.as_boxes() {
2650        let [inner] = boxes else {
2651            return Err(Error::parse("a boxed power takes one box", span));
2652        };
2653        if inner.count() == 0 {
2654            return Ok(Power::ConvergeTrace);
2655        }
2656        let Some(vals) = inner.to_f64_vec() else {
2657            return Err(Error::parse("power must be numeric", span));
2658        };
2659        let [n] = vals[..] else {
2660            return Err(Error::not_yet("a boxed list of power counts (u^:(<n))", span));
2661        };
2662        if n.fract() != 0.0 || n.abs() > 1e6 {
2663            return Err(Error::parse("a boxed power must be a whole count", span));
2664        }
2665        // `u^:(<n)` is `u^:(i.n)`: n counts, downwards where n is negative.
2666        if n == 0.0 {
2667            return Err(Error::domain("a boxed power traces at least one application", span));
2668        }
2669        // A negative n counts the same way with the obverse, which the
2670        // caller has already put in the verb's place.
2671        return Ok(Power::Each((0..n.abs() as u64).collect()));
2672    }
2673    let Some(vals) = arr.to_f64_vec() else {
2674        return Err(Error::parse("power must be numeric", span));
2675    };
2676    if vals.len() > 1 {
2677        // A list of counts gives one answer each, framed.
2678        let mut counts = Vec::with_capacity(vals.len());
2679        for n in &vals {
2680            if n.fract() != 0.0 || *n < 0.0 || *n > 1e6 {
2681                return Err(Error::not_yet("a power count outside 0 … 1e6", span));
2682            }
2683            counts.push(*n as u64);
2684        }
2685        return Ok(Power::Each(counts));
2686    }
2687    let [n] = vals[..] else {
2688        return Err(Error::not_yet("power over a list of counts (u^:n)", span));
2689    };
2690    if n == f64::INFINITY {
2691        return Ok(Power::Converge);
2692    }
2693    if n.fract() != 0.0 {
2694        return Err(Error::parse("power must be a whole number", span));
2695    }
2696    if n < 0.0 {
2697        // A negative power is the obverse applied that many times; the
2698        // caller substitutes the obverse for the verb.
2699        return Ok(Power::Times((-n) as u64));
2700    }
2701    Ok(Power::Times(n as u64))
2702}
2703
2704/// The obverse of a verb, or the diagnostic naming the verb that has none.
2705pub(crate) fn obverse_of(v: &Verb, span: Span) -> Result<Verb> {
2706    crate::verb::obverse(v).ok_or_else(|| {
2707        Error::not_yet(format!("the obverse of {} (no inverse is known)", v.name()), span)
2708    })
2709}
2710
2711/// One side of `` u`v ``: a verb becomes the box holding its atomic
2712/// representation, a noun stands for itself. Catenating the two is the tie,
2713/// which is why `` u`v`w `` builds up left to right with no special case.
2714fn tie_side(f: &Frag, scope: &Names, span: Span) -> Result<Array> {
2715    if f.is_real_verb() {
2716        let (v, _) = as_verb(f.clone())?;
2717        return Ok(Array::boxed(verb_ar(&v, span)?.to_array()));
2718    }
2719    noun_in_scope(f, scope)
2720        .ok_or_else(|| Error::not_yet("a tie over a computed noun", span))
2721}
2722
2723/// A verb's atomic representation, with the diagnostic for the verbs libjay
2724/// has no J spelling to give.
2725fn verb_ar(v: &Verb, span: Span) -> Result<crate::gerund::Ar> {
2726    crate::gerund::verb_ar(v).ok_or_else(|| {
2727        Error::not_yet(format!("the atomic representation of {}", v.name()), span)
2728    })
2729}
2730
2731/// A noun fragment's value, a name that holds a literal included. A gerund
2732/// is data, so `` g =. +`- `` and then `g@.1` has to find what g holds.
2733fn noun_in_scope(f: &Frag, scope: &Names) -> Option<Array> {
2734    if let Frag::Name(n, _) = f {
2735        return scope.consts.get(n).cloned();
2736    }
2737    noun_value(f)
2738}
2739
2740/// The verbs a gerund holds. A lone verb is a gerund of one, and boxed data
2741/// is read as the atomic representations it is.
2742fn gerund_verbs(f: &Frag, scope: &Names, span: Span) -> Result<Vec<Verb>> {
2743    if f.is_real_verb() {
2744        return Ok(vec![as_verb(f.clone())?.0]);
2745    }
2746    let arr = noun_in_scope(f, scope)
2747        .ok_or_else(|| Error::not_yet("a gerund computed at run time", span))?;
2748    let Some(items) = arr.as_boxes() else {
2749        return Err(Error::domain("a gerund is boxed data", span));
2750    };
2751    items.iter().map(|a| ar_verb(a, scope, span)).collect()
2752}
2753
2754/// One atomic representation as the verb it stands for.
2755fn ar_verb(a: &Array, scope: &Names, span: Span) -> Result<Verb> {
2756    let ar = crate::gerund::Ar::from_array(a)
2757        .ok_or_else(|| Error::domain("this is not an atomic representation", span))?;
2758    let (v, _) = as_verb(ar_frag(&ar, scope, span)?)?;
2759    Ok(v)
2760}
2761
2762/// One atomic representation as the fragment it stands for: a verb, or the
2763/// noun a modifier takes as an operand.
2764fn ar_frag(ar: &crate::gerund::Ar, scope: &Names, span: Span) -> Result<Frag> {
2765    use crate::gerund::Ar;
2766    match ar {
2767        Ar::Noun(a) => Ok(Frag::Noun(Expr::Const(a.clone(), span))),
2768        Ar::Prim(word) => {
2769            if word == "[:" {
2770                return Ok(Frag::Verb(VerbFrag::Cap, span));
2771            }
2772            match verb_for(word) {
2773                Some(v) => Ok(Frag::Verb(VerbFrag::V(v), span)),
2774                None => Err(Error::domain(
2775                    format!("`{word}` is not a verb an atomic representation may name"),
2776                    span,
2777                )),
2778            }
2779        }
2780        Ar::Train(parts) => {
2781            let frags: Result<Vec<Frag>> =
2782                parts.iter().map(|p| ar_frag(p, scope, span)).collect();
2783            let mut frags = frags?;
2784            match frags.len() {
2785                2 => {
2786                    let b = frags.pop().expect("two parts");
2787                    let a = frags.pop().expect("two parts");
2788                    apply_bident(a, b, &scope.nouns)
2789                }
2790                3 => {
2791                    let h = frags.pop().expect("three parts");
2792                    let g = frags.pop().expect("three parts");
2793                    let f = frags.pop().expect("three parts");
2794                    apply_fork(f, g, h)
2795                }
2796                _ => Err(Error::domain("a train is two or three parts", span)),
2797            }
2798        }
2799        Ar::Derived(word, ops) => {
2800            let frags: Result<Vec<Frag>> = ops.iter().map(|p| ar_frag(p, scope, span)).collect();
2801            let mut frags = frags?;
2802            if let Some(glyph) = adverb(word) {
2803                if frags.len() != 1 {
2804                    return Err(Error::domain(format!("{glyph} takes one operand"), span));
2805                }
2806                let u = frags.pop().expect("one operand");
2807                return apply_adverb(u, Frag::Adverb(Modifier::Prim(glyph), span), scope);
2808            }
2809            if let Some(glyph) = conjunction(word) {
2810                if frags.len() != 2 {
2811                    return Err(Error::domain(format!("{glyph} takes two operands"), span));
2812                }
2813                let v = frags.pop().expect("two operands");
2814                let u = frags.pop().expect("two operands");
2815                return apply_conj(u, Frag::Conj(Modifier::Prim(glyph), span), v, scope);
2816            }
2817            Err(Error::domain(
2818                format!("`{word}` is not a modifier an atomic representation may name"),
2819                span,
2820            ))
2821        }
2822    }
2823}
2824
2825/// The train a gerund spells: `` `:6 `` groups the verbs from the right,
2826/// three at a time, which is how J reads a train written out.
2827fn train_of(vs: Vec<Verb>, span: Span) -> Result<Frag> {
2828    let mut frags: Vec<Frag> =
2829        vs.into_iter().map(|v| Frag::Verb(VerbFrag::V(v), span)).collect();
2830    while frags.len() > 3 {
2831        let h = frags.pop().expect("three or more");
2832        let g = frags.pop().expect("three or more");
2833        let f = frags.pop().expect("three or more");
2834        frags.push(apply_fork(f, g, h)?);
2835    }
2836    match frags.len() {
2837        1 => Ok(frags.pop().expect("one")),
2838        2 => {
2839            let b = frags.pop().expect("two");
2840            let a = frags.pop().expect("two");
2841            apply_bident(a, b, &HashSet::new())
2842        }
2843        _ => {
2844            let h = frags.pop().expect("three");
2845            let g = frags.pop().expect("three");
2846            let f = frags.pop().expect("three");
2847            apply_fork(f, g, h)
2848        }
2849    }
2850}
2851
2852fn apply_fork(f: Frag, g: Frag, h: Frag) -> Result<Frag> {
2853    let span = Span::merge(Span::merge(f.span(), g.span()), h.span());
2854    let (gv, _) = as_verb(g)?;
2855    let (hv, _) = as_verb(h)?;
2856    match f {
2857        // `[: g h` is g atop h: the left tine produces nothing to fork over.
2858        Frag::Verb(VerbFrag::Cap, _) => {
2859            Ok(Frag::Verb(VerbFrag::V(Verb::Atop(Box::new(gv), Box::new(hv))), span))
2860        }
2861        Frag::Verb(VerbFrag::V(fv), _) => Ok(Frag::Verb(
2862            VerbFrag::V(Verb::Fork(Box::new(fv), Box::new(gv), Box::new(hv))),
2863            span,
2864        )),
2865        noun => {
2866            let Some(arr) = as_const(&noun) else {
2867                return Err(Error::not_yet("noun forks over a non-literal noun", span));
2868            };
2869            Ok(Frag::Verb(
2870                VerbFrag::V(Verb::NounFork(arr.clone(), Box::new(gv), Box::new(hv))),
2871                span,
2872            ))
2873        }
2874    }
2875}
2876
2877fn apply_bident(a: Frag, b: Frag, nouns: &HashSet<String>) -> Result<Frag> {
2878    let span = Span::merge(a.span(), b.span());
2879    // A name here is not a verb, or it would have been substituted; if it
2880    // is not a value either, that is what is wrong with the sentence, and
2881    // it is what the reference reports.
2882    if let Frag::Name(n, nspan) = &a && !nouns.contains(n) {
2883        return Err(Error::new(
2884            ErrorKind::Value,
2885            format!("undefined name: {n}"),
2886            Some(*nspan),
2887        ));
2888    }
2889    if a.is_real_verb() && b.is_real_verb() {
2890        let (f, _) = as_verb(a)?;
2891        let (g, _) = as_verb(b)?;
2892        return Ok(Frag::Verb(VerbFrag::V(Verb::Hook(Box::new(f), Box::new(g))), span));
2893    }
2894    // Two verbs are the only pair J makes a train of. Anything else here —
2895    // a noun beside a noun, a noun beside a verb, a leftover modifier — is
2896    // a sentence the language does not have a reading for, which is what
2897    // the reference calls a syntax error. It is not a queue position.
2898    if matches!(a, Frag::Verb(VerbFrag::Cap, _)) {
2899        return Err(Error::parse("`[:` caps a fork; it has no verb of its own", span));
2900    }
2901    Err(Error::parse("syntax error", span))
2902}
2903
2904fn apply_assign(target: Frag, value: Frag, scope: Scope) -> Result<Frag> {
2905    let span = Span::merge(target.span(), value.span());
2906    match target {
2907        // `=.` names a local and `=:` a global; the two differ only inside
2908        // an explicit definition, which is the only thing with a local
2909        // frame to name.
2910        Frag::Name(name, _) => match value {
2911            // Naming a verb is settled here, at parse time: `parse` records
2912            // the name and substitutes the verb into later sentences.
2913            Frag::Verb(VerbFrag::V(verb), _) => Ok(Frag::VerbDef(name, verb, span)),
2914            Frag::Verb(VerbFrag::Cap, _) => Err(Error::not_yet("assigning [: on its own", span)),
2915            // Naming a modifier is settled at parse time too: the name
2916            // stands for the spelling wherever a later sentence writes it.
2917            Frag::Adverb(m, _) => Ok(Frag::ModDef(name, false, m, span)),
2918            Frag::Conj(m, _) => Ok(Frag::ModDef(name, true, m, span)),
2919            v if v.is_noun() => {
2920                let value = as_noun(v)?;
2921                Ok(Frag::Noun(Expr::Assign { name, value: Box::new(value), scope, span }))
2922            }
2923            other => Err(Error::internal(format!("cannot assign {other:?}"))),
2924        },
2925        Frag::Noun(_) => Err(Error::not_yet("multiple assignment", span)),
2926        other => Err(Error::internal(format!("expected an assignment target, got {other:?}"))),
2927    }
2928}
2929
2930#[cfg(test)]
2931mod tests {
2932    use super::*;
2933    use crate::dtype::DType;
2934    use crate::error::ErrorKind;
2935    use rstest::rstest;
2936
2937    fn parse_str(src: &str) -> Result<Vec<Expr>> {
2938        parse(&SourceParts::from_source(src).expect("source parts"))
2939    }
2940
2941    /// Parse literal text with no interpolation. `{. ` and `}.` are J words
2942    /// that `from_source` would read as a hole, so those tests take the
2943    /// pre-split path instead.
2944    fn one_literal(src: &str) -> Expr {
2945        let sp = SourceParts::from_parts(&[src], &[]);
2946        let mut s = parse(&sp).unwrap_or_else(|e| panic!("parse of {src:?} failed: {e}"));
2947        assert_eq!(s.len(), 1, "expected one sentence in {src:?}");
2948        s.pop().expect("one sentence")
2949    }
2950
2951    fn stmts(src: &str) -> Vec<Expr> {
2952        parse_str(src).unwrap_or_else(|e| panic!("parse of {src:?} failed: {e}"))
2953    }
2954
2955    /// The single statement of a one-sentence program.
2956    fn one(src: &str) -> Expr {
2957        let mut s = stmts(src);
2958        assert_eq!(s.len(), 1, "expected one sentence in {src:?}");
2959        s.pop().expect("one sentence")
2960    }
2961
2962    fn err(src: &str) -> Error {
2963        match parse_str(src) {
2964            Ok(v) => panic!("expected an error for {src:?}, got {v:?}"),
2965            Err(e) => e,
2966        }
2967    }
2968
2969    // The shape inspectors return owned copies so that a test can inspect
2970    // the result of `one(...)` in one expression.
2971
2972    fn konst(e: &Expr) -> Array {
2973        match e {
2974            Expr::Const(a, _) => a.clone(),
2975            other => panic!("expected a constant, got {other:?}"),
2976        }
2977    }
2978
2979    fn ints(e: &Expr) -> Vec<i64> {
2980        konst(e).as_i64_slice().expect("integer data").to_vec()
2981    }
2982
2983    fn prim_of(v: &Verb) -> Prim {
2984        match v {
2985            Verb::Prim(p) => *p,
2986            other => panic!("expected a primitive, got {other:?}"),
2987        }
2988    }
2989
2990    fn monad_of(e: &Expr) -> (Verb, Expr) {
2991        match e {
2992            Expr::Monad { verb, y, .. } => (verb.clone(), (**y).clone()),
2993            other => panic!("expected a monad, got {other:?}"),
2994        }
2995    }
2996
2997    fn dyad_of(e: &Expr) -> (Verb, Expr, Expr) {
2998        match e {
2999            Expr::Dyad { verb, x, y, .. } => (verb.clone(), (**x).clone(), (**y).clone()),
3000            other => panic!("expected a dyad, got {other:?}"),
3001        }
3002    }
3003
3004    // ------------------------------------------------------------- literals
3005
3006    #[test]
3007    fn single_number_is_an_atom() {
3008        let e = one("5");
3009        assert_eq!(konst(&e).shape, Vec::<usize>::new());
3010        assert_eq!(ints(&e), vec![5]);
3011        assert_eq!(e.span(), Span::new(0, 1));
3012    }
3013
3014    #[test]
3015    fn adjacent_numbers_merge_into_one_vector() {
3016        let e = one("1 2 3");
3017        assert_eq!(konst(&e).shape, vec![3]);
3018        assert_eq!(ints(&e), vec![1, 2, 3]);
3019        assert_eq!(e.span(), Span::new(0, 5));
3020    }
3021
3022    #[test]
3023    fn a_float_makes_the_whole_vector_float() {
3024        let a = konst(&one("1 2.5 3"));
3025        assert_eq!(a.dtype(), DType::F64);
3026        assert_eq!(a.as_f64_slice(), Some(&[1.0, 2.5, 3.0][..]));
3027    }
3028
3029    #[test]
3030    fn negatives_and_infinities() {
3031        let a = konst(&one("_3 1.5 _ __"));
3032        assert_eq!(a.shape, vec![4]);
3033        let v = a.as_f64_slice().expect("float vector");
3034        assert_eq!(v[0], -3.0);
3035        assert_eq!(v[1], 1.5);
3036        assert!(v[2].is_infinite() && v[2] > 0.0);
3037        assert!(v[3].is_infinite() && v[3] < 0.0);
3038    }
3039
3040    #[test]
3041    fn negative_integers_stay_integers() {
3042        let a = konst(&one("_3 _4"));
3043        assert_eq!(a.dtype(), DType::I64);
3044        assert_eq!(a.as_i64_slice(), Some(&[-3i64, -4][..]));
3045    }
3046
3047    #[rstest]
3048    #[case("1e3", 1000.0)]
3049    #[case("1e_3", 0.001)]
3050    #[case("2.5e2", 250.0)]
3051    #[case("_1.5", -1.5)]
3052    fn exponent_and_sign_forms(#[case] src: &str, #[case] want: f64) {
3053        let a = konst(&one(src));
3054        assert_eq!(a.dtype(), DType::F64);
3055        assert_eq!(a.to_f64_vec().expect("numeric"), vec![want]);
3056    }
3057
3058    #[test]
3059    fn adjacent_numbers_stop_at_a_non_number() {
3060        // `i.` after a vector is a separate word, not numeric characters.
3061        let (_, x, y) = dyad_of(&one("2 3 i. 4"));
3062        assert_eq!(konst(&x).shape, vec![2]);
3063        assert_eq!(konst(&y).shape, Vec::<usize>::new());
3064    }
3065
3066    #[test]
3067    fn string_of_several_characters_is_a_vector() {
3068        let e = one("'abc'");
3069        let a = konst(&e);
3070        assert_eq!(a.shape, vec![3]);
3071        assert_eq!(a.data, Data::Char(vec!['a', 'b', 'c'].into()));
3072        assert_eq!(e.span(), Span::new(0, 5));
3073    }
3074
3075    #[test]
3076    fn one_character_string_is_an_atom() {
3077        let a = konst(&one("'a'"));
3078        assert_eq!(a.shape, Vec::<usize>::new());
3079        assert_eq!(a.data, Data::Char(vec!['a'].into()));
3080    }
3081
3082    #[test]
3083    fn empty_string_is_an_empty_vector() {
3084        let a = konst(&one("''"));
3085        assert_eq!(a.shape, vec![0]);
3086        assert_eq!(a.dtype(), DType::Char);
3087    }
3088
3089    #[test]
3090    fn doubled_quote_is_an_escaped_quote() {
3091        let a = konst(&one("'it''s'"));
3092        assert_eq!(a.shape, vec![4]);
3093        assert_eq!(a.data, Data::Char(vec!['i', 't', '\'', 's'].into()));
3094    }
3095
3096    #[test]
3097    fn unterminated_string_is_a_parse_error() {
3098        let e = err("'abc");
3099        assert_eq!(e.kind, ErrorKind::Parse);
3100        assert!(e.msg.contains("unterminated"), "{}", e.msg);
3101        assert_eq!(e.span, Some(Span::new(0, 4)));
3102    }
3103
3104    // ------------------------------------------------------------- comments
3105
3106    #[test]
3107    fn comment_runs_to_end_of_line() {
3108        let e = one("1 2 NB. and the rest + - ' is ignored");
3109        assert_eq!(konst(&e).shape, vec![2]);
3110    }
3111
3112    #[test]
3113    fn comment_only_line_yields_no_sentence() {
3114        assert!(stmts("NB. nothing here").is_empty());
3115        let s = stmts("NB. header\n5");
3116        assert_eq!(s.len(), 1);
3117        assert_eq!(ints(&s[0]), vec![5]);
3118    }
3119
3120    #[test]
3121    fn nb_inside_a_name_is_not_a_comment() {
3122        // `aNB` is a name; only a whole word `NB.` starts a comment.
3123        match one("aNB") {
3124            Expr::Name(n, _) => assert_eq!(n, "aNB"),
3125            other => panic!("expected a name, got {other:?}"),
3126        }
3127    }
3128
3129    // -------------------------------------------------------------- parsing
3130
3131    #[test]
3132    fn empty_program_has_no_sentences() {
3133        assert!(stmts("").is_empty());
3134        assert!(stmts("\n\n").is_empty());
3135    }
3136
3137    #[test]
3138    fn trains_of_dyads_are_right_associative() {
3139        let e = one("1 + 2 + 3");
3140        let (v, x, y) = dyad_of(&e);
3141        assert_eq!(prim_of(&v).name, "+");
3142        assert_eq!(ints(&x), vec![1]);
3143        let (v2, x2, y2) = dyad_of(&y);
3144        assert_eq!(prim_of(&v2).name, "+");
3145        assert_eq!(ints(&x2), vec![2]);
3146        assert_eq!(ints(&y2), vec![3]);
3147        assert_eq!(e.span(), Span::new(0, 9));
3148    }
3149
3150    #[test]
3151    fn a_verb_with_no_left_argument_is_a_monad() {
3152        let e = one("- 5");
3153        let (v, y) = monad_of(&e);
3154        assert_eq!(prim_of(&v).monad, MonadOp::Scalar(ScalarMonad::Neg));
3155        assert_eq!(ints(&y), vec![5]);
3156        assert_eq!(e.span(), Span::new(0, 3));
3157    }
3158
3159    #[test]
3160    fn a_verb_with_a_left_argument_is_a_dyad() {
3161        let (v, _, _) = dyad_of(&one("1 - 5"));
3162        assert_eq!(prim_of(&v).dyad, DyadOp::Scalar(ScalarDyad::Sub));
3163    }
3164
3165    #[test]
3166    fn a_monad_binds_to_the_right_inside_a_dyad() {
3167        let (v, x, y) = dyad_of(&one("2 * - 3"));
3168        assert_eq!(prim_of(&v).name, "*");
3169        assert_eq!(ints(&x), vec![2]);
3170        let (mv, my) = monad_of(&y);
3171        assert_eq!(prim_of(&mv).name, "-");
3172        assert_eq!(ints(&my), vec![3]);
3173    }
3174
3175    #[test]
3176    fn parentheses_group_the_left_argument() {
3177        let (v, x, y) = dyad_of(&one("(1 + 2) * 3"));
3178        assert_eq!(prim_of(&v).name, "*");
3179        let (iv, _, _) = dyad_of(&x);
3180        assert_eq!(prim_of(&iv).name, "+");
3181        // The parentheses are dropped, but the span still covers them, so
3182        // that a caret under the group underlines something balanced.
3183        assert_eq!(x.span(), Span::new(0, 7));
3184        assert_eq!(ints(&y), vec![3]);
3185    }
3186
3187    #[test]
3188    fn names_are_nouns() {
3189        match one("x") {
3190            Expr::Name(n, s) => {
3191                assert_eq!(n, "x");
3192                assert_eq!(s, Span::new(0, 1));
3193            }
3194            other => panic!("expected a name, got {other:?}"),
3195        }
3196        let (_, x, y) = dyad_of(&one("x + y"));
3197        assert!(matches!(x, Expr::Name(..)));
3198        assert!(matches!(y, Expr::Name(..)));
3199    }
3200
3201    #[test]
3202    fn echo_is_a_verb() {
3203        let (v, y) = monad_of(&one("echo 5"));
3204        assert_eq!(prim_of(&v).monad, MonadOp::Echo);
3205        assert_eq!(ints(&y), vec![5]);
3206    }
3207
3208    #[test]
3209    fn inflected_letter_words_are_primitives() {
3210        let (v, _) = monad_of(&one("i. 3"));
3211        let p = prim_of(&v);
3212        assert_eq!(p.monad, MonadOp::IotaJ);
3213        assert_eq!(p.ranks, [1, RANK_INF, RANK_INF]);
3214    }
3215
3216    #[rstest]
3217    #[case("|: 1 2 3", MonadOp::TransposeAxes)]
3218    #[case("$ 1 2 3", MonadOp::ShapeOf)]
3219    #[case("# 1 2 3", MonadOp::Tally)]
3220    #[case(", 1 2 3", MonadOp::Ravel)]
3221    #[case("%: 1 2 3", MonadOp::Scalar(ScalarMonad::Sqrt))]
3222    #[case("<. 1.5", MonadOp::Scalar(ScalarMonad::Floor))]
3223    fn inflected_symbol_words(#[case] src: &str, #[case] want: MonadOp) {
3224        let (v, _) = monad_of(&one(src));
3225        assert_eq!(prim_of(&v).monad, want);
3226    }
3227
3228    #[rstest]
3229    #[case("{. 1 2 3", MonadOp::Head, DyadOp::Take)]
3230    #[case("}. 1 2 3", MonadOp::Behead, DyadOp::Drop)]
3231    fn brace_words(#[case] src: &str, #[case] monad: MonadOp, #[case] dyad: DyadOp) {
3232        let (v, _) = monad_of(&one_literal(src));
3233        let p = prim_of(&v);
3234        assert_eq!(p.monad, monad);
3235        assert_eq!(p.dyad, dyad);
3236        assert_eq!(p.ranks, [RANK_INF, 1, RANK_INF]);
3237    }
3238
3239    #[test]
3240    fn a_brace_word_takes_a_left_argument() {
3241        let (v, x, y) = dyad_of(&one_literal("2 {. 1 2 3"));
3242        assert_eq!(prim_of(&v).dyad, DyadOp::Take);
3243        assert_eq!(ints(&x), vec![2]);
3244        assert_eq!(konst(&y).shape, vec![3]);
3245    }
3246
3247    #[rstest]
3248    #[case("2 $ 1 2 3", DyadOp::Reshape)]
3249    #[case("2 [ 3", DyadOp::Left)]
3250    #[case("2 ] 3", DyadOp::Right)]
3251    #[case("2 <. 3", DyadOp::Scalar(ScalarDyad::Min))]
3252    #[case("2 >: 3", DyadOp::Scalar(ScalarDyad::Ge))]
3253    fn dyadic_primitives(#[case] src: &str, #[case] want: DyadOp) {
3254        let (v, _, _) = dyad_of(&one(src));
3255        assert_eq!(prim_of(&v).dyad, want);
3256    }
3257
3258    #[test]
3259    fn unimplemented_meanings_reach_the_verb_not_the_parser() {
3260        let (v, _, _) = dyad_of(&one("2 $. 'a b'"));
3261        assert_eq!(prim_of(&v).dyad, DyadOp::NotYet("sparse arrays ($.)"));
3262        // `s:` itself is implemented; the symbol-table forms of its dyad
3263        // are refused inside the verb, not at the parser.
3264        let (v, _, _) = dyad_of(&one("2 s: 'a b'"));
3265        assert_eq!(prim_of(&v).dyad, DyadOp::SymbolForm);
3266    }
3267
3268    #[test]
3269    fn multiple_sentences_become_multiple_statements() {
3270        let s = stmts("a =. 1 2\n+/ a\n");
3271        assert_eq!(s.len(), 2);
3272        assert!(matches!(s[0], Expr::Assign { .. }));
3273        assert!(matches!(s[1], Expr::Monad { .. }));
3274    }
3275
3276    // ------------------------------------------------------------ modifiers
3277
3278    #[test]
3279    fn an_adverb_binds_before_the_verb_is_applied() {
3280        let e = one("+/ 1 2 3");
3281        let (v, y) = monad_of(&e);
3282        match &v {
3283            Verb::Reduce(inner) => assert_eq!(prim_of(inner).name, "+"),
3284            other => panic!("expected a reduction, got {other:?}"),
3285        }
3286        assert_eq!(konst(&y).shape, vec![3]);
3287        assert_eq!(e.span(), Span::new(0, 8));
3288    }
3289
3290    #[test]
3291    fn rank_applies_to_the_derived_verb() {
3292        let (v, _) = monad_of(&one("+/\"1 m"));
3293        match &v {
3294            Verb::Rank(inner, ranks) => {
3295                assert_eq!(*ranks, [1, 1, 1]);
3296                assert!(matches!(**inner, Verb::Reduce(_)), "got {inner:?}");
3297            }
3298            other => panic!("expected a ranked verb, got {other:?}"),
3299        }
3300    }
3301
3302    #[rstest]
3303    #[case("+\"1 m", [1, 1, 1])]
3304    #[case("+\"1 2 m", [2, 1, 2])]
3305    #[case("+\"0 1 2 m", [0, 1, 2])]
3306    #[case("+\"_ m", [RANK_INF, RANK_INF, RANK_INF])]
3307    #[case("+\"_1 m", [-1, -1, -1])]
3308    #[case("+\"2.0 m", [2, 2, 2])]
3309    fn rank_specifications(#[case] src: &str, #[case] want: [i64; 3]) {
3310        let (v, _) = monad_of(&one(src));
3311        assert_eq!(v.ranks(), want);
3312    }
3313
3314    #[test]
3315    fn rank_must_be_one_to_three_integer_atoms() {
3316        let e = err("+\"1 2 3 4 m");
3317        assert_eq!(e.kind, ErrorKind::Parse);
3318        assert!(e.msg.contains("1 to 3 atoms"), "{}", e.msg);
3319        let e = err("+\"1.5 m");
3320        assert_eq!(e.kind, ErrorKind::Parse);
3321        assert!(e.msg.contains("integer"), "{}", e.msg);
3322        let e = err("+\"'a' m");
3323        assert_eq!(e.kind, ErrorKind::Parse);
3324        assert!(e.msg.contains("numeric"), "{}", e.msg);
3325    }
3326
3327    #[test]
3328    fn verb_rank_is_not_supported_yet() {
3329        let e = err("+\"- m");
3330        assert_eq!(e.kind, ErrorKind::NotYet);
3331        assert!(e.msg.contains("verb rank"), "{}", e.msg);
3332    }
3333
3334    #[test]
3335    fn computed_rank_is_not_supported_yet() {
3336        let e = err("+\"{r} m");
3337        assert_eq!(e.kind, ErrorKind::NotYet);
3338        assert!(e.msg.contains("computed rank"), "{}", e.msg);
3339    }
3340
3341    #[test]
3342    fn atop_conjunction() {
3343        let (v, _) = monad_of(&one("+/ @: , y"));
3344        match &v {
3345            Verb::Atop(f, g) => {
3346                assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
3347                assert_eq!(prim_of(g).name, ",");
3348            }
3349            other => panic!("expected an atop, got {other:?}"),
3350        }
3351    }
3352
3353    #[rstest]
3354    #[case("+ ^: {n} y", "computed power")]
3355    #[case("(+/ % #) ^: _1 y", "the obverse of")]
3356    #[case("(+/ % #) &. , y", "the obverse of")]
3357    #[case("(1 + 2) & , y", "bonds over a non-literal noun")]
3358        fn other_conjunctions_are_not_supported_yet(#[case] src: &str, #[case] msg: &str) {
3359        let e = err(src);
3360        assert_eq!(e.kind, ErrorKind::NotYet);
3361        assert!(e.msg.contains(msg), "{}", e.msg);
3362    }
3363
3364    #[test]
3365    fn atop_at_rank_and_compose() {
3366        // `u@v` is `u@:v` at v's ranks; `u&v` is the composition at v's
3367        // monadic rank; `u&:v` is that composition on the arguments whole.
3368        let (v, _) = monad_of(&one("+/ @ (,\"1) y"));
3369        match &v {
3370            Verb::Rank(inner, ranks) => {
3371                assert_eq!(*ranks, [1, 1, 1]);
3372                assert!(matches!(**inner, Verb::Atop(..)), "got {inner:?}");
3373            }
3374            other => panic!("expected a ranked atop, got {other:?}"),
3375        }
3376        let (v, _) = monad_of(&one("+ & (*:\"0) y"));
3377        match &v {
3378            Verb::Rank(inner, ranks) => {
3379                assert_eq!(*ranks, [0, 0, 0]);
3380                assert!(matches!(**inner, Verb::Compose(..)), "got {inner:?}");
3381            }
3382            other => panic!("expected a ranked composition, got {other:?}"),
3383        }
3384        let (v, _) = monad_of(&one("+ &: *: y"));
3385        assert!(matches!(v, Verb::Compose(..)), "got {v:?}");
3386    }
3387
3388    #[test]
3389    fn a_noun_operand_bonds_the_conjunction() {
3390        // `m&v y` is `m v y` whole. The bond's own rank is infinite — J's
3391        // `1 2&+ b. 0` reports `_ _ _` — and the verb inside it applies its
3392        // own ranks to the pair.
3393        let (v, _) = monad_of(&one("1 & + y"));
3394        match &v {
3395            Verb::BondLeft(a, g) => {
3396                assert_eq!(a.as_i64_slice(), Some(&[1i64][..]));
3397                assert_eq!(prim_of(g).name, "+");
3398            }
3399            other => panic!("expected a left bond, got {other:?}"),
3400        }
3401        assert_eq!(v.ranks(), [crate::verb::RANK_INF; 3]);
3402        let (v, _) = monad_of(&one("{. & 2 y"));
3403        assert!(matches!(v, Verb::BondRight(..)), "got {v:?}");
3404        assert_eq!(v.ranks(), [crate::verb::RANK_INF; 3]);
3405    }
3406
3407    #[test]
3408    fn window_scan_and_commute_adverbs() {
3409        let (v, _) = monad_of(&one("+/\\ 1 2 3"));
3410        match &v {
3411            Verb::Windowed(u, WindowKind::Prefix) => assert!(matches!(**u, Verb::Reduce(_))),
3412            other => panic!("expected a prefix application, got {other:?}"),
3413        }
3414        // The window size is the left argument, so the derived verb has both
3415        // valences and its left cell is an atom.
3416        assert_eq!(v.ranks(), [RANK_INF, 0, RANK_INF]);
3417        let (v, _, _) = dyad_of(&one("2 +/\\ 1 2 3"));
3418        assert!(matches!(v, Verb::Windowed(_, WindowKind::Prefix)));
3419        let (v, _) = monad_of(&one("+/\\. 1 2 3"));
3420        assert!(matches!(v, Verb::Windowed(_, WindowKind::Suffix)));
3421        let (v, _) = monad_of(&one("+~ 1 2 3"));
3422        match &v {
3423            Verb::Commute(u) => assert_eq!(prim_of(u).name, "+"),
3424            other => panic!("expected a commute, got {other:?}"),
3425        }
3426        let (v, _) = monad_of(&one("+:^:3 (1)"));
3427        assert!(matches!(v, Verb::PowerN(_, Power::Times(3))));
3428        let (v, _) = monad_of(&one("%:^:_ (100)"));
3429        assert!(matches!(v, Verb::PowerN(_, Power::Converge)));
3430    }
3431
3432    #[test]
3433    fn the_key_adverb_derives_a_verb() {
3434        match one("+/. 1 2 3") {
3435            Expr::Monad { verb: Verb::Key(_), .. } => {}
3436            other => panic!("expected a key, got {other:?}"),
3437        }
3438    }
3439
3440    #[test]
3441    fn noun_operand_adverbs_are_not_supported_yet() {
3442        let e = err("1/ 2");
3443        assert_eq!(e.kind, ErrorKind::NotYet);
3444        assert!(e.msg.contains("noun-operand adverbs"), "{}", e.msg);
3445    }
3446
3447    #[test]
3448    fn noun_operand_conjunctions_are_not_supported_yet() {
3449        let e = err("1 @: + y");
3450        assert_eq!(e.kind, ErrorKind::NotYet);
3451        assert!(e.msg.contains("noun-operand conjunctions"), "{}", e.msg);
3452    }
3453
3454    // --------------------------------------------------------------- trains
3455
3456    #[test]
3457    fn three_verbs_in_parentheses_are_a_fork() {
3458        let (v, y) = monad_of(&one("(+/ % #) 1 2 3"));
3459        match &v {
3460            Verb::Fork(f, g, h) => {
3461                assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
3462                assert_eq!(prim_of(g).name, "%");
3463                assert_eq!(prim_of(h).name, "#");
3464            }
3465            other => panic!("expected a fork, got {other:?}"),
3466        }
3467        assert_eq!(konst(&y).shape, vec![3]);
3468    }
3469
3470    #[test]
3471    fn a_noun_left_tine_is_a_noun_fork() {
3472        let (v, _) = monad_of(&one("(2 + #) 1 2 3"));
3473        match &v {
3474            Verb::NounFork(a, g, h) => {
3475                assert_eq!(a.as_i64_slice(), Some(&[2i64][..]));
3476                assert_eq!(prim_of(g).name, "+");
3477                assert_eq!(prim_of(h).name, "#");
3478            }
3479            other => panic!("expected a noun fork, got {other:?}"),
3480        }
3481    }
3482
3483    #[test]
3484    fn two_verbs_in_parentheses_are_a_hook() {
3485        let (v, _) = monad_of(&one("(+ #) 1 2 3"));
3486        match &v {
3487            Verb::Hook(f, g) => {
3488                assert_eq!(prim_of(f).name, "+");
3489                assert_eq!(prim_of(g).name, "#");
3490            }
3491            other => panic!("expected a hook, got {other:?}"),
3492        }
3493    }
3494
3495    #[test]
3496    fn cap_makes_a_fork_an_atop() {
3497        let (v, _) = monad_of(&one("([: +/ ,) 1 2 3"));
3498        match &v {
3499            Verb::Atop(f, g) => {
3500                assert!(matches!(**f, Verb::Reduce(_)), "got {f:?}");
3501                assert_eq!(prim_of(g).name, ",");
3502            }
3503            other => panic!("expected an atop, got {other:?}"),
3504        }
3505    }
3506
3507    #[test]
3508    fn a_five_verb_train_folds_from_the_right() {
3509        // (a b c d e) is a fork whose right tine is the fork (c d e).
3510        let (v, _) = monad_of(&one("(] , [ , ]) 1 2 3"));
3511        match &v {
3512            Verb::Fork(f, g, h) => {
3513                assert_eq!(prim_of(f).name, "]");
3514                assert_eq!(prim_of(g).name, ",");
3515                assert!(matches!(**h, Verb::Fork(..)), "got {h:?}");
3516            }
3517            other => panic!("expected a fork, got {other:?}"),
3518        }
3519    }
3520
3521    #[test]
3522    fn a_noun_fork_needs_a_literal_noun() {
3523        let e = err("({n} + #) 1 2 3");
3524        assert_eq!(e.kind, ErrorKind::NotYet);
3525        assert!(e.msg.contains("noun forks"), "{}", e.msg);
3526    }
3527
3528    #[test]
3529    fn cap_is_never_applied_as_a_verb() {
3530        // `[:` has no meaning of its own; it only caps a fork. Here it is
3531        // left over beside the result of `# 1 2 3`.
3532        let e = err("[: # 1 2 3");
3533        assert_eq!(e.kind, ErrorKind::Parse);
3534        assert!(e.msg.contains("caps a fork"), "{}", e.msg);
3535    }
3536
3537    #[test]
3538    fn two_nouns_side_by_side_are_a_syntax_error() {
3539        // The reference reads no train here, and neither does libjay.
3540        let e = err("'ab' 'cd'");
3541        assert_eq!(e.kind, ErrorKind::Parse);
3542        assert_eq!(e.msg, "syntax error");
3543    }
3544
3545    #[test]
3546    fn a_sentence_that_is_a_verb_is_not_supported_yet() {
3547        let e = err("+/ % #");
3548        assert_eq!(e.kind, ErrorKind::NotYet);
3549        assert!(e.msg.contains("tacit"), "{}", e.msg);
3550    }
3551
3552    // ----------------------------------------------------------- assignment
3553
3554    #[rstest]
3555    #[case("x =. 5", Scope::Local)]
3556    #[case("x =: 5", Scope::Global)]
3557    fn assignment_yields_an_assign_node(#[case] src: &str, #[case] want: Scope) {
3558        match one(src) {
3559            Expr::Assign { name, value, scope, span } => {
3560                assert_eq!(name, "x");
3561                assert_eq!(ints(&value), vec![5]);
3562                assert_eq!(scope, want);
3563                assert_eq!(span, Span::new(0, 6));
3564            }
3565            other => panic!("expected an assignment, got {other:?}"),
3566        }
3567    }
3568
3569    #[test]
3570    fn assignment_in_expression_position() {
3571        let (v, x, y) = dyad_of(&one("y + x =. 3"));
3572        assert_eq!(prim_of(&v).name, "+");
3573        assert!(matches!(x, Expr::Name(..)));
3574        match y {
3575            Expr::Assign { name, span, .. } => {
3576                assert_eq!(name, "x");
3577                assert_eq!(span, Span::new(4, 10));
3578            }
3579            other => panic!("expected an assignment, got {other:?}"),
3580        }
3581    }
3582
3583    #[test]
3584    fn assignment_takes_the_whole_right_hand_sentence() {
3585        match one("x =. 1 + 2") {
3586            Expr::Assign { value, .. } => {
3587                let (v, _, _) = dyad_of(&value);
3588                assert_eq!(prim_of(&v).name, "+");
3589            }
3590            other => panic!("expected an assignment, got {other:?}"),
3591        }
3592    }
3593
3594    // ---------------------------------------------------- naming a verb
3595
3596    #[test]
3597    fn assigning_a_verb_names_it_and_runs_nothing() {
3598        let s = stmts("mean =. +/ % #");
3599        assert_eq!(s.len(), 1);
3600        match &s[0] {
3601            Expr::VerbDef { name, verb, span } => {
3602                assert_eq!(name, "mean");
3603                assert!(matches!(verb, Verb::Fork(..)), "got {verb:?}");
3604                assert_eq!(*span, Span::new(0, 14));
3605            }
3606            other => panic!("expected a verb definition, got {other:?}"),
3607        }
3608    }
3609
3610    #[test]
3611    fn a_named_verb_applies_in_a_later_sentence() {
3612        let s = stmts("mean =. +/ % #\nmean 1 2 3 4");
3613        assert_eq!(s.len(), 2);
3614        let (v, y) = monad_of(&s[1]);
3615        assert!(matches!(v, Verb::Fork(..)), "got {v:?}");
3616        assert_eq!(konst(&y).shape, vec![4]);
3617    }
3618
3619    #[test]
3620    fn a_named_verb_is_a_verb_inside_a_train_and_under_a_conjunction() {
3621        let (v, _) = monad_of(&stmts("mean =. +/ % #\n(mean - {.) 1 2 3 4").pop().expect("two"));
3622        match &v {
3623            Verb::Fork(f, g, h) => {
3624                assert!(matches!(**f, Verb::Fork(..)), "got {f:?}");
3625                assert_eq!(prim_of(g).name, "-");
3626                assert_eq!(prim_of(h).name, "{.");
3627            }
3628            other => panic!("expected a fork, got {other:?}"),
3629        }
3630        let (v, _) = monad_of(&stmts("mean =. +/ % #\nmean\"1 m").pop().expect("two"));
3631        match &v {
3632            Verb::Rank(inner, r) => {
3633                assert_eq!(*r, [1, 1, 1]);
3634                assert!(matches!(**inner, Verb::Fork(..)), "got {inner:?}");
3635            }
3636            other => panic!("expected a ranked verb, got {other:?}"),
3637        }
3638    }
3639
3640    #[test]
3641    fn redefinition_rebinds_from_that_sentence_on() {
3642        let s = stmts("f =. +/\nf 1 2 3\nf =. #\nf 1 2 3");
3643        assert_eq!(s.len(), 4);
3644        assert!(matches!(monad_of(&s[1]).0, Verb::Reduce(_)));
3645        assert_eq!(prim_of(&monad_of(&s[3]).0).name, "#");
3646    }
3647
3648    #[test]
3649    fn a_name_may_change_part_of_speech_in_either_direction() {
3650        // The oracle accepts both; the last assignment decides.
3651        let s = stmts("a =. 1 2 3\na =. +/\na 1 2 3");
3652        assert!(matches!(s[0], Expr::Assign { .. }));
3653        assert!(matches!(s[1], Expr::VerbDef { .. }));
3654        assert!(matches!(monad_of(&s[2]).0, Verb::Reduce(_)));
3655        let s = stmts("f =. +/\nf =. 10 20\nf");
3656        assert!(matches!(s[0], Expr::VerbDef { .. }));
3657        assert!(matches!(s[1], Expr::Assign { .. }));
3658        assert!(matches!(s[2], Expr::Name(..)));
3659    }
3660
3661    #[test]
3662    fn an_undefined_name_applied_as_a_verb_is_a_value_error() {
3663        // The reference says `value error: zz`, pointing at the name.
3664        let e = err("zz 1 2 3");
3665        assert_eq!(e.kind, ErrorKind::Value);
3666        assert_eq!(e.msg, "undefined name: zz");
3667        assert_eq!(e.span, Some(Span::new(0, 2)));
3668        // A name that does hold a value is a different complaint: two
3669        // nouns side by side, which the reference calls a syntax error.
3670        let e = err("a =. 5\na 1 2 3");
3671        assert_eq!(e.kind, ErrorKind::Parse);
3672        assert_eq!(e.msg, "syntax error");
3673    }
3674
3675    #[test]
3676    fn assignment_names_an_adverb_or_a_conjunction() {
3677        match one("insert =. /") {
3678            Expr::ModDef { name, spelling, conjunction, .. } => {
3679                assert_eq!(name, "insert");
3680                assert_eq!(spelling, "/");
3681                assert!(!conjunction);
3682            }
3683            other => panic!("expected a modifier definition, got {other:?}"),
3684        }
3685        match one("atop =. @") {
3686            Expr::ModDef { spelling, conjunction, .. } => {
3687                assert_eq!(spelling, "@");
3688                assert!(conjunction);
3689            }
3690            other => panic!("expected a modifier definition, got {other:?}"),
3691        }
3692        // The name is a modifier from there on, so the sentence that uses
3693        // it parses around it as the glyph would.
3694        let s = stmts("insert =. /\n+ insert 1 2 3");
3695        assert!(matches!(s[1], Expr::Monad { verb: Verb::Reduce(_), .. }), "{:?}", s[1]);
3696    }
3697
3698    #[test]
3699    fn a_sentence_that_is_a_modifier_is_a_named_gap() {
3700        let e = err("insert =. /\ninsert");
3701        assert_eq!(e.kind, ErrorKind::NotYet);
3702        assert!(e.msg.contains("displaying a modifier"), "{}", e.msg);
3703    }
3704
3705    #[rstest]
3706    #[case("f =. 3 : 'y + 1'", None)]
3707    #[case("f =. 4 : 'x + y'", Some("x"))]
3708    #[case("f =. {{ y + 1 }}", None)]
3709    #[case("f =. {{ x + y }}", Some("x"))]
3710    fn an_explicit_definition_names_a_verb(#[case] src: &str, #[case] left: Option<&str>) {
3711        match one(src) {
3712            Expr::VerbDef { name, verb: Verb::Explicit(d), .. } => {
3713                assert_eq!(name, "f");
3714                assert_eq!(d.left.as_deref(), left);
3715                assert_eq!(d.right, "y");
3716                assert_eq!(d.body.len(), 1);
3717            }
3718            other => panic!("expected an explicit verb definition, got {other:?}"),
3719        }
3720    }
3721
3722    #[rstest]
3723    #[case("f =. 13 : 'y + 1'", "tacit definitions")]
3724    fn definition_forms_libjay_has_not_are_named(#[case] src: &str, #[case] msg: &str) {
3725        let e = err(src);
3726        assert_eq!(e.kind, ErrorKind::NotYet);
3727        assert!(e.msg.contains(msg), "{}", e.msg);
3728    }
3729
3730    /// `1 :` and `2 :` say the part of speech; a `{{ }}` leaves it to the
3731    /// operand names its body uses.
3732    #[rstest]
3733    #[case("f =. 1 : 'y + 1'", Some(false))]
3734    #[case("f =. 2 : 'u v y'", Some(true))]
3735    #[case("f =. {{ y + 1 }}", None)]
3736    #[case("f =. {{ u y }}", Some(false))]
3737    #[case("f =. {{ m + y }}", Some(false))]
3738    #[case("f =. {{ u v y }}", Some(true))]
3739    #[case("f =. {{ v y }}", Some(true))]
3740    #[case("f =. {{ n + y }}", Some(true))]
3741    #[case("f =. {{ u n y }}", Some(true))]
3742    #[case("f =. {{)a\nu y\n}}", Some(false))]
3743    #[case("f =. {{)c\nu v y\n}}", Some(true))]
3744    #[case("f =. {{)v\ny\n}}", None)]
3745    fn an_explicit_definitions_part_of_speech(#[case] src: &str, #[case] want: Option<bool>) {
3746        match (one(src), want) {
3747            (Expr::ModDef { name, conjunction, .. }, Some(conj)) => {
3748                assert_eq!(name, "f");
3749                assert_eq!(conjunction, conj, "{src:?}");
3750            }
3751            (Expr::VerbDef { name, .. }, None) => assert_eq!(name, "f"),
3752            (other, _) => panic!("expected {want:?} for {src:?}, got {other:?}"),
3753        }
3754    }
3755
3756    #[test]
3757    fn a_control_word_outside_a_definition_is_a_parse_error() {
3758        let e = err("if. 1 do. 2 end.");
3759        assert_eq!(e.kind, ErrorKind::Parse);
3760        assert!(e.msg.contains("only meaningful inside an explicit definition"), "{}", e.msg);
3761    }
3762
3763    #[test]
3764    fn multiple_assignment_is_not_supported_yet() {
3765        let e = err("'a b' =. 1 2");
3766        assert_eq!(e.kind, ErrorKind::NotYet);
3767        assert!(e.msg.contains("multiple assignment"), "{}", e.msg);
3768    }
3769
3770    // -------------------------------------------------------- interpolation
3771
3772    #[test]
3773    fn a_hole_is_a_noun() {
3774        let e = one("{a} + 1");
3775        let (_, x, y) = dyad_of(&e);
3776        match x {
3777            Expr::Param(i, s) => {
3778                assert_eq!(i, 0);
3779                assert_eq!(s, Span::new(0, 3));
3780            }
3781            other => panic!("expected a parameter, got {other:?}"),
3782        }
3783        assert_eq!(ints(&y), vec![1]);
3784        assert_eq!(e.span(), Span::new(0, 7));
3785    }
3786
3787    #[test]
3788    fn holes_are_numbered_and_shared_by_name() {
3789        let sp = SourceParts::from_source("{a} + {b} + {a}").expect("source parts");
3790        assert_eq!(sp.param_names, vec!["a".to_string(), "b".to_string()]);
3791        let e = parse(&sp).expect("parse").pop().expect("one sentence");
3792        let (_, x, y) = dyad_of(&e);
3793        assert!(matches!(x, Expr::Param(0, _)));
3794        let (_, x2, y2) = dyad_of(&y);
3795        assert!(matches!(x2, Expr::Param(1, _)));
3796        assert!(matches!(y2, Expr::Param(0, _)));
3797    }
3798
3799    #[rstest]
3800    #[case("3j4", 3.0, 4.0)]
3801    #[case("_1j_2", -1.0, -2.0)]
3802    #[case("1e1j2", 10.0, 2.0)]
3803    #[case("2ad90", 0.0, 2.0)]
3804    #[case("1ad180", -1.0, 0.0)]
3805    fn complex_literals(#[case] src: &str, #[case] re: f64, #[case] im: f64) {
3806        let a = konst(&one(src));
3807        assert_eq!(a.dtype(), DType::Complex);
3808        let z = a.as_complex_slice().expect("complex data")[0];
3809        assert!((z[0] - re).abs() < 1e-12 && (z[1] - im).abs() < 1e-12, "{z:?}");
3810    }
3811
3812    #[test]
3813    fn a_hole_takes_a_verb_like_any_noun() {
3814        let (v, y) = monad_of(&one("+/ {data}"));
3815        assert!(matches!(v, Verb::Reduce(_)));
3816        assert!(matches!(y, Expr::Param(0, _)));
3817    }
3818
3819    #[test]
3820    fn braces_inside_a_string_are_not_holes() {
3821        let sp = SourceParts::from_source("'{a}'").expect("source parts");
3822        assert!(sp.param_names.is_empty());
3823        let a = konst(&parse(&sp).expect("parse")[0]);
3824        assert_eq!(a.data, Data::Char(vec!['{', 'a', '}'].into()));
3825    }
3826
3827    #[test]
3828    fn parts_of_one_sentence_lex_across_a_hole() {
3829        // The t-string path: literal parts with a hole between them.
3830        let sp = SourceParts::from_parts(&["1 + ", " * 2"], &["v"]);
3831        assert_eq!(sp.display, "1 + {v} * 2");
3832        let e = parse(&sp).expect("parse").pop().expect("one sentence");
3833        let (_, x, y) = dyad_of(&e);
3834        assert_eq!(ints(&x), vec![1]);
3835        let (_, x2, y2) = dyad_of(&y);
3836        assert!(matches!(x2, Expr::Param(0, _)));
3837        assert_eq!(ints(&y2), vec![2]);
3838    }
3839
3840    #[test]
3841    fn spans_of_later_sentences_index_the_whole_source() {
3842        let src = "5\n1 + 2";
3843        let s = stmts(src);
3844        assert_eq!(s[1].span(), Span::new(2, 7));
3845        assert_eq!(&src[2..7], "1 + 2");
3846    }
3847
3848    // --------------------------------------------------------------- errors
3849
3850    #[test]
3851    fn unknown_word_reports_its_span() {
3852        let e = err("1 [. 2");
3853        assert_eq!(e.kind, ErrorKind::Parse);
3854        assert_eq!(e.msg, "unknown word: [.");
3855        assert_eq!(e.span, Some(Span::new(2, 4)));
3856    }
3857
3858    #[test]
3859    fn an_inflected_unknown_word_is_reported_whole() {
3860        let e = err("1 ]: 2");
3861        assert_eq!(e.msg, "unknown word: ]:");
3862        assert_eq!(e.span, Some(Span::new(2, 4)));
3863    }
3864
3865    /// The exact suffixes read; the forms that spell no number do not.
3866    #[rstest]
3867    #[case("1.5x", 0, 4)]
3868    #[case("1e10x", 0, 5)]
3869    fn a_fractional_extended_literal_is_ill_formed(
3870        #[case] src: &str,
3871        #[case] start: usize,
3872        #[case] end: usize,
3873    ) {
3874        let e = err(src);
3875        assert_eq!(e.kind, ErrorKind::Parse);
3876        assert!(e.msg.contains("invalid number"), "{}", e.msg);
3877        assert_eq!(e.span, Some(Span::new(start, end)));
3878    }
3879
3880    #[test]
3881    fn a_malformed_number_is_a_parse_error() {
3882        let e = err("1.2.3");
3883        assert_eq!(e.kind, ErrorKind::Parse);
3884        assert!(e.msg.contains("invalid number"), "{}", e.msg);
3885    }
3886
3887    #[test]
3888    fn an_unbalanced_sentence_is_a_syntax_error() {
3889        // The parenthesis itself is what is wrong, so that is what the
3890        // span covers.
3891        let e = err("(1 + 2");
3892        assert_eq!(e.kind, ErrorKind::Parse);
3893        assert!(e.msg.contains("no closing"), "{}", e.msg);
3894        assert_eq!(e.span, Some(Span::new(0, 1)));
3895    }
3896
3897    #[test]
3898    fn a_stray_right_parenthesis_is_a_syntax_error() {
3899        let e = err("1 + 2)");
3900        assert_eq!(e.kind, ErrorKind::Parse);
3901        assert!(e.msg.contains("no opening"), "{}", e.msg);
3902        assert_eq!(e.span, Some(Span::new(5, 6)));
3903    }
3904
3905    #[test]
3906    fn the_error_of_a_later_sentence_points_at_that_sentence() {
3907        let e = err("1 + 2\n3 [. 4");
3908        assert_eq!(e.span, Some(Span::new(8, 10)));
3909    }
3910}