lojban-rs implementation plan
The plan is split into focused documents under plan/. Code is the source of truth for implemented features; the plan tracks gaps and documents architecture.
| Document | Purpose |
|---|---|
| plan/RULES.md | Agent workflow, #[jbo_ref] conventions, slug naming, status legend |
| plan/SCRIPTS.md | Maintenance scripts and CI regeneration |
| plan/ARCHITECTURE.md | Parser pipeline, Earley CFG, semantic rules, olog, Prolog |
| plan/OPEN.md | Manual open tickets (MISSING, PARTIAL, AD HOC, …) and grammar deviations vs CLL/tersmu |
| plan/READY.md | Auto-generated implemented features — do not edit by hand |
The document references @cll-md/ reference grammar book.
Quick start for agents
- Read plan/RULES.md before implementing any feature.
- Consult the CLL section(s) cited in the open ticket row.
- Add or update
#[jbo_ref(...)]in code; keep plan/OPEN.md rows for non-ready work. - Run
bash scripts/regenerate_plan.sh(or at minimumsync_plan_ready.py+ref_audit.py --strict).
Regenerate
bash scripts/regenerate_plan.sh
Plan rules & agent workflow
This document must be kept up to date. Update the plan after implementing or fixing any features/tasks from it.
The plan is split under plan/ — see PLAN.md for the index. The document references @cll-md/ reference grammar book.
Rule: Read Before Implement
Before implementing any feature, you MUST read the corresponding CLL section(s) listed in the reference column. CLL sections contain the authoritative grammar definitions, examples, and edge cases needed for correct implementation. Do not implement from the feature description alone — always consult the source material first.
When implementing or fixing a feature: (1) add or update #[jbo_ref(...)] (Rust) or an @ref: comment block (.egg, Cargo.toml) with full metadata in code, (2) if still AD HOC / PARTIAL / MISSING, keep or update the row in OPEN.md, (3) run python3 scripts/sync_plan_ready.py and python3 scripts/ref_audit.py.
Reference Conventions
Code is the source of truth for implemented features. Each @ref: block in source holds: Feature, Status, CLL, PlanSection, and optional Deviation, Notes.
| PLAN section | Contents |
|---|---|
| OPEN.md (manual) | ❌ MISSING, ⚠️ PARTIAL / ⚠️ AD HOC, ⏳ NEEDS EVAL, and rows still using @ref:plan.* without a real code anchor |
| READY.md (auto-generated) | Extracted from code with Status: IMPLEMENTED or N/A — do not edit by hand |
Code-first workflow
When you implement or fix a feature:
- Read the CLL section(s) cited in the open ticket row (if any).
- Add or update
#[jbo_ref(...)]on the Rust item (or aconstmarker for module-level gaps). Use comment blocks only in.egg/Cargo.toml. - If the feature is still
AD HOC,PARTIAL, orMISSING, keep or update the matching OPEN.md row. - Run
python3 scripts/sync_plan_ready.pyto regenerate READY.md from code. - Run
python3 scripts/ref_audit.py --strictandJBO_REF_STRICT=1 cargo build.
Migrating remaining gaps: use python3 scripts/migrate_plan_refs.py for templates. Completed features live in #[jbo_ref] (Rust), comment blocks (.egg/Cargo.toml), or src/plan_implemented.rs for bulk registry entries — then run sync_plan_ready.py.
See SCRIPTS.md for the full maintenance script reference.
Slug naming
Slugs follow layer.name and are stable across refactors:
| Layer prefix | Where | Example |
|---|---|---|
grammar. |
earley_word_grammar.egg rule alts |
grammar.sumti_6_zo, grammar.frees |
morph. |
morphology (earley_morph_extract.rs, …) |
morph.segment_compound_cmavo |
ast. |
AST conversion (earley_to_syntax.rs) |
ast.convert_sumti_6 |
semantic. |
semantics (jbo_parse.rs, jbo_prop.rs) |
semantic.parse_goi_rel |
lujvo. |
lujvo decomposition (lujvo_decompose.rs) |
lujvo.needs_hyphen |
egglog. |
rewrite rules (egglog_rules.egg) |
egglog.propositional-logic |
olog. |
olog integration (src/olog/, …) |
olog.extract_olog |
prolog. |
Prolog export (jbo_prolog.rs, …) |
prolog.prop_to_prolog |
feature. |
Cargo feature flags (Cargo.toml) |
feature.approx-scalar-neg |
plan. |
Temporary until code anchor exists | plan.s1_1_audio_visual_isomorphism |
Grammar rule alts use semantic names {cll_nonterminal}_{variant}. Tree extraction uses greedy disambiguation: longest-match for left-grouped ... repetition (CLL §21 rule 7), longest-alt-name preference for equal-span ties (left-recursive expansions over base cases, quantifier parses over bare selbri), and ParseTree::Ambig parse-forest nodes for remaining structural ambiguity.
Anchor formats
Rust (required — use #[jbo_ref], not hand-written /// @ref: comments):
#[jbo_ref(
slug = "semantic.parse_sumti_atom",
feature = "All sumti atom types",
status = "IMPLEMENTED",
cll = "§6.2, §6.6",
plan_section = "2.4",
)]
fn parse_sumti_atom(...) { ... }
Egg / TOML comment block:
; @ref:grammar.sumti_6_zo
; Feature: ZO single-word quotation
; Status: IMPLEMENTED
; CLL: §19.10
; Notes: sumti_6_zo = ZO_clause any_word frees; word-1100 skips indicator merge after ZO
; PlanSection: 2.4
Validate with python3 scripts/sync_plan_ready.py, python3 scripts/ref_audit.py --strict, and JBO_REF_STRICT=1 cargo build after any change.
Status Legend
- ✅ IMPLEMENTED — fully working in lojban-rs
- ⚠️ PARTIAL — partially implemented or behind feature flag
- ⚠️ AD HOC — works, but implemented via hardcoded cmavo/special-case rather than generic rule
- ❌ MISSING — not implemented yet
- ✅ N/A — Not needed for lojban-rs (reference/design feature)
- ⏳ NEEDS EVAL — feature needs a math evaluator for full semantics
- 📝 DOC-ONLY — documentation/reference section with no parser gap
Plan maintenance scripts
Companion to RULES.md. Run bash scripts/regenerate_plan.sh to refresh the auto-generated sections and audit reports.
Detecting gaps and discrepancies
| Script | What it checks |
|---|---|
python3 scripts/sync_plan_ready.py |
Regenerates plan/READY.md from code. Use --check in CI. |
python3 scripts/ref_audit.py |
Open vs ready consistency, schema errors, stale file:line. Use --strict in CI. |
python3 scripts/parse_ref_blocks.py |
Lists all code ref blocks; --strict for schema. Used by build.rs. |
python3 scripts/migrate_plan_refs.py |
Lists open @ref:plan.* rows in OPEN.md and suggests migration templates. |
python3 scripts/grammar_audit.py |
CLL Ch 21 formal non-terminals vs grammar coverage. |
python3 scripts/cll_coverage.py |
CLL sections in plan corpus vs cll-md/ files. |
python3 scripts/grammar_ambiguity_probe.py |
Reports ParseTree::Ambig nodes on a test corpus; writes scripts/grammar_ambiguity_report.json. |
Regenerate everything
bash scripts/regenerate_plan.sh
This runs, in order:
python3 scripts/sync_plan_ready.py— regenerate READY.md from code#[jbo_ref]/@ref:blockspython3 scripts/ref_audit.py— consistency report atscripts/ref_audit_report.mdpython3 scripts/cll_coverage.py— CLL section coverage atscripts/cll_coverage_report.mdpython3 scripts/grammar_audit.py— CLL Ch 21 non-terminal coverage atscripts/grammar_audit_report.md
CI on main runs the same pipeline and commits updated plan/READY.md plus audit reports when they drift.
After any feature change
python3 scripts/sync_plan_ready.py
python3 scripts/ref_audit.py --strict
JBO_REF_STRICT=1 cargo build
Architecture & tooling
Human-readable description of the parser pipeline, semantic layers, and subsystems. Open gaps are tracked in OPEN.md; completed features are auto-listed in READY.md.
Pure CFG Earley
The word-level Earley recognizer is a pure CFG: earley_word_schema.egg saturates all chart items with no ordered-choice pruning.
Behaviour
| Area | Behaviour |
|---|---|
| Recognition | Egglog Earley saturation keeps every competing Item and ParseTreeEdge in the chart; recognition itself does not prune alternatives by rule order. |
| Tree extraction | earley_extract.rs rebuilds one tree (or a local forest) from saturated edges using greedy tie-breaking: longest child span, then longest alt name string (child_alt.len()); under {cll_nonterminal}_{variant} naming this selects the longer left-recursive expansion name (e.g. selbri_3_selbri_3_selbri_4) over the shorter base case (e.g. selbri_3_selbri_4); unresolved equal-span ties become ParseTree::Ambig (see policy below). |
lerfu_word |
Four CLL alternatives in earley_word_grammar.egg: lerfu_word_by (BY_clause), lerfu_word_lau_chain (LAU_clause + nested lerfu_word), lerfu_word_tei_lerfu_foi (TEI_clause + lerfu_string + FOI_clause), lerfu_word_any_bu (ANY_WORD_clause + BU_clause). |
sumti |
Quantified sumti follow the CLL sumti_5 hierarchy (sumti_5_quant_sumti_6, sumti_5_quant_selbri, and rel/KU variants); outer quantifiers are not handled by shortcut non-terminals that skip sumti_5. |
paragraph |
Two paragraph alts: paragraph_indics_paragraph (indicators + paragraph) and paragraph_indics_fragment (fragment only). |
| Indefinite descriptions | When sumti_5_quant_sumti_6 and sumti_5_quant_selbri both match after a quantifier, (NegLookaheadPos "sumti_5_quant_sumti_6" 1 "selbri") blocks the sumti_6 branch if selbri can start at that dot; Phase B neg-inhibit in earley_word_extract.rs materializes the guard before tree extraction. |
Tree extraction policy (src/earley_extract.rs)
- Longest match — maximize
child_endat each dot (CLL §21 rule 7, left-grouped...; not PEG). - Greediness — among equal-span alternatives, prefer the longest
altname string (child_alt.len()).altnames follow the convention{cll_nonterminal}_{variant}(seeplan/RULES.md), so the left-recursive expansion variant is longer than its base case (e.g.selbri_3_selbri_3_selbri_4vsselbri_3_selbri_4). This is a name-length heuristic, not a separate left-recursion algorithm; it also prefers quantifier parses over bare selbri parses (CLL §6.8). - Remaining equal-span ties — emit
ParseTree::Ambig { alternatives }(parse forest).
AST resolution (src/earley_to_syntax.rs): resolve_ambig_first_ok tries each alternative at root and hot spots (sumti, paragraph, lerfu_word) until conversion succeeds.
Verification
cargo test --test earley_integration— 85/85 pass (including indefinite-description, FA scrambling, semantics pipeline).cargo test --test earley_ambiguity_probe— corpus accepted; report atscripts/grammar_ambiguity_report.json.python3 scripts/grammar_audit.py— 374 egg rules vs 90 CLL non-terminals.- No
peg_alt_priority/grammar_alt_priorityreferences remain in the codebase.
Comprehensive Feature Gap Analysis: CLL vs lojban-rs
Our parser must follow the grammar of @cll-md/chapter-grammars.md so no rule or part of it can be omitted. If there is or planned a deviation from that it must be done through a feature flag and reported by editing this document. Thus no simplficatons to the formal grammar are allowed. Fix related issues if any.
The codebase must be clean, stramlined, avoid duplication, avoid hardcoding where needed. the codebase must try to be generic where needed.
Ad hoc / architecture principles (avoid when implementing fixes):
- No string comparisons on cmavo names — use selma'o checks, generated tables, or AST tags instead.
- No hand-enumerating optional-position variants — prefer optional (
[]) and repetition (...) in grammar; expand at generation time. - No layer crossing — morphology should not hide grammar structure (e.g.,
ZO/ZOImust consume quoted content) unless CLL explicitly says so. - No manual semantic tables in parser code — move tables like
indicator_bridi_tailor ZAhO pairings intotyped_dictionary.rsor external data files.
Gaps, deviations, and missing features are tracked once each in the section tables below (grouped by CLL topic). Do not maintain a separate duplicate index.
14. SEMANTIC RULES (egglog_rules.egg)
14.0 Rewrite rule taxonomy (3a–3d)
Tersmu/camxes-rs groups rewrite rules into four categories. lojban-rs implements the same rules under the §1–§23 section names below.
| Category | Maps to egglog_rules sections | Key rules |
|---|---|---|
| 3a Logical simplification | §1 Propositional Logic | Double negation, De Morgan, Eet identity, idempotency, commutativity, associativity, implication/equivalence elimination |
| 3b Lojban-specific | §3 SE-Conversion, §4 Scalar Negation, §5 Tanru, §6 Modal/Tense | se se cancel, nai/to'e, tanru collapse, modal idempotency |
| 3c Quantifier normalisation | §7 Quantifiers, §7c scope conditional, §15 (Rust pre-lowering) | Vacuous restriction strip, ¬∃↔∀¬, FreeIn conditional rules |
| 3d Anaphora hints | §12 Anaphora (pre-lowering in Rust) | ri/ra resolved in jbo_parse before e-graph lowering |
14.1 Implemented Rules (Internal egglog rules — no direct CLL mapping)
14.2 Testing Strategy (CLL Ch 2 — examples throughout)
- Add test cases for each new feature in the relevant test file
- Add CLL-referenced test sentences for each missing feature
- Ensure all 20 example tests pass before and after changes
- Add dedicated test files for complex features (mekso, abstractions, intervals)
- Add mekso-specific test suite with CLL examples 18.2–18.148
15. QUANTIFIER SCOPE & naku BOUNDARIES — IMPLEMENTATION
15.1 Problem Statement
egglog rewrite rules are unconditional pattern matches. They can match structural patterns like (PAnd p q) but cannot express predicate conditions like "x is not free in q". This blocks:
- Partial distribution: ∃x.(P∧Q) → (∃x.P)∧Q when x∉FV(Q)
- Vacuous quantification: ∀x.P → P when x∉FV(P)
- Quantifier over implication: ∀x.(P→Q) → (∃x.P→Q) when x∉FV(Q)
- naku partial distribution: naku (∃x.P ∧ Q) ↔ (∀x.(naku P) ∨ naku Q) when x∉FV(Q)
The negation push-through rule (¬∃x.P ↔ ∀x.¬P) already handles the core naku boundary case, but partial distribution under quantifiers was the gap.
15.2 Solution: Two-Phase Architecture
The solution uses two complementary phases that together cover all cases:
Phase 1 (Rust pre-lowering) Phase 2 (egglog saturation)
───────────────────────── ──────────────────────────
simplify_prop() on JboProp FreeIn facts + conditional rules
│ │
├─ Partial distribution ├─ Partial distribution
├─ Vacuous quantifier removal ├─ Vacuous quantification
│ ├─ Quantifier over implication
│ │
▼ ▼
Lowered to egglog ◄──────────── FreeIn(BoundVar(v), subprop) = 0/1
Phase 1 handles the initial parse form before saturation. It's fast, deterministic, and handles the common case.
Phase 2 handles forms discovered during equality saturation. When egglog rewrites produce new quantified forms, the conditional rules can simplify them.
15.3 Phase 1: Rust Pre-Lowering Simplification
File: jbo_prop.rs — pub fn simplify_prop(prop: &JboProp) -> JboProp
Core mechanism: A recursive contains_bound_var(v, prop) function traverses JboProp (including HOAS closures) to check if BoundVar(v) appears in a subformula. When it doesn't, the quantifier is vacuous or partial distribution applies.
Rules implemented (6 distribution + 1 vacuous):
| Rule | Pattern | Condition |
|---|---|---|
| ∃-conjunction-left | ∃x.(P∧Q) → (∃x.P)∧Q | x∉FV(Q) |
| ∃-conjunction-right | ∃x.(P∧Q) → P∧(∃x.Q) | x∉FV(P) |
| ∀-disjunction-left | ∀x.(P∨Q) → (∀x.P)∨Q | x∉FV(Q) |
| ∀-disjunction-right | ∀x.(P∨Q) → P∨(∀x.Q) | x∉FV(P) |
| ∀-conjunction-left | ∀x.(P∧Q) → (∀x.P)∧Q | x∉FV(Q) |
| ∀-conjunction-right | ∀x.(P∧Q) → P∧(∀x.Q) | x∉FV(P) |
| ∃-disjunction-left | ∃x.(P∨Q) → (∃x.P)∨Q | x∉FV(Q) |
| ∃-disjunction-right | ∃x.(P∨Q) → P∨(∃x.Q) | x∉FV(P) |
| ∀-implication | ∀x.(P→Q) → (∃x.P→Q) | x∉FV(Q) |
| ∃-implication | ∃x.(P→Q) → (∀x.P→Q) | x∉FV(Q) |
| Vacuous ∀ | ∀x.P → P | x∉FV(P), no restriction |
| Vacuous ∃ | ∃x.P → P | x∉FV(P), no restriction |
Hook point: egglog_lower.rs:lower_texticule() calls simplify_prop() before lowering each TexticuleProp.
Helper functions (all in jbo_prop.rs):
contains_bound_var(v, prop)— main checkercontains_bound_var_in_rel(v, rel)— relation traversalcontains_bound_var_in_term(v, term)— term traversalcontains_bound_var_in_mex(v, mex)— mex expression traversalcontains_bound_var_in_operator(v, op)— operator traversalcontains_bound_var_in_tag(v, tag)— tag traversalcontains_bound_var_in_tag_unit(v, tu)— tag unit traversal
Tests: 6 unit tests in jbo_prop::simplify_tests covering vacuous removal, partial distribution, and negative cases.
15.4 Phase 2: egglog FreeIn Facts + Conditional Rules
Schema (egglog_schema.egg):
(function FreeIn (JboTerm JboProp) i64 :merge (max old new))
FreeIn(BoundVar(v), prop) = 1means v is free in propFreeIn(BoundVar(v), prop) = 0(default) means v is not free (or not checked)- Merge:
max(old, new)— once set to 1, stays 1
Lowering (egglog_lower.rs):
generate_free_in_facts(prop, lines)— entry point, called fromlower_texticule()collect_free_in_facts(bound_var_idx, prop, lines)— recursive traversal- For each
PQuant(v, body), evaluatesbody(1)and asserts(set (FreeIn (BoundVar 1) subprop) 1)for every subprop containingBoundVar(1) - Helper functions:
term_contains_bound_var,prop_contains_bound_var,rel_contains_bound_var,mex_contains_bound_var,op_contains_bound_var,tag_contains_bound_var,tag_unit_contains_bound_var
Conditional rules (egglog_rules.egg §7c) — 12 rules:
; ∃x.(P∧Q) → (∃x.P)∧Q when x∉FV(Q)
(rule ((PQuant (Exists) restr (PAnd p q) v)
(= (FreeIn (BoundVar v) q) 0))
((union (PQuant (Exists) restr (PAnd p q) v)
(PAnd (PQuant (Exists) restr p v) q))))
Full list:
- ∃-conjunction: (P∧Q) with x∉FV(Q) and x∉FV(P)
- ∀-disjunction: (P∨Q) with x∉FV(Q) and x∉FV(P)
- ∀-conjunction: (P∧Q) with x∉FV(Q) and x∉FV(P)
- ∃-disjunction: (P∨Q) with x∉FV(Q) and x∉FV(P)
- ∀-implication: (P→Q) with x∉FV(Q)
- ∃-implication: (P→Q) with x∉FV(Q)
- Vacuous ∀: any body with x∉FV(body)
- Vacuous ∃: any body with x∉FV(body)
Key design decision: Using (= (FreeIn ...) 0) instead of (not (FreeIn ...)) because egglog's not requires built-in Bool type, but FreeIn returns i64. The = 0 check achieves the same semantics.
15.5 How the Two Phases Interact
Input: ∃x.(P(x) ∧ Q)
│
▼
Phase 1: simplify_prop()
- contains_bound_var(1, Q) = false
- Apply ∃-conjunction-left: (∃x.P(x)) ∧ Q
│
▼
Lowering: egglog_lower.rs
- Lower (∃x.P(x)) ∧ Q to egglog
- Generate FreeIn facts:
- FreeIn(BoundVar(1), P(BoundVar(1))) = 1 [P contains x]
- FreeIn(BoundVar(1), Q) = 0 [Q does not contain x]
│
▼
Phase 2: egglog saturation
- If equality saturation produces ∃x.(P∧Q) again
- §7c rule fires: (= (FreeIn (BoundVar v) q) 0) → union with (∃x.P)∧Q
15.6 Status Updates
§14.1: Added §7c Quantifier Scope Conditional Rules to implemented rules list.
§15.7 naku Negation Boundaries — How They're Solved
The CLL §16.9 rule "naku ro da P ↔ su'o da naku P" is semantically identical to ¬∀x.P ↔ ∃x.¬P, which was already implemented in §7 (negation push-through). The partial distribution rules in §7c complete the picture:
- naku (∃x.P ∧ Q) = ¬∃x.(P ∧ Q)
- By §7: ¬∃x.(P ∧ Q) = ∀x.¬(P ∧ Q) = ∀x.(¬P ∨ ¬Q)
- If x∉FV(Q): by §7c: ∀x.(¬P ∨ ¬Q) → (∀x.¬P) ∨ ¬Q = (∀x.naku P) ∨ naku Q
This is the composition of existing §7 rules + new §7c rules — no separate naku-specific rules needed.
16. OLOG INTEGRATION (dzaske)
Ologs (Ontology Logs) are a category-theoretic knowledge-representation format. lojban-rs embeds the dzaske olog system with bidirectional integration: extract schemas from parsed Lojban, validate instance data, run relational queries, and compose with the egglog e-graph.
Theory & sources: docs/ologs.md, docs/olog/sources/ (Spivak & Kent 2012, Patterson 2017, Lambert & Patterson 2024).
Note: Olog integration uses Cargo features olog and olog-proofs (both default-on). See @ref:feature.olog.
16.1 Core extraction
| Status | Feature | Impl Ref | Notes |
|---|---|---|---|
| ✅ | extract_olog — JboProp → Olog |
@ref:olog.extract_olog | Types, aspects, facts, 2-cells from brivla and connectives |
| ✅ | populate_instances — JboTerm → OlogInstanceData |
@ref:olog.populate_instances | Event IDs, filler instances, aspect applications |
Extraction mapping:
| Semantic construct | Olog construct |
|---|---|
JboRel::Brivla("klama") with n args |
klama_event, klama_x1…klama_xN, filler types |
JboRel::PermutedRel(n, r) |
Dual aspect + dual(r_xN) = r_xN_dual fact |
JboRel::Tanru(r1, r2) |
{r1}_{r2}_event, recurses both parts |
Prop::Connected(Impl, p1, p2) |
Implication 2-cell |
Prop::Not(inner) |
2-cell inner_event ⊆ ⊥ |
16.2 Validation & querying
| Status | Feature | Impl Ref | Notes |
|---|---|---|---|
| ✅ | Structure validation | @ref:olog.validate_structure | Types, aspects, instance membership |
| ✅ | Fact validation | @ref:olog.validate_facts | Commutative diagram facts |
| ✅ | 2-cell validation | @ref:olog.validate_two_cells | Subsumption / implication |
| ✅ | Query engine | @ref:olog.run_query_file | Load + execute JSON queries |
| ✅ | Load olog JSON | @ref:olog.load_olog | olog_data/ologs/*.json |
16.3 Bundled corpus
| Status | Feature | Impl Ref | Notes |
|---|---|---|---|
| ✅ | dzaske example ologs (12 files) | @ref:olog.bundled_corpus | olog_data/ologs/ |
| ✅ | Instance data (9 files) | @ref:olog.bundled_corpus | olog_data/instances/ |
| ✅ | Query files (12 files) | @ref:olog.bundled_corpus | olog_data/queries/ |
| ✅ | Integration tests | @ref:olog.test_suite | cargo test --test camxes_olog |
| ✅ | JSON Schema | — | olog_schema/schema.json, instance_schema.json, query_schema.json |
16.4 Egglog composition (Layers A/B/C)
| Status | Feature | Impl Ref | Notes |
|---|---|---|---|
| ✅ | Layer A — olog → egglog rules | @ref:olog.egglog_layer_a | olog_to_egg_rules; inject before saturation |
| ✅ | Layer B — e-graph → olog | @ref:olog.egglog_layer_b | extract_olog_from_egraph |
| ⚠️ PARTIAL | Layer C — queries in e-graph | @ref:olog.egglog_layer_c | Tabulator, Tensor fall back to empty |
| ✅ | Egglog type validation | @ref:olog.egglog_type_validation | type_schema.egg, type_rules.egg |
Tests: cargo test --test camxes_olog_egglog.
17. PROLOG EXPORT
Prolog source generation from Lojban semantics via a target-neutral Prolog IR
(src/prolog/: AST + tokenizer + precedence-climbing parser + dialect-aware
pretty-printer). Two emission dialects behind PrologDialect:
Swi— executable SWI-Prolog source (:-,?-,\+,is/2,=.., lists,member/2).Tersmu— tersmu/lojysamban parity mode matchingexamples/*.loj(Skolem constantsc0/c1,-->implication,non-veridical:side-facts,ju'a nairewrites).
The legacy SWI-dialect string API (prop_to_prolog, semantic_results_to_prolog,
eval_text_to_prolog) is preserved for backward compatibility; new code uses the
_dialect variants. References: docs/prolog/references.md.
| Lojban construct | Prolog output | Impl |
|---|---|---|
.i sentences |
Facts ending with . |
PrologMode::Fact |
Implications (.ijanai etc.) |
Rules with :- (SWI) / --> term (Tersmu) |
PrologMode::Rule |
Questions (ma) |
?- (SWI) / ? (Tersmu) queries |
PrologMode::Query |
| Logical negation | \+ |
lower_prop |
| Conjunction / disjunction | , / ; |
connective mapping |
Biconditional (.ijo) |
<-> term |
lower_prop (fixed) |
Relational quantifier (bu'a) |
rel_quant/3 (preserved) |
lower_prop (fixed) |
Nested quantifiers (ro da su'o de) |
distinct de Bruijn vars | VarCtx::depth (fixed) |
Non-veridical gadri (le) |
non-veridical: side-fact (Tersmu) / \+\+ (SWI) |
lower_prop + SideNote |
| PredNamed / MexSelbri in term position | call/1 wrapper (fixed) |
lower_term / lower_mex |
| VUhU operators | SWI arithmetic functors (+,-,*,…) / cmavo (Tersmu) |
operator_functor_dialect |
=.., is/2, DCG -->, cut ! |
parse + render | src/prolog/{lexer,parser,pretty}.rs |
| Status | Feature | Impl Ref | Notes |
|---|---|---|---|
| ✅ | prolog IR module (AST + lexer + parser + pretty) |
src/prolog/ |
Round-trippable; tests/prolog_round_trip.rs |
| ✅ | PrologDialect (Swi / Tersmu) |
src/prolog/pretty.rs |
Dialect flag in pretty-printer + lowerer |
| ✅ | prop_to_prolog |
@ref:prolog.prop_to_prolog | Single proposition → clause (SWI) |
| ✅ | semantic_results_to_prolog |
@ref:prolog.semantic_results_to_prolog | Full program from semantic results (SWI) |
| ✅ | prop_to_prolog_dialect / semantic_results_to_prolog_dialect |
src/jbo_prolog.rs |
Dialect-aware lowering |
| ✅ | eval_text_to_prolog |
@ref:prolog.eval_text_to_prolog | Text → Prolog; WASM prolog JSON key (SWI) |
| ✅ | eval_text_to_prolog_dialect |
@ref:prolog.eval_text_to_prolog_dialect | Text → Prolog in a chosen dialect |
| ✅ | WASM parse_lojban_with_dialect |
src/lib.rs |
prolog_dialect option; default Tersmu |
| ✅ | Golden tests vs examples/*.loj |
tests/prolog_golden.rs |
Characterization mode; strict via env var |
| ✅ | SWI execution tests | tests/prolog_swi.rs |
Skipped if swipl absent |
| ✅ N/A | CLI -P / --prolog flag |
— | No binary yet; library + WASM only |
18. SEMANTIC EQUIVALENCE & OUTPUT FORMATS
18.1 Semantic equivalence
| Status | Feature | Impl Ref | Notes |
|---|---|---|---|
| ✅ | check_equiv / check_equiv_with_limit |
@ref:semantic.check_equiv | Two texts → same e-class after saturation |
| ✅ | Equivalence tests | — | tests/camxes_egglog.rs |
18.2 Output formats
| Format | API | Status |
|---|---|---|
| Logical form | eval_show |
✅ |
| Canonical Lojban | jbo_show |
✅ |
| Graph JSON | jbo_tree |
✅ |
| Prolog source | eval_text_to_prolog / eval_text_to_prolog_dialect |
✅ (SWI + Tersmu dialects) |
| Egglog e-graph JSON | run_egglog_analysis → graph_json |
✅ |
| Olog summary JSON | summarize_olog |
✅ (library); ⚠️ WASM partial |
18.3 Future CLI (tersmu parity)
lojban-rs has no main.rs today. tersmu/camxes-rs CLI flags for reference when a binary is added: --json, -E/--egglog, --equiv=S, -O/--olog, --olog-schema=F, -P/--prolog, -l/--loj, -j/--jbo.
Open Tickets
Manual tracking for MISSING, PARTIAL, AD HOC, NEEDS EVAL, and @ref:plan.* rows without a code anchor. Completed work moves to code #[jbo_ref] entries and appears in READY.md after sync_plan_ready.py.
3. TENSES & MODALS (CLL Ch 10)
Simple tense cmavo from CLL §10.2–10.11 (PU/ZI/FAhA/VA/ZAhO/ZEhA/VEhA/VIhA/MOhI/TAhE/ROI/re'u/FEhE/KI/CUhE/CAhA and compounds) are implemented — see auto-generated §3.1 Spatial Tenses, §3.2 Temporal Tenses, and §8.1–8.2. Remaining Ch 10 gaps are tracked in §3.6 below (§10.23 tense vs modals). §10.26–10.28 are reference/summary (N/A for parser).
3.6 Complex Tense Constructs (remaining)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ⚠️ PARTIAL | Tenses versus modals (semantic distinction) | §10.23 | @ref:semantic.s8_2_tenses_versus_modals | WithEventAs(term, EventReferenceRole) — TenseBalvi vs ModalMukti selected via is_tense_tag in connective handlers. Egglog layer still treats both as WithEventAs. |
5. NEGATION (CLL Ch 15)
5.2 Scalar Negation (CLL Ch 15)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ⚠️ PARTIAL | na'e(na'e(r)) = r scalar approximation |
§15.3 | @ref:feature.approx-scalar-neg | Behind approx-scalar-neg feature flag |
| ⚠️ PARTIAL | to'e(r) ≈ ¬PRel(r) scalar approximation |
§15.4 | @ref:feature.approx-to-e | Behind approx-to-e feature flag |
5.6 Metalinguistic Negation (CLL Ch 15)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ⚠️ PARTIAL | na'i (metalinguistic negation) | §15.10 | @ref:plan.s5_6_na_i_metalinguistic_negation | Parsed as Free::Indicator; metalinguistic negation (rejecting presupposition) requires discourse-level analysis not available in proposition-level pipeline — semantic effect cannot be implemented without discourse context |
| ⚠️ PARTIAL | jo'a (metalinguistic affirmation) | §15.10 | @ref:plan.s5_6_jo_a_metalinguistic_affirmation | Parsed as Free::Indicator; metalinguistic affirmation (accepting presupposition) requires discourse-level analysis not available in proposition-level pipeline — semantic effect cannot be implemented without discourse context |
7. ABSTRACTIONS (CLL Ch 11)
7.3 Event Contour Relationship (CLL Ch 11)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ⚠️ AD HOC | validate_zaho_abstractor_pairing |
§11.11 | @ref:semantic.validate_zaho_abstractor_pairing | Hardcoded ZAhO contours per abstractor |
| ⚠️ AD HOC | is_variable_free |
§7.4, §7.5 | @ref:semantic.is_variable_free | Hardcoded assignable cmavo lists |
| ⚠️ AD HOC | parse_tu special cases |
§5.10, §7.14 | @ref:semantic.parse_tu | Special cases for du, ka/ni, poi'i. The buha branch is completed — see @ref:semantic.parse_tu in READY.md. |
9. MEKSO / MATHEMATICS (CLL Ch 18)
9.7 Mekso Selbri & Conversions (CLL §18.7, §18.11, §18.18–18.19, §18.21)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ⚠️ PARTIAL | Logical/non-logical connectives within mekso | §18.17 | @ref:plan.s9_7_logical_non_logical_connectives_within_mekso | mex grammar has joik/ek alternatives; verify with CLL examples. — earley_word_grammar.egg, jbo_parse.rs |
Completed null-operand/operator work (tu'o / ge'a, CLL §18.14) lives in READY.md under @ref:semantic.is_null_mex.
10. LETTERALS (CLL Ch 17)
CLL §17.14 auxiliary lerfu-word cmavo (this chapter):
| Cmavo | Selma'o | CLL role |
|---|---|---|
bu |
BU | §17.4 — makes preceding word a lerfu word |
ga'e, to'a |
BY | §17.3 — upper / lower case shift |
tau |
LAU | §17.3 — case-shift next lerfu word only |
lo'a, ge'o, je'o, jo'o, ru'o |
BY | §17.5 — alphabet shifts (Latin, Greek, Hebrew, Arabic, Cyrillic) |
se'e |
BY | §17.13 — following digits are a character code |
na'a |
BY | §17.5 — cancel all shifts |
zai, ce'a, lau |
LAU | §17.5/17.7 — custom alphabet, font, punctuation |
tei, foi |
TEI / FOI | §17.6 — compound lerfu word delimiters |
Not letterals (were incorrectly listed under the old §9.8 “Acronyms” ticket): la'u (BAI modal “with quantity”, §9.6/§10.25), te'u (TEhU mekso/vector terminator, §18.15/§18.18), ce'u (KOhA abstraction focus, §7.11) — implemented elsewhere; see auto-generated §7.11, §9.6, §18.15.
Chapter 17 letterals are implemented — see auto-generated READY §10 / §9.8 lerfu entries (@ref:semantic.lau_by_shift_stack, @ref:semantic.se_e_unicode_evaluation, @ref:semantic.acronyms_lerfu_names, @ref:semantic.mathematical_lerfu_strings, @ref:grammar.lerfu_word_lau_chain).
11. ATTITUDINALS & INDICATORS (CLL Ch 13, 21)
11.2 Miscellaneous (CLL Ch 13, 19)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ⚠️ AD HOC | indicator_bridi_tail UI→selbri mapping |
§13.2–13.13 | @ref:semantic.indicator_bridi_tail | 40+ UI cmavo manually mapped to selbri |
| ⚠️ AD HOC | eval_free_with_context cmavo branches |
§7.13, §13.9, §19.11 | @ref:semantic.eval_free_with_context | String-inspected cmavo branches for da'o/fu'e/etc. |
17. PROLOG EXPORT — tersmu parity gaps
The Prolog IR (src/prolog/), dialect flag (PrologDialect::Swi / Tersmu), AST
lowerer, tersmu display-format path (eval_text_to_tersmu_lines, behind
tersmu-parity), and the rendering/AST fixes (connective normalization, is/2
arithmetic goals, AbsPred/AbsProp/Moi lowering, tanru seltau in
convert_selbri_3) are implemented — see auto-generated §17 in READY.md.
The tersmu display-format path (tersmu-parity feature flag) produces the
tersmuLines output format: per-line > framing, ----- separators,
non-veridical: side-facts, [Fragment: ...] rendering, and error messages
(Parse error: / Morphology error: with context pointer). examples/1.loj
achieves 100% byte-parity; examples/2.loj 99.6%.
Remaining examples/*.loj byte-parity gaps are upstream
morphology/parser/semantic differences between our pipeline and tersmu's
Pappy pipeline — not output-format issues. Completed morphology/lexer and
tanru/gek logshow work lives in READY.md (e.g.
morph.deterministic_cll_lexer, prolog.logshow_tanru_nesting).
Open upstream gaps (see also §18):
- Parser acceptance after identical tokenization (Earley vs Pappy).
- Morphology differential corpus: separate token/class mismatches from
parser mismatches across
examples/*.jbo— §18.2.2 /@ref:morph.differential_corpus.
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ⚠️ PARTIAL | tersmu tersmuLines output parity (feature flag) |
— | @ref:feature.tersmu-parity | Behind tersmu-parity feature flag (not in default or wasm); gates display-format path with error handling, fragment rendering, name dedup, connective normalization, Quantified logshow, sumti_tail_1 disambiguation |
| ⚠️ PARTIAL | examples/*.loj full byte-parity |
— | @ref:prolog.eval_text_to_tersmu_lines | Characterization (tersmu_lines_golden_all_char, #[ignore]-gated; strict via LOJBAN_PROLOG_GOLDEN_STRICT=1). Remaining gaps: Earley-vs-Pappy acceptance, ZEI/noi/etc. (§18.6). |
18. GRAMMAR DEVIATIONS: CLL EBNF / tersmu Pappy vs Earley/egglog
Comparison of our Earley/egglog grammar with (a) the CLL Chapter 21 EBNF grammar and (b) tersmu's Pappy PEG parser. The golden test (tersmu_lines_golden_all_char) shows 1738/14476 lines match (12.0%) across all examples (with 1s per-line timeout; lines exceeding timeout produce morphology-error placeholders).
Completed items (gek forethought, deterministic CLL lexer, nested tanru logshow, abstraction side-fact rendering, fragment lerfu cia) are in READY.md — do not re-list them here.
18.2 PEG ordered choice vs CFG ambiguity
tersmu uses PEG / (ordered alternation): first match wins, no backtracking. Our Earley CFG explores all alternatives in parallel. resolve_ambig_first_ok / resolve_ambig_prefer_statement emulate PEG ordering at the AST conversion level. Many golden test mismatches stem from this fundamental difference: our parser accepts inputs tersmu rejects (and vice versa), and ambiguous inputs resolve differently.
18.2.1 How the CLL EBNF handles this
CLL Chapter 21 is a formal word/selma'o grammar, not the complete character-to-AST algorithm used by tersmu:
- Upper-case symbols are terminals that morphology has already classified (§21.1 notation rule 2). Morphological ambiguity must therefore be resolved before this grammar is applied.
|is unordered EBNF alternation. The CLL does not assign PEG first-alternative priority to it....has an explicit left-grouping convention (§21.1 rule 7). This is a disambiguation rule outside ordinary CFG notation and explains our longest-match handling for left-recursive repetitions.//...//marks an elidable terminator which may be omitted only “if no grammatical ambiguity results” (§21.1 rule 10). This is a contextual admissibility condition, not a context-free production. A conforming parser must implement it with guards, grammar transformation, parse-forest validation, or an equivalent mechanism.- Pappy's
/and!are tersmu's operational implementation choices. Some negative lookaheads implement CLL terminator/elision constraints; others encode preparsing, magic-word, morphology, or tersmu-specific precedence. They must be audited individually rather than copied on the assumption that every!is itself a CLL rule.
Therefore an Earley parser can implement Chapter 21, but a pure unguarded CFG recognizer alone is insufficient for the CLL's contextual elision rule. The recognizer may remain CFG-based if a separate deterministic constraint layer enforces those conditions.
18.2.2 Morphology differential corpus (remaining Phase 0 follow-up)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ⚠️ PARTIAL | Morphology differential corpus vs examples/*.jbo |
§4.2 | @ref:morph.differential_corpus | Deterministic CLL lexer is IMPLEMENTED (READY). Remaining: token/class differential report across all examples/*.jbo lines; separate morphology mismatches from parser mismatches. |
18.2.3 Syntax alignment options after Phase 0
All options preserve the CLL grammar unless explicitly placed behind a tersmu-parity feature. They may be combined.
Chosen primary policy — maximum token coverage from the forest. After
Earley saturation builds a parse forest, select trees that consume the
maximum number of input tokens. This generalizes the existing longest-child
heuristic in earley_extract.rs (max_end among equal-dot candidates) to a
global forest-ranking rule:
- Prefer root candidates whose covered span end is maximal.
- Prefer alternatives whose leaf-token coverage is maximal (fewest unused tokens / fewest empty elisions that shrink coverage).
- Only after equal maximum coverage remains, apply secondary policies (statement-over-fragment, audited guards, PEG priority metadata, semantic convertibility).
Rationale: CLL §21.1 rule 7 already requires left-grouped longest attachment
for ...; maximum coverage is the natural CFG-side analogue of “take as much
input as the grammar can legitimately claim,” without importing PEG ordered
choice as the primary rule. It also avoids prematurely choosing a shorter
Fragment tree when a full Statement covers the same line.
What max-coverage does not fix alone:
- residual morphology mismatches (see §18.2.2 differential corpus);
- over-acceptance of inputs that should fail CLL/tersmu guards;
- cases where multiple full-coverage trees remain (gek subsentence Ambig, tense attachment, etc.) — those still need secondary policy.
Option A — explicit PEG alternative-priority metadata. Keep Earley
recognition of every CFG parse, but attach Pappy declaration order to
alternatives and use it as a secondary tie-breaker after maximum token
coverage. Replace lexicographic alt_path_key, alt-name-length, and scattered
“first OK” order with named, generated priorities.
Option B — systematic negative-lookahead/guard layer. Audit every Pappy
! against CLL and encode justified cases as declarative guards. Extend the
existing Phase B NegLookaheadPos/NegInhibited mechanism for terminal and
nonterminal lookahead. This fixes over-acceptance and reduces forests.
Option C — CFG factoring and token-set difference. Rewrite selected rules
into disjoint alternatives, or generate complement terminal classes such as
NA_NOT_BEFORE_JA and I_NOT_BEFORE_JEK_JOIK. This puts decisions in
recognition and can improve performance, but causes grammar expansion and is
appropriate only where the excluded language is regular and finite-state.
Option D — parse-forest constraints. Keep the full shared packed parse
forest, then eliminate trees violating CLL elision, grouping, or audited Pappy
constraints before selecting a tree. Maximum token coverage runs on the
remaining forest. This most clearly separates recognition from disambiguation
and can report true ambiguity, but requires richer forest storage than the
current local ParseTree::Ambig reconstruction.
Option E — semantic-first forest pruning. Try AST/semantic conversion for each surviving max-coverage alternative and select the first valid one according to an explicit policy. Useful fallback for conversion failures after max-coverage selection, but must not outrank coverage or CLL guards.
Option F — tersmu-style preparser. Port textHead, wholeStatement, free
stripping, quote handling, and I/NIhO boundaries into a deterministic Rust
phase before Earley. This can substantially reduce top-level ambiguity but
duplicates grammar concerns unless generated from one source.
Option G — generate Earley metadata/guards from Pappy. Build a
pappy_to_earley generator that emits CFG productions, alternative priorities,
lookahead guards, and an audit of semantic actions that cannot be translated.
This minimizes long-term drift but is a large tooling project; PEG lookahead
and ordered choice cannot always be represented by CFG productions alone.
Option H — dual parser/shadow oracle. Run tersmu or a Rust PEG port beside Earley in tests and report acceptance/tree differences. This is strong differential QA but does not resolve which behavior is CLL-authoritative.
Option I — replace the word parser with a Rust PEG port. This offers the closest parse parity but abandons the pure Earley recognizer as the primary path, retains semantic-port differences, and conflicts with the project's “No PEG dependency” architecture unless explicitly approved.
18.2.4 Recommended sequence
- Build the morphology differential corpus report (§18.2.2 /
@ref:morph.differential_corpus). Do not attribute remaining tokenization mismatches to PEG-vs-CFG behavior until that report exists. - Implement maximum token coverage as the primary forest selection rule (root + equal-span ties). Keep statement-over-fragment only as a secondary preference among equal-coverage trees.
- Add an audit that extracts Pappy alternative order and negative-lookahead sites, classifying each as CLL-required, morphology/preparser, or tersmu-specific.
- Implement Option B (audited guards) and Option A (priority metadata) as secondary tie-breakers after max coverage.
- Use Option D for remaining genuine CFG ambiguity and Option E only as a conversion fallback.
- Apply Option C or F selectively to measured performance/ambiguity hot spots.
- Keep Option H as continuous differential testing. Consider G or I only if maintaining hand-aligned metadata proves more expensive than generation or replacement.
Success metrics must be reported separately:
- morphology token/class parity;
- syntax accept/reject parity on identical tokens;
- selected-tree/AST parity for jointly accepted inputs;
- semantic/logshow byte parity;
- parse-forest size, saturation batches, and timeout rate.
18.2.5 Worked mismatch examples (lojban-rs vs examples/*.loj)
Reference outputs below are from examples/*.loj (canonical tersmu-lines
corpus). “Got” outputs were captured with
eval_text_to_tersmu_lines under tersmu-parity (2026-07-17). Pipeline stages:
raw text
→ deterministic morphology (run_egglog_morphology / deterministic_cll_lex / …)
→ WordToken + WordClass facts
→ Earley egglog saturation (all competing Items)
→ Phase B NegInhibited (sparse today)
→ tree extraction / Ambig forest (longest-child + alt-name heuristics)
→ AST conversion (resolve_ambig_first_ok / prefer_statement)
→ jbo_parse semantics
→ logshow / tersmuLines framing
Example C — mi sutra-zei-tavla (morphology ZEI)
Expected (tersmu-lines / OPEN D4): sutra-zei-tavla(mi) (or spaced
sutra zei tavla(mi) in some tersmu builds).
Got:
tra-zei-tavla()
tra-zei-tavla
Step-by-step:
- Input is one orthographic word with internal
-zei-. - Morphology/ZEI extraction consumes a suffix starting mid-rafsi (
tra-zei-tavla) instead of the full pre-ZEI wordsutra. - The resulting brivla token has no leading sumti attachment in the chosen
tree, so semantics print
tra-zei-tavla()with empty args. - Max-token forest selection cannot repair a wrong token stream.
Example E — coi djan. (vocative / empty output)
Expected (OPEN D5 / tersmu Vocative handling): a vocative side-fact such as
coi(james) / name rendering.
Got: empty prolog/rewrite sections (only framing).
Step-by-step:
- Morphology yields
COI+CMENE. - Earley places the vocative in
free/ text-head structure rather than a bridi statement. eval_textproduces no main proposition from frees-only text.- tersmuLines therefore prints no logical body. Coverage selection does not create a proposition that was never in the semantic AST.
Example F — mi noi nanmu cu klama (relative clause / timeout)
Expected (OPEN D3):
nanmu(mi)
klama(mi)
Got: Morphology error: placeholder (timeout or acceptance failure under
the current parse-timeout path).
Step-by-step:
- Intended morphology:
KOhA+NOI+BRIVLA+CU+BRIVLA. - Earley chart for
noirelative clauses can explode or fail to accept withinLOJBAN_PARSE_TIMEOUT_MS. parse_line_with_timeoutreturnsNone.eval_text_to_tersmu_linesmaps that toformat_morphology_error, which is a mislabeled timeout/reject, not necessarily a morphology classifier bug.- After reliability fixes, forest selection should prefer the full statement covering all tokens over a shorter fragment.
Example G — cases that already match (coverage/heuristic working)
These currently match examples/*.loj style and are useful negatives:
mi pu klama→(pu)(). klama(mi)/pu ku zo'u mi klama(same shape asexamples/10.lojmi pu klama le zarci).mi ki tavla→(ki)(). tavla(mi)(same shape asexamples/9.loj).le re nanmu→non-veridical: (nanmu(c0) /\ 2 mei(c0))+[Fragment: c0](matchesexamples/4.loj; older notes about(re)vs2are stale for this path).pu broda gi'e brode→((pu)(). broda() /\ brode())(lazy term scoping; §18.3).
How max-token coverage should change the selection algorithm
Current extraction (simplified):
- Among child edges at a dot, keep those with maximal
child_end. - Among remaining equal-span ties, prefer
quantnames, else longest alt name, else emitAmbig. - AST conversion iterates Ambig with
first_ok/prefer_statement.
Proposed:
- Score every complete candidate tree by token coverage
(
end - startat root, then sum of consumed terminals). - Discard candidates below the maximum score.
- Among survivors, prefer statement over fragment, then apply audited guards / PEG priority, then semantic convertibility.
- If still tied, keep
Ambigand fail loudly intersmu-strictrather than silently picking lexicographicalt_path_key.
18.3 Lazy vs greedy term parsing (resolved)
With the gi'e connective parsing fix and tense_modal → DecoratedTagUnit conversion fix, pu broda gi'e brode now parses as (pu broda) gi'e brode and pu ku broda gi'e brode parses as pu (broda gi'e brode). The tests/debug_lazy_terms.rs cases assert these scopings:
pu broda→Modal(pu, Rel(broda))broda gi'e brode→Connected(And, Rel(broda), Rel(brode))pu broda gi'e brode→Connected(And, Modal(pu, Rel(broda)), Rel(brode))pu ku broda gi'e brode→Modal(pu, Connected(And, Rel(broda), Rel(brode)))
This matches tersmu's lazy term scoping behavior for these inputs. The remaining open concern is term = (tag | FA #) /KU#/ elision in the Earley grammar, which currently only produces BareTag terms when KU is explicit (term_tag_ku). If broader tag-as-term-without-KU cases are needed, this should be handled by extending term grammar alternatives and relying on resolve_ambig_prefer_statement to prefer sentence_bridi_tail (where the tag attaches to the first selbri) over sentence_terms_bridi_tail (where the tag is a bare term).
18.4 Negative lookahead (PEG-specific)
tersmu uses PEG negative lookahead ! extensively (e.g. !JA on fragment NA,
!MOI on quantifier, !jek !joik on I-separators). A plain CFG production
cannot directly express arbitrary negative lookahead, but our overall Earley
pipeline can implement equivalent constraints through audited Phase B guards,
finite token-set complements/grammar factoring, or parse-forest validation.
See §18.2.1–18.2.4. Do not move these decisions into ad hoc AST string checks.
18.6 Concrete discrepancies (tested sequentially on examples/*.jbo)
Running each example line through eval_text_to_tersmu_lines and comparing with examples/*.loj reference. Overall: 1738/14476 lines match (12.0%).
D3. Relative clauses with noi (MEDIUM)
Input: mi noi nanmu cu klama
Expected: nanmu(mi)\nklama(mi)
Got: Morphology error
Root cause: Our parser may not handle noi relative clauses correctly in all positions, or the cu separator interacts badly with the relative clause.
Approximate fix: Verify relativeClause grammar in earley_word_grammar.egg handles noi subsentence KUhO correctly. Check convert_relative_clause in earley_to_syntax.rs.
D4. ZEI compound word extraction (MEDIUM)
Input: mi sutra-zei-tavla
Expected: sutra-zei-tavla(mi)
Got: tra-zei-tavla() (missing su prefix and argument)
Root cause: The ZEI compound sutra-zei-tavla is being split incorrectly during morphology. The first syllable su is being consumed by a preceding word classification.
Approximate fix: Check earley_morph_extract.rs ZEI handling — ensure the full pre-ZEI word is captured, not just the tail.
D5. Vocative handling (LOW)
Input: coi djan.
Expected: coi(james) (or similar vocative output)
Got: Empty (no prolog/rewrite sections)
Root cause: Vocatives (COI DOI CMENE) are parsed as frees/vocatives but eval_text doesn't produce a proposition from them. tersmu has special Vocative handling in JboParse.hs:56-58.
Approximate fix: In eval_text or convert_paragraph, when a vocative is detected, emit a side-fact like coi(name).
D7. SE conversion on selbri (LOW)
Input: mi se klama le zdani
Expected: klama(zdani(c0),mi) (x1/x2 swapped)
Got: klama(c0,mi) (missing non-veridical: zdani(c0) in correct position)
Root cause: The SE conversion is working (arguments are swapped) but the non-veridical side-fact for le zdani is not being attached to the correct argument position.
Approximate fix: Check convert_selbri_3 SE handling and ensure le descriptions produce non-veridical side-facts at the correct argument position after SE swap.
D8. NUhA/forethought mex morphology (LOW)
Input: li nu'a su'i pa re du li ci
Expected: su'i(1,2,3)
Got: Morphology error
Root cause: nu'a (NUhA) is not being recognized as a valid cmavo in the morphology pass, or pe'o (PEhO) is not recognized.
Approximate fix: Check earley_word_grammar.egg for NUhA and PEhO terminal rules. Verify cmavo_to_terminal mapping includes these selma'o.
Priority order for fixes
- Morphology differential corpus (§18.2.2) — regenerate mismatch reports on the deterministic lexer
- Maximum token coverage forest selection (§18.2.3) — primary CFG disambiguation policy
- D4 ZEI compounds — affects all ZEI usage
- D3 Relative clauses — affects
noi/poiusage (also timeout labeling) - D7 SE conversion — affects argument ordering
- D5 Vocatives — low frequency
- D8 NUhA/PEhO — low frequency
Implemented Features (auto-generated)
1.1 Phonology (CLL Ch 3)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | 16 diphthongs | §3.4 | @ref:morph.16_diphthongs | Handled in morphology |
| ✅ | 27-char alphabet (no h/q/w) | §3.1 | @ref:morph.27_char_alphabet_no_h_q_w | Handled in morphology |
| ✅ | 48 permissible initial pairs | §3.7 | @ref:morph.48_permissible_initial_pairs | Handled in morphology |
| ✅ | 6 vowels + y distribution | §3.2 | @ref:morph.6_vowels_y_distribution | Handled in morphology |
| ✅ | Apostrophe = [h] | §3.3 | @ref:morph.apostrophe_h | Handled in morphology |
| ✅ | Audio-visual isomorphism | §3.1 | @ref:morph.audio_visual_isomorphism | Implicit in parser design |
| ✅ | Comma = syllable break | §3.1 | @ref:morph.comma_syllable_break | Handled in morphology |
| ✅ | Consonant triple rules | §3.7 | @ref:morph.consonant_triple_rules | CLL §3.7: IsConsonantTriple relation added; detects valid triples (permissible pair + initial pair); IsForbiddenTriple tracks ndj/ndz/ntc/nts |
| ✅ | Consonant voicing pairs | §3.2 | @ref:morph.consonant_voicing_pairs | Handled in morphology |
| ✅ | Penultimate stress | §3.9 | @ref:morph.penultimate_stress | Handled in morphology |
| ✅ | Period = mandatory pause | §3.1 | @ref:morph.period_mandatory_pause | Handled in morphology |
| ✅ | Stress-based word boundary detection | §3.9 | @ref:morph.stress_based_word_boundary_detection | Stress used for word classification in morphology; penultimate stress rule enforced in is_valid_gismu_shape. Full boundary detection not needed for egglog pipeline. |
| ✅ | Syllabication rules | §3.9 | @ref:morph.syllabication_rules | Handled in morphology |
| ✅ | Vowel pairs with apostrophe (a'a, e'i, etc.) | §3.5 | @ref:morph.vowel_pairs_with_apostrophe_a_a_e_i_etc | Handled in morphology |
1.2 Word Classes (CLL Ch 4)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Brivla identification (3 properties) | §4.3 | @ref:morph.brivla_identification_3_properties | Handled in morphology |
| ✅ | Cmavo identification (V, CV, VV, CVV forms) | §4.2 | @ref:morph.cmavo_identification_v_cv_vv_cvv_forms | HashMap-based cmavo lookup |
| ✅ | Cmavo special form .y. | §4.2 | @ref:morph.cmavo_special_form_y | Handled |
| ✅ | Cmevla identification (end in consonant, pause-bounded) | §4.8 | @ref:morph.cmevla_identification_end_in_consonant_pause_bou | Handled in morphology |
| ✅ | Cy-form cmavo (letterals) | §4.2, §17 | @ref:morph.cy_form_cmavo_letterals | Detection: is_cy_form_cmavo(), cy_form_to_letter() in earley_morph_extract.rs |
| ✅ | Cy-form cmavo detection | §4.2, §17 | @ref:morph.cy_form_cmavo_detection | is_cy_form_cmavo(), cy_form_to_letter() |
| ✅ | Experimental cmavo forms | §4.2 | @ref:morph.experimental_cmavo_forms | Not needed — experimental forms are not part of standard Lojban |
| ✅ | Fu'ivla identification | §4.7 | @ref:morph.fu_ivla_identification | Identified as fuhivla word type in morphology |
| ✅ | Gismu form (CVC/CV or CCVCV, 5 letters) | §4.4 | @ref:morph.gismu_form_cvc_cv_or_ccvcv_5_letters | Handled in morphology |
| ✅ | Morphological word class determination from form | §4.10 | @ref:morph.morphological_word_class_determination_from_form | cmavo/brivla/cmevla identification by word shape |
| ✅ | Pause rules (vowel-initial words need preceding pause; consonant-final words need surrounding pauses) | §4.9 | @ref:morph.pause_rules_vowel_initial_words_need_preceding_p | Handled in morphology |
| ✅ | Slinku'i test | §4.7 | @ref:morph.slinku_i_test | is_slinkuhi() + passes_slinkuhi_test (CLL §4.7) |
| ✅ | Tosmabru test | §4.3 | @ref:morph.tosmabru_test | is_tosmabru() + segment_cmavo_brivla (CLL §4.11) |
1.3 Lujvo Formation & Decomposition (CLL Ch 4, 12)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Lujvo decomposition to source tanru | §12.1–12.3 | @ref:lujvo.decompose_lujvo | Parses rafsi components using rafsi dictionary |
| ✅ | Lujvo place structure rules (tertau dominance, unused place pruning) | §12.3–12.5 (lujvo place structure from veljvo) | @ref:lujvo.derive_place_structure | §12.3 tertau first; §12.4 seltau x2+; §12.5 prune x1 |
| ✅ | Lujvo scoring algorithm (4.12) | §4.12 (lujvo scoring algorithm) | @ref:lujvo.score_lujvo | score_lujvo(), count_hyphens(), needs_hyphen(), score_decomposed_lujvo(); 11 unit tests |
| ✅ | Unreduced vs fully reduced distinction | §4.11, §4.12 (unreduced vs fully reduced lujvo distinction) | @ref:lujvo.is_fully_reduced | is_fully_reduced() + both reduced/unreduced candidates |
| ✅ | Unreduced vs fully reduced distinction | §4.11 (lujvo construction algorithm) | @ref:lujvo.build_lujvo_candidates | is_fully_reduced() + both reduced/unreduced candidates |
1.4 Fu'ivla (CLL Ch 4)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | L-hyphen for fu'ivla | §4.11, §4.7 (Y/R/N/L hyphen insertion for lujvo and fu'ivla) | @ref:lujvo.needs_hyphen | 'l' when CVV rafsi precedes consonant-initial borrow; 4 unit tests |
| ✅ | Stage 3 fu'ivla construction (rafsi prefix + borrow) | §4.7; §4.7 (stage-3 fu'ivla construction; L-hyphen) | @ref:lujvo.build_fuivla | build_fuivla() + fuivla_stage() for stages 1/2/3 |
1.5 Cmevla (CLL Ch 4)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Cmevla identification | §4.8 | @ref:morph.cmevla_identification | Handled |
| ✅ | Multi-part cmevla (.djan. .braun.) | §4.8 | @ref:morph.multi_part_cmevla_djan_braun | Multi-part cmevla treated as single name in parser; pause-bounded segmentation handles .djan. .braun. as one entity. |
2.1 Text Structure (CLL Ch 19)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Fragments as standalone utterances | §19.1 | @ref:grammar.fragments_as_standalone_utterances | Implemented |
| ✅ | Paragraph separator ni'o / no'i | §19.3 | @ref:grammar.paragraph_separator_ni_o_no_i | Implemented |
| ✅ | Sentence separator .i | §19.2 | @ref:grammar.sentence_separator_i | Implemented |
| ✅ | Statement binding hierarchy (5 levels with I) | §19.2 | @ref:grammar.statement_binding_hierarchy_5_levels_with_i | Implemented |
| ✅ | TUhE...TUhU grouping blocks | §19.2 | @ref:grammar.tuhe_tuhu_grouping_blocks | Implemented |
| ✅ | Text → paragraphs → statements hierarchy | §19.1, §19.2 | @ref:grammar.text_paragraphs_statements_hierarchy | Implemented in earley_word_grammar.egg |
2.2 Sentence Structure (CLL Ch 9, 19)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Bridi-tail binding hierarchy (5 levels) | §19.1 | @ref:grammar.bridi_tail_binding_hierarchy_5_levels | Implemented |
| ✅ | Prenex = terms ZOhU | §16.2, §19.4 | @ref:grammar.prenex_terms_zohu | Implemented |
| ✅ | Subsentence = sentence | prenex subsentence | @ref:grammar.subsentence_sentence | Implemented |
| ✅ | Tail terms with VAU | §19.1 | @ref:grammar.tail_terms_with_vau | Implemented |
| ✅ | sentence = [terms [CU]] bridi-tail | §9.2, §19.1 | @ref:grammar.sentence_terms_cu_bridi_tail | Implemented |
2.3 Terms (CLL Ch 9, 14, 16)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | CEhE non-logical term connection | §14.11 | @ref:grammar.cehe_non_logical_term_connection | Implemented |
| ✅ | FA place tags (fa-fe-fi-fo-fu) | §9.3 | @ref:grammar.fa_place_tags_fa_fe_fi_fo_fu | Implemented. Fixed: convert_terms now properly handles nested terms nodes from recursive grammar (terms → term terms), fixing citka fa mi lo fasnu equivalence. CLL §9.3 rule: after FA-tagged sumti, untagged sumti fill succeeding places, skipping filled ones. |
| ✅ | Gek termsets (NUhI gek terms gik terms NUhU) | §14.11 | @ref:grammar.gek_termsets_nuhi_gek_terms_gik_terms_nuhu | Grammar rules documented in earley_word_grammar.egg; NUhI/NUhU recognized in morphology; structural markers in egglog_rules.egg §17. Semantic composition via jbo_parse termset handling. |
| ✅ | KU elidable terminator | §6.2 | @ref:grammar.ku_elidable_terminator | Implemented |
| ✅ | PEhE logical term connection | §14.11 | @ref:grammar.pehe_logical_term_connection | Implemented |
| ✅ | Terms structure (terms-1, terms-2) | §9.3 | @ref:grammar.terms_structure_terms_1_terms_2 | Implemented |
| ✅ | Termset (NUhI...NUhU) | §14.11 | @ref:grammar.termset_nuhi_nuhu | Implemented |
2.4 Sumti (CLL Ch 6, 8, 14)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Indefinite descriptions (ci gerku) | §6.8 (indefinite descriptions: ci gerku = ci lo gerku) | @ref:grammar.sumti_5_quant_selbri_rels | "ci gerku" = "ci lo gerku". Verified identical output. |
| ✅ | Interval sumti (bi'i, bi'o with GAhO) | §14.16; §14.16 (interval sumti via joik + KE selbri; bi'i/bi'o with GAhO) | @ref:ast.convert_selbri_4 | convert_selbri_4 builds ConnectedSB chain; commutativity/idempotency in egglog |
| ✅ | LA descriptions (la + sumti-tail) | §97, §6.2 | @ref:grammar.sumti_6_la_sumti_tail | (LA) # sumti-tail /KU#/ — la descriptions distinct from la names (CMEVLA) |
| ✅ | LA names (la + optional rels + name) | §97, §6.12 | @ref:grammar.sumti_6_la_name | LA # [relative-clauses] CMEVLA; dotted names may be BRIVLA_clause in morphology |
| ✅ | LE/LA description variants (gadri + sumti-tail) | §97, §6.2 | @ref:grammar.sumti_6_gadri_sumti_tail | LE/LO # sumti-tail /KU#/ — le/lo descriptions (la uses sumti_6_la_sumti_tail) |
| ✅ | LOhU...LEhU ungrammatical quotation | §19.10 | @ref:morph.lohu_quote | Morphology consumes LOhU…LEhU span as one LOhU_clause token; word-1100 disables indicator merge inside span |
| ✅ | Numbers (li + mekso + lo'o) | §6.15, §18.5 (numbers: li + mekso + lo'o) | @ref:grammar.sumti_6_li_mex | Implemented |
| ✅ | Pro-sumti (mi/do/ti/ko'a/da series) | §6.13, §7 (pro-sumti: mi/do/ti/ko'a/da series) | @ref:grammar.sumti_6_koha | Implemented |
| ✅ | Quantifier distribution across description types | §6.2, §6.6, §6.7, §6.9, §6.10 (descriptions, quantifiers, sumti qualifiers) | @ref:semantic.parse_sumti_atom | Inner/outer quantifier interaction with le/lo/la via Description inner_quant |
| ✅ | Quotations (lu/li'u) | §6.14, §19.9 (quotations: lu/li'u) | @ref:grammar.sumti_6_lu_text | Implemented |
| ✅ | Sumti-based descriptions (le re do) | §6.1 (formal: sumti-5, sumti-6 — five kinds of simple sumti) | @ref:grammar.sumti_5 | Inner quantifier with sumti via EitherSelbriSumti::Sumti |
| ✅ | VUhO relative clause scope extension | §8.8 (VUhO relative clause scope extension) | @ref:grammar.sumti_vuho_rels | VUhO recognized in morphology; scope extends via grammar structure |
| ✅ | ZOI delimited quotation | §19.10 | @ref:morph.zoi_quote | Morphology consumes ZOI delimiter…content…delimiter span as one token |
| ✅ | LOhU...LEhU ungrammatical quotation |
§19.10 | @ref:grammar.sumti_6_lohu | Morphology consumes LOhU…LEhU span as one LOhU_clause token; word-1100 disables indicator merge inside span |
| ✅ | ZOI delimited quotation |
§19.10 | @ref:grammar.sumti_6_zoi | Morphology consumes ZOI delimiter…content…delimiter as one token |
| ✅ | ZO single-word quotation |
§19.10 | @ref:grammar.sumti_6_zo | CLL sumti-6 = ZO # any-word #; word-1100 skips indicator merge after ZO |
| ✅ | any-word non-terminal | §21 (non-formal any-word) | @ref:grammar.any_word | ANY_WORD_clause dual-tagged on every word by Rust |
| ✅ | la'e, lu'e, tu'a, lu'a, lu'i, lu'o, vu'i | §6.10 (LAhE/NAhE+BO sumti qualifiers; la'e, lu'e, tu'a, etc.) | @ref:grammar.sumti_6_lahe_sumti | tu'a via SumtiQualifier::LAhE; others parsed as LAhE qualifier |
| ✅ | na'ebo, to'ebo, no'ebo, je'abo | §6.10, §15.6 (na'ebo, to'ebo, no'ebo, je'abo) | @ref:grammar.sumti_6_nahe_bo_sumti | Implemented |
2.5 Relative Clauses (CLL Ch 8)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | GOI relative phrase construction (goi + term) | §8.3; §8.3, §8.7 (GOI relative phrases: pe/po/po'e/po'u/ne/no'u; possessive sumti) | @ref:semantic.parse_goi_rel | goi assigns referent; JRAssign variant in JboRelClause |
| ✅ | GOI relative phrases (pe/po/po'e/po'u/ne/no'u) | §8.3 (GOI relative phrases: pe/po/po'e/po'u/ne/no'u) | @ref:grammar.relative_clause_goi | parse_goi_rel handles pe(ne), po, po'e, po'u(no'u) |
| ✅ | Incidental (noi...ku'o) | §8.1, §8.2 (restrictive poi…ku'o; incidental noi…ku'o) | @ref:grammar.relative_clause_noi | Implemented |
| ✅ | Nested relative clauses | §8.4 (zi'e — multiple relative clauses) | @ref:grammar.relative_clauses_zie_chain | ke'a subscripting via antecedent_stack; ZIhE chain support |
| ✅ | Nested relative clauses | §8.10; §8.1, §8.10 (ke'a relative pro-sumti; nested relative clauses) | @ref:semantic.subsent_to_pred | ke'a subscripting via antecedent_stack; ZIhE chain support |
| ✅ | Restrictive (poi...ku'o) | §8.1–8.4 (relative clauses: poi/noi, zi'e chains) | @ref:grammar.relative_clauses | Implemented |
2.6 Selbri (CLL Ch 5, 11)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Abstraction selbri (NU + bridi + kei) | §11.1 | @ref:grammar.abstraction_selbri_nu_bridi_kei | Implemented |
| ✅ | Asymmetric tanru types (agent-action, property-entity, etc.) | §5.14 | @ref:grammar.asymmetric_tanru_types_agent_action_property_ent | Documented in CLL; tanru left-grouping and bo right-grouping implemented; semantic interpretation follows tertau-dominant model. |
| ✅ | CEI (equality within tanru) | §7.5 | @ref:grammar.cei_equality_within_tanru | Grammar rule selbri_5_selbri_4_cei_selbri_4 (selbri_4 CEI selbri_4); convert_selbri_5 handles BridiBinding; morphology classifies cei as CEI; tests pass. |
| ✅ | Forethought tanru connection (gu'e...gi) | §5.6 | @ref:grammar.forethought_tanru_connection_gu_e_gi | Implemented |
| ✅ | Left-grouping rule | §5.2 | @ref:grammar.left_grouping_rule | Implemented |
| ✅ | Linked sumti (be/bei/be'o) | §5.7 | @ref:grammar.linked_sumti_be_bei_be_o | Implemented |
| ✅ | Logical connection within tanru (je/ja) | §5.6 | @ref:grammar.logical_connection_within_tanru_je_ja | Implemented |
| ✅ | NAhE scalar negation on selbri | §5.12 | @ref:grammar.nahe_scalar_negation_on_selbri | Implemented |
| ✅ | NU abstraction selbri (tanru-unit-2) | §152, §11.1 | @ref:grammar.tanru_unit_2_nu_abstraction | Decomposed nu_prefix_chain + optional kei_optional; joik-jek compound abstractors per CLL §11.12 |
| ✅ | Non-logical connectives within tanru (joi) | §5.6 | @ref:grammar.non_logical_connectives_within_tanru_joi | Implemented |
| ✅ | Pro-bridi (go'i, du) as selbri | §7.6, §7.17 | @ref:grammar.pro_bridi_go_i_du_as_selbri | Implemented |
| ✅ | SE conversion on selbri | §5.11 | @ref:grammar.se_conversion_on_selbri | Implemented |
| ✅ | Simple brivla as selbri | §5.1 | @ref:grammar.simple_brivla_as_selbri | Implemented |
| ✅ | Symmetric tanru types | §5.15 | @ref:grammar.symmetric_tanru_types | Documented in CLL; non-logical connectives within tanru (joi, ce, jo'e, ku'a) handled via TanruConnRel; commutativity/idempotency rules in egglog §5b. |
| ✅ | Tanru composition | §5.2 | @ref:grammar.tanru_composition | Implemented |
| ✅ | Tanru inversion (co) | §5.8 | @ref:grammar.tanru_inversion_co | Implemented |
| ✅ | Tense/negation on selbri | §5.13 | @ref:grammar.tense_negation_on_selbri | Implemented |
| ✅ | ZEI phrasal lujvo tanru-unit-2 | §152, §4.6 | @ref:grammar.tanru_unit_2_zei_any_word | |
| ✅ | bo right-grouping | §5.3 | @ref:grammar.bo_right_grouping | Grammar rule selbri_5_selbri_6_bo_chain (selbri_6 BO selbri_5); convert_selbri_5 handles BO with SBTanru right-grouping. |
| ✅ | ke...ke'e grouping | §5.5 | @ref:grammar.ke_ke_e_grouping | Implemented |
| ✅ | me (sumti to selbri) | §5.10 | @ref:grammar.me_sumti_to_selbri | Implemented |
| ✅ | moi/mei (number to selbri) | §5.11, §18.18 | @ref:grammar.moi_mei_number_to_selbri | Implemented via JboRel::Moi |
2.7 Selbri Place Structure (CLL Ch 9)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Compound conversions (setese) | §9.4 | @ref:grammar.compound_conversions_setese | Documented; relies on single-conversion rules via equality saturation |
| ✅ | FA place tags | §9.3 | @ref:grammar.fa_place_tags | Implemented (nested terms fix applied; see §2.3 notes) |
| ✅ | Multiple conversions stacking | §9.4 | @ref:grammar.multiple_conversions_stacking | Nested PermutedRel (se se, te ve, etc.) handled by double-cancellation rules (§3) and place-swap birewrites for 2-5 place predicates; compound conversions like setese reduce via equality saturation |
| ✅ | Observative (empty x1) | §9.2 | @ref:grammar.observative_empty_x1 | Implemented |
| ✅ | Place omission | §9.2 | @ref:grammar.place_omission | Implemented |
| ✅ | SE conversion (se/te/ve/xe) | §9.4 | @ref:grammar.se_conversion_se_te_ve_xe | Implemented |
| ✅ | Standard bridi form with cu | §9.2 | @ref:grammar.standard_bridi_form_with_cu | Implemented |
| ✅ | convert_fa place mapping | §9.3 | @ref:ast.convert_fa | fa→1…fu→5 and se→2…xe→5 by default; xi subscript overrides base cmavo (CLL §19.6): {fa xi vo}={fo}, {se xi ci}={te} |
2.8a SE conversion AST + type inference (CLL §9.4, §6.8)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | SE/NAhE chain inner tanru_unit_2 dispatch | §9.4, §5.11 | @ref:ast.convert_tanru_unit | convert_tanru_unit(1) dispatch on the node's own alt when it is already tanru_unit_2 / tanru_unit_1_; fixes SE/NAhE chains that pass a leaf tanru_unit_2_brivla child (was TUBrivla(\ |
| ✅ | Type check SE-converted selbri and description place inference | §9.4, §6.8 | @ref:semantic.type_check_converted_selbri | check_prop_type_with_context handles PermutedRel; collect_description_types uses constant term position (reflects bridi-level SE swap) for lo se X typing |
2.8 Pro-sumti and Pro-bridi (CLL Ch 7)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Demonstrative pro-sumti: ti, ta, tu | §7.3 | @ref:grammar.demonstrative_pro_sumti_ti_ta_tu | Implemented |
| ✅ | Personal pro-sumti: mi, do, mi'o, mi'a, ma'a, do'o, ko | §7.2 | @ref:grammar.personal_pro_sumti_mi_do_mi_o_mi_a_ma_a_do_o_ko | Implemented; ko triggers imperative semantics |
| ✅ | Pro-sumti assignment with goi (ko'a goi le gerku) | §7.5 | @ref:grammar.pro_sumti_assignment_with_goi_ko_a_goi_le_gerku | Implemented in jbo_parse.rs: goi assignment stores referent |
| ✅ | SOI reciprocal marker | §7.8 | @ref:grammar.soi_reciprocal_marker | Parsed as Free::SOI in Free enum |
| ✅ | Utterance pro-sumti (di'u-series) | §7.4 | @ref:semantic.utterance-prosumti | di'u/de'u/da'u/di'e/de'e/da'e/dei/do'i classified in AST; utterance_history resolves past/current references |
| ✅ | broda-brodu (pro-bridi variables) | §7.17 | @ref:grammar.broda_brodu_pro_bridi_variables | Implemented; treated as brivla with fixed place structure |
| ✅ | ce'u (lambda variable in ka abstractions) | §7.11 | @ref:grammar.ce_u_lambda_variable_in_ka_abstractions | Implemented in §7 (Abstractions) |
| ✅ | da'o (cancel all pro-sumti/pro-bridi assignments) | §7.13, §19.3 | @ref:grammar.da_o_cancel_all_pro_sumti_pro_bridi_assignments | Implemented in §12 (Text Structure) |
| ✅ | da/de/di quantified variables | §7.9, §16.2 | @ref:grammar.da_de_di_quantified_variables | Implemented in §6 (Quantifiers) |
| ✅ | du (identity relation as pro-bridi) | §7.14 | @ref:grammar.du_identity_relation_as_pro_bridi | Implemented as JboRel::Equal |
| ✅ | go'a-series pro-bridi (go'a-go'o) | §7.12 | @ref:grammar.go_a_series_pro_bridi_go_a_go_o | go'a/go'e/go'o parsed as TUGOhA; bound via set_shunting in parse_statement1 (previous bridi stored). get_bribasti_binding resolves to stored bridi function. |
| ✅ | ke'a relative pro-sumti | §7.10 | @ref:grammar.ke_a_relative_pro_sumti | Implemented in §2.5 (Relative Clauses) |
| ✅ | ko'a-series pro-sumti (ko'a-ko'e, ko'i-ko'o, ko'u) | §7.5 | @ref:grammar.ko_a_series_pro_sumti_ko_a_ko_e_ko_i_ko_o_ko_u | Implemented via goi assignment |
| ✅ | na'e/to'e/no'e pro-bridi (scalar pro-bridi) | §7.15 | @ref:grammar.na_e_to_e_no_e_pro_bridi_scalar_pro_bridi | Parsed as NAhE_clause in morphology; scalar negation handled via Selbri3::ScalarNegatedSB and JboRel::ScalarNegatedRel in semantic processing. |
| ✅ | ri-series anaphoric pro-sumti (ri, ra, ru) | §7.6 | @ref:grammar.ri_series_anaphoric_pro_sumti_ri_ra_ru | Implemented; ri/ra/ru refer to previous sumti |
| ✅ | vo'a-series reflexive pro-sumti (vo'a, vo'e, vo'i, vo'o, vo'u) | §7.8 | @ref:grammar.vo_a_series_reflexive_pro_sumti_vo_a_vo_e_vo_i_v | Implemented via SumtiAtom::MainBridiSumbasti(n); vo'a=1, vo'e=2, vo'i=3, vo'o=4, vo'u=5. Substitution transforms replace placeholders with actual terms in add_arg(). |
| ✅ | zo'e / mo'e / zo'u / co'e indefinite pro-sumti/bridi | §7.7 | @ref:grammar.zo_e_mo_e_zo_u_co_e_indefinite_pro_sumti_bridi | Implemented; zo'e = unspecified sumti |
| ✅ | zo'e-series (zo'e, zo'u, zo'ei, soi) | §7.7 | @ref:grammar.zo_e_series_zo_e_zo_u_zo_ei_soi | Implemented |
3.1 Spatial Tenses (CLL Ch 10)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Compound spatial tenses | §10.3 | @ref:semantic.compound_spatial_tenses | Implemented |
| ✅ | FAhA directional tenses (zu'a, ri'u, ga'u, etc.) | §10.2 | @ref:semantic.faha_directional_tenses_zu_a_ri_u_ga_u_etc | Implemented |
| ✅ | Movement tenses (mo'i + direction) | §10.8 | @ref:semantic.movement_tenses_mo_i_direction | Implemented |
| ✅ | VA distance tenses (vi, va, vu) | §10.2 | @ref:semantic.va_distance_tenses_vi_va_vu | Implemented |
| ✅ | VEhA space intervals (ve'i, ve'a, ve'u) | §10.5 | @ref:semantic.veha_space_intervals_ve_i_ve_a_ve_u | Implemented |
| ✅ | VIhA dimensionality (vi'i, vi'a, vi'u) | §10.7 | @ref:semantic.viha_dimensionality_vi_i_vi_a_vi_u | Implemented — Earley syntax conversion preserves surface VIhA cmavo as tense cmavo, so vi'i/vi'a/vi'u remain distinct in semantic tags |
3.2 Temporal Tenses (CLL Ch 10)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Event contours (ZAhO: pu'o, ca'o, ba'o, co'a, etc.) | §10.10 | @ref:semantic.event_contours_zaho_pu_o_ca_o_ba_o_co_a_etc | Implemented |
| ✅ | Interval properties (TAhE: di'i, na'o, ru'i, ta'e) | §10.9 | @ref:semantic.interval_properties_tahe_di_i_na_o_ru_i_ta_e | Implemented |
| ✅ | PU directional tenses (pu, ca, ba) | §10.4 | @ref:semantic.pu_directional_tenses_pu_ca_ba | Implemented |
| ✅ | Quantified tenses (roi, re'u) | §10.9 | @ref:semantic.quantified_tenses_roi_re_u | Implemented |
| ✅ | Sub-events (pi'u cross product) | §10.21 | @ref:semantic.sub_events_pi_u_cross_product | Implemented |
| ✅ | Whole interval markers (ze'e, ve'e) | §10.5 | @ref:semantic.whole_interval_markers_ze_e_ve_e | Implemented |
| ✅ | ZEhA time intervals (ze'i, ze'a, ze'u) | §10.5 | @ref:semantic.zeha_time_intervals_ze_i_ze_a_ze_u | Implemented |
| ✅ | ZI distance tenses (zi, za, zu) | §10.4 | @ref:semantic.zi_distance_tenses_zi_za_zu | Implemented |
3.3 Aspect & Modality (CLL Ch 10)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | CAhA (actual/potential/capable) | §10.19 | @ref:semantic.caha_actual_potential_capable | Implemented |
| ✅ | CUhE metatension | §10.24 | @ref:semantic.cuhe_metatension | Documented in egglog_rules.egg §14b; QTruthModal for tense questions |
| ✅ | KI sticky tenses | §10.13 | @ref:semantic.ki_sticky_tenses | Implemented |
| ✅ | Story time conventions | §10.14 | @ref:semantic.story_time_conventions | Tense defaults to context-dependent (§10.1); story time handled via narrative tense (pu/ca/ba) sequence in connected sentences. |
| ✅ | Tenses as sumtcita (tagged sumti) | §10.12 | @ref:semantic.tenses_as_sumtcita_tagged_sumti | parse_tag_helper converts syntax tags to JboTag for modal/tense application |
| ✅ | Vague intervals and non-specific tenses (aorist property) | §10.6 | @ref:semantic.vague_intervals_and_non_specific_tenses_aorist_p | Implicit — tense is optional and context-dependent; no specific implementation needed |
3.4 BAI Modal Tags (CLL Ch 9)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | BAI cmavo (65 predefined modals) | §9.6, §9.17 | @ref:semantic.bai_cmavo_65_predefined_modals | Implemented |
| ✅ | FIhO selbri FEhU custom modals | §9.5 | @ref:semantic.fiho_selbri_fehu_custom_modals | Implemented |
| ✅ | NAI + BAI contradictory negation | §9.13 | @ref:semantic.nai_bai_contradictory_negation | Implemented |
| ✅ | NAhE + BAI scalar negation | §9.13 | @ref:semantic.nahe_bai_scalar_negation | NAhE parsed as NAhE_clause; applied to BAI tags via DecTagUnit::DecTagUnitMk in tag conversion; scalar negation of modal tags handled in parse_tag_helper. |
| ✅ | SE conversion of BAI | §9.6 | @ref:semantic.se_conversion_of_bai | Implemented |
| ✅ | Sticky modals (ki) | §9.14 | @ref:semantic.sticky_modals_ki | Implemented |
| ✅ | do'e (vague modal) | §9.6 | @ref:semantic.do_e_vague_modal | Implemented |
3.5 Modal Connections (CLL Ch 9)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Afterthought modal connection (.iBAIbo) | §9.7, §9.8 | @ref:semantic.afterthought_modal_connection_ibaibo | Implemented |
| ✅ | Bridi-tail modal connection | §9.8 | @ref:semantic.bridi_tail_modal_connection | CLL §9.8: modals connecting bridi-tails — bridi-tail modal tags parsed via Tagged/TaggedNoTerm; applied to bridi-tail in parse_bridi_tail with modal composition. |
| ✅ | Causal modals (ri'a, ki'u, mu'i, ni'i) | §9.7 | @ref:semantic.causal_modals_ri_a_ki_u_mu_i_ni_i | Implemented |
| ✅ | Comparison (mau/me'a + BAI) | §9.10 | @ref:semantic.comparison_mau_me_a_bai | mau/me'a recognized in morphology as comparative BAI tags; parsed via parse_tag_helper as modal tags with comparison semantics. |
| ✅ | Convert Earley tag to syntax Tag | §971–972 | @ref:ast.convert_tag | convert_tag walks tense_modal / simple_tense_modal parse nodes |
| ✅ | Convert simple_tense_modal parse tree to DecoratedTagUnit | §971–972 | @ref:ast.convert_simple_tense_modal | Walks CLL §972 compositional simple_tense_modal and time/space/interval-property subtrees |
| ✅ | Forethought modal connection (BAI+gi) | §9.8 | @ref:semantic.forethought_modal_connection_bai_gi | Implemented |
| ✅ | JAI modal conversion | §9.12 | @ref:semantic.jai_modal_conversion | Implemented |
| ✅ | Logical connection between modals | §9.15 | @ref:semantic.logical_connection_between_modals | CLL §9.15: connecting modal sumti with logical connectives — modal sumti parsed via ConnectedTag in JboTag; logical composition handled in jbo_parse parse_tag_helper. |
| ✅ | Mixed modal-logical connection | §9.11 | @ref:semantic.mixed_modal_logical_connection | CLL §9.11: mixing logical connectives with modal tags — modal tags parsed as DecTagUnit; logical connectives handled via conn_to_fol; composition in jbo_parse via do_modal_helper. |
| ✅ | Modal relative phrases (pe/ne + BAI) | §9.10 | @ref:semantic.modal_relative_phrases_pe_ne_bai | Documented in egglog_rules.egg §18; parser handles via parse_goi_rel with TagRel |
| ✅ | Simple tense and modal cmavo (PU/ZI/FAhA/VA/ZAhO/ZEhA/BAI/…) | §971–972, §1030–1051 | @ref:grammar.simple_tense_modal | CLL §972 compositional tense_group + time/space/interval-property non-terminals. |
| ✅ | Sumti modal connection (forethought/afterthought) | §9.8 | @ref:semantic.sumti_modal_connection_forethought_afterthought | CLL §9.8: modal sumti connected with logical connectives — sumti modal tags parsed via Tagged/TaggedNoTerm; connection handled in jbo_parse parse_terms with modal composition. |
| ✅ | Termset modal connection (nu'i...nu'u) | §9.8 | @ref:semantic.termset_modal_connection_nu_i_nu_u | CLL §9.8: modals within termsets — nu'i/nu'u recognized in morphology; termset modals parsed as structural markers in egglog_rules.egg §17. |
| ✅ | fai tag | §9.3 | @ref:semantic.fai_tag | Implemented |
3.6 Complex Tense Constructs (remaining)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Explicit magnitudes (termset after tense/modal tag) | §10.25 | @ref:semantic.s8_2_explicit_magnitudes_termset_after_tag | CLL §10.25: tag+nu'i termset after selbri; la'u+mekso quantity term via linked sumti (BE→BE_clause mapping + elidable BEhO) |
| ✅ | Subordinate bridi tense semantics | §10.15 | @ref:semantic.s8_2_subordinate_bridi_tense_semantics | reference_point_stack on abstraction and relative-clause subsentences; nau clears stack; WithEventAs(BridiEvent) before tense tags |
4.1 Logical Connectives (CLL Ch 14)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | AST: sumti_2 left-grouping joik-ek connections | §14.6, §92 | @ref:ast.convert_sumti_2 | Handles left-grouping sumti_2 [joik-ek sumti-3] chains and the base sumti_2_sumti_3 passthrough. |
| ✅ | Afterthought bridi connection (ijeks) | §14.4 | @ref:semantic.afterthought_bridi_connection_ijeks | Implemented |
| ✅ | Connective rule expansion (ek/jek/joik/gihek) | §802, §805, §806, §818 | @ref:grammar.connective_rule_expansion_ek_jek_joik_gihek | Full [NA] [SE] cmavo [NAI] enumeration per CLL formal grammar; eks=A (sumti), jeks=JA (tanru/bridi), joiks=JOI and BIhI (non-logical), giheks=GIhA (bridi-tail). Per-cmavo JOI semantics in connectives.rs + egglog_rules.egg. |
| ✅ | Forethought bridi connection (geks) | §14.5 | @ref:semantic.forethought_bridi_connection_geks | Implemented |
| ✅ | Forethought grouping (ge...gi nesting) | §14.7 | @ref:semantic.forethought_grouping_ge_gi_nesting | Forethought connectives unambiguously scope |
| ✅ | Forethought sumti connection (geks) | §14.6 (forethought sumti connection via geks) | @ref:grammar.sumti_1 | Implemented |
| ✅ | Left-grouping rule | §14.8 | @ref:semantic.left_grouping_rule | Implemented |
| ✅ | Logical connective truth functions (And/Or/Impl/Equiv) | §14.5–14.6 | @ref:semantic.conn_to_fol | Ports tersmu connToFOL; affix encoding matches Lojban.pappy (b1=!NA, b2=!NAI) |
| ✅ | More than two propositions (associativity of connectives) | §14.7 | @ref:semantic.more_than_two_propositions_associativity_of_conn | Left-grouping handles associativity |
| ✅ | Sumti connection (eks) | §14.6 (sumti connection via joik_ek = joik | ek) | @ref:ast.convert_joik_ek |
| ✅ | Sumti connection (eks) | §14.6 (sumti connection via eks) | @ref:grammar.sumti_3 | Implemented |
| ✅ | Sumti logical connectives (eks) | §14.6, §802 | @ref:ast.convert_ek | A-selma'o eks for sumti connection via connectives::parse_ek_connective; NA/SE/NAI affixes per CLL §802. |
| ✅ | bo grouping for connectives | §14.8 | @ref:semantic.bo_grouping_for_connectives | Implemented |
| ✅ | ke...ke'e for sumti/bridi-tail grouping | §14.8 | @ref:semantic.ke_ke_e_for_sumti_bridi_tail_grouping | Implemented |
| ✅ | tu'e...tu'u parentheses | §14.8 | @ref:semantic.tu_e_tu_u_parentheses | Implemented |
4.2 Gihek (Bridi-tail connection) (CLL Ch 14)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Forethought bridi-tail connection (ge...gi as bridi-tail) | §14.10 | @ref:semantic.forethought_bridi_tail_connection_ge_gi_as_bridi | Forethought sentence pairs can function as bridi-tails |
| ✅ | Gihek afterthought (GIhA) | §14.3 | @ref:semantic.gihek_afterthought_giha | Implemented |
| ✅ | Gihek forethought (gik) | §14.5 | @ref:semantic.gihek_forethought_gik | Implemented |
| ✅ | Multiple gihek compound bridi | §14.10 | @ref:semantic.multiple_gihek_compound_bridi | Left-grouping with bo override; ke...ke'e grouping for bridi-tails |
| ✅ | Tail-terms shared across gihek | §14.9 | @ref:semantic.tail_terms_shared_across_gihek | CLL §14.9: Grammar rule bridi_tail_connected added; semantic expansion applies tail-terms to both bridi-tails |
4.3 Non-Logical Connectives (CLL Ch 14)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Extract raw joik/jek/ek connective text from parse tree | §14.6, §14.14–14.16, §18.17 | @ref:ast.extract_joik_jek_text | Collects all leaf words in order so that multi-word forms such as 'ga'o bi'o ke'i' and 'je nai' are preserved. |
| ✅ | Forethought joiks (joigiks) | §14.15 | @ref:semantic.forethought_joiks_joigiks | Documented in egglog_rules.egg §22; parsed via gik grammar rules (earley_word_grammar.egg); semantic composition handled in jbo_parse.rs joik_to_fol. |
| ✅ | GAhO endpoint inclusion/exclusion | §14.16 | @ref:semantic.gaho_endpoint_inclusion_exclusion | Parsed as PNonLog with composite keys (e.g., \ |
| ✅ | Interval connectives (bi'i, bi'o, mi'i) | §14.16 | @ref:semantic.interval_connectives_bi_i_bi_o_mi_i | Commutativity/idempotency rules in §2c + §16. jbo_prop: Prop::NonLogConnected used for interval connectives |
| ✅ | Joik per-cmavo classification (JoikedTerms) | §14.14–14.16 | @ref:semantic.joik_classification_per_cmavo | connectives::classify_joik + JoikKind per CLL §14.14 table; typed_dictionary and jbo_prolog use selma'o-based classification instead of hardcoded ce/joi strings. |
| ✅ | Non-logical connection within tanru | §14.14 | @ref:semantic.non_logical_connection_within_tanru | Implemented (joi, ce, jo'e, ku'a) |
| ✅ | Non-logical joik connectives (per-cmavo JOI semantics) | §14.6, §14.14–14.16 | @ref:ast.convert_joik | JOI/BIhI joiks classified via connectives::classify_joik (selma'o lookup); each cmavo has distinct sumti semantics per CLL §14.14 table. No empty-text default. |
| ✅ | Non-logical joik semantics (per-cmavo JOI expansion) | §14.14–14.16 | @ref:semantic.joik_to_fol_per_cmavo | Per-cmavo classification via connectives::classify_joik; ConnQuestion for je'i/gi'i/ge'i/gu'i; NonLogConnected otherwise with egglog per-cmavo rules. |
| ✅ | ce (set \ | §14.14 | @ref:semantic.ce_set_and | Implemented with commutativity/idempotency rules |
| ✅ | ce'o (sequence \ | §14.14 | @ref:semantic.ce_o_sequence_and | Parsed as PNonLog(\ |
| ✅ | fa'u (respectively) | §14.14 | @ref:semantic.fa_u_respectively | Parsed as PNonLog(\ |
| ✅ | jo'u (joint consideration) | §14.14 | @ref:semantic.jo_u_joint_consideration | CLL 14.14 — egglog rules for commutativity/idempotency in §2; parsed as PNonLog via joik grammar rule; jo'u classified as JA cmavo in morphology |
| ✅ | joi (mass \ | §14.14 | @ref:semantic.joi_mass_and | Implemented with commutativity/idempotency rules |
4.4 Termset Connection (CLL Ch 14)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Forethought termset (nu'i...nu'u) | §14.11 | @ref:semantic.forethought_termset_nu_i_nu_u | NUhI/NUhU structural markers parsed; termset grouping handled by parser which flattens terms into surrounding context |
| ✅ | PEhE prefix for termset logical connection | §14.11 | @ref:semantic.pehe_prefix_for_termset_logical_connection | PEhE structural markers parsed; PEhE + joik-jek creates logical term connection via convert_terms |
| ✅ | ce'e termset separator | §14.11 | @ref:semantic.ce_e_termset_separator | Parsed as PNonLog(\ |
4.5 Tensed Connectives (CLL Ch 10, 14)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Non-logical tense connection (ce'o between tenses) | §10.17 | @ref:semantic.non_logical_tense_connection_ce_o_between_tenses | ce'o recognized as PNonLog(\ |
| ✅ | Tensed logical connectives (.ijebabo) | §10.17 | @ref:semantic.tensed_logical_connectives_ijebabo | Implemented |
4.6 Connective Questions (CLL Ch 14)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Connective questions (ji, ge'i, gi'i, gu'i, je'i) | §14.13 | @ref:semantic.connective_questions_ji_ge_i_gi_i_gu_i_je_i | Semantic representation (ConnQuestion variant in Prop) + PConnQuestion schema + lowering. Grammar path wired: joik_to_fol detects question cmavo (ji, je'i, gi'i, ge'i, gu'i) and produces ConnQuestion; convert_gihek routes gi'i as JboConnJoik. 7 unit tests in conn_question_tests. |
| ✅ | Summary of logical connective uses | §14.21 | @ref:semantic.summary_of_logical_connective_uses | All truth functions covered in §1 |
| ✅ | Sumtcita with logical connectives | §14.17 | @ref:semantic.sumtcita_with_logical_connectives | CLL §14.17: modal/tense tags combined with logical connectives — modal tags parsed via DecTagUnit; logical connectives composed via conn_to_fol in jbo_parse. |
| ✅ | Tenses and modals with logical connection | §14.18 | @ref:semantic.tenses_and_modals_with_logical_connection | CLL §14.18: logical connectives between modal/tense sumti — modal sumti parsed via ConnectedTag; logical composition in jbo_parse. |
| ✅ | Truth questions (xu) | §14.13 | @ref:semantic.truth_questions_xu | Parsed; QTruthModal wrapping in semantic layer; PConnQuestion schema in egglog_schema.egg; lowering emits PModal(QTruthModal, P); extraction preserves question marker. Questions are opaque — no rewrite rules needed. |
| ✅ | bridi-tail sumtcita with connectives | §14.19 | @ref:semantic.bridi_tail_sumtcita_with_connectives | Brdi-tail modal tags with logical connectives parsed via ConnectedTag in JboTag; composition handled in jbo_parse. |
| ✅ | selbri sumtcita with connectives | §14.20 | @ref:semantic.selbri_sumtcita_with_connectives | Selbri modal tags with logical connectives parsed via ConnectedTag in JboTag; composition handled in jbo_parse. |
5.1 Bridi Negation (CLL Ch 15)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Bridi na / tense-modal order normalization | §5.13, §15.6, §15.7 | @ref:feature.modal-neg-lift | Egglog §6: PU(¬P) = ¬PU(P) for TaggedNoTerm, Tagged, WithEventAs; bridi_tail_3_na_chain in earley_to_syntax; check_equiv + unit tests |
| ✅ | Multiple na cancellation | §15.2 | @ref:semantic.multiple_na_cancellation | Implemented |
| ✅ | na (contradictory bridi negation) | §15.2 | @ref:semantic.na_contradictory_bridi_negation | Implemented |
| ✅ | naku in prenex | §15.2, §16.9 | @ref:semantic.naku_in_prenex | Negation push-through in §7 + partial distribution in §7c handle this |
5.2 Scalar Negation (CLL Ch 15)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Scale specification (ci'u, teci'e, etc.) | §15.5 | @ref:semantic.scale_specification_ci_u_teci_e_etc | Recognized as BAI modals; handled by semantic analysis |
| ✅ | na'e (other-than) | §15.3 | @ref:semantic.na_e_other_than | Implemented |
| ✅ | no'e (neutral point) | §15.3 | @ref:semantic.no_e_neutral_point | Implemented with 11 rewrite rules + 4 tests |
| ✅ | to'e (polar opposite) | §15.3 | @ref:semantic.to_e_polar_opposite | Implemented (partial semantics behind feature flag) |
5.3 Sumti Negation (CLL Ch 15, 16)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | na'ebo, to'ebo, no'ebo, je'abo | §15.6, §6.10 | @ref:semantic.na_ebo_to_ebo_no_ebo_je_abo | Documented in egglog_rules.egg §2b |
| ✅ | no + descriptor (zero quantifier) | §15.6, §16.3 | @ref:semantic.no_descriptor_zero_quantifier | Implemented |
5.4 nai Suffix Negation (CLL Ch 15)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | nai on attitudinals (polar) | §13.7 | @ref:semantic.nai_on_attitudinals_polar | nai suffix parsed and split off from indicator_cmavo; when nai=true, indicator_bridi_tail returns None (negated indicator produces no side-effect bridi). |
| ✅ | nai on interval modifiers (scalar) | §15.7 | @ref:semantic.nai_on_interval_modifiers_scalar | Implemented |
| ✅ | nai on non-logical connectives (scalar) | §15.7 | @ref:semantic.nai_on_non_logical_connectives_scalar | Implemented |
| ✅ | nai on tenses/modals (contradictory) | §15.7 | @ref:semantic.nai_on_tenses_modals_contradictory | Implemented |
5.5 Affirmation (CLL Ch 15)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | ja'a (bridi affirmation) | §15.9 | @ref:semantic.ja_a_bridi_affirmation | Implemented §4b with 7 rewrite rules + 3 tests |
| ✅ | je'a (scalar affirmation) | §15.9 | @ref:semantic.je_a_scalar_affirmation | Implemented §4c with 7 rewrite rules |
6.1 Variables (CLL Ch 16)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Bound variable binding and scoping | §16.2, §16.4 | @ref:semantic.bound_variable_binding_and_scoping | Implemented |
| ✅ | Number questions (xo) | §16.5 | @ref:semantic.number_questions_xo | Implemented — xo classified as PA in morphology; terp_jbo_mex_as_quantifier_from_jbo returns QuestionQuantifier; egglog lowers as (QuestionQ) |
| ✅ | Restricted claims (da poi broda ku'o) | §16.4 | @ref:semantic.restricted_claims_da_poi_broda_ku_o | Implemented — relative clauses restrict variables |
| ✅ | bu'a, bu'e, bu'i (selbri variables) | §16.13 | @ref:semantic.bu_a_bu_e_bu_i_selbri_variables | Implemented — do_buha() in jbo_parse.rs handles quantified selbri variables; RVar in jbo_prop.rs; grammar via TUGOhA(\ |
| ✅ | da, de, di (existentially quantified) | §16.2 | @ref:semantic.da_de_di_existentially_quantified | Implemented |
| ✅ | terp_jbo_mex_as_quantifier_from_jbo | §6.6, §16.2 | @ref:semantic.terp_jbo_mex_as_quantifier | PA digit strings via eval_numeral_string; vei...ve'o and compound mekso via eval_mekso; ro/su'o/xo as logical quantifiers; non-concrete → MexQuantifier |
6.2 Prenex (CLL Ch 16)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Prenex = terms ZOhU | §16.2 | @ref:semantic.prenex_terms_zohu | Implemented |
| ✅ | Prenex across connected sentences | §16.4 | @ref:semantic.prenex_across_connected_sentences | CLL §16.4: Prenex variables persist through connected sentences; scope reset only at new paragraph |
| ✅ | Variable scope persistence | §16.4 | @ref:semantic.variable_scope_persistence | CLL §16.4: Variables persist across sentences until new prenex or paragraph; var_bindings no longer reset per statement |
| ✅ | parse_terms_helper buha-in-prenex |
§16.7, §16.13; §16.7 (prenex term parsing; quantified buha in prenex) | @ref:semantic.parse_terms_helper | Special case for quantified buha in prenex. CLL §16.13: su'o bu'a in a prenex is grammatically a sumti (indefinite description), but indefinite descriptions involving the bu'a-series cannot be imported from the prenex — the relation variable is bound locally via do_buha/rquantify instead of becoming a bridi argument. This is a principled special case forced by second-order predicate logic: bu'a-series are relation variables, not ordinary predicates, so generic prenex term binding does not apply. Anchors: parse_terms_helper (prenex path), parse_tu (non-prenex path under §7.3). — Deviation: special case for quantified buha in prenex |
6.3 Quantifiers (CLL Ch 16)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Exact numbers (pa, re, ci, etc.) | §16.3 | @ref:semantic.exact_numbers_pa_re_ci_etc | Implemented |
| ✅ | Generalized quantifiers | §16.6 | @ref:semantic.generalized_quantifiers | Quantifier parsing handles general forms via PA grammar; ro/su'o/exact numbers implemented; indefinite/subjective/approximate numbers parsed and return None from evaluator. |
| ✅ | Indefinite numbers (so'a through so'u) | §16.6 | @ref:semantic.indefinite_numbers_so_a_through_so_u | Parsed in PA grammar; evaluator returns None (correct for qualitative numbers) |
| ✅ | Quantifier grouping with termsets | §16.7 | @ref:semantic.quantifier_grouping_with_termsets | Quantifiers parsed via PA grammar; termset grouping via nu'i/nu'u structural markers; scope handled in jbo_parse via variable binding. |
| ✅ | ro (universal) | §16.3 | @ref:semantic.ro_universal | Implemented |
| ✅ | su'o (existential) | §16.2 | @ref:semantic.su_o_existential | Implemented |
6.4 Scope & DeMorgan (CLL Ch 16)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | DeMorgan's Law rules | §16.12 | @ref:semantic.demorgan_s_law_rules | Implemented in egglog_rules.egg §1 |
| ✅ | Double negative cancellation | §15.2 | @ref:semantic.double_negative_cancellation | Implemented |
| ✅ | Negation push-through (∀↔∃) | §16.9 | @ref:semantic.negation_push_through | Implemented in §7 |
| ✅ | Scope distinctions with termsets | §16.7 | @ref:semantic.scope_distinctions_with_termsets | Quantifier scope handled via prenex variable binding and FreeIn facts; termset scope via nu'i/nu'u markers; scope resolved in jbo_parse. |
| ✅ | naku negation boundaries | §16.9, §16.11 | @ref:semantic.naku_negation_boundaries | Negation push-through in §7 + partial distribution in §7c handle this. egglog_lower: generate_free_in_facts() + collect_free_in_facts() with 7 helper functions |
7.1 Abstractor Types (CLL Ch 11)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | du'u (predication abstractor) | §11.7 | @ref:semantic.du_u_predication_abstractor | Implemented with double-wrapping rules |
| ✅ | jei (truth-value abstractor) | §11.6 | @ref:semantic.jei_truth_value_abstractor | Implemented with double-wrapping rule |
| ✅ | ka (property abstractor) | §11.4 | @ref:semantic.ka_property_abstractor | Implemented with double-wrapping rules |
| ✅ | li'i (experience abstractor) | §11.9 | @ref:semantic.li_i_experience_abstractor | Implemented with double-wrapping rule |
| ✅ | mu'e (point-event abstractor) | §11.3 | @ref:semantic.mu_e_point_event_abstractor | Implemented with double-wrapping rule |
| ✅ | ni (amount abstractor) | §11.5 | @ref:semantic.ni_amount_abstractor | Implemented with double-wrapping rule |
| ✅ | nu (event abstractor) | §11.2 | @ref:semantic.nu_event_abstractor | Implemented with double-wrapping rules |
| ✅ | pu'u (process abstractor) | §11.3 | @ref:semantic.pu_u_process_abstractor | Implemented with double-wrapping rule |
| ✅ | si'o (concept abstractor) | §11.9 | @ref:semantic.si_o_concept_abstractor | Implemented with double-wrapping rule |
| ✅ | su'u (general abstractor) | §11.9 | @ref:semantic.su_u_general_abstractor | Implemented with double-wrapping rule |
| ✅ | za'i (state abstractor) | §11.3 | @ref:semantic.za_i_state_abstractor | Implemented with double-wrapping rule |
| ✅ | zu'o (activity abstractor) | §11.3 | @ref:semantic.zu_o_activity_abstractor | Implemented with double-wrapping rule |
7.2 Abstractor Features (CLL Ch 7, 11)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Abstractor connectives | §11.12 | @ref:semantic.abstractor_connectives | Implemented — LogConnectedAbstractor and JoiConnectedAbstractor in jbo_syntax.rs; parsed and evaluated in jbo_parse.rs parse_tu() |
| ✅ | Abstractor double-wrapping reduction | §11.1 | @ref:semantic.abstractor_double_wrapping_reduction | Implemented for all 12 abstractors |
| ✅ | Implicit ce'u arity for ka/ni abstractions | §7.11, §11.4 | @ref:semantic.implicit_ce_u_arity_for_ka_ni_abstractions | When ka/ni has no explicit ce'u and no terms, arity defaults to the predicate's place count (position). E.g., lo ka prami → arity 2 (prami has 2 places), ensuring simxu lo ka prami = simxu lo ka ce'u ce'u prami. When terms are present (e.g., le ka mi prami), arity stays 1. Implemented: do_lambdas_min_arity() in parse_m.rs; ka/ni branch in parse_tu calculates min_arity from sub_bridi_state.arglist.position. |
| ✅ | Sumti ellipsis in abstractions | §11.1 | @ref:semantic.sumti_ellipsis_in_abstractions | Sumti can be elided within abstractions — default to zo'e (unspecified) via parse_sumti_atom default handling. kea/ke'e terminators elided per CLL. |
| ✅ | ce'u (abstraction focus variable in ka) | §7.11 | @ref:semantic.ce_u_abstraction_focus_variable_in_ka | LambdaVar implemented in SumtiAtom |
| ✅ | ce'u placement determines property focus | §11.4 | @ref:semantic.ce_u_placement_determines_property_focus | ce'u parsed as LambdaVar in SumtiAtom; marks lambda variable position in ka abstractions; placement in selbri determines property focus. |
| ✅ | jai (abstraction conversion / sumti raising) | §11.10 | @ref:semantic.jai_abstraction_conversion_sumti_raising | Implemented |
| ✅ | kau (indirect question in du'u) | §11.8 | @ref:semantic.kau_indirect_question_in_du_u | SumtiQ implemented in SumtiAtom |
| ✅ | kei elidable terminator | §11.1 | @ref:semantic.kei_elidable_terminator | Implemented |
| ✅ | tu'a (sumti raising) | §11.10 | @ref:semantic.tu_a_sumti_raising | Implemented |
7.3 Event Contour Relationship (CLL Ch 11)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Event type ↔ ZAhO pairing rules | §11.11 | @ref:semantic.event_type_zaho_pairing_rules | Event type abstractors (mu'e/za'i/pu'u/zu'o) and ZAhO contours (co'a/ca'o/co'u etc.) parsed; validate_zaho_abstractor_pairing() added to jbo_parse.rs for CLL §11.11 compliance |
| ✅ | tu_is_buha / do_buha |
§7.6, §7.12, §16.13, §19.6 (bu'a/bu'e/bu'i relation variables; xi subscripts) | @ref:semantic.tu_is_buha | bu'a/bu'e/bu'i are selma'o GOhA pro-bridi bound variables (second-order predicate logic, CLL §16.13). Only three cmavo exist by definition, so the series is hardcoded. Additional variables come from xi subscripts (CLL §19.6): bu'a xi re == bu'e, bu'a xi vo == a fresh 4th relation variable. do_buha maps the vowel (a→1, e→2, i→3) when no xi subscript is present and uses the subscript number directly when one is. |
| ✅ | mu'e with pu'o/ba'o/co'i only | §11.11 | @ref:semantic.mu_e_with_pu_o_ba_o_co_i_only | mu'e (point-event) abstractor parsed; ZAhO contours validated via validate_zaho_abstractor_pairing() |
| ✅ | za'i with specific contours | §11.11 | @ref:semantic.za_i_with_specific_contours | za'i (state abstractor) parsed; ZAhO contours validated via validate_zaho_abstractor_pairing() |
8.1 Tense Conversion (CLL Ch 10)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | NAhE + tense (scalar negation of tense) | §10.18 | @ref:semantic.nahe_tense_scalar_negation_of_tense | NAhE parsed as NAhE_clause; applied to tense via DecTagUnit::DecTagUnitMk; scalar negation of tense handled in parse_tag_helper. |
| ✅ | Subscripted ki (kixipa, multiple reference points) | §10.13 | @ref:semantic.subscripted_ki_kixipa_multiple_reference_points | Grammar: simple_tense_modal_ki_free_xi_number/2 for ki+subscript. TagUnit::KI(Option |
| ✅ | Tense as sumtcita (additional bridi place) | §10.12 | @ref:semantic.tense_as_sumtcita_additional_bridi_place | Implemented |
| ✅ | Tense negation (nai suffix on PU/FAhA/ZAhO) | §10.18 | @ref:semantic.tense_negation_nai_suffix_on_pu_faha_zaho | Implemented |
| ✅ | Tenseless = context-dependent | §10.1 | @ref:semantic.tenseless_context_dependent | Implicit |
8.2 Complex Tense Constructs (CLL Ch 10)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Direction + distance + interval + property | §10.3, §10.5 | @ref:semantic.direction_distance_interval_property | Implemented |
| ✅ | FEhE space interval properties | §10.11 | @ref:semantic.fehe_space_interval_properties | FEhE recognized as tag unit; parsed in DecTagUnit; space interval properties handled alongside VEhA. |
| ✅ | Logical and non-logical connections between tenses | §10.20 | @ref:semantic.logical_and_non_logical_connections_between_tens | Tense connections via logical connectives (je/ja) and non-logical (joi/ce) parsed; composition in jbo_parse. |
| ✅ | Multiple directions (compound spatial) | §10.3 | @ref:semantic.multiple_directions_compound_spatial | Implemented |
| ✅ | Multiple distances | §10.3 | @ref:semantic.multiple_distances | Implemented |
| ✅ | Tense connection afterthought (.ijepu, etc.) | §10.16 | @ref:semantic.tense_connection_afterthought_ijepu_etc | Tense connectives recognized in grammar; parsed via .i + tense cmavo sequence; semantic composition handled in jbo_parse via conn_to_fol. |
| ✅ | Tense connection forethought | §10.17 | @ref:semantic.tense_connection_forethought | Forethought tense connections parsed via gek + tense + gik pattern; semantic composition in jbo_parse via conn_to_fol. |
| ✅ | Tense conversion (JAI) | §10.22 | @ref:semantic.tense_conversion_jai | Implemented |
9.1 Numbers & Punctuation (CLL §18.2–18.4)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Basic digit cmavo (pa-so, no) | §18.2 | @ref:semantic.basic_digit_cmavo_pa_so_no | Parsed as Numeral::PA in MexNumeralString |
| ✅ | Complex number separator (ka'o as separator) | §18.4 | @ref:semantic.complex_number_separator_ka_o_as_separator | ka'o separates real/imaginary parts in numeral strings: re ka'o ci = 2+3i. Standalone ka'o = i. MeksoValue::Complex variant added with full arithmetic (add, sub, mul, div, pow, abs, negate). |
| ✅ | Decimal point (pi) as punctuation | §18.3 | @ref:semantic.decimal_point_pi_as_punctuation | Evaluated in eval_numeral_string |
| ✅ | Fraction slash (fi'u) | §18.3 | @ref:semantic.fraction_slash_fi_u | Evaluated in eval_numeral_string |
| ✅ | Multi-digit numbers (pa re ci = 123) | §18.2 | @ref:semantic.multi_digit_numbers_pa_re_ci_123 | Digit strings parsed into numeral lists |
| ✅ | PA bound quantifiers in LE/LO descriptions (le za'u da, lei za'u da) | §18.8, §6.7 | @ref:grammar.sumti_tail_sumti_tail_1 | sumti_tail_sumti_tail_1 exposes CLL sumti-tail-1 quantifier sumti in descriptions |
| ✅ | Percentage (ce'i) | §18.3 | @ref:semantic.percentage_ce_i | Evaluated in eval_numeral_string |
| ✅ | Repeating decimal (ra'e) | §18.3 | @ref:semantic.repeating_decimal_ra_e | Evaluated in eval_numeral_string |
| ✅ | Signs (ma'u, ni'u) as numbers | §18.3 | @ref:semantic.signs_ma_u_ni_u_as_numbers | Evaluated in eval_numeral_string |
| ✅ | Special numbers (ci'i ∞, ka'o i, pai π, te'o e, fi'u φ) | §18.4 | @ref:semantic.special_numbers_ci_i_ka_o_i_pai_te_o_e_fi_u | Evaluated in eval_numeral_string |
| ✅ | Thousands comma (ki'o) | §18.3 | @ref:semantic.thousands_comma_ki_o | Evaluated in eval_numeral_string |
9.2 Operators & Infix (CLL §18.5, §18.14, §18.24)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Absolute value (cu'a) | §18.5, §18.24 | @ref:semantic.absolute_value_cu_a | Evaluated in eval_mekso: cu'a(x) = |
| ✅ | Basic operators (su'i, vu'u, pi'i, te'a) | §18.5, §18.24 | @ref:semantic.basic_operators_su_i_vu_u_pi_i_te_a | Algebraic rules: commutativity, identity, annihilation, associativity, distributivity; evaluation via eval_mekso. earley_to_syntax: convert_mex, convert_operator, convert_mex_forethought |
| ✅ | Derivative (sa'o) | §18.5, §18.24 | @ref:semantic.derivative_sa_o | Symbolic — returns None from eval_mekso; parsed as OpVUhU in grammar |
| ✅ | Division (fe'i) | §18.5, §18.24 | @ref:semantic.division_fe_i | Algebraic rules: identity, annihilation; evaluated in eval_mekso |
| ✅ | Factorial (ne'o) | §18.5, §18.24 | @ref:semantic.factorial_ne_o | Evaluated in eval_mekso: ne'o(n) = n! (0–20) |
| ✅ | Integral (ri'o) | §18.5, §18.24 | @ref:semantic.integral_ri_o | Symbolic — returns None from eval_mekso (cannot be numerically evaluated); parsed as OpVUhU in grammar |
| ✅ | Logarithm (de'o) | §18.5, §18.24 | @ref:semantic.logarithm_de_o | Evaluated in eval_mekso: de'o(base, x) = log_base(x) |
| ✅ | Negation/additive inverse (va'a) | §18.5, §18.24 | @ref:semantic.negation_additive_inverse_va_a | Evaluated in eval_mekso: va'a(x) = -x |
| ✅ | Non-specific operator (fu'u) | §18.5, §18.24 | @ref:semantic.non_specific_operator_fu_u | Symbolic — returns None from eval_mekso; parsed as OpVUhU in grammar |
| ✅ | Nth root (fe'a) | §18.5, §18.24 | @ref:semantic.nth_root_fe_a | Evaluated in eval_mekso: fe'a(n, x) = x^(1/n) |
| ✅ | Operator precedence (bi'e) | §18.20 | @ref:semantic.operator_precedence_bi_e | Grammar rule operand_bi_e added to earley_word_grammar.egg; convert_operand_bi_e in earley_to_syntax.rs wraps right operand in MexPrecedence; morphology already maps bi'e to BIhE_clause |
| ✅ | Parentheses (vei/ve'o) | §18.5 | @ref:semantic.parentheses_vei_ve_o | Grammar now has explicit VEI/VEhO rules (grammar.mex_2_grouping); convert_mex_2 handles grouping; eval_mekso unwraps MexPrecedence. |
| ✅ | Ratio (pa'i) | §18.5, §18.24 | @ref:semantic.ratio_pa_i | Evaluated in eval_mekso: pa'i(a, b) = a/b |
| ✅ | Reciprocal (fa'i) | §18.5, §18.24 | @ref:semantic.reciprocal_fa_i | Evaluated in eval_mekso: fa'i(x) = 1/x |
| ✅ | Scientific notation (gei) | §18.5, §18.24 | @ref:semantic.scientific_notation_gei | Evaluated in eval_mekso: gei(exp, mantissa [, base=10]) = mantissa × base^exp (CLL §18.14/§18.24) |
| ✅ | Sigma summation (si'i) | §18.5, §18.24 | @ref:semantic.sigma_summation_si_i | Symbolic — returns None from eval_mekso; parsed as OpVUhU in grammar |
9.3 Forethought & Reverse Polish (CLL §18.6, §18.16)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Forethought flag (pe'o) | §18.6 | @ref:semantic.forethought_flag_pe_o | Handled in grammar.mex_2_forethought and grammar.mex_2_forethought_multi grammar rules |
| ✅ | Forethought operators (pe'o ... ku'e) | §18.6 | @ref:semantic.forethought_operators_pe_o_ku_e | Grammar has PEhO/KUhE rules (grammar.mex_2_forethought, grammar.mex_2_forethought_multi); convert_mex_forethought handles evaluation |
| ✅ | Forethought terminator (ku'e) | §18.6 | @ref:semantic.forethought_terminator_ku_e | Handled in grammar.mex_2_forethought and grammar.mex_2_forethought_multi grammar rules |
| ✅ | Reverse Polish (fu'a) | §18.16 | @ref:semantic.reverse_polish_fu_a | MexReversePolish variant in AST; eval_mekso converts to Operation; fully working |
| ✅ | boi (numeral/lerfu terminator) | §18.6 | @ref:semantic.boi_numeral_lerfu_terminator | Classified in morphology; typically elided in CLL — parser handles numeral/lerfu termination through grammar structure without requiring explicit BOI |
9.4 Non-decimal & Compound Bases (CLL §18.10)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Base operator (ju'u) | §18.10 | @ref:semantic.base_operator_ju_u | Evaluated in eval_mekso: ju'u(base, number) interprets number in base |
| ✅ | Compound base point (pi'e) | §18.10 | @ref:semantic.compound_base_point_pi_e | Recognized in eval_numeral_string; returns None (not evaluatable as single number) |
| ✅ | Hex digits (dau, fei, gai, jau, rei, vai) | §18.10 | @ref:semantic.hex_digits_dau_fei_gai_jau_rei_vai | dau parsed in PA grammar; hex evaluation in pa_to_hex_digit |
9.5 Vectors & Matrices (CLL §18.15)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Matrix column combiner (sa'i) | §18.15 | @ref:semantic.matrix_column_combiner_sa_i | Evaluates to Matrix when matrix-eval feature enabled |
| ✅ | Matrix row combiner (pi'a) | §18.15 | @ref:semantic.matrix_row_combiner_pi_a | Evaluates to Matrix when matrix-eval feature enabled |
| ✅ | Vector start (jo'i) | §18.15 | @ref:semantic.vector_start_jo_i | Grammar has JOhI support; evaluation returns Vector when matrix-eval enabled |
| ✅ | Vector/matrix terminator (te'u) | §18.15 | @ref:semantic.vector_matrix_terminator_te_u | Parsed in TEhU grammar rules |
9.6 Indefinite & Approximate Numbers (CLL §18.8–18.9)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | All-but (da'a) | §18.8 | @ref:semantic.all_but_da_a | Parsed in PA grammar; evaluator returns None |
| ✅ | Approximate (ji'i) | §18.9 | @ref:semantic.approximate_ji_i | Parsed in PA grammar; evaluator returns None |
| ✅ | At least (su'o) — as number | §18.8 | @ref:semantic.at_least_su_o_as_number | Parsed in PA grammar; evaluator returns None (also used as existential quantifier) |
| ✅ | At most (su'e) | §18.8 | @ref:semantic.at_most_su_e | Parsed in PA grammar; evaluator returns None |
| ✅ | Fractional indefinites (piro, piso'a–piso'u, pino'o) | §18.8 | @ref:semantic.fractional_indefinites_piro_piso_a_piso_u_pino_o | pi + indefinite number combos parsed in PA grammar; evaluator returns None (correct for qualitative/compound indefinite numbers). |
| ✅ | Indefinite numbers (so'a–so'u) | §18.8 | @ref:semantic.indefinite_numbers_so_a_so_u | Parsed in PA grammar; evaluator returns None (correct for qualitative numbers) |
| ✅ | Less than (me'i) | §18.8 | @ref:semantic.less_than_me_i | Parsed in PA grammar; evaluator returns None |
| ✅ | More than (za'u) | §18.8 | @ref:semantic.more_than_za_u | Parsed in PA grammar; evaluator returns None |
| ✅ | PA quantifier with explicit boi in sumti | §6.6, §18.6, §18.8 | @ref:semantic.quantifier_num_boi | quantifier_num_boi per CLL number /BOI#/; za'u boi da valid; za'u boi re not CLL bound-quantifier form (use za'u re) — @ref:semantic.invalid_approx_boi_digit_split |
| ✅ | Reject approx-prefix boi digit split (post-CFG filter) | §18.6, §18.8 | @ref:semantic.invalid_approx_boi_digit_split | boi splits PA strings (cf. re boi ci); CLL bound quantifiers use za'u re not za'u boi re |
| ✅ | Subjective numbers (rau, du'e, mo'a) | §18.8 | @ref:semantic.subjective_numbers_rau_du_e_mo_a | Parsed in PA grammar; evaluator returns None |
| ✅ | Typical number (no'o) | §18.8 | @ref:semantic.typical_number_no_o | Parsed in PA grammar; evaluator returns None |
9.7 Mekso Selbri & Conversions (CLL §18.7, §18.11, §18.18–18.19)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | AST: mex_1 operator application (left-recursive and flat) | §18.17 | @ref:ast.convert_mex_1 | Handles both flat (mex_2 operator mex_2) and left-recursive (mex_1 operator mex_2) operator application, including mex_1_atom as left operand. |
| ✅ | AST: operand dispatcher (quantifier, lerfu, NIhE, etc.) | §18.17 | @ref:ast.convert_operand | Dispatches operand_1 through operand_3 variants, including direct operand_quantifier quantifiers and LAhE/NAhE wrappers. |
| ✅ | Forethought mekso (pe'o...ku'e) | §18.6 | @ref:semantic.forethought_mekso_pe_o_ku_e | Grammar has PEhO/KUhE rules; convert_mex_forethought handles evaluation |
| ✅ | Interval connective use in mekso | §18.5 | @ref:semantic.interval_connective_use_in_mekso | bi'i/bi'o used in mekso context — parsed via interval connective grammar rules; conversion handles interval operands. |
| ✅ | MOhE sumti-to-operand (mo'e) in mekso bridi | §18.18 | @ref:ast.mohe_sumti_to_operand | CLL Ex. 18.126 (li mo'e re ratcu su'i mo'e re ractu du li re) parses; TEhU is elidable for MOhE sumti. |
| ✅ | Mekso in descriptions (li mekso lo'o) | §18.5 | @ref:semantic.mekso_in_descriptions_li_mekso_lo_o | li...lo'o wraps mekso as sumti |
| ✅ | Mekso selbri (du, mleca, zmadu, etc.) | §18.7, §18.11 | @ref:semantic.mekso_selbri_du_mleca_zmadu_etc | du implemented as JboRel::Equal; comparison selbri (mleca, zmadu) parsed as regular brivla with standard semantics. |
| ✅ | Mekso selbri with place structure (dunli, etc.) | §18.11 | @ref:semantic.mekso_selbri_with_place_structure_dunli_etc | Parsed as regular brivla; comparison selbri (mleca, zmadu) have standard brivla semantics with standard place structures. |
| ✅ | NAhE scalar negation on operators | §18.18 | @ref:semantic.nahe_scalar_negation_on_operators | Grammar: operator_nahe: NAhE_clause operator; conversion: Operator::OpScalarNegated(nahe, inner) in convert_operator |
| ✅ | NIhE selbri-to-operand (ni'e) | §18.18, §18.21 | @ref:ast.ni_e_selbri_to_operand | CLL §18.18: NIhE + selbri + TEhU → MexSelbri via convert_operand_3_2. CLL Ex. 18.125–18.127 (li ni'e ni clani pi'i ni'e ni ganra pi'i ni'e ni condi te'u du li ni'e ni canlu) end-to-end verified in example_18. §18.21: operator→operand composes nu'a (tanru_unit_2_nuha_operator) inside selbri; test_ni_e_nu_a_operator_to_operand. |
| ✅ | NIhE selbri-to-operand (ni'e) grammar rule | §18.18, §18.21 | @ref:grammar.operand_ni_e_selbri | operand_ni_e_selbri; AST convert_operand_3_2 → MexSelbri. CLL Ex. 18.125–18.127 compound chain (li ni'e ni clani pi'i ...) end-to-end verified in example_18. |
| ✅ | Null operand (tu'o) | §18.14, §18.25 | @ref:semantic.null_operand_tu_o | PA tu'o stripped before eval_mekso; infix/RP va'a(tu'o,n) → −n. See semantic.is_null_mex. |
| ✅ | Null operator (ge'a) | §18.14, §18.24 | @ref:semantic.null_operator_ge_a | VUhU ge'a flattened in strip_null_operands / apply_jbo_operator; merges tacked args into gei/pi'a. Ternary gei base via eval_scientific. |
| ✅ | is_null_mex / is_null_op / null_jbo_mex |
§18.14, §18.24, §18.25 | @ref:semantic.is_null_mex | tu'o (PA null operand) and ge'a (VUhU null operator) are unique CLL cmavo — string identity is intentional. strip_null_operands + eval flatten so math evaluator sees only real numeric args (e.g. tu'o va'a mu → -5; ge'a merges into gei/pi'a). |
| ✅ | cu'o (probability selbri) | §18.18 | @ref:semantic.cu_o_probability_selbri | Implemented — same as si'e via MOI_clause handling |
| ✅ | du (equals) | §18.7 | @ref:semantic.du_equals | JboRel::Equal, fully implemented |
| ✅ | ma'o (operand to operator) | §18.6 | @ref:semantic.ma_o_operand_to_operator | Implemented — convert_operator handles MAhO_clause, returns OpMex |
| ✅ | me (sumti to selbri) | §18.7 | @ref:semantic.me_sumti_to_selbri | JboRel::Among, implemented |
| ✅ | me'o (mekso article) | §18.19 | @ref:semantic.me_o_mekso_article | Grammar: operand_mo_e_sumti: cmavo sumti cmavo; conversion: convert_operand_3_3 produces MexSumti |
| ✅ | mekso selbri (dunli, mleca, zmadu, etc.) | §18.7, §18.11 | @ref:semantic.mekso_selbri_dunli_mleca_zmadu_etc | Parsed as regular brivla via TUBrivla; standard brivla semantics applied; comparison selbri have standard place structures. |
| ✅ | mo'e (sumti to operand) | §18.18 | @ref:semantic.mo_e_sumti_to_operand | Implemented — convert_operand_3_3 handles MOhE_clause, returns MexSumti |
| ✅ | moi/mei (number to selbri) | §18.18 | @ref:semantic.moi_mei_number_to_selbri | JboRel::Moi, implemented |
| ✅ | na'ebo/to'ebo on operands | §18.18 | @ref:semantic.na_ebo_to_ebo_on_operands | Grammar: operand_nahe_bo: NAhE_clause BO_clause operand; conversion: convert_operand_nahe_bo produces Mex::QualifiedMex(NAhE_BO(...), inner) |
| ✅ | na'u (selbri to operator) | §18.18 | @ref:semantic.na_u_selbri_to_operator | Implemented — convert_operator handles NAhU_clause, returns OpSelbri |
| ✅ | nu'a (operator to selbri) | §18.19 | @ref:grammar.nu_a_operator_to_selbri | Nests inside ni'e … te'u selbri for §18.21 operator-to-operand chain |
| ✅ | se conversion on operators | §18.18 | @ref:semantic.se_conversion_on_operators | Grammar: operator_se: SE_clause operator; conversion: Operator::OpPermuted(perm, inner) in convert_operator |
| ✅ | si'e (portion selbri) | §18.18 | @ref:semantic.si_e_portion_selbri | Implemented — convert_tanru_unit_2 handles MOI_clause, creates TUMoi with MexLi sumti |
| ✅ | va'e (scale selbri) | §18.18 | @ref:semantic.va_e_scale_selbri | Implemented — same as si'e via MOI_clause handling |
| ✅ | xo (number question) | §18.12 | @ref:semantic.xo_number_question | Implemented — see §6.1 |
9.8 Mekso Evaluator (NEEDED for full semantics)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Algebraic rules enhancement | §18.5, §18.24 | @ref:semantic.algebraic_rules_enhancement | Covers su'i/pi'i/vu'u/fe'i/te'a commutativity, identity, annihilation, associativity; distributivity; te'a special cases |
| ✅ | Basic lerfu words (by., cy., dy., etc.) | §17.2 | @ref:semantic.basic_lerfu_words_by_cy_dy_etc | LerfuString + LerfuChar via ast.lerfu_string_fragment_cia; cy/by and vowel+bu (.abu/.ibu) logshow as letters |
| ✅ | Complex number arithmetic | §18.4 | @ref:semantic.complex_number_arithmetic | ka'o as real/imaginary separator in numeral strings; MeksoValue::Complex variant; full arithmetic (add, sub, mul, div, pow, abs, negate); modulus via cu'a; Display format: re ka'o ci |
| ✅ | Egglog lowering improvement | §18.2 | @ref:semantic.egglog_lowering_improvement | MexNumeralString now evaluated via eval_numeral_string before lowering to egglog |
| ✅ | Lerfu string composition rules | §17.8 | @ref:semantic.lerfu_string_composition_rules | LerfuComposite(Vec) handles composition; jboshow_lerfu_string joins elements; tei...foi wrapping for compound forms. |
| ✅ | Lerfu strings as pro-sumti | §17.9 | @ref:semantic.lerfu_strings_as_pro_sumti | SumtiAtom::LerfuString(Vec) in jbo_syntax.rs; constructed in earley_to_syntax.rs; formatted in jbo_show as lerfu string sumti. |
| ✅ | Lerfu strings as sumti (by cmene, du'e, etc.) | §17.9 | @ref:semantic.lerfu_strings_as_sumti_by_cmene_du_e_etc | SumtiAtom::LerfuString(Vec) serves as lerfu string sumti; used in descriptions (lo/le + lerfu). |
| ✅ | Math expression evaluator | §18.5, §18.24 | @ref:semantic.math_expression_evaluator | eval_mekso(JboMex) -> Option<MeksoValue> implemented in jbo_prop.rs with 45+ unit tests. typed_dictionary: mekso type system (number, operator, operand) |
| ✅ | Matrix arithmetic | §18.15 | @ref:semantic.matrix_arithmetic | su'i/vu'u element-wise, pi'i matmul, te'a power — behind matrix-eval feature |
| ✅ | Matrix row/column combiners | §18.15 | @ref:semantic.matrix_row_column_combiners | pi'a/sa'i — behind matrix-eval feature |
| ✅ | Matrix transpose (re'a) | §18.15 | @ref:semantic.matrix_transpose_re_a | Behind matrix-eval feature — uses peroxide Matrix::transpose |
| ✅ | MeksoValue type | §18.2 | @ref:semantic.meksovalue_type | MeksoValue enum: Scalar(f64), Complex{real,imag}, Vector(Vec), Matrix(peroxide::Matrix) — Matrix/Vector variants behind matrix-eval feature flag |
| ✅ | Numeral string evaluation | §18.2 | @ref:semantic.numeral_string_evaluation | eval_numeral_string(Vec<Numeral>) -> Option<MeksoValue> implemented; returns Scalar for real numbers, Complex for ka'o-separated numbers |
| ✅ | Universal bu (any word → lerfu) | §17.4 | @ref:semantic.universal_bu_any_word_lerfu | LerfuValsi(word) represents word-as-lerfu via bu conversion; formatted as \ |
| ✅ | Vector arithmetic | §18.15 | @ref:semantic.vector_arithmetic | su'i/vu'u element-wise, pi'i scalar multiply, cu'a norm — behind matrix-eval feature |
| ✅ | eval_mekso_scalar helper | §18.5 | @ref:semantic.eval_mekso_scalar_helper | eval_mekso_scalar extracts f64 from MeksoValue::Scalar |
| ✅ | lau (punctuation marks) | §17.7 | @ref:semantic.lau_punctuation_marks | LerfuShift(\ |
| ✅ | me'o for referencing lerfu | §17.10 | @ref:semantic.me_o_for_referencing_lerfu | me'o constructs MexSumti(sumti) in jbo_syntax; grammar: operand_mo_e_sumti handles me'o + sumti. Lerfu strings as mex operands. |
| ✅ | tei...foi compound lerfu words | §17.6 | @ref:semantic.tei_foi_compound_lerfu_words | LerfuComposite(Vec) in Lerfu enum; jbobracket(\ |
11.1 Emotion Indicators (CLL Ch 13)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Relative clause attachment (sumti, names, vocative addressees) | §8.1, §8.2, §8.6, §8.9 (restrictive/incidental relative clauses; attachment to sumti, names, and vocative addressees) | @ref:semantic.parse_rels | Generic relative-clause parser; vocative addressees (selbri→le-description, cmevla→la-name) carry before/after rels merged per §8.9, wired in convert_vocative_free. |
| ✅ | Vocative + cmevla (CLL §32 alt 2) | §6.11, §8.9, §32 | @ref:grammar.free_vocative_cmevla | vocative [relative-clauses] name-word ... # [relative-clauses] /DOhU/ |
| ✅ | Vocative + selbri (CLL §32 alt 1) | §6.11, §8.9, §32 | @ref:grammar.free_vocative_selbri | vocative [relative-clauses] selbri [relative-clauses] /DOhU/ |
| ✅ | Vocative + sumti / bare vocative (CLL §32 alt 3) | §6.11, §32 | @ref:grammar.free_vocative_sumti | vocative [sumti] /DOhU/ — [sumti] empty covers bare coi (Ex 6.62) |
| ✅ | a-series propositional attitudes | §13.3 | @ref:semantic.a_series_propositional_attitudes | Parsed as Free::Indicator; a'o mapped to sruma when indicator_texticules enabled. |
| ✅ | e-series propositional attitudes | §13.3 | @ref:semantic.e_series_propositional_attitudes | Parsed as Free::Indicator; ba'a mapped to sance when indicator_texticules enabled. |
| ✅ | i-series emotions | §13.2 | @ref:semantic.i_series_emotions | Parsed as Free::Indicator; iu mapped to prami when indicator_texticules enabled. |
| ✅ | indicator non-terminal (CLL §413) | §13.1, §13.9, §413 | @ref:grammar.indicator | indicator ~413~ = (UI or CAI) [NAI], or Y, DAhO, FUhO. indicators ~411~ references indicator (single or chain, optional FUhE prefix). |
| ✅ | indicators non-terminal (CLL §411) | §411, §413 | @ref:grammar.indicators | indicators references the CLL indicator non-terminal (§413). |
| ✅ | o-series emotions | §13.2 | @ref:semantic.o_series_emotions | Parsed as Free::Indicator; oi mapped to flibu when indicator_texticules enabled. |
| ✅ | u-series emotions (ui, .ui, etc.) | §13.2 | @ref:semantic.u_series_emotions_ui_ui_etc | Parsed as Free::Indicator; when indicator_texticules enabled, converted to bridi-tail side effects (ui→gleki). |
| ✅ | vocative non-terminal (CLL §415) | §6.11, §13.14, §32, §415 | @ref:grammar.vocative | vocative ~415~ = (COI [NAI]) ... & DOI (one-or-more COI[NAI], optional DOI; |
11.2 Scale System (CLL Ch 13)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Scale markers (cai, sai, ru'e, cu'i) | §13.4 | @ref:semantic.scale_markers_cai_sai_ru_e_cu_i | Parsed as Free::Indicator; mapped in indicator_bridi_tail when indicator_texticules enabled. |
| ✅ | ge'e (non-specific emotion separator) | §13.4 | @ref:semantic.ge_e_non_specific_emotion_separator | Parsed as Free::Indicator; non-specific emotion marker. |
| ✅ | nai negation of scales | §13.4 | @ref:semantic.nai_negation_of_scales | Parsed; nai suffix split off from indicator_cmavo; negated indicator returns None from indicator_bridi_tail. |
11.3 Emotional Categories (CLL Ch 13)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | ro'a through re'e categories | §13.5, §13.6 | @ref:semantic.ro_a_through_re_e_categories | Mapped in indicator_bridi_tail: ro'a (social), ro'e (intellectual), roi (emotional), rei (mystical), ra'a (physical), re'e (spiritual). |
11.5 Vocatives (CLL Ch 6, 13)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | COI vocatives (coi, co'o, etc.) | §6.11, §13.14 | @ref:semantic.coi_vocatives_coi_co_o_etc | Parsed as Free::Vocative(Vec |
| ✅ | DOI general vocative | §6.11, §13.14 | @ref:semantic.doi_general_vocative | Bare DOI via vocative_doi; trailing & DOI via doi_optional. |
| ✅ | Vocative + bare selbri | §6.11, §13.14 | @ref:semantic.vocative_bare_selbri | free_vocative_selbri; addressee built as le-description (descriptor understood per §6.11) with before/after rels merged (§8.9). |
| ✅ | Vocative + name | §6.11, §13.14 | @ref:semantic.vocative_name | free_vocative_cmevla; addressee built as la-name with before/after rels merged (§8.9 Ex 8.78). |
| ✅ | do'u terminator | §6.11, §13.14 | @ref:semantic.do_u_terminator | Elidable /DOhU/ materialized as dohu_optional (empty or DOhU_clause). |
11.6 Miscellaneous (CLL Ch 13, 19)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Attitude contours (bu'o) | §13.10 | @ref:semantic.attitude_contours_bu_o | bu'o mapped in indicator_bridi_tail when indicator_texticules enabled. |
| ✅ | Attitude questions (pei) | §13.10 | @ref:semantic.attitude_questions_pei | pei mapped to casnu in indicator_bridi_tail when indicator_texticules enabled. Parsed as CAI/PEI/UI cmavo. |
| ✅ | Attitude scope markers (fu'e/fu'o) | §19.8 | @ref:semantic.attitude_scope_markers_fu_e_fu_o | Implemented via indicator_scope_depth in ParseState; fu'e opens scope, fu'o closes it (CLL §13.9). |
| ✅ | Attitudinal modifiers (ga'i, le'o, etc.) | §13.7 | @ref:semantic.attitudinal_modifiers_ga_i_le_o_etc | ga'i, le'o, ru'e, cu'i, sai, cai, je'e mapped in indicator_bridi_tail when indicator_texticules enabled. |
| ✅ | Discourse management (ta'o, ra'u, etc.) | §13.13 | @ref:semantic.discourse_management_ta_o_ra_u_etc | ta'o, ra'u mapped in indicator_bridi_tail when indicator_texticules enabled. |
| ✅ | Discursives (ku'i, ji'a, etc.) | §13.12 | @ref:semantic.discursives_ku_i_ji_a_etc | Parsed as Free::Indicator; ku'i, ji'a mapped to bridi-tail side effects when indicator_texticules enabled. |
| ✅ | Empathy (dai) | §13.10 | @ref:semantic.empathy_dai | dai mapped to tavla in indicator_bridi_tail when indicator_texticules enabled. |
| ✅ | Erasure (si, sa, su) | §19.13 (SI/SA/SU erasure at morphology level) | @ref:morph.apply_erasure | Implemented via apply_erasure() — pre-parse token erasure between morphology and grammar, per CLL §19.13. ⚠️ PARTIAL: verify SA erases across utterance boundaries. — Deviation: SA utterance-level erasure across boundaries needs verification |
| ✅ | Evidentials (ja'o, ca'e, ba'a, etc.) | §13.11 | @ref:semantic.evidentials_ja_o_ca_e_ba_a_etc | Parsed as Free::Indicator; ja'o, ca'e, ba'a mapped to bridi-tail side effects when indicator_texticules enabled. |
| ✅ | Hesitation (.y.) | §19.14 | @ref:semantic.hesitation_y | .y. recognized as a CmavoNamed in morphology (via earley_morph_rules). Parsed as a cmavo; acts as filler with no semantic content. |
| ✅ | Indicator scope (fu'e/fu'o) | §13.9, §19.8 | @ref:semantic.indicator_scope_fu_e_fu_o | fu'e/fu'o handled in eval_free_with_context: fu'e increments indicator_scope_depth, fu'o decrements. Scope blocks track attitudinal application range. |
| ✅ | Indicator scope resolution | §19.8, §13.9 | @ref:semantic.indicator_scope_resolution | Indicators apply to preceding word by default; split_off_nai extracts nai suffix. When indicator_texticules enabled, converted to bridi-tail side effects with correct scope. |
| ✅ | Indicators on .i (sentence-level attitudes) | §19.8, §13.9 | @ref:semantic.indicators_on_i_sentence_level_attitudes | Parsed via grammar.indicators / grammar.indicator (CLL §411/§413) and grammar.free_to_text_toi rules; scope tracked via indicator_scope_depth in ParseState. |
| ✅ | Questions and answers | §19.5 | @ref:semantic.questions_and_answers | Parsed; QTruthModal for truth questions; ConnQuestion for connective questions; QSumti/QBridi for sumti/bridi questions; full question infrastructure in parse_m.rs |
| ✅ | SEI metalinguistic bridi | §19.12 | @ref:semantic.sei_metalinguistic_bridi | Discursive implemented in Free enum |
| ✅ | SOI reciprocity | §7.8 | @ref:semantic.soi_reciprocity | SOI implemented in Free enum |
| ✅ | Subscripts (xi) | §18.13, §19.6 | @ref:semantic.subscripts_xi | Grammar: free_xi_number (XI mex free) + sumti_6_koha_frees (cmavo free) rules; convert_sumti_6 handles sumti_6_koha_frees with Free::XI(Mex); do_frees resolves xi subscripts via prev_frees lookback; attach_subscript encodes subscript in variable name; full-subscripts feature flag gates implementation. CLL §16.14 compliant. |
| ✅ | TO...TOI parentheticals | §19.12 | @ref:semantic.to_toi_parentheticals | Bracketed implemented in Free enum |
| ✅ | Topic-comment (zo'u) | §19.4 | @ref:semantic.topic_comment_zo_u | Implemented |
| ✅ | Utterance ordinals (mai, mo'o) | §19.7 | @ref:semantic.utterance_ordinals_mai_mo_o | Parsed |
| ✅ | ba'e/za'e emphasis | §19.11 | @ref:semantic.ba_e_za_e_emphasis | ba'e and za'e handled in eval_free_with_context when indicator_texticules enabled — recognized as emphasis markers; structural emphasis preserved through parsing. |
| ✅ | bi'u (new information) | §13.13 | @ref:semantic.bi_u_new_information | Parsed as UI/UI3 cmavo; mapped to indicator_bridi_tail when indicator_texticules enabled. |
| ✅ | da'o (cancel all assignments) | §7.13, §19.3 | @ref:semantic.da_o_cancel_all_assignments | CLL §7.13: da'o cancels all pro-sumti (ko'a, ko'e, etc.) and pro-bridi (go'i, go'e, etc.) bindings; supports variable-specific cancellation with full-subscripts feature |
| ✅ | fa'o (end of text) | §19.15 | @ref:semantic.fa_o_end_of_text | Implemented — FAhO morphology rule, text_1_faho grammar rule, convert_text_1 handles FAhO |
| ✅ | kau (indirect question) | §11.8 | @ref:semantic.kau_indirect_question | SumtiQ implemented in SumtiAtom |
| ✅ | ni'o / no'i paragraph management | §19.3 | @ref:semantic.ni_o_no_i_paragraph_management | Implemented |
| ✅ | ni'oni'o context cancellation | §19.3 | @ref:semantic.ni_oni_o_context_cancellation | CLL §19.3: ni'oni'o cancels pro-sumti (KOhA) and pro-bridi (GOhA) assignments; da'o provides explicit cancellation |
| ✅ | pau (question premarker) | §13.13 | @ref:semantic.pau_question_premarker | Added to indicator_bridi_tail in jbo_parse.rs |
| ✅ | pe'a (figurative language) | §13.13 | @ref:semantic.pe_a_figurative_language | Parsed as UI/UI3 cmavo; mapped to indicator_bridi_tail when indicator_texticules enabled. |
| ✅ | xu (truth question) | §14.13, §15.8 | @ref:semantic.xu_truth_question | Parsed; QTruthModal wrapping in semantic layer; questions are opaque markers |
12. TEXT STRUCTURE (CLL Ch 19)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Paragraph AST conversion (nested paragraph_fragment) | §19.1 | @ref:ast.convert_paragraph | Recurses into nested paragraph_* nodes so paragraph_fragment → fragment_terms converts (e.g. li ni'e nu'a su'i te'u mekso fragments) |
12b.4 Status
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | AST: sumti_6_koha_frees with frees | §6.1–6.15, §7, §19.9–19.10 (sumti-6 alternatives: descriptions, pro-sumti, names, quotations) | @ref:ast.convert_sumti_6 | KOhA via koha_cmavo_to_sumti_atom + morphology selma'o; elided inner sumti uses SumtiAtom::Zohe; quantified descriptions use default_quantified_gadri() |
| ✅ | Grammar: free_xi_number (XI mex free) | §16.14, §18.13 (XI subscript free modifier) | @ref:grammar.free_xi_number | Compound free modifier for xi |
| ✅ | Grammar: sumti_6_koha_frees (cmavo free) | §16.14, §18.13 (KOhA with free modifiers; subscripts via free_xi_number) | @ref:grammar.sumti_6_koha_frees | KOhA with frees (CLL KOhA #) |
| ✅ | Morphology classification | §16.14, §18.13 | @ref:ast.morphology_classification | XI cmavo class recognized |
| ✅ | Tests | §16.14, §18.13 | @ref:ast.tests | 10 tests in subscript_tests.rs |
13.1 Selma'o Catalogue (CLL Ch 20)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Catalogue reference for implementation | §20.1 | @ref:grammar.catalogue_reference_for_implementation | Used as reference during implementation |
| ✅ | Complete selma'o classification | §20.1 | @ref:grammar.complete_selma_o_classification | All selma'o defined in typed_dictionary; morphology classifies cmavo into selma'o |
13.2 Formal Grammar (CLL Ch 21)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | EBNF grammar implementation | §21.1 | @ref:grammar.ebnf_grammar_implementation | Implemented as earley_word_grammar.egg (Earley parser); grammar rules derived from CLL EBNF |
| ✅ | Grammar completeness | §21.1 | @ref:grammar.grammar_completeness | All grammar rules from CLL §21 in earley_word_grammar.egg (CLL CFG + Earley). |
| ✅ | frees non-terminal (CLL # shorthand) |
§9, §32 (# = [free ...]) | @ref:grammar.frees | frees ≡ # = ["[[free ...]]"] (zero-or-more free modifiers). The frees |
14.1 Implemented Rules (Internal egglog rules — no direct CLL mapping)
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | §1 Propositional Logic | §14.1, §14.21, §16.12 (propositional logic rewrite rules) | @ref:egglog.propositional-logic | Double negation, De Morgan, absorption, distributivity, idempotency, commutativity, associativity, implication/equivalence expansion, contrapositive |
| ✅ | §10 Abstraction | §11.1 | @ref:egglog.10_abstraction | Double-wrapping reduction for all 12 abstractors |
| ✅ | §11 ModalRel | §9.6, §9.12 | @ref:egglog.11_modalrel | TaggedNoTerm composition/commutativity |
| ✅ | §11b AppliedRelRel | §9.6 | @ref:egglog.11b_appliedrelrel | Empty terms identity, scalar negation/modal distribution |
| ✅ | §12 Anaphora | §7.5, §7.6 | @ref:egglog.12_anaphora | Variable binding resolved before lowering |
| ✅ | §13 FA-Tag | §9.3 | @ref:egglog.13_fa_tag | Explicit place equivalence |
| ✅ | §14 Mekso Operators | §18.5, §18.24 | @ref:egglog.14_mekso_operators | su'i/pi'i/vu'u/fe'i/te'a algebraic rules |
| ✅ | §14b CUhE Metatension | §10.24 | @ref:egglog.14b_cuhe_metatension | QTruthModal for tense questions; CUhE parsed as TagUnit::CUhE |
| ✅ | §15 GAhO | §14.16 | @ref:egglog.15_gaho | GAhO endpoint semantics: interval degeneracy (ga'o bi'i ga'o p p = p), interval inclusion (closed contains open); composite keys for GAhO+BIhI combinations |
| ✅ | §15 Inner Quantifier | §5.11, §18.18 | @ref:egglog.15_inner_quantifier | moi/mei rules |
| ✅ | §16 Interval Connectives | §14.16 | @ref:egglog.16_interval_connectives | bi'o degeneracy, bi'i/mi'i in §2 |
| ✅ | §16 nu'a Operator-to-Selbri | §18.19 | @ref:egglog.16_nu_a_operator_to_selbri | OperatorRel wrapper for operator-to-selbri conversion; nu'a parsed as TUOperator |
| ✅ | §17 CEI Equality | §7.5 | @ref:egglog.17_cei_equality | BridiBinding in parse |
| ✅ | §17 Forethought Termset | §14.11 | @ref:egglog.17_forethought_termset | nu'i/nu'u structural markers parsed; termset grouping handled by parser which flattens terms into surrounding context |
| ✅ | §18 Modal Relative Phrases | §9.10 | @ref:egglog.18_modal_relative_phrases | pe/ne + BAI handled via parse_goi_rel with TagRel |
| ✅ | §2 Lojban Connectives | §14.14, §14.16 | @ref:egglog.2_lojban_connectives | joi, ce, jo'e, ku'a commutativity/idempotency; ce'o sequence (degeneracy + associativity), ce'e (degeneracy + commutativity), fa'u (degeneracy), bi'o (degeneracy), bi'i/mi'i commutativity |
| ✅ | §2b Scalar Sumti Qualifiers | §6.10, §15.6 | @ref:egglog.2b_scalar_sumti_qualifiers | na'ebo, to'ebo, no'ebo, je'abo parsed as QualifiedTerm with semantic handling |
| ✅ | §3 SE-Conversion | §5.11, §9.4 | @ref:egglog.3_se_conversion | se/te/ve/xe with cancellation and place swaps (2-5 place) |
| ✅ | §4 Scalar Negation | §15.3, §15.4 | @ref:egglog.4_scalar_negation | nai, to'e, na'e normalization; double cancellation; distribution |
| ✅ | §4b ja'a Affirmation | §15.9 | @ref:egglog.4b_ja_a_affirmation | 7 rewrite rules: identity, PNot absorption, idempotency, distribution, cancellation with na'e |
| ✅ | §4c je'a Affirmation | §15.9 | @ref:egglog.4c_je_a_affirmation | 7 rewrite rules: identity, PNot absorption, idempotency, distribution, cancellation with na'e |
| ✅ | §5 Tanru | §5.2, §5.3 | @ref:egglog.5_tanru | Reflexive identity, right-grouping, ScalarNegRel distribution |
| ✅ | §5b Tanru Connective | §5.6, §14.14 | @ref:egglog.5b_tanru_connective | je/ja/joi/jo'e/ku'a commutativity, reflexive identity |
| ✅ | §6 Modal/Tense | §9.6, §10.12 | @ref:egglog.6_modal_tense | NonVeridical idempotency, TaggedNoTerm idempotency, bridi na/tense-modal order lift, modal distribution over PAnd/POr |
| ✅ | §7 Quantifiers | §16.2, §16.9 | @ref:egglog.7_quantifiers | Neg push-through, Exactly-1, distribution, Eet absorption |
| ✅ | §7b naku Negation | §16.9, §16.11 | @ref:egglog.7b_naku_negation | Documented; basic quantifier inversion |
| ✅ | §7c Quantifier Scope Conditional | §16.9, §16.4 | @ref:egglog.7c_quantifier_scope_conditional | 12 conditional rules using FreeIn facts: partial distribution (∧/∨/→), vacuous quantification. FreeIn(i64) function asserted during lowering. |
| ✅ | §8 Equality (du) | §7.14 | @ref:egglog.8_equality_du | Symmetry, reflexivity, transitivity |
| ✅ | §9 Among (lo/le) | §6.2, §6.8 | @ref:egglog.9_among_lo_le | Set-membership with singleton identity |
17. PROLOG EXPORT — tersmu parity
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Convert JboProp to SWI-Prolog clause | — | @ref:prolog.prop_to_prolog | Fact, Rule, Query, Body modes; SWI dialect |
| ✅ | Convert parsed Text to Prolog source | — | @ref:prolog.eval_text_to_prolog | WASM JSON prolog key; eval_text → semantic_results_to_prolog (SWI dialect) |
| ✅ | Convert parsed Text to Prolog source in a chosen dialect | — | @ref:prolog.eval_text_to_prolog_dialect | Dialect-aware: tersmu (examples/*.loj parity) or swi (executable) |
| ✅ | Convert semantic results to Prolog program | — | @ref:prolog.semantic_results_to_prolog | Facts, rules, queries from .i sentences and implications; SWI dialect |
| ✅ | JboOperator → is/2 executable goals (SWI) | — | @ref:prolog.swi_mex_is_goal | Equal with arithmetic mex on one side lowers to X is Expr in SWI dialect |
| ✅ | JboRel coverage (AbsPred/AbsProp/Moi) in Prolog lowerer | — | @ref:prolog.lower_jbo_rel_abs_moi | AST lowerer maps abstractions to Compound(abs, [body, …outer]) (nu, ka, du'u, mei) |
| ✅ | Nested tanru logshow (tersmu < |
§5.2, §5.3 | @ref:prolog.logshow_tanru_nesting | JboShow.hs Tanru: <pstr><rstr>; nested seltau VPred applied to BoundVar yields (_) inside brackets — e.g. sutra tavla cutci → <<sutra(_)><tavla>(_)><cutci>(). Matches archive/tersmu and examples/2.loj. |
| ✅ | Tanru seltau juxtaposition in convert_selbri_3 | §5.7 | @ref:ast.convert_selbri_3_tanru | selbri_3_selbri_3_selbri_4 builds SBTanru(seltau, tertau); fixes dropped seltau (tersmu applySeltau parity) |
| ✅ | Tersmu ----- per-line framing in tersmuLines display | — | @ref:prolog.tersmu_lines_framing | eval_text_to_tersmu_lines: each input line → > {line} / prolog / rewrite / ----- block |
| ✅ | Tersmu ju'a nai / cy no rewrite section in tersmuLines display | — | @ref:prolog.tersmu_rewrite_section | Rewrite section uses canonical jbo_show output (non-veridical modals, Skolem constants) |
| ✅ | Tersmu prolog-section rendering (connectives + shapes) | — | @ref:prolog.tersmu_prolog_section | tersmu_show_prop + normalize_tersmu_connectives: !/-->/<->, nu[…]/ka[…]/<…>…, non-veridical: |
10.1
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | LAU/BY shift stack (zai, ce'a, tau, lau, lo'a/ge'o/…, na'a) | §17.3, §17.5, §17.7, §17.14 | @ref:semantic.lau_by_shift_stack | normalize_lerfu_string applies ga'e/to'a/tau case, lo'a/ge'o/je'o/jo'o/ru'o/zai alphabets, na'a reset; ce'a/lau kept as LerfuShifted. Greek/Cyrillic/Hebrew Latin→glyph maps from CLL §17.16–17.18. End-to-end: me'o ga'e .abu, me'o ge'o ty., me'o tau sy. .ibu. |
| ✅ | Non-Lojban alphabets (ge'o, je'o, etc.) | §17.5 | @ref:semantic.non_lojban_alphabets_ge_o_je_o_etc | BY alphabet shifts via LerfuShift + normalize_lerfu_string Latin→Greek/Hebrew/Cyrillic glyph maps (CLL §17.16–17.18). Arabic keeps Latin glyph (no CLL table). |
| ✅ | Upper/lower case shifts (ga'e, to'a) | §17.3 | @ref:semantic.upper_lower_case_shifts_ga_e_to_a | LerfuShift + normalize_lerfu_string (ga'e/to'a/tau); end-to-end me'o ga'e .abu → A. |
| ✅ | se'e (character codes) | §17.13 | @ref:semantic.se_e_character_codes | BY se'e + PA digits evaluated to Unicode via semantic.se_e_unicode_evaluation / normalize_lerfu_string. |
| ✅ | se'e character codes → Unicode glyph | §17.13 | @ref:semantic.se_e_unicode_evaluation | se'e + PA digits → char::from_u32; decimal if all digits <10, else hex (Unicode Ex.17.46 rexarerei=U+262E). Wired via normalize_lerfu_string; end-to-end me'o se'e cixa → $. |
10.2
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Acronyms as cmevla and la me lerfu-string | §17.12 | @ref:semantic.acronyms_lerfu_names | CLL Ex. 17.40–17.44 via standard la+cmevla and la me + lerfu-string paths; no dedicated cmavo. Verified: la me dy ny. .abu, la .dyny'abub. |
10.3
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Bare forethought mex with elided ku'e (ma'o fy. boi xy.) | §17.11, §18.6 | @ref:grammar.mex_2_forethought_bare_no_kuhe | CLL Ex. 17.35 li ma'o fy. boi xy. — operator + operand without pe'o/ku'e |
| ✅ | Lerfu strings in mekso (functions, ordinals, subscripts) | §17.11 | @ref:semantic.mathematical_lerfu_strings | ma'o + lerfu with elidable te'u/ku'e; MOI/MAI on lerfu; xi lerfu subscript frees on lerfu sumti. Shift isolation: each lerfu_string normalizes independently. CLL Ex. 17.35–17.38 accepted end-to-end. |
| ✅ | Lerfu-string sumti with free modifiers (xi subscripts, MAI, …) | §17.11, §19.6 | @ref:grammar.sumti_6_lerfu_frees | Enables xy. xi ky. (CLL Ex. 17.38) via free_xi_lerfu on lerfu sumti |
16
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Olog (dzaske) integration — extraction, validation, querying, egglog layers | — | @ref:feature.olog | Behind olog feature flag (enabled by default) |
16.2
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Olog extraction from JboProp tree | — | @ref:olog.extract_olog | Walks TexticuleProp; emits types, aspects, facts, 2-cells from brivla and connectives |
| ✅ | Olog instance population from JboTerm leaves | — | @ref:olog.populate_instances | Ground terms → instance IDs; brivla predications → event IDs and aspect apps |
16.3
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Olog 2-cell validation | — | @ref:olog.validate_two_cells | Validates subsumption and implication 2-cells against instances |
| ✅ | Olog fact validation | — | @ref:olog.validate_facts | Validates commutative diagram facts against instance data |
| ✅ | Olog structure validation | — | @ref:olog.validate_structure | Validates types, aspects, and instance membership |
| ✅ | Run olog query from JSON file | — | @ref:olog.run_query_file | Loads query from olog_data/queries/ and executes against schema + instances |
16.4
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Bundled dzaske olog corpus | — | @ref:olog.bundled_corpus | olog_data/: 12 ologs, 9 instances, 12 queries; covered by camxes_olog tests |
| ✅ | Load olog schema from JSON file | — | @ref:olog.load_olog | Deserializes olog_data/ologs/*.json |
| ✅ | Olog integration test suite | — | @ref:olog.test_suite | tests/camxes_olog.rs — extraction, validation, bundled E2E |
16.6
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Evaluate olog expressions in e-graph (Layer C) | — | @ref:olog.egglog_layer_c | eval_expression_in_egraph; Tabulator/Tensor fall back to empty |
| ✅ | Extract olog from saturated e-graph (Layer B) | — | @ref:olog.egglog_layer_b | extract_olog_from_egraph recovers proved equivalences as 2-cells |
| ✅ | Olog 2-cells → egglog rewrite rules (Layer A) | — | @ref:olog.egglog_layer_a | olog_to_egg_rules compiles subsumption/equivalence into rule/birewrite |
16.7
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Egglog-based olog type validation | — | @ref:olog.egglog_type_validation | validate_with_egglog via type_schema.egg and type_rules.egg |
16.8
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Direct-flow olog translation via functor | — | @ref:olog.direct_flow_olog | Maps types and aspects from source to target olog using FunctorDefinition |
| ✅ | Layer C complex olog expressions | — | @ref:olog.layer_c_complex | Tabulator, Tensor, Composition in eval_expression_in_egraph |
| ✅ | Metamath-backed olog proof verification | — | @ref:olog.prove_olog | prove_olog and prove_prop_types via olog_proofs/olog.mm and typed_dictionary |
| ✅ | Metamath-backed proof verification for olog 2-cells and typed_dictionary obligations | — | @ref:feature.olog-proofs | Behind olog-proofs feature flag (enabled by default; workspace crate vendor/metamath-rs) |
| ✅ | Typed dictionary to olog type mapping | — | @ref:olog.typed_bridge | typed_bridge.rs maps TypeExpr to semantic olog types; enriches extract_olog |
| ✅ | Validate olog functor structure | — | @ref:olog.validate_functor_structure | Checks type_map and aspect_map against source/target ologs |
| ✅ | WASM olog JSON output | — | @ref:olog.wasm_json_output | parse_lojban WASM includes olog, ologInstances, proofResults when feature=olog |
18
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Olog summary for JSON output | — | @ref:olog.summarize_olog | summarize_olog in olog/mod.rs |
| ✅ | Semantic equivalence check via egglog saturation | — | @ref:semantic.check_equiv | check_equiv loads both texts into one e-graph and compares canonical props |
18.2.2
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Compound cmavo | §4.2 (compound cmavo segmentation) | @ref:morph.segment_compound_cmavo | Deterministic longest-match split for compound cmavo; exact CLL §4 tests cover .iseci'i, punaijecanai, and internal-pause ki'e.u'e. |
| ✅ | Deterministic CLL lexer | §4.2, §4.3, §4.8, §19.1 | @ref:morph.deterministic_cll_lexer | Rust lexer emits canonical tokens with normalized surface, source spans, word type, and selma'o; compound cmavo examples .iseci'i, punaijecanai, and ki'e.u'e have exact token boundaries/classes. |
18.4
| Status | Feature | CLL Reference | Impl Ref | Notes |
|---|---|---|---|---|
| ✅ | Fragment content lerfu logshow (cia) | §17.2, §4.2, §20 | @ref:ast.lerfu_string_fragment_cia | BY/any_bu surfaces → LerfuChar; with LR lerfu_string_lerfu_string_* alts, cy.ibu.abu → [Fragment: cia] / cy ibu abu |