Module talk:Auphen: Difference between revisions
Log the ~ word boundary (D16) |
Drop the kept-behaviour clause that D15 contradicts (flag 49) |
||
| Line 26: | Line 26: | ||
* '''D13''' — a UTF-8 codepoint layer replaces the JS's UTF-16 indexing: combining marks are separate characters, and digraph phones work in categories (CWS bans them). | * '''D13''' — a UTF-8 codepoint layer replaces the JS's UTF-16 indexing: combining marks are separate characters, and digraph phones work in categories (CWS bans them). | ||
Kept behaviours: <code>@0</code>/<code>@-0</code> select nothing; an empty ELS is skip, not delete | Kept behaviours: <code>@0</code>/<code>@-0</code> select nothing; an empty ELS is skip, not delete; capitals never survive to output; candidates are collected against the pre-rule word and applied together (no intra-rule bleeding). | ||
== Performance == | == Performance == | ||
Category matching currently materialises the Cartesian product of the category references in a rule, so cost is (category size) to the power of (number of references) — dominated by large sets like <code>[C]</code>. A guard (<code>opts.explodeCap</code>, default 5,000,000) skips a pathological rule with a warning rather than exceeding Scribunto's CPU limit. '''Tracked follow-up:''' a streaming/positional matcher that tests membership per word-position, removing the ceiling entirely. | Category matching currently materialises the Cartesian product of the category references in a rule, so cost is (category size) to the power of (number of references) — dominated by large sets like <code>[C]</code>. A guard (<code>opts.explodeCap</code>, default 5,000,000) skips a pathological rule with a warning rather than exceeding Scribunto's CPU limit. '''Tracked follow-up:''' a streaming/positional matcher that tests membership per word-position, removing the ceiling entirely. | ||
Revision as of 20:09, 28 July 2026
This page records the design, provenance, and behavioural divergences of Module:Auphen — out-of-frame notes, kept off the module source.
Provenance
Auphen is a pure-Lua (Scribunto) port of a JavaScript sound-change engine, itself an implementation of ConWorkShop's PhoMo rule notation. Rule anatomy (target / change / environment / exception / else), the affix-vs-replace split, category sets, and the operator set follow PhoMo; the divergences below are deliberate. The engine is developed and tested off-wiki: a 334-case local suite covering every operation, ground-truth parity against the original JS engine, and the live YBS-PJ ruleset.
Divergences
Fixed bugs in the source JS engine (each has a proving test off-wiki):
- D1 — the ELS
@-index is parsed and used as a fallback instance filter (the JS assigned it to the CHG index, so ELS indices were dead). - D2 — ditto
"fires inside the exception as well as the environment (the JS dropped the "previous" flag). - D3 —
?-reversal indices are computed on the clean word; negatives are not off by one, and positive?nstarts at char n. - D4 — positive-index affix insertion/deletion is not off by one.
- D5 — circumfix
A#Bwraps the word (the JS concatenated A+B). - D6 — local conditions inside an affix rule are cleanly false.
- D14 — category→category mapping pairs members by declaration order, not a longest-first sort, so digraph categories map correctly (e.g. palatalization
[H]/[J]where[J]holdstʃ, dʒ: declared order gives s→ʃ, t→tʃ, g→ɣ). The JS sorted members longest-first, silently mapping s→tʃ. Longest-first is still used for matching, so multi-character phones still match greedily. - D15 —
%("same as the target") substitutes on every occurrence in a result, so%%doubles the target (e.g. gemination[C]/%%/_4). The JS replaced only the first%. A literal per-cent sign in output is written!%. - D16 (Auphen addition) —
~(tilde) is a universal word boundary. The engine splits input on it, so each part is processed as its own word (its own#edges), and the parts are joined with a space; a~produced late by a rule becomes a plain display space. It does not clash with nasal vowels (precomposed likeã, or a combining U+0303 tilde — both distinct codepoints from ASCII~).
Divergences from CWS (documented quirks fixed, not reproduced):
- D7 — a category/index resolving out of range skips the candidate (CWS deletes the target).
- D8 —
!escape makes the next character a literal. - D9 / D10 — movement
>and copy>!use clean semantics; CWS's off-by-one is not reproduced. - D11 —
-word operations are opt-in (opts.dashToSpace). - D12 — the wildcard
*in local conditions is defined and reliable. - D13 — a UTF-8 codepoint layer replaces the JS's UTF-16 indexing: combining marks are separate characters, and digraph phones work in categories (CWS bans them).
Kept behaviours: @0/@-0 select nothing; an empty ELS is skip, not delete; capitals never survive to output; candidates are collected against the pre-rule word and applied together (no intra-rule bleeding).
Performance
Category matching currently materialises the Cartesian product of the category references in a rule, so cost is (category size) to the power of (number of references) — dominated by large sets like [C]. A guard (opts.explodeCap, default 5,000,000) skips a pathological rule with a warning rather than exceeding Scribunto's CPU limit. Tracked follow-up: a streaming/positional matcher that tests membership per word-position, removing the ceiling entirely.