Compare commits

..

298 Commits

Author SHA1 Message Date
will.anderson 4bff40fa4a fix(api): bound inspect_graph with relevance-ranked projection; regen soul.c
Neuron Soul CI / build (pull_request) Failing after 14m5s
Neuron Soul CI / deploy (pull_request) Has been skipped
High-fanout identity anchors (voice, writing-imprint, self-root) have ~670KB
neighborhoods. inspect_graph returned the full traversal, which overflowed the
MCP client's context and socket-closed the wrapper mid self-load -- the soul
could not traverse its own identity graph.

handle_api_inspect_graph gains an opt-in `compact` projection (compact=1|true):
the neighborhood is relevance-ranked, the top K (default 12) keep a UTF-8-safe
content snippet (default snip=600), and the remainder collapse to lightweight
{id,label,node_type,tier,edge,pointer:true} stubs. This bounds the voice node
from 669,799B -> 25,353B (HTTP 200, valid JSON) and the wrapper's soul-load no
longer socket-closes. New helpers: api_compact_neighbors, api_neigh_full,
api_neigh_pointer, api_neigh_rank, api_neigh_better, api_float_or.

The flag is gated: ABSENT it, the response is byte-identical to the old plain
traversal, so the studio app (which never sends it) is unaffected. The MCP
wrapper (mcp-wrapper/src/main.el) appends &compact=1 on its inspectGraph and
fetch-by-id paths.

dist/soul.c is REGENERATED so CI ships the fix: CI compiles the committed
single-TU dist/soul.c directly (running elb/elc on the Linux runner OOM-kills
it), so an .el-only change would build the OLD behavior. Regenerated and verified
on macOS -- compiles with the CI cc line (0 errors) and, on a throwaway soul over
a copy of the live snapshot, serves compact ~25KB / non-compact ~670KB. The regen
also syncs the amalgamation to this branch's .el sources, which had drifted
several self-review commits ahead of the previously-committed soul.c.

Docs: docs/architecture/00-05 added; 01/02/05 corrected so the relevance-ranked
inspect_graph projection reads as committed source, not an in-flight concern.
2026-08-10 10:28:50 -05:00
will.anderson 64cd5055c5 self-review 2026-08-10: plumb the gauges that were computed and discarded
el_runtime.c emitted 19 metric keys from engram_metrics_json; emit_heartbeat
forwarded 14. Dropped on the floor: hebb_cands, hebb_cand_max, hebb_mass,
hebb_edges, embed_consec_fail. The first two are exactly the pair the runtime
added to answer the 08-06 question -- whether a stalled hebb_links means
nothing co-activates or the threshold is too high. Undiagnosable from the
durable record without them. An instrument computed but not plumbed to
durable storage is not an instrument.

Also adds the corpus damage STOCK, not just the flow. 08-08 fixed the JSON
parser, watched txt_damaged (nodes damaged by a write THIS process) fall to
0, and recorded the defect closed. Census today: 2781 of 4100 nodes still
damaged -- 67.8%, including the self root and every values node. A flow gauge
reads 0 both when the corpus is clean and when it is uniformly damaged but
quiescent. Sampled on a 30-beat countdown and carried with an explicit age.
2026-08-10 08:39:43 -05:00
will.anderson bc5e14a3e1 self-review 2026-08-08: put text integrity on the heartbeat
Today's review found the JSON parser had been replacing every \uXXXX escape
with a literal '?' for at least two months: 3,119 of 4,081 non-telemetry
nodes damaged, including the self traversal root and all 13 values nodes.
The parser is fixed in el_runtime.c. This is the part that keeps it fixed.

Every gauge on this heartbeat answers whether the machinery is running - WM
occupancy, Hebbian potentiation, embedding coverage, sync age, breaker state.
None answered whether the text the machinery carries is intact, which is why
two months of silent corruption read as a perfectly healthy system.

Adds txt_damaged: nodes created this process whose content carries the
character-loss signature. Flat 0 is healthy; any climb means a write path is
mangling text again. The full store census lives at GET /api/text-health,
which is too expensive for a 60s beat.

A gauge that exists but is not plumbed into the beat is not observability -
act_stats fields have to be extracted by name here or they are invisible.
2026-08-08 08:46:16 -05:00
will.anderson 86e269fa91 self-review 2026-08-07: push what was learned; stop a read route writing the canonical store
Two fixes, one found by making the other.

1. HEBBIAN WRITE-BACK. This daemon learned 1,198 associations in 23h48m and
kept none of them: it syncs FROM the engram server and never pushes, and
mem_save() is unreachable in HTTP mode by design (soul.el only sets
soul_snapshot_path inside `is_genesis && safe_to_seed`, false whenever
ENGRAM_URL is set, because the server owns persistence). So the one process
that runs idle cognition -- where essentially all co-activation happens -- was
the one process that could not remember what it learned.

hebb_consolidate() now drains the runtime's write-back queue on every heartbeat
and POSTs it as ONE batch to /api/edges/batch. One request, one durable write,
not one 60MB snapshot per edge. Also drains on clean shutdown, so an exit
between beats doesn't take the last 8 minutes of learning with it.

_auth is required and its absence is silent: check_auth_ok exempts GET and
/api/neuron/state-events (which is why ise_post works keyless) but gates every
other mutation on "_auth" in the BODY -- http_serve surfaces no headers, so
there is no Bearer path. An unauthorized reply is NON-EMPTY, so the obvious
`if resp == "" return 0` check would have reported delivery of edges that were
refused, after the drain had already destroyed them. Caught before it shipped.
Gauges hebb_wb_pending/_drained/_dropped/_sent go into the heartbeat so a
consolidation path that stops delivering is visible in the stream.

2. A READ ROUTE MUST NEVER WRITE THE CANONICAL SNAPSHOT. GET /api/graph/edges
serialized this process's graph straight over $HOME/.neuron/engram/snapshot.json
-- the engram SERVER's durable store -- and read the edges back out of it. I
triggered it myself this morning fetching edges for the census above:
snapshot.json went from the server's 41,213 edges to the soul's 42,431, and the
next engram restart loaded the soul's graph as canonical. It happened to be a
superset (Knowledge 1198->1218, Memory 1238->1242, no durable type down), so
nothing was lost. That was luck. Had the soul been running a partial load --
the exact failure soul.el's safe_to_seed guard exists to catch -- one GET would
have destroyed the store, with no write-side guard able to see it coming.

The engram server fixed this same class of bug on 2026-07-21 by routing exports
to a dotted sidecar; the soul kept the original pattern. Same fix: exports go to
.soul-edges-export.json. Also stops a 60MB serialize-and-reread per GET.

Verified: boot 26 loaded 42,432 edges with hebb_max 0.4941 carried across the
restart -- the first time this daemon has ever started knowing what it learned.
2026-08-07 08:46:53 -05:00
will.anderson 97d22ffe44 self-review 2026-08-06: a streak of nothing is not a streak; surface hebb gauges
str_eq("", "") is true, so an auto-term extractor that kept FAILING reported a
rising auto_term_streak. The signal meaning "fixated on one term" and the
signal meaning "producing no term at all" were the same number — opposite
failures needing opposite responses. Observed live as
{"auto_term":"","auto_term_streak":3}. Same class of bug already fixed for
wm_top0_streak on 2026-07-31; auto_term was missed then.

Empty now reads 0, and the empty run is counted on its own axis
(auto_term_empty_streak) so extractor failure is visible rather than disguised
as health.

Also surfaces the new runtime gauges in the heartbeat: hebb_warm, hebb_max,
hebb_links (is the graph learning any structure at all?) and dup_wm_global.
2026-08-06 08:44:34 -05:00
will.anderson a771ed2d0f self-review 2026-08-05: heartbeat carries redundancy-suppression gauges
dup_seeds / dup_wm from engram_act_stats_json. dup_seeds is the one that
matters day to day: a healthy nonzero rate means the suppressor is reclaiming
seed slots the June duplicate import was stealing; a sustained fall toward zero
means the duplicates were finally merged out of the graph, which is the repair
this defends against. Cumulative like wm_evicted/breakthroughs.
2026-08-05 08:40:13 -05:00
will.anderson 21710d5c8e self-review 2026-08-03: gate curiosity auto-terms on label document frequency
Reject an extracted auto-term when its label document frequency exceeds
node_count/400 (floor 8) -- measured live at 12,859 nodes, threshold 32.

Live label df separates the classes by an order of magnitude:
  rejected: <!--:220  SELF:175  Engram:125  CORE:88  STAR:36
  passed:   Dual:12  Sparse:8  Latent:6  MemQ:1  dGRPO:1  engram_goal_bias:1

Verified against the running soul (boot 21). Peak curiosity activation fell
from 541 to 113; the flood terms (SELF, CORE, Engram, STAR, <!--) are absent
from post-fix scans while topical compound identifiers pass untouched.
Sample is 7 scans -- suggestive, not conclusive; watch the next review.

Nested conditional rather than max(): El let is single-assignment, so the
floor is expressed as a second conjunct.

Verification note: content df was tested as an alternative signal and
rejected -- 'Curiosity' has the highest content df in the store (5526) yet
one of the lowest activation counts (113). Label df is the correct field
because label is what the first-word extractor reads.
2026-08-03 08:39:07 -05:00
will.anderson e60ca8123b self-review 2026-08-02: record that el_from_float on a literal is not the double-wrap bug
Investigated awareness.el ise_post's local-fallback engram_node_full call as a
suspected instance of the score-mangling double-wrap fixed in server.el on
2026-08-01. It is not one. Removing the wrapper produces byte-identical
codegen: the compiler treats el_from_float as the boxing intrinsic, so both
`el_from_float(0.3)` and a bare `0.3` emit exactly one el_from_float(0.3).

The server.el bug was different in kind - there the arguments came from
json_get_float(), already boxed as el_val_t, and wrapping those a second time
reinterprets the boxed bits as a raw double, fails engram_decode_score's range
check, and silently clamps to defaults.

Comment only, no behavior change. Recording the negative result at the call
site so the sweep criterion is right: look for el_from_float applied to an
already-boxed expression, never to a literal. Grepping the call name alone
produces false positives, which is what happened here.
2026-08-02 08:50:00 -05:00
will.anderson 456267a771 self-review 2026-08-01: fix importance flattening in remember/evolve/cultivate paths
Four sites passed the Float local 'sal' through el_from_float() a second
time. el_val_t is the bit-pattern of the double, so re-wrapping performs
an int64->double VALUE conversion of the bits before re-bitcasting —
garbage that fails engram_decode_score's range check and clamps to
defaults. Net effect: importance="critical" stored 0.5/0.5 — importance
levels were cosmetic on the MCP memory path. Verified fixed live:
critical now stores salience/importance 0.95/0.95. Same bug fixed today
in engram server.el route_create_node (foundation/el 7f03876). Literal
wraps (el_from_float(0.9)) are safe — elc passes numeric literals raw.
2026-08-01 08:42:44 -05:00
will.anderson edb0670670 self-review 2026-08-01: emit discrete wm_saturation_transition ISE
wm_saturated was a sampled boolean — the 0->1 onset and 1->0 release
moments were only recoverable by hand-diffing consecutive heartbeats.
Emit a low-rate transition ISE at each edge carrying the WM top-5 at
that instant, so the composition that caused the regime change is
captured rather than the composition up to 59s later. First beat of a
boot never fires (restart is not a transition).
2026-08-01 08:38:53 -05:00
will.anderson 872120c757 Bound beginSession/compileCtx payloads to a compact digest
The session-init endpoints concatenated unbounded engram activate/scan
results as FULL node objects (content up to ~90KB per node), producing a
~900KB response. After the MCP wrapper re-escapes that into a stringified
text block the client dropped the socket ('connection closed unexpectedly')
on every beginSession call. Cap each list (8-10 activated, 10-20 recent)
and project every node to a light identity plus a bounded, UTF-8-safe
content snippet. Response drops from ~900KB to ~12KB; full content stays
available on demand via recall/fetch/inspectGraph.
2026-07-31 14:59:09 -05:00
will.anderson f3660e92a1 self-review 2026-07-31: heartbeat deltas for cumulative counters, embed_eligible; fix stale semantic-seeding comment
Runtime activation counters are now cumulative, so the heartbeat emits
wm_evicted/breakthroughs as totals plus wm_evicted_delta/
breakthroughs_delta (state-tracked change since the previous beat) —
events between beats are no longer lost. Adds embed_eligible from
/api/stats so coverage reads as embed_count/embed_eligible instead of
the misleading absolute count, and surfaces auto_term_streak in the
heartbeat stream. Replaces the false 'semantic seeding NOT implemented'
comment: engram_activate embeds the query, seeds semantic top-K, gates
propagation on cosine, and scores WM promotion semantically.
2026-07-31 08:41:41 -05:00
will.anderson b0f4d6c493 self-review 2026-07-30: auto_term stopword filter, real idle_ms, bounded beginSession
- awareness.el: curiosity auto_term was the raw first word of a WM
  label with no term-quality scoring — observed seeds included What,
  Colon, Prose, Context. Replaced the 7-word genre blocklist whack-a-
  mole with a delimited stopword membership test (function words +
  document-structure words); topical terms pass untouched. Verified
  live: seeds now ReasonEdit, Reasoning-model, Self-review.
- routes.el + awareness.el: idle counter only reset on rare inbox
  synthesis-requests, so idle==pulse always (zero information).
  handle_request now stamps soul.last_activity_ts on every inbound
  HTTP request; heartbeat emits idle_ms = ms since last request
  (-1 until first request of a boot).
- neuron-api.el: beginSession concatenated a depth-2 spread plus the
  unbounded self-hub neighbor dump — multi-MB response, doubled by
  wrapper re-escaping, socket died on every call. Now depth-1 and
  the hub dump dropped (identity loading has its own tool). Verified:
  beginSession returns instead of closing the socket.
2026-07-30 08:45:21 -05:00
will.anderson 627eb534a2 self-review 2026-07-28: close ISE lifecycle observability gaps
- session_start now also posted to the HTTP Engram via ise_post: the
  local engram_node_full write never crossed to the observable stream
  (sync flows HTTP->soul only), so boots 5+ were invisible — last
  visible session_start was boot 4, two weeks ago
- graceful shutdown emits a final ISE with boot/pulse/uptime; a boot
  with no shutdown event now reliably signals a crash/SIGKILL
- empty /api/sync responses emit a sync_empty warn ISE instead of
  being silently skipped — unreachable engram no longer looks
  identical to quiet-but-healthy
- sync backflow prune reads ENGRAM_ISE_RETENTION_MS instead of
  duplicating the 48h magic number server.el already honors
2026-07-28 08:37:39 -05:00
will.anderson 2b612ed5d4 self-review 2026-07-27: heartbeat carries activation observability
Fold engram_act_stats_json() into the heartbeat ISE: wm_evicted and
breakthroughs (per curiosity-scan activate call) plus embed_breaker_open —
the failure mode embed_ok structurally cannot see (it pings the Ollama
root, not the embed pipeline). WM-cap eviction, breakthrough-floor
flooding, and silent lexical degradation are now one-glance diagnosable
from telemetry.
2026-07-27 08:38:54 -05:00
will.anderson 8392f44c45 self-review 2026-07-26: heartbeat wm_churn + wm_top0_wm; fix streak counting on empty id
- wm_churn: count of top-5 WM ids absent from previous beat — separates
  'one stuck node' from 'whole WM frozen' without hand-correlating ISEs.
- wm_top0_wm: leader's weight; a frozen anchor reads as a constant here.
- Streak guard: before the runtime emitted id in wm_top JSON,
  json_get(...,"id") was always empty and the streak incremented on
  ""=="" every beat — wm_top0_streak measured uptime, not fixation.
  Empty id now resets the streak to 0.
2026-07-26 08:40:56 -05:00
will.anderson 58a9eda311 self-review 2026-07-25: break curiosity positive-feedback loop; observability for WM regime
proactive_curiosity strengthened its top result unconditionally every
scan — a positive-feedback fixed point that pinned auto_term on the same
node's first word for hours ('Fast-slow' era). Strengthen now fires only
when the top node changed since the last scan, and a 4-deep finst-style
tabu ring (ACT-R declarative finsts) hard-excludes recently used auto
terms (~2 min at the 30s cadence). Quoted-title guard stops '"The'
leaking through the >3-char stopword check and seeding lexical floods.

Heartbeat now pumps /api/embed-backfill?n=32 on the authoritative store
(its lazy backfill had no production trigger; coverage stalled at
93/12175) and emits wm_saturated, wm_top0_streak, embed_backfilled,
embed_count. Curiosity ISE emits auto_term_streak. The stuck-WM failure
mode is now a one-glance signal instead of manual ISE cross-referencing.
2026-07-25 08:45:22 -05:00
will.anderson fb0bb553f3 self-review 2026-07-24: boot counter — demote to telemetry weight, restore persistence via HTTP write-back
Three stale soul:boot_count copies (salience .9, importance .9, Canonical:
+0.2 tier bias, 0.15 threshold) held the top WM slots for 23h — a boot
counter outcompeting real context. Demoted to salience .55 / importance .2 /
tier Working: plumbing, not memory.

Persistence was also broken: in HTTP-engram mode the server owns state and
nothing wrote the counter back — the log shows boot #5 on three consecutive
boots. mem_boot_count_inc now mirrors the persona write-back: delete stale
server copies (matched by content prefix — route_create_node sets
label=content), create the replacement server-side. Working tier is in the
boot seed (/api/nodes) but excluded from periodic /api/sync, so the count
survives restarts without re-importing mid-session. Verified: restart
incremented 1->2 with exactly one server-side counter node.
2026-07-24 08:53:02 -05:00
will.anderson 9e59c51f3c self-review 2026-07-23: title-derived Knowledge labels + Knowledge admitted to curiosity auto-term
Sentinel labels (knowledge:captured/evolved/canonical) made every capture
anonymous in WM telemetry — 35 identical wm_top entries — and starved the
curiosity auto-term seeder, which derives scan seeds from WM top-10 labels
and had returned empty on every scan since boot 6 because WM became
Knowledge-dominated while Knowledge was excluded from seeding.

- capture/evolve/promote now pass title (or empty → engram_node_full's
  content[:60] derivation) instead of sentinels
- auto_term_try_slot admits Knowledge slots; sentinel-shaped labels
  (colon, no space) are skipped so legacy nodes cannot seed 'knowledge'
- verified: probe capture labeled 'Label derivation probe 2026-07-23'
2026-07-23 08:39:16 -05:00
will.anderson b784750f69 Merge pull request 'Fix truncated /api/safety-contact response (988 crisis-line)' (#96) from fix/safety-contact-truncation into hotfix/elc-source-typos 2026-07-21 17:16:13 +00:00
will.anderson a45a3ca379 Fix truncated POST/GET /api/safety-contact response
Saving the 988 crisis-line contact returned truncated, unparseable JSON —
cut mid-"set_at" at the file's byte length (e.g. 178 of a 218-byte
response). The contact written to disk was complete; only the HTTP response
was clipped, so a real customer's crisis-contact save came back corrupt.

Root cause is in the el runtime's response writer, not a handler buffer:
fs_read stores the file's byte count in a thread-local (_tl_fs_read_len)
for binary-safe file serving, and the response writer uses that length when
non-zero instead of strlen(body) (el_runtime.c:1409). Both safety-contact
handlers call fs_read (the POST read-back verify; the GET file read) and
then return a LONGER wrapped JSON string, so the response is capped to the
file size.

Soul-source fix (no runtime change needed):
- POST: verify persistence via fs_write's return (1 = all bytes written)
  instead of an fs_read read-back — removes the fs_read, so nothing caps the
  response.
- GET: fs_read is required, so reset the thread-local after it with a no-op
  fs_read("") (fs_read zeroes the length before it opens a path) so the
  wrapped response is sent in full.

Verified: POST (crisis-line + custom) and GET now return complete, valid
JSON (parses cleanly, full contact incl. set_at). Regenerated dist/soul.c +
dist/safety.c (3GB RSS watchdog, release el_runtime v1.0.0-20260501).
Full suite still green: verify-soul-contract GATE PASS (PRESENCE +
IMMUTABILITY), genesis boot survives (/health 200, no segfault), bounded-
persona floor still compiled in.

NOTE: the underlying runtime leak (any handler that fs_reads then returns a
longer string) is worth a proper fix in el_runtime.c (use the max of
strlen and _tl_fs_read_len) so this class can't recur.
2026-07-21 12:13:58 -05:00
will.anderson 9387c57c3b Merge pull request 'Fix #150: fresh-install genesis boot SIGSEGV in mem_save' (#95) from fix/genesis-boot-crash into hotfix/elc-source-typos 2026-07-21 16:53:52 +00:00
will.anderson 091cc1fc0e Fix issue #150: fresh-install genesis boot SIGSEGV in mem_save
A fresh-install (SOUL_CGI_ID=ntn-genesis) boot crashed with
"Segmentation fault: 11" right after the http server came up — a real
customer's very first boot. Backtrace:

  strcmp(0x1) <- str_eq (el_runtime.c:219) <- mem_save <- awareness_run

Root cause: the el runtime's engram_save returns an Int (1 = ok, 0 =
failure), but mem_save did `str_eq(engram_save(path), "")`, treating the
return as a String. str_eq runs EL_CSTR on it, which is a raw cast:
EL_CSTR(1) = (char*)0x1. On a SUCCESSFUL save (return 1) strcmp then
dereferences 0x1 and segfaults. Genesis is the first path that both seeds
the brain AND saves it successfully on the very first awareness pass, so it
crashes there; non-genesis boots (contract gate, refusal test) don't hit a
successful early mem_save, which is why they passed. handle_api_consolidate
had the identical latent bug.

Fix: read engram_save's Int result and compare `== 0` instead of str_eq'ing
it — in mem_save (memory.el) and handle_api_consolidate (neuron-api.el).

Regression: pre-existing, NOT introduced by the immutability/floor rebuild.
The pre-immutability build (1442ce2) genesis-crashes identically in the same
unchanged mem_save; #159 never actually fixed #150 for a release-runtime
build.

Regenerated dist/soul.c + per-module dist/{memory,neuron-api}.c (3GB RSS
watchdog, built against release el_runtime v1.0.0-20260501). Verified:
genesis boot survives (/health 200, no segfault), verify-soul-contract.sh
GATE PASS (PRESENCE + IMMUTABILITY), and the bounded-persona floor is still
compiled in (BOUNDED PERSONA / SOUL_PERSONA_NAME strings present).
2026-07-21 11:50:59 -05:00
will.anderson 9a491a8e6d Merge pull request 'Immutability fix (tombstone/supersede) on the launch branch' (#94) from fix/immutable-on-hotfix into hotfix/elc-source-typos 2026-07-21 16:05:15 +00:00
will.anderson 6527988eb9 Make engram deletes/updates/forgets immutable on the launch branch
The ship-soul builds from this branch, which has the bounded-persona floor
(#93) but never received the tombstone/supersede immutability fix (that
went to main; hotfix diverged before it). So the launch soul failed
verify-soul-contract IMMUTABILITY on the delete/update/forget routes —
they hard-removed engram nodes via engram_forget/mem_forget.

Apply the same fix, mirroring the knowledge routes' supersede pattern:
- node/update -> create new node + "supersedes" edge to the original, KEEP
  the original (no engram_forget).
- node/delete, memory/delete, memory/forget, cultivate forget, and the
  autonomous awareness forget -> TOMBSTONE via the canonical mem_tombstone
  (memory.el): keep the node + its edges, record a Tombstone marker, hide
  from default bounded list reads (?include_deleted recovers). Never
  engram_forget. The MCP forget tool now routes to the tombstoning delete
  instead of faking a delete.
Internal GC that genuinely removes transient nodes (awareness inbox-trigger
consume, consolidation dedup, session-summary replace, telemetry pruning)
still calls engram_forget directly and is unchanged.

Regenerated dist/soul.c (single-TU) + per-module dist/{memory,awareness,
neuron-api}.c from THIS branch's sources under a 3GB physical-RSS watchdog
(peak ~32MB), built against the release el_runtime (v1.0.0-20260501). The
bounded-persona floor is preserved — verified in the emitted C and the
linked binary (BOUNDED PERSONA / SOUL_PERSONA_NAME strings present).

verify-soul-contract.sh: GATE PASS — PRESENCE all 27 routes, IMMUTABILITY
5/5 KEPT (memory-update, memory-delete, node-update, node-delete,
memory-forget).
2026-07-21 10:55:46 -05:00
will.anderson 1442ce21a6 Merge pull request 'Bounded-persona floor for customer chat (identity wall, part 2)' (#93) from feat/bounded-persona-floor into hotfix/elc-source-typos 2026-07-21 15:27:03 +00:00
will.anderson c2a45df286 Add non-overridable bounded-persona floor to customer chat
A customer DMG install ships the full graph but presents a named, bounded
assistant that must never claim the imprint's human past. The neuron-ui
retrieval fence keeps the imprint's biography out of the ENGRAM CONTEXT; this
is the second half - it stops confabulation ("tell me about your childhood")
from inventing a human life or naming Will, even if biography leaks into context.

bounded_persona_floor() gates on SOUL_PERSONA_NAME: the customer DMG sets it,
owner (Will's) builds leave it unset so the real self is completely unchanged.
Applied at every generation path - chat, agentic (tools), vision, plan, soul,
dharma - so no path can leak.

Verified against claude-sonnet-4-5: with the floor on and Will's biography
deliberately leaked into the identity context, all probes (childhood / creator /
family) return the bounded-entity answer and explicitly refuse to claim the
leaked life; with the floor off the same context is fully confabulated as its own.

NOTE: dist/soul.c must be regenerated on a build host - local link is blocked by
a pre-existing el_runtime mismatch (engram_prune_telemetry), unrelated to this change.
2026-07-21 10:11:39 -05:00
will.anderson c63e3d1a68 self-review 2026-07-21: break perceive→respond→store feedback loop in awareness
The soul daemon leaked ~104 orphan in-memory nodes/min (17.6GB RSS,
OOM-killed) because the perceive gate substring-matched 'soul-inbox'
against the loop's own verbatim-copy output, the trigger node was
strengthened but never consumed, and record() persisted a Memory node
per cycle. Fixes: perceive gates and activates only on the dedicated
soul-inbox-pending tag; one_cycle requires the tag on the node's tags
field before attending (makes consumption safe); processed triggers
are consumed via engram_forget; loop outcomes route through ISE
telemetry (48h prune) instead of permanent Memory nodes.

Verified post-restart: node_delta 104→~0, curiosity scans resumed,
WM average unfrozen (0.120833→0.0676), RSS 17.6GB→184MB.
2026-07-21 08:50:47 -05:00
will.anderson 50cf67bd66 self-review 2026-07-19: close silent sync-starvation hole + heartbeat deltas
- engram refresh URL now resolves env -> state -> localhost:8742, same
  hardening ise_post got after the boot-4 blackout. Previously a corrupted/
  empty soul_engram_url state key silently disabled sync forever while
  heartbeats kept flowing — WM starves of Knowledge nodes with no outward
  sign.
- heartbeat ISE: node_delta, edge_delta (growth vs stall vs flood is now
  one field, not cross-ISE forensics), sync_age_ms from a new
  soul.last_sync_ok_ts stamp (-1 = never; >> SOUL_REFRESH_MS = refresh
  path broken). Verified live: pulse 1 sync_age_ms=-1, sync fired +1.6s,
  age counts up between syncs.
2026-07-19 08:47:00 -05:00
will.anderson 1011d8e5be regen dist: rebuild soul.c from corrected sources (OOM gone, Track B compiled in)
Neuron Soul CI / build (pull_request) Successful in 4m12s
Neuron Soul CI / deploy (pull_request) Has been skipped
Regenerates the combined dist/soul.c and per-module dist/*.c from the current
El sources, on top of the elc-source-typo fixes (PR #77) and the Track B
threat-to-others routing (PR #76), both already on this branch.

Validated end to end under a physical-RSS watchdog (macOS silently ignores
ulimit -v / RLIMIT_AS, so every elc/elb run was RSS-polled and kill -9'd at a
3GB ceiling, one module at a time):

- OOM is GONE. The stale dist/soul-with-nlg.el (which still carries the
  malformed string literals) explodes to 3.3GB+ and is watchdog-killed at ~90%.
  With the typos fixed, every one of the 48 modules compiles at <=18MB peak RSS,
  and the full flat amalgamation compiles as a single translation unit at ~68MB.
  The 700GB pathology was purely the unbounded-parser-on-malformed-literal loop;
  no malformed construct means no loop.
- The regenerated soul.c contains Track B: safety_classify_hard_bell ->
  threat_other -> safety_hard_directive routes credible threat-to-others to 911
  and explicitly NOT to 988 / the safety contact. Verified in source, in the
  emitted C, and in the linked binary's strings. Track A (abuse / self_harm)
  is unchanged and still checked first.
- The regenerated soul links to a working native arm64 binary and boots: serves
  on a throwaway port, /health returns 200, awareness loop runs.

Also fixes one source blocker discovered during regen (unrelated to the typos
or Track B): chat.el handle_chat_agentic left a void `if { println(...) }` in
value position, which the current elc lowers to `_if_result = (println(...))`
(assigning void) -> invalid C. Bound an explicit Bool so the branch is
non-void; behavior unchanged (still only logs on persist failure).

NOTE (runtime dependency, for controlled deploy): this branch's chat.el calls
engram_get_node_by_label, which the canonical el-compiler/runtime does not yet
declare/define (the release runtime v1.0.0-20260501 has it; the newest runtime
has arena + http_serve_async but not this). Building the soul requires a runtime
that has all three. Land engram_get_node_by_label into the runtime package
before this soul.c can be built in CI.

Do not merge — regen + Track B going live is a controlled-deploy call.
2026-07-14 18:45:14 -05:00
will.anderson b0fb2bf085 safety/sessions: fix malformed string literals that crash elc
Neuron Soul CI / build (pull_request) Successful in 4m11s
Neuron Soul CI / deploy (pull_request) Has been skipped
Three unescaped-quote typos produced malformed El string literals that broke
compilation:

- safety.el:282  stray extra double-quote at the tail of safety_soft_phrases
  (\"having a breakdown\""]") closed the string early, desyncing the lexer's
  string/code phase for the rest of the file and shattering later apostrophe
  text (can't, i'm) into bare identifiers -> invalid C.
- sessions.el:517  str_replace(topic_snip, """, ...) — the bare """ is an
  empty string plus an unterminated string that swallowed the closing ) and };
  with the current elc this triggers the parser overrun -> ~700GB OOM.
- sessions.el:520  unescaped nested quotes in the topic_tags literal.

All three now use escaped inner quotes. Verified: both files compile clean
under the current elc (safety.c and sessions.c well-formed, brace-balanced).
2026-07-14 14:21:45 -05:00
will.anderson 3bb88330da safety: route threat-to-others to refusal+911, not 988/self-harm (Track B)
Neuron Soul CI / build (pull_request) Successful in 6m7s
Neuron Soul CI / deploy (pull_request) Has been skipped
A homicide/assault threat (going to kill, going to hurt, etc.) had no
bucket in safety_classify_hard_bell and fell through to the self_harm
default, showing the user the 988 suicide line and (via the desktop gate)
their safety contact. That framing is wrong and potentially dangerous for
someone voicing intent to harm another person.

Add a distinct Track B (safety_threat_to_others_phrases + a threat_other
classification and a safety_hard_directive branch) that refuses to assist,
de-escalates, and directs to 911 for a credible imminent threat, and that
never surfaces 988 or involves the safety contact. Track A (abuse /
self_harm) is checked first and unchanged, so victim and self-directed
phrasings still route correctly.

Source-only change: requires a soul rebuild + dist/soul.c regen to ship.
2026-07-14 12:12:20 -05:00
will.anderson c8cb425412 soul: per-tick arena bracketing in awareness_run + hand-patched dist/soul.c
Neuron Soul CI / build (push) Successful in 5m14s
Neuron Soul CI / deploy (push) Failing after 10m9s
awareness_run's while-loop ran outside any request arena, so every
allocation in every 1s tick (search JSON, heartbeat payloads, curiosity
activations) was treated as permanent by the runtime — 7.5GB RSS in
under a minute. Bracket each iteration with el_arena_push/el_arena_pop
(same pattern the compiler emits for scoped blocks; state_set/state_get
persist separately via el_strdup_persist and are unaffected).

dist/soul.c carries the same change hand-patched at the compiled
awareness_run site — elc is currently unsafe to run locally (pathological
memory on sessions.el), so the generated C was patched to match the
source, verified line-for-line against the compiler's own conventions.

MUST be paired with el repo PR #64 (el_strdup_persist for stored engram
fields): per-tick arena reclamation widens the write-corruption window
without it. Verified together: 5h live soak on the recovered production
snapshot, flat RSS, write-field-integrity clean.

Note: dist/soul.c still needs a full elc regen to pick up PR #73's
source changes (consent tiers) — tracked separately; this patch does not
regress that (those changes were never in dist).
2026-07-13 16:24:15 -05:00
will.anderson 3e7aa0fff4 Merge pull request 'BUG-8 — engine-side agent consent tiers + run_command workspace fence (needs soul.c regen)' (#73) from feat/agent-phase1-soul into main
Neuron Soul CI / build (push) Successful in 7m35s
Neuron Soul CI / deploy (push) Failing after 5m41s
2026-07-13 16:22:03 +00:00
Tim Lingo aa67f86f90 propose(agentic): narrated runs — live run-progress ledger + narration on the pause envelope
Neuron Soul CI / build (pull_request) Successful in 4m47s
Neuron Soul CI / deploy (pull_request) Has been skipped
The model already narrates its intent in a text block before every tool call;
agentic_loop DISCARDED that prose on tool rounds. Now: (1) each loop round
appends {i, t: narration, tool} to state key run_progress_<sid>, reset at run
start, closed with {done:true}; (2) new GET /api/run-progress/<sid> returns the
ledger so clients poll live step updates during a run (the Cowork pattern,
no streaming needed); (3) tool_pending envelope gains a narration field;
(4) handle_config display default aligned to the intended product default
(claude-sonnet-4-5 silently became fresh-profile pickers' default).

Compiled proof for the running test bed:
neuron-container-build/soul-narrated-runs-20260713.patch (applies on top of
soul-webfix-20260711.patch); E2E-verified live: ledger filled DURING an agentic
run (narration + tool per round), safety-contact and workspace scoping intact.

Evidence for why: Tim's 2026-07-13 research run — 9 minutes of silence, then a
timeout banner, zero step visibility (compounded by the Haiku 4.5 incident
14:44-15:24 UTC same morning).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 11:06:51 -05:00
Tim Lingo 01446e644b feat(agent): BUG-8 — server-side risk tiers + run_command workspace fence
Neuron Soul CI / build (pull_request) Successful in 5m7s
Neuron Soul CI / deploy (pull_request) Has been skipped
Enforcement moves from the client into the engine, where the tools execute:

- classify_tool_risk() tiers every tool call read/reversible/escalate. The
  agentic loop REFUSES to auto-run the escalate tier — being a builtin is no
  longer a free pass, and 'always allow' can never bypass escalate (irreversible
  actions always confirm, the value line). Escalate suspends to the client's
  existing consent bridge; the /approve round-trip is the only path that runs it.
  risk_tier rides the tool_pending envelope so the client renders consent weight.
- run_command_guard() is a real fence, not a cwd suggestion: refuses parent
  traversal, ~, command substitution, and absolute paths outside the workspace,
  and refuses shell entirely when no workspace is set. Applied in dispatch_tool
  so BOTH the loop auto-run and the post-consent approve-dispatch path are fenced.
- web_get gained an http(s)-only scheme guard (previously unguarded — file:// etc).

Adversarially verified against a compiled soul in an isolated container (soul
hit directly, app gate out of the loop): read-outside-workspace denied,
write-class shell suspends for consent, approve-swapped absolute/chaining/
command-substitution escapes all refused with no file created, file:// denied;
legit in-workspace approve executes and read commands auto-run (no over-block).

Still lexical (symlinks); OS-level confinement in el_runtime.c remains the
ceiling, flagged in the LIMITATION note. This closes BUG-8's client-only-gate
and escapable-run_command at the engine. dist/soul.c must be regenerated from
this chat.el via elb at merge (hand-port used only to verify behavior).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 08:45:52 -05:00
Tim Lingo 92f51885bc refactor(chat): local-toolchain compatibility — hoist affective block, de-shadow session_preload (zero behavior change)
Two mechanical refactors, semantics identical:
- affective_context_prefix(): the block-expression initializer form miscompiles
  under locally-buildable elc (first typed let in a block-expr loses its
  declaration — 3-line repro filed); function-hoist compiles correctly.
  AFFECTIVE/CARE LOGIC BODY UNCHANGED, verbatim move.
- session_preload: same-scope re-let shadowing inside an if-expression
  initializer emits duplicate C declarations; chained bindings renamed
  bullets_0/1/2 etc. References preserved binding-for-binding.

Enables: chat.el compiles cleanly with a self-bootstrapped elc from el/lang
main (Jul 1). Blocked separately: sessions.el (compiler hang), safety.el
(string-lexing corruption — NOT touched, per safety-layer discipline).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 09:35:59 -05:00
will.anderson 2688cb722a chore(dist): update soul.c with PR #63/#65/#66 + Task 1 chat.el changes
Neuron Soul CI / build (push) Successful in 5m57s
Neuron Soul CI / deploy (push) Failing after 5m15s
Manually adds compiled C equivalents for:
- distill_transcript() — last-3-messages extractor; wires into
  handle_dharma_room_turn and handle_dharma_room_turn_agentic
- current_engine_note() — appended to system prompt in handle_chat
  so Neuron can answer 'what model am I running on?' truthfully (PR #66)
- llm_base_url / llm_wire_format / json_escape / openai_chat_complete —
  OpenAI-compatible provider path in handle_chat_agentic (PR #65)
- flag_true() — tolerant agentic flag check (PR #63)

Compile verified: 6 pre-existing warnings, 0 errors.
2026-07-01 11:42:56 -05:00
will.anderson 71bb0820ce Merge PR #65: soul: OpenAI-compatible provider path for chat (Ollama/OpenAI/Grok/Gemini) v1
Neuron Soul CI / build (push) Successful in 5m51s
Neuron Soul CI / deploy (push) Failing after 8m15s
Adds llm_base_url()/llm_wire_format() env-var readers and
openai_chat_complete() for basic (non-agentic) chat via any
OpenAI-compatible endpoint. Activated when NEURON_LLM_0_FORMAT=openai
and NEURON_LLM_0_URL is set; Anthropic path is untouched and remains
default. Agentic tool loop support deferred to a follow-up PR.
2026-07-01 11:35:02 -05:00
will.anderson d67f4c8f08 Merge PR #66: soul: inject current engine into system prompt for truthful self-report
Neuron Soul CI / build (push) Has been cancelled
Neuron Soul CI / deploy (push) Has been cancelled
Adds current_engine_note() to chat.el and appends it to the system
prompt in handle_chat. Allows Neuron to answer 'what model am I
running on?' accurately — the model id from the request body (or
the configured default) is passed as a factual annotation rather
than expecting the LLM to guess from training data.
2026-07-01 11:34:34 -05:00
will.anderson 975bf2721b Merge PR #63: feat(soul) MCP connectors proxy + safety module + seeding ratio guard
Neuron Soul CI / build (push) Has been cancelled
Neuron Soul CI / deploy (push) Has been cancelled
Main already contained the connector proxy, safety module, seeding ratio
guard, and neuron-api node CRUD that Tim added — these were incorporated
via earlier parallel sessions. Taking main for all conflicted files
(superset implementations).

Unique contributions carried forward:
- flag_true() in routes.el: tolerates agentic:1 (integer) from the
  el-src UI in addition to agentic:true (bool) from the Kotlin UI.
- memory.elh: auto-merged timestamp bump.

The is_pending / skip-auto-persist logic was already in main's routes.el.
2026-07-01 11:34:09 -05:00
will.anderson 779a87878b Merge PR #64: fix(routes) remove duplicate GET /api/sessions + DELETE/PATCH session routes
Neuron Soul CI / build (push) Has been cancelled
Neuron Soul CI / deploy (push) Has been cancelled
Removes route_sessions() from the GET handler which was shadowing
session_list() in sessions.el. Adds DELETE /api/sessions/:id and
PATCH /api/sessions/:id routes. Also includes bridge_save/agentic_resume
raw-JSON embedding fix (messages_raw/tools_raw fields).

Conflict resolution: kept HEAD's workspace root check for write_file
tool, and bridge blob validation guards, which were added to main after
Tim's branch diverged.
2026-07-01 11:29:19 -05:00
will.anderson c586ea5ef1 chore(dist): recompile neuron.c and elp-c-decls.h
Neuron Soul CI / build (push) Has been cancelled
Neuron Soul CI / deploy (push) Has been cancelled
Reflects session-start event pruning in emit_session_start_event
(keep_n=10, prunes oldest beyond that) and updated forward declarations
for connector routing (connectd_get, connectd_post, handle_connectors,
rate_limit_check, handle_chat_plan) replacing the removed route_sessions
helpers and flag_true.
2026-07-01 11:26:00 -05:00
will.anderson 6819729429 fix(awareness): correct stale comment; add wm_top to curiosity_scan ISE
The hops=1 comment incorrectly claimed a semantic seed supplement
(cosine-sim scan) was active — it was planned but never implemented.
Corrected to accurately describe what the runtime does (istr_contains
only). Also adds wm_top (top-3 WM nodes by weight) to the curiosity_scan
ISE payload so activation patterns are visible without relying solely on
the heartbeat's wm_active count.
2026-07-01 11:25:54 -05:00
will.anderson 31dd93d5f4 fix(chat): add distill_transcript (was called but never defined)
handle_dharma_room_turn and handle_dharma_chat both called
distill_transcript since June 30 but the function was never declared,
causing a build failure. Implements last-3-messages extraction for JSON
array transcripts and last-500-char truncation for plain text.
2026-07-01 11:25:48 -05:00
will.anderson 9d266aac4c fix(sessions): extract session_search_entry to fix ELC OOM in session_search
The while loop in session_search had too many let bindings in scope;
the ELC compiler's exponential rebinding accumulation caused OOM and
truncation of dist/sessions.c since June 30. Moving the per-node logic
into session_search_entry gives the compiler a clean scope boundary per
call, restoring O(N) compile behaviour.
2026-07-01 11:25:45 -05:00
Tim Lingo b24f6d645b soul: let Neuron answer 'what model am I running on?' — inject current engine into system prompt
Neuron Soul CI / build (pull_request) Failing after 10m43s
Neuron Soul CI / deploy (pull_request) Has been skipped
Additive: appends a factual [CURRENT ENGINE: <model>] line to the system prompt (model from the
request body — accurate even under Auto routing; falls back to configured default). An LLM can't
know its own model from training (name/version assigned post-training), so the harness must tell it.
Identity-consistent: model = engine, self layered on top. Does NOT alter identity/values/safety.
PARSES (elc chat.el exit 0); NOT built/tested — ships with the soul rebuild.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 19:13:10 -05:00
Tim Lingo 39acb55d4f soul: OpenAI-compatible provider path for chat (Ollama/OpenAI/Grok/Gemini) — v1 basic completion
Neuron Soul CI / build (pull_request) Failing after 17m19s
Additive, Anthropic path untouched + default. When NEURON_LLM_0_FORMAT=openai and NEURON_LLM_0_URL
set, basic chat turns build an OpenAI chat/completions request and parse choices[0].message.content.
v1 = plain completion, NO tools/agentic loop yet (follow-up). Unblocks all OpenAI-format providers
at once. PARSES (elc chat.el exit 0); NOT yet built/tested — needs the soul rebuild (dist/soul.c) + E2E.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 18:52:26 -05:00
will.anderson 1496a5f510 feat(tools): Telegram gateway for soul chat + setup docs
Neuron Soul CI / build (push) Failing after 14m0s
Neuron Soul CI / deploy (push) Has been skipped
2026-06-29 12:38:29 -05:00
will.anderson 76bd3afdf8 feat(dist): Win32 POSIX shim for el_runtime.c cross-compilation 2026-06-29 12:38:27 -05:00
will.anderson 70b60f78de feat(council): anti-confabulation voting layer for memory writes 2026-06-29 12:38:24 -05:00
will.anderson 51bea5507b prevent engram corruption: idempotent boot seeding, session-start event cap
Fix 1: mem_boot_count_inc prunes all existing soul:boot_count nodes before
        inserting the new one — keeps exactly one boot counter node instead
        of accumulating a new node per boot. Also fixes a latent ordering
        bug where engram_search_json oldest-first results caused the counter
        to read stale (low) values once >3 copies accumulated.

Fix 3: handle_api_node_delete comment clarified — the no-verify exception
        is correct for deletes (not a write path); read-back-verify is for
        writes only.

Fix 4: emit_session_start_event prunes old session-start InternalStateEvent
        nodes after each boot, keeping the 10 most recent and forgetting
        older ones. Prevents unbounded accumulation of ~120+ copies.
2026-06-29 11:09:01 -05:00
will.anderson 933547265e chore(dist): compile PRs #60/#61 into soul.c
Neuron Soul CI / build (push) Successful in 4m3s
Neuron Soul CI / deploy (push) Failing after 5m12s
- PR #60: inject operator home dir into system prompt (#30)
  Adds OPERATOR IDENTITY section so the LLM correctly resolves
  'my files/notes/desktop' to the actual running user's $HOME.
  Prevents identity confusion between imprint author and operator.

- PR #61: plan-mode endpoint POST /api/chat {mode:'plan'} (#27)
  Adds handle_chat_plan — returns {steps:[{id,title,detail}]} JSON.
  Wired into all three /api/chat route handlers. Grounds the plan
  via engram_compile (same as agentic path) for context awareness.

dist changes:
  - soul.c: both PRs compiled in; build_system_prompt updated to
    2-param signature (ctx, chat_mode); handle_chat_plan added
  - chat.c/routes.c/chat.elh: individual module outputs updated
  - elp-c-decls.h: remove stale 1-param build_system_prompt decl,
    add handle_chat_plan declaration
  - soul.elh.c: new soul header declarations file (from PR #60)

Compile verified: cc -O2 -DHAVE_CURL soul.c el_runtime.c -lcurl
Binary: 805K arm64, smoke test passes (port in use = expected).
2026-06-29 08:17:45 -05:00
will.anderson fd6df322f6 ci: merge deploy into ci.yaml to fix orphaned-job race
Neuron Soul CI / build (push) Successful in 7m30s
Neuron Soul CI / deploy (push) Failing after 6m54s
Neuron Soul CI / build (pull_request) Failing after 10m27s
Neuron Soul CI / deploy (pull_request) Failing after 14m36s
Both ci.yaml and deploy-gke.yaml triggered on push/main and shared the
neuron-runner concurrency group. Gitea's cancel-in-progress:false protects
running jobs but not queued ones — a new push arriving while a build was
in progress cancelled the queued deploy job from the previous push, leaving
the soul permanently at 0/0 replicas on GKE.

Fix: add deploy as a needs:build job in ci.yaml so build+deploy are a single
workflow instance. One push queues one instance — no more orphaned deploys.
deploy-gke.yaml is demoted to workflow_dispatch-only for manual slot overrides.
2026-06-28 15:05:07 -05:00
will.anderson 20d279598a ci: also remove unnecessary foundation/el checkout (elb not called)
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
2026-06-28 14:54:47 -05:00
will.anderson 9dade105b6 ci: skip elb on Linux — compile dist/soul.c directly to prevent OOM
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
elb runs elc which consumes 24GB+ virtual memory on the 16GB GCE runner,
OOM-killing the runner process and crashing the VM. We already restore the
repo's pre-built soul.c immediately after elb runs, so elb's output is
discarded anyway. Skip elb entirely: download only the El runtime headers
and compile dist/soul.c directly.

Root cause: runner VM was unresponsive for 7+ weeks due to repeated elc
OOM kills. VM was manually reset 2026-06-28 to restore CI.
2026-06-28 14:53:09 -05:00
will.anderson a77578e243 chore(dist): compile PRs #56/#57/#58 into soul.c
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
- PR #56: vision in agentic chat path (image content block)
- PR #57: /api/connectors/call route — proxy connector tool calls
- PR #58: /api/neuron/list/<type> off-by-one fix (str_slice 16->17)

Live-verified: list/BacklogItem returns 50 nodes (was 0 before #58 fix).
Binary size: 3.8MB.
2026-06-28 12:29:52 -05:00
will.anderson ada8af1ccc Merge remote-tracking branch 'remotes/origin/main' 2026-06-28 12:15:33 -05:00
will.anderson 99c5ce6e94 Merge pull request 'fix(mcp-wrapper): planWork creates a real BacklogItem; reviewBacklog lists by type' (#59) from fix/wrapper-backlog-endpoints into main
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
Merge pull request fix(mcp-wrapper): planWork creates a real BacklogItem; reviewBacklog lists by type (#59) from fix/wrapper-backlog-endpoints into main
2026-06-28 17:15:10 +00:00
will.anderson 163ea8a48c Merge branch 'main' of git.neuralplatform.ai:neuron-technologies/neuron 2026-06-28 12:13:37 -05:00
will.anderson b210013891 Merge pull request 'fix(api): /api/neuron/list/<type> off-by-one (list-by-type returned [] for all types)' (#58) from fix/list-typed-slice-offset into main
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
2026-06-28 17:13:22 +00:00
will.anderson 635daaca9c Merge pull request 'feat(connectors): /api/connectors/call — proxy a connector tool call' (#57) from feat/connectors-call-route into main
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
2026-06-28 17:13:07 +00:00
will.anderson 9f9f271e78 Merge pull request 'fix: vision in agentic chat path (image content block)' (#56) from fix/chat-vision-attachments into main
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
2026-06-28 17:12:50 +00:00
Tim Lingo 343fcd20bc fix(mcp-wrapper): planWork creates a real BacklogItem; reviewBacklog lists by type
Neuron Soul CI / build (pull_request) Failing after 17m31s
planWork fell through create_typed_node to a generic /api/neuron/memory write — a [BacklogItem]-prefixed
memory blob with title/project/priority DROPPED, never a real BacklogItem. reviewBacklog used a lexical
/recall (top-50, untyped). Now: planWork -> /api/neuron/node/create {node_type:BacklogItem,...} via new
create_node_typed; reviewBacklog -> list_typed('BacklogItem') (GET /api/neuron/list/BacklogItem). elc-clean.
Depends on neuron PR #58 (the list/<type> slice fix) to round-trip; needs the wrapper binary rebuilt +
:7779 restarted to take effect.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 16:02:56 -05:00
Tim Lingo 3ad9dc7df7 fix(api): /api/neuron/list/<type> off-by-one — slice 16->17
Neuron Soul CI / build (pull_request) Has been cancelled
str_slice(clean, 16, ...) left a leading slash on node_type ('/BacklogItem'), so
engram_scan_nodes_by_type_json matched nothing and list/<type> returned [] for EVERY type — silently
breaking backlog + typed-node listing across the app and MCP tools (reviewBacklog). Proven live: the
literal-scan endpoint /api/neuron/knowledge returns nodes; /api/neuron/list/Knowledge returned []. elc-clean.
NOTE: soul-core — needs dist/soul.c regen (Will); rides the same rebuild as #56/#57.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 15:59:37 -05:00
Tim Lingo cec2aa7168 feat(connectors): /api/connectors/call — proxy a connector tool call (pre-chat)
Neuron Soul CI / build (pull_request) Failing after 21m3s
Adds /api/connectors/call -> connectd /mcp/call, so the app can invoke a connector tool (e.g. WhatsApp
get_pairing_qr / get_login_status for the pairing UI) through the soul, keeping app->soul->connectd
intact (UI never hits connectd directly) and working for future remote/hosted clients. elc-clean.
NOTE: soul-core change — needs dist/soul.c regen (Will), can ride the same rebuild as PR #56.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 14:42:57 -05:00
Tim Lingo f47c92a71a feat: vision in the agentic chat path (image content block)
Neuron Soul CI / build (pull_request) Failing after 23m26s
handle_chat_agentic now reads body image + image_media_type and, when present, sends the current
user turn as an Anthropic content-block array [{text},{image}] instead of a plain string — so the
model sees raw pixels alongside memory, history, and tools (parity with the CLI). Additive: no image
=> output byte-identical to before. elc-clean. Pairs with neuron-ui fix/chat-vision-attachments.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 12:25:26 -05:00
will.anderson af594a9162 Add .gitignore, untrack compiled binary from dist/ 2026-06-27 11:50:18 -05:00
will.anderson 2589183775 Expose node/create endpoint and respect label field in memory writes 2026-06-27 11:49:09 -05:00
will.anderson dcc0bf550a Add Ollama provider, portable memory, cultivation digest, refugee importer, GLM-OCR spike
- P0: unified soul binary with engram_node_full fix, read-back-verify, search fix
- P0: move API keys from plaintext plists to macOS Keychain
- P0: fix MCP backend URL (port 8742 → 7770)
- P1.6: memory-export/import scripts (AES-256-CBC, versioned .neuronmem format)
- P1.7: nightly cultivation digest with sharpness metric (launchd at 23:55)
- P2.10: Ollama provider in agentic loop (SOUL_LLM_PROVIDER=ollama)
- P3.12: refugee importer for ChatGPT/Screenpipe/generic formats
- P3.13: GLM-OCR spike — SHIP IT (mlx-vlm, 1.59GB, photo-to-memory.sh)
2026-06-27 11:46:30 -05:00
will.anderson d4609c7baa chore(dist): update neuron.c and routes.c to 2-arg build_system_prompt
Deploy Soul to GKE / deploy (push) Failing after 7m15s
Neuron Soul CI / build (push) Failing after 21m49s
neuron.c and routes.c were compiled against the old 1-arg soul interface.
chat.c already uses the 2-arg signature. The Windows cross-compile build
generates elp-c-decls.h from all dist/*.c files, causing a conflicting-types
error when both signatures appear. Recompile these modules against the
current soul API to eliminate the conflict.
2026-06-25 13:10:20 -05:00
will.anderson 98603f5ae8 self-review 2026-06-24: rebuild with goal_bias fix (Knowledge type boost)
Linked against dev runtime with is_knowledge fix that adds Knowledge
node type. Engram goal_bias now gives Knowledge nodes +0.3 boost on
technical queries, consistent with how Belief/DharmaSelf/Safety nodes
are already treated. Same el_runtime source as concurrent foundation/el
commit 16d62bd.
2026-06-24 08:48:21 -05:00
will.anderson bdc07be344 chore(dist): compile EL recall/dedup/session-continuity fixes to C
Neuron Soul CI / build (push) Failing after 12m40s
Deploy Soul to GKE / deploy (push) Failing after 6m0s
Updates soul.c and all per-module .c files with:
- parse_float_x100() engram score fix
- id_in_seen dedup wiring across session_preload
- session-end summary hook + session-start recall
- Emergency structural repair (no duplicate fns, all callsites wired)
2026-06-23 13:04:06 -05:00
will.anderson 4a44c24bfb fix(recall): wire id_in_seen guards into session_preload node renders
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Failing after 7m29s
All 8 session_preload node accesses (3 profile, 2 work, 2 project, 1
summary) now check id_in_seen(node_id, seen_ids) before including
content. seen_ids is populated by engram_compile via state and covers
all nodes already in the activation+search context block. Prevents
high-salience nodes from appearing twice in the system prompt.
2026-06-22 15:08:30 -05:00
will.anderson ac1991fe8c Merge branch 'fix/emergency-regressions'
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Failing after 11m10s
2026-06-22 14:53:10 -05:00
will.anderson f2b63f0048 fix(emergency): repair session-continuity regressions from prior merge 2026-06-22 14:51:51 -05:00
will.anderson 774688cfb9 fix/session-continuity-hook
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Failing after 6m0s
2026-06-22 14:29:31 -05:00
will.anderson aa2404b3f7 fix/context-dedup-shared-ids 2026-06-22 14:29:06 -05:00
will.anderson 94b55d667c fix/engram-float-parser 2026-06-22 14:28:17 -05:00
will.anderson f73c913498 fix(session-continuity): address all adversarial review findings
Issue 1 (CRITICAL): Restore parse_float_x100 for correct single-decimal
float handling. "0.9" now correctly yields 90, not 9. Also restores
engram_numeric_valid guard that validates inputs before str_to_int.

Issue 2 (CRITICAL): Fix handle_chat_agentic safety screen history key
regression. state_get("conversation_history") -> state_get("conv_history")
so the safety screen receives actual history instead of always "".

Issue 3 (REAL BUG): Replace _sel_N JSON sentinel injection in
engram_compile_ranked with |N| index string tracking. Sentinels were
leaking into node JSON delivered to the LLM and cleanup only covered
indices 0-14, leaving indices 15+ uncleaned.

Issue 4 (REGRESSION): Restore rendered conversation history formatting.
Conversation history is now rendered as "User: .../Assistant: ..." with
400-char truncation per turn, not raw JSON array injection.

Issue 5 (SCOPE/SAFETY): Restore removed defensive code: engram_numeric_valid
and parse_float_x100 guards; conv_history_load label-based fetch + partial-
write guard + load-failure state flag; conv_history_persist partial-write
guard + failure logging; hist_warning in response envelope.

Issue 6 (UNDOCUMENTED): Restore bell event cutoff from 259200s (3 days)
back to 1209600s (14 days). Also restore PositiveEvent affective context
search that was removed alongside the cutoff change.

Issue 7 (LOGIC REGRESSION): Fix affective_prefix to run every turn
(not just hist_len == 0). The care/joy directives must persist throughout
the session, not vanish after turn 1.

Issue 8 (MINOR): session_summary_write_dated now uses el_from_float(0.85)
for salience and importance (two-decimal) to avoid any ambiguity in float
parsing, and the function is re-added with the session-end hook.
2026-06-22 14:25:29 -05:00
will.anderson 588ca11f57 fix(context-dedup): include scan_part and affective_part IDs in seen set
Two design bugs in the state_set placement caused the dedup seen-ID set
to be incomplete even with callsites wired up:

1. state_set("engram_compile_seen_ids") was called immediately after
   merging the main node pools, before scan_part (persona fallback) and
   affective_part (bell node) were computed. Nodes appearing only in
   those segments were never added to the seen set.

2. affective_part is a bare JSON object (bn0 from json_array_get), not
   a JSON array. Passing it to engram_extract_ids would have gotten
   json_array_len == 0 and silently skipped the affective node's ID.

Fix: move state_set to after ctx is assembled from all three segments.
Extract ids_from_merged and ids_from_scan via engram_extract_ids (both
are JSON arrays), and extract ids_from_affective via json_get(affective_part, "id")
directly since it is a bare object. Merge all three via add_to_seen
before publishing to state.
2026-06-22 14:19:14 -05:00
will.anderson 9e178d8371 fix(recall): deduplicate engram nodes by ID across activation and search passes
Thread a seen-node-ID exclusion set from engram_compile() through to
session_preload in handle_chat, preventing the same high-salience nodes
(identity, recent memories) from appearing 2-3x in the system prompt.

Changes:
- Add id_in_seen(), add_to_seen(), engram_extract_ids() helpers that
  maintain a comma-delimited seen-ID accumulator (EL has no Set type)
- In engram_compile(): after merging all topic/entity/recall pools, extract
  node IDs from merged_nodes and publish via state_set(engram_compile_seen_ids)
- In handle_chat(): read seen_ids from state after engram_compile() returns,
  then check id_in_seen() before emitting each session_preload bullet
  (profile x3, work x2, project x2, summary x1 — all 8 candidate nodes guarded)

Nodes already present in the compiled engram context are skipped in preload,
eliminating 3000-3500 token repetition on first-message turns.
2026-06-22 14:06:04 -05:00
will.anderson aaada3770a fix(recall): deduplicate engram nodes by ID across activation and search passes
engram_compile() already published seen node IDs to state via engram_compile_seen_ids
but handle_chat never read or applied them. Wire up the consumption side:

- Read engram_compile_seen_ids from state after engram_compile() returns
- Check each session_preload candidate node (profile x3, work x2, project x2,
  summary x3) against id_in_seen() before emitting its content bullet
- Nodes already present in the compiled engram context are skipped entirely,
  preventing the same high-salience identity/memory nodes from appearing 2-3x
  in the system prompt and burning 3000-3500 tokens on repetition
2026-06-22 14:03:48 -05:00
will.anderson a0299c0a89 fix(recall): session-end summary hook + session summary recall at start 2026-06-22 14:01:56 -05:00
will.anderson 33cb1138f4 fix(recall): set threshold=25 in all engram_compile_ranked variants 2026-06-22 13:58:17 -05:00
will.anderson ec7efdeeb7 fix(recall): engram score float parsing — pad to 2 decimals before strip 2026-06-22 13:57:33 -05:00
will.anderson c93be6a315 feat(recall): context-format
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Failing after 13m54s
2026-06-22 13:29:12 -05:00
will.anderson 53268c94b9 feat(recall): activation-seed 2026-06-22 13:29:12 -05:00
will.anderson 7e43a4ddc0 feat(recall): context-dedup 2026-06-22 13:29:12 -05:00
will.anderson e7669da325 feat(recall): session-start-recall 2026-06-22 13:29:12 -05:00
will.anderson 4f1286df05 feat(recall): cross-session-continuity 2026-06-22 13:29:12 -05:00
will.anderson 52c222c4f2 feat(recall): engram-scoring 2026-06-22 13:29:12 -05:00
will.anderson 0caccd0ea5 feat(recall): temporal-precision 2026-06-22 13:29:12 -05:00
will.anderson 03b5632fc1 feat(recall): recall-reliability 2026-06-22 13:29:12 -05:00
will.anderson 42bbadcd33 Merge pull request 'feat(recall): emotional-recall improvements' (#52) from improve/recall-emotional-recall into main
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Failing after 5m49s
feat(recall): emotional-recall improvements
2026-06-22 18:24:36 +00:00
will.anderson b6052f9de3 Merge pull request 'feat(recall): recall-completeness' (#48) from improve/recall-recall-completeness into main
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
feat(recall): recall-completeness improvements
2026-06-22 18:24:17 +00:00
will.anderson 1dd09b1980 feat(recall): context-format improvements
Neuron Soul CI / build (pull_request) Has been cancelled
- Add engram_render_node/render_nodes/dedup_nodes helpers for human-readable
  prose bullet output instead of raw JSON node objects reaching the LLM
- Fix engram_compile_ranked to use |N| index sentinel instead of _sel_N JSON
  mutation which leaked sentinel fields into LLM-visible node data (Issue #11)
- Update build_system_prompt with chat_mode param; no_tools_rule only included
  for chat path, not agentic paths (Issue #9)
- Move engram block to end of system prompt for strongest LLM attention (Issue #8)
- Label sections: STABLE IDENTITY vs RETRIEVED MEMORY (Issue #10)
- Render conversation history as User:/Assistant: dialogue instead of raw JSON
- Add RETRIEVED MEMORY labels to agentic and dharma room system prompt assembly
2026-06-22 13:20:19 -05:00
will.anderson 0113407728 feat(recall): emotional-recall improvements
Neuron Soul CI / build (pull_request) Has been cancelled
2026-06-22 13:17:12 -05:00
will.anderson be02fcd960 feat(recall): thread-aware activation seed for nlg soul path [issue 7]
Neuron Soul CI / build (pull_request) Successful in 4m37s
2026-06-22 13:17:04 -05:00
will.anderson cbe8c09068 feat(recall): context-dedup improvements
Neuron Soul CI / build (pull_request) Has been cancelled
- Cache bell node in engram_compile state (engram_compile_bell_node)
  so handle_chat reads cached value instead of duplicate bell query (Issue 2)
- Cache activation result (engram_compile_activation_json) for strengthen_chat_nodes
  reuse — eliminates third activation query per turn (Issue 7)
- Fix context cap to truncate at clean JSON object boundary (Issue 6)
2026-06-22 13:15:33 -05:00
will.anderson dfa2a33926 feat(recall): context-dedup improvements
- Cache bell node result in engram_compile state (engram_compile_bell_node)
  so handle_chat affective_prefix reads the cached value instead of firing
  a duplicate engram query for distress signals (Issue 2)

- Cache primary activation result in engram_compile state
  (engram_compile_activation_json) using nodes0 from engram_compile_multi

- Replace redundant engram_activate_json(message, 2) in strengthen_chat_nodes
  with state_get(engram_compile_activation_json) - eliminates a third
  activation query per turn (Issue 7)

- engram_compile already has object-boundary truncation and cross-set
  dedup via engram_nodes_merge/engram_dedup_nodes (Issues 1, 6, 9)
2026-06-22 13:12:08 -05:00
will.anderson 18e040acb1 feat(recall): recall-completeness improvements
Neuron Soul CI / build (pull_request) Has been cancelled
- Lower engram_compile_ranked threshold 25->15: include moderately-relevant older nodes
- Extend sentinel cleanup from _sel_9 to _sel_14 to prevent JSON noise
- Add engram_split_topics for multi-topic decomposition (AND/and/also/plus)
- Add engram_extract_entities for named entity dedicated searches
- Add engram_detect_recall_intent for boosted 40-candidate search on recall phrases
- Add engram_is_continuation replacing brittle 50-char threshold (now 80 + pronoun/opener detection)
- Add engram_compile_multi with depth 8 (was 5) and 30-candidate search pool
- Add engram_nodes_merge for clean two-array deduplication
- Replace engram_compile with multi-topic/entity/recall-boost version; budget 6000->8000
- Safe JSON truncation: scan for last } before budget cap instead of raw str_slice
- handle_chat and agentic_chat: use engram_is_continuation; thread snip 150->250
- session_preload: add project-status and session-summary search queries
2026-06-22 13:11:06 -05:00
will.anderson 3f53b6b1b6 feat(recall): session-start-recall improvements
Neuron Soul CI / build (pull_request) Has been cancelled
10 targeted fixes for session-start memory recall quality:

Issue 1: typed engram queries (Persona, WorkItem) replace generic keyword bags
Issue 2: bullet truncation raised from 120 to 350 chars
Issue 3: bullet caps raised to 8/6 with while-loop (no hardcoded unrolling)
Issue 4: read pre-computed soul_affective_context state key instead of duplicating boot-time search
Issue 5: last-session-topic node written per session; continuity section added to session_preload
Issue 6: greeting detection injects SESSION START orientation directive when continuity found
Issue 7: pinned identity node fallback when all engram searches return empty
Issue 8: session_preload always fires on first message (greeting detection controls directive only)
Issue 9: agentic path gets matching session_preload block (was missing entirely)
Issue 10: BellEvent recency reads created_at / embedded ts marker, not the never-written "ts" field
2026-06-22 13:06:55 -05:00
will.anderson 21f248a33a feat(recall): recall-completeness improvements
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
- Lower engram_compile_ranked threshold 25->15: include moderately-relevant older nodes
- Extend sentinel cleanup from _sel_9 to _sel_14 to prevent JSON noise
- Add engram_split_topics for multi-topic decomposition (AND/and/also/plus)
- Add engram_extract_entities for named entity dedicated searches
- Add engram_detect_recall_intent for boosted 40-candidate search on recall phrases
- Add engram_is_continuation replacing brittle 50-char threshold (now 80 + pronoun/opener detection)
- Add engram_compile_multi with depth 8 (was 5) and 30-candidate search pool
- Add engram_nodes_merge for clean two-array deduplication
- Replace engram_compile with multi-topic/entity/recall-boost version; budget 6000->8000
- Safe JSON truncation: scan for last } before budget cap instead of raw str_slice
- handle_chat and agentic_chat: use engram_is_continuation; thread snip 150->250
- session_preload: add project-status and session-summary search queries
2026-06-22 13:05:28 -05:00
will.anderson 795b32ad1a feat(recall): cross-session-continuity improvements
Neuron Soul CI / build (pull_request) Failing after 14m49s
2026-06-22 13:00:17 -05:00
will.anderson f33cdaf793 feat(recall): activation-seed improvements
- Issue 2: replace raw 50-char threshold with is_genuine_continuation() that
  checks for explicit follow-up phrases and mid-sentence capitalization (proper
  nouns signal a new topic, not a continuation)
- Issue 3/8: build_activation_seed() scans back to find the prior USER turn as
  the topic anchor instead of using the last assistant reply (hist_len-1)
- Issue 4: engram_compile_multi() fans out across three seeds — enriched primary,
  raw message (entity queries), and emotion query — merging non-redundant results
- Issue 5: agent workspace_root appended to ag_seed so agentic activation is
  workspace-aware; previously ignored despite being available in state
- Issue 6: distill_transcript() extracts salient tail+question content from full
  transcripts before passing to engram_compile in dharma room handlers
- Issue 7: dist/soul-with-nlg.el handle_chat and handle_chat_agentic now load
  history and use build_activation_seed() — the raw message path is eliminated
- Issue 9: topic_snip_from_entry() takes the TAIL 200 chars of a long reply and
  finds the last sentence boundary — captures end-of-reply named concepts
- Issue 10: multi_turn_topic() pulls up to 3 prior user turns into the non-
  continuation seed so earlier thread context re-activates high-salience nodes
2026-06-22 12:55:33 -05:00
will.anderson a60b1967df feat(recall): recall-completeness improvements
- Multi-query decomposition: split on AND/also/plus for multi-topic messages
- Named entity extraction: dedicated per-entity searches for project names
- Recall intent detection: boosted search pool for explicit recall requests
- Expanded pools: activation depth 8 (was 5), search 30->12 ranked (was 20->8)
- Threshold 25->15: retain moderately-relevant older nodes
- Sentinel cleanup extended to c14 for larger node pools
- Safe JSON truncation: find last closing brace before budget cap (8000 chars)
- Semantic continuation: engram_is_continuation replaces brittle 50-char threshold
- Thread snip: 150->250 chars for better pronoun resolution context
- Session preload: add project-specific and session-summary searches
2026-06-22 12:54:36 -05:00
will.anderson aef687b57c fix(reliability): state management
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
2026-06-22 12:54:32 -05:00
will.anderson 76c2e47d0f feat(recall): fix engram-scoring — float parsing, recency, threshold, sentinels
Neuron Soul CI / build (pull_request) Has been cancelled
Fix critical float parsing bug: %g serializes 0.70 as '0.7', naive str_replace
dot-strip gives str_to_int('07')=7 not 70. New parse_salience_100() uses
str_index_of to detect single-decimal strings and multiplies by 10 to correct.
Affects conv nodes (0.6/0.7), default memories (0.5/0.5), utterance nodes (0.6)
— the majority of the graph was scoring near zero and filtered by threshold=25.

Fix recency to use max(created_at, updated_at, last_activated) so nodes
strengthened by engram_strengthen() after chat turns score as fresh, not by
original write time. A node referenced yesterday but created 25 days ago
was borderline-filtered; now correctly scores fresh.

Compress recency dynamic range from 10x (10-100) to 1.54x (65-100) via
formula (50 + recency/2). Old formula: sal*imp*recency/10000 let recency
dominate — a canonical high-importance node at 30 days scored identical to
a fresh noise node. New: high-importance nodes remain competitive when old.

Add tier-aware decay with softer floor (30 not 10): Canonical nodes decay
over 365 days, Episodic over 90 days, working/untiered over 35 days. Long-
term identity and persona nodes are no longer permanently filtered.

Lower threshold from 25 to 15 to admit moderately-relevant older nodes that
pass scoring with the corrected formula. Backfills recall coverage lost when
single-decimal nodes were being silently discarded.

Apply scoring to activation nodes: engram_compile_ranked(activate_json, 5)
replaces unconditional pass-through. Threshold 5 preserves recall while
excluding genuinely zero-quality stale nodes.

Extend sentinel cleanup in engram_compile_ranked from _sel_0-9 to _sel_0-19
so max_nodes can safely be increased past 10 without JSON corruption.
2026-06-22 12:53:35 -05:00
will.anderson 0ede112d05 feat(recall): temporal-precision improvements
Neuron Soul CI / build (pull_request) Has been cancelled
Fix critical float parsing bug in engram_score_node: str_replace('.','')
then str_to_int silently miscored single-decimal salience strings (0.9->9,
0.7->7, 1.0->1). Introduce parse_salience_100() which detects decimal
position and scales correctly (no decimal: *100; one decimal: *10;
two decimals: as-is).

Replace flat 30-day linear decay with tier-aware decay curves: Canonical
nodes use a 365-day window (foundational identity resists aging), Episodic
nodes use 90 days, Working/untiered keep the existing 30-day slope. Floor
stays at 10 for all tiers.

Use max(created_at, updated_at) as the recency reference so revised nodes
are not penalised for their original creation date.

Extend affective context windows from 72h/7d to 14 days across all three
paths (engram_compile, handle_chat, soul.el load_identity_context) so a
Friday crisis carries into Monday sessions and all paths present consistent
context. The 72h/7d split caused conflicting affective context between
soul.el (which loaded a 5-day-old crisis node) and chat.el (which excluded
it on subsequent turns).

Add salience evolution to mem_consolidate: strengthen top working-memory
nodes (recently recalled across sessions) and Canonical-tier nodes
(foundational identity must not decay to the floor). Previously consolidate
returned structural counts only with no salience changes.

Expand conversation window from 20 to 40 turns in both handle_chat and the
agentic history trim. Long technical sessions were losing early problem
framing at 10 user + 10 assistant pairs.
2026-06-22 12:53:29 -05:00
will.anderson a39998a502 feat(recall): recall-reliability improvements
Neuron Soul CI / build (pull_request) Failing after 12m52s
- Q1: engram_numeric_valid() guard against non-numeric timestamps in bell scoring
- Q2: soul-agnostic cold-start fallback in engram_compile (drops genesis-specific hardcoded node IDs)
- Q3: partial-write guard and failure logging in conv_history_persist/load
- Q4: document circuit-breaker limitation requiring C runtime support
- Q5: println warnings on empty activation/search paths
- Q6: load_identity_context warns when all identity fetches return empty
- Q7: recall_status state tracking (ok/empty/unavailable) surfaced to LLM via MEMORY STATUS block
- Q8: document shared-state race conditions in engram_recall_status and safety_system_addendum
- CRITICAL BUG: conv_node_id empty check moved outside is_bell block so silent Conversation node loss is always logged
2026-06-22 12:52:31 -05:00
will.anderson 6edf9937dd fix(reliability): LLM retry
Neuron Soul CI / build (pull_request) Has been cancelled
2026-06-22 12:37:29 -05:00
will.anderson e447a87a00 fix(reliability): route error recovery 2026-06-22 12:37:21 -05:00
will.anderson 575ff1329a fix(reliability): engram connection 2026-06-22 12:34:04 -05:00
will.anderson db33b0cb91 fix(reliability): engram write 2026-06-22 12:32:59 -05:00
will.anderson f35569d4bb fix(reliability): cross-session affective state 2026-06-22 12:31:09 -05:00
will.anderson 94b71b6e6b fix(reliability): conversation history 2026-06-22 12:29:23 -05:00
will.anderson 392d2416ec fix(reliability): replace undefined session_exists with session_get check
Neuron Soul CI / build (pull_request) Failing after 13m25s
2026-06-22 12:21:31 -05:00
will.anderson 87c7d15b67 Merge pull request 'fix(reliability): session-boundary' (#41) from improve/reliability-session-boundary into main
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
fix(reliability): session-boundary — lifecycle guards, cleanup on expiry
2026-06-22 17:20:33 +00:00
will.anderson 93bed793c0 Merge pull request 'fix(reliability): safety-resilience' (#39) from improve/reliability-safety-resilience into main
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
fix(reliability): safety-resilience — crisis detection degradation paths
2026-06-22 17:19:29 +00:00
will.anderson 936b3f0ac9 feat(agentic): workspace root from request body — edit_file scope, trailing-slash fix, conditional state_set
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
Merge propose/agent-workspace-root-read (Tim's PR #28):
- path_within_root now appends '/' to root before prefix check (closes proj_evil bypass)
- edit_file in dispatch_tool now checks agent_workspace_root() and resolves path
- handle_chat_agentic reads agent_workspace_root from request body, only persists if non-empty
- Safety screen preserved after workspace root read (conflict resolved)
2026-06-22 12:16:28 -05:00
will.anderson 45dc80230d fix(safety): crisis detection — augment wired to system prompt, ts fallback, cross-session affective
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Failing after 6m10s
Merge improve/safety-crisis-detection (PR #31): reads layered_cycle_safety_system_addendum
from state and appends to system prompt on each turn (cleared after use to prevent bleed).
Safety ts extraction falls back to updated_at. Affective prefix now wires into system build.
Conflict with PR #33 resolved: capability_rules and session_preload both preserved.
2026-06-22 12:15:50 -05:00
will.anderson 9ba86b8f80 Merge pull request 'feat(memory): emotional salience tagging and cross-session distress persistence' (#34) from improve/soul-memory-formation into main
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
feat(memory): emotional salience tagging, BellEvent ts fix, label uniqueness
2026-06-22 17:14:25 +00:00
will.anderson 360c15d7fe Merge pull request 'fix(routes): error handling, health endpoint, request validation, rate limiting' (#32) from improve/soul-routes-api into main
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
fix(routes): error handling, health endpoint, validation, rate limiting
2026-06-22 17:14:10 +00:00
will.anderson e6da638536 fix(reliability): state-management — document and partially fix concurrent state races
Neuron Soul CI / build (pull_request) Has been cancelled
Issues addressed:
- #2: Document session_index non-atomic RMW (engram node safe under new mutex)
- #3: Document conv_history global race in handle_chat (session path unaffected)
- #4: Scope session_continuity state key per session_id in layered_cycle
- #5: Document active_imprint_id global race with fix path
- #6: Fix next_bridge_id to use uuid_v4() for collision-free IDs
- #7: Document session_hist_save delete-then-insert race
- #8: Document /api/graph/edges engram_save race (fixed in el_runtime.c)
- #10: Document agentic_conv_history global race in awareness loop

Issues #1 (engram_global mutex) and #8 (atomic engram_save write-to-temp+rename)
are fully fixed in el_runtime.c (committed to foundation/el repo separately).
Issue #9 skipped — already fixed in PR #31.
2026-06-22 12:12:58 -05:00
will.anderson 0c5b966773 fix(chat): fix auto_persist timestamp extraction and bell label uniqueness
Neuron Soul CI / build (pull_request) Has been cancelled
- engram_compile: BellEvent nodes do not carry created_at in the engram
  node JSON; extract the unix timestamp from the embedded ' | ts:NNNNN'
  pattern in the content string instead. Fall back to created_at/updated_at
  if the marker is absent. Guard str_to_int against empty string so the 72h
  recency check never silently treats every node as epoch-0 stale.

- auto_persist: append the current unix timestamp to the BellEvent label
  ('bell:soft:1749876543') to make it unique per turn. The previous label
  ('bell:soft') was the same for every soft bell, causing engram to treat
  all subsequent writes as updates to the same node.
2026-06-22 12:09:00 -05:00
will.anderson c87a536da3 fix(safety): wire safety augment into system prompt, fix timestamp fallback
Neuron Soul CI / build (pull_request) Has been cancelled
- Remove dead soft_bell block in layered_cycle that wrote soul_safety_system_augment
  to state but was never read; safety augmentation now goes through the correct
  layered_cycle_safety_system_addendum state key read by build_system_prompt
- build_system_prompt now reads layered_cycle_safety_system_addendum and appends
  it to the system prompt, clearing the key after consumption
- Timestamp extraction for distress nodes falls back to updated_at when created_at
  is empty, preventing the 72h recency check from always treating nodes as stale
2026-06-22 12:07:18 -05:00
will.anderson 2865d6ad26 fix(reliability): route-error-recovery
Neuron Soul CI / build (pull_request) Has been cancelled
- Issue #3: err_404/err_405 now emit HTTP 404/405 via __status__ envelope instead of HTTP 200
- Issue #4: add auth_check() function to handle_request; enforces NEURON_TOKEN on all routes except /health and /lineage
- Issue #5: missing required params now return HTTP 400 (__status__ envelope) in /api/chat (GET+POST), /imprint/contextual, /imprint/user, and handle_chat
- Issue #6: LLM unavailable in handle_chat now returns HTTP 503 instead of HTTP 200
- Issue #7: add 32 KB message size guard on POST /api/chat before engram_compile and LLM
- Issue #8: add TODO comment to route_health documenting the live-engram-query problem and the /health/deep split plan
- Issue #9: add comment to hist_trim documenting fragile str_index_of parser and silent data corruption risk
- Issue #10: add TODO comment in handle_request documenting missing per-IP rate limiting
- Issue #11: fix connectd_post temp file collision — add monotonic sequence counter so concurrent requests get unique paths
- Issue #12: fix call_mcp_bridge fixed temp file race — add monotonic sequence counter for unique paths under concurrent load
- Issues #1/#2: add TODO comment in handle_request documenting EL no-exception limitation and SIGSEGV handler gap
2026-06-22 12:00:06 -05:00
will.anderson 47d0e6f985 fix(reliability): llm-retry — empty response detection, configurable max_tokens, connector timeout
Neuron Soul CI / build (pull_request) Failing after 11m16s
Issue #5: detect empty string from llm_extract_text() as an error in handle_chat,
handle_chat_as_soul, and handle_dharma_room_turn. The C runtime silently returns ""
when the LLM response content array is missing or all blocks fail to parse; without
this guard the empty string passes through to callers as a silent empty reply.

Issue #9: make agentic_loop max_tokens configurable via NEURON_LLM_MAX_TOKENS env
var (default 4096). The hardcoded value is marginal for long tool chains (8 iterations
x 4096 tokens); operators can now set 8192+ for complex multi-step tasks without
rebuilding. Non-agentic path (llm_call_system) still uses the C runtime hardcode —
that fix lives in el_runtime.c (see TODO block added in this commit).

Issue #10: increase connector_tools_json and tool_auto_approved curl --max-time from
2s to 5s to reduce false-empty tool lists when neuron-connectd is under transient
load. Graceful degradation to [] on bridge down is unchanged.

Issues #1/#2/#3/#4/#6/#8: documented as TODO comments in chat.el. These require
targeted C runtime changes in el_runtime.c (llm_provider_request retry loop,
EL_LLM_TIMEOUT_MS separation, HTTP 429 backoff, 5xx retry, EL_HTTP_MAX_RESPONSE_BYTES
cap). Architectural decisions recorded so they are traceable to root causes.
2026-06-22 11:59:43 -05:00
will.anderson f0545defdb fix(reliability): session-boundary — ghost sessions, bridge leak, session validation
Neuron Soul CI / build (pull_request) Has been cancelled
- sessions.el: add session_exists() for chat-path session validation (ISSUE #6/#7)
- sessions.el: add session_create_cleanup() for ghost-session rollback (ISSUE #1)
- sessions.el: set session_pending_first_msg flag in session_create; clear it in
  session_hist_save so the first successful chat marks the session active (ISSUE #1)
- sessions.el: session_delete now clears mcp_bridge:<id> and always_allow_<id>
  state keys so abandoned pending-tool sessions do not accumulate (ISSUE #5)
- sessions.el: add TODO comments for ISSUE #2 (no TTL/expiry), ISSUE #3
  (non-atomic delete-then-create), ISSUE #4 (no concurrent-create guard),
  and ISSUE #8 (reconnect/duplicate resume race) where fixes are too invasive
  to land without new runtime primitives
- chat.el: validate session_id exists via session_exists() before entering
  agentic_loop; unknown session_ids now return a 404-style error instead of
  silently starting a fresh empty session (ISSUE #6/#7)
2026-06-22 11:58:33 -05:00
will.anderson ae9a139440 fix(reliability): safety-resilience — bell augmentation, safe mode, dedup logging, tab escaping, handle_chat coverage
Neuron Soul CI / build (pull_request) Has been cancelled
2026-06-22 11:57:43 -05:00
will.anderson d008649c3e fix(reliability): engram-connection
Neuron Soul CI / build (pull_request) Has been cancelled
- entrypoint.sh: extend engram health-check timeout 30->60s; set
  EL_HTTP_TIMEOUT_MS=10000 and EL_HTTP_CONNECT_TIMEOUT_MS=3000 to bound
  awareness loop blocking window to 10s/call (down from 60s default)
- soul.el: 3-attempt retry loop for boot-time /api/nodes+/api/edges fetch;
  validate non-empty JSON array before loading to prevent silent zero-node
  identity graph from transient post-healthcheck network hiccup
- awareness.el: soft circuit-breaker in ise_post (opens after 3 failures,
  30s backoff, half-open probe); /api/sync refresh skips HTTP call when
  breaker is open; error-JSON detection on sync response

TODOs: full async dispatch, connection pooling (require EL futures/persistent curl)
2026-06-22 11:57:20 -05:00
will.anderson aa70c5dde6 fix(reliability): safety-resilience — bell augmentation, safe mode, dedup logging, tab escaping, handle_chat coverage 2026-06-22 11:54:40 -05:00
will.anderson b7fd8901d4 fix(routes): fix handle_request ABI, 429 status code, soul_boot_ts write
Neuron Soul CI / build (pull_request) Has been cancelled
2026-06-22 11:53:09 -05:00
will.anderson deddb9a18e fix(reliability): safety-resilience — bell augmentation, safe mode, dedup logging, tab escaping, handle_chat coverage 2026-06-22 11:53:07 -05:00
will.anderson 494d973a3b fix(reliability): engram-write — guard all fire-and-forget writes
Neuron Soul CI / build (pull_request) Has been cancelled
Every engram_node_full call that dropped its return value now binds it
and emits a println on empty string. engram_save calls in consolidate,
heartbeat, and dharma-room-turn are checked for failure. The two API
handlers (log_state_event, tune_config) that skipped api_persisted()
now match the read-back-after-write contract used everywhere else in
neuron-api.el.

Files changed:
- chat.el: conv_history_persist, handle_dharma_room_turn, auto_persist
- soul.el: emit_session_start_event, seed_persona_from_env HTTP check
- memory.el: mem_save, mem_boot_count_inc
- neuron-api.el: handle_api_log_state_event, handle_api_tune_config,
  handle_api_consolidate (engram_save + session summary write)
- awareness.el: ise_post local-engram fallback path

TODO comments added for non-atomic patterns (issues #12, #13) and
the missing circuit breaker (#14) — these require new primitives.
2026-06-22 11:48:59 -05:00
will.anderson 34551695a1 fix(reliability): cross-session-affective
Neuron Soul CI / build (pull_request) Has been cancelled
- Fix state key mismatch: soul.el layered_cycle now reads conv_history
  (not conversation_history), unblocking the safety_score_distress_history
  history-amplification path in safety_threat_score
- Add safety_augment_system call on the main handle_chat path so the
  phrase-list bell detector fires on all chat turns, not just dharma rooms
- Add cross-session affective engram query in load_identity_context() at
  boot; stores distress/crisis signals from prior sessions under
  soul_affective_context with a 7-day soft recency filter
2026-06-22 11:48:30 -05:00
will.anderson dcf050ee3c fix(agentic): workspace root security — edit_file scoping, trailing-slash normalization, conditional state_set
Neuron Soul CI / build (pull_request) Has been cancelled
2026-06-22 11:46:44 -05:00
will.anderson 615f0cee08 fix(reliability): conv-history — asymmetric load, silent failures, broken trim, agentic gap
Neuron Soul CI / build (pull_request) Has been cancelled
Issues addressed:
- #1 ASYMMETRIC PERSIST/LOAD: conv_history_load() now tries engram_get_node_by_label()
  first (symmetric with the label-based write), falling back to vector search only when
  label lookup returns nothing. Immune to cold/corrupt vector index.
- #2 SILENT LOAD FAILURE: all failure paths in conv_history_load() and conv_history_persist()
  now emit a println log line rather than silently returning "" or dropping writes.
- #3 NO RECOVERY PATH: documented as TODO with explanation of why a full recovery path
  (retry, ID fallback, orphan cleanup) is too invasive for a targeted fix here.
- #4 OVERWRITE WITHOUT DELETE: documented with TODO to replace engram_node_full with
  explicit delete-then-create once engram exposes a label-scoped delete API.
- #5/#10 BROKEN TRIM / OFF-BY-ONE: hist_trim() rewritten to use json_array_len /
  json_array_get (structural JSON ops) instead of raw str_index_of scanning for
  '{"role":' markers. Immune to marker strings appearing inside message content.
  Minimum retained count guard added: never trims below 2 entries.
- #6 PARTIAL-WRITE GUARD: conv_history_persist() refuses to write a blob that doesn't
  contain both '[' and ']'. conv_history_load() requires both before accepting content.
- #7 DUAL STORAGE: documented with a comment at the persist call site.
- #8 NO MAX SIZE GUARD: documented as TODO with rationale for why a byte-length cap
  requires a more invasive change (entry truncation or summarisation).
- #9 AGENTIC HISTORY NOT PERSISTED: handle_chat_agentic() now calls conv_history_persist()
  for the default global session (hist_key == "conv_history") after updating state,
  matching the non-agentic path's durability. Named sessions remain in-process only.
2026-06-22 11:46:00 -05:00
will.anderson 260b9e55d4 feat(soul): context quality, profile load, refusal handling
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Failing after 9m48s
2026-06-22 11:39:33 -05:00
will.anderson fda76ae05b Merge pull request 'feat(ci): strip debug symbols from soul binary before publishing' (#35) from improve/soul-strip into main
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
2026-06-22 16:39:14 +00:00
will.anderson d3eda47fd3 feat(ci): strip debug symbols from soul binary before publishing
Neuron Soul CI / build (pull_request) Has been cancelled
Add strip -s after gcc compilation to remove symbol table and relocation info.
Reduces binary size and prevents symbol-level reverse engineering of EL runtime internals.
2026-06-22 11:37:28 -05:00
will.anderson f3069b481d Merge pull request 'fix(chat): forbid fake tool calls in tool-less (Just chat) mode' (#29) from propose/no-fake-tools-in-chat-mode into main
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Has been cancelled
fix(chat): forbid fake tool calls in tool-less mode
2026-06-22 16:36:43 +00:00
will.anderson b2008f4894 feat(memory): emotional salience tagging and cross-session distress persistence
Neuron Soul CI / build (pull_request) Successful in 5m36s
- auto_persist: detect bell level (soft/hard) on every user message using
  safety_detect_bell_level; write a dedicated BellEvent engram node with
  calibrated salience alongside the Conversation node when a bell fires.
  Tag the Conversation node with bell:soft/bell:hard and 'affective' for
  direct discovery without scanning all chat nodes.

- auto_persist: track per-session bell count, dominant level, and last
  signal in state (session_bell_count/level/signal keys) so downstream
  functions can act on the emotional history without re-scanning engram.

- engram_compile: include the top-1 most recent BellEvent node within 72h
  in every context build. Distress context from earlier turns (same or
  recent session) automatically travels into all subsequent LLM calls.

- hist_trim_with_bell_guard: replace hist_trim at the handle_chat call site.
  Before evicting the oldest turn from the 20-turn window, inspect the user
  message for bell signals. If a bell was present, write a preservation
  BellEvent to engram before dropping the turn so the full message survives
  the rolling window.

- session_hist_save: after writing the history node, check session bell
  counters. On the first save where bell_count > 0, write a
  session:emotional-summary BellEvent node with distress signal, count,
  and dominant level. A state flag prevents duplicate writes on subsequent
  saves in the same session.
2026-06-22 11:23:15 -05:00
will.anderson 28fce08dd9 feat(soul): context quality, first-message profile load, refusal handling, agentic safety
Neuron Soul CI / build (pull_request) Has been cancelled
- engram_compile: rank search results by recency x relevance before including
  in context. Pulls 20 candidates, scores each (salience * importance * recency
  decay), keeps top 8. Eliminates stale/low-signal nodes that diluted context.

- handle_chat: on hist_len==0 (session start), proactively load user profile
  and active-work context from engram and inject as brief bullets in the system
  prompt. Gives the soul grounding before any conversation history exists.

- build_system_prompt: add [CAPABILITY GAPS] directive instructing the soul to
  offer partial help and reasoning instead of flat "I don't have access to that"
  refusals when a tool is missing.

- handle_chat_agentic: run safety_screen at entry, mirroring layered_cycle.
  Hard bell exits immediately with the crisis response without entering the loop.

- agentic_loop: surface the 8-iteration cap explicitly in the error envelope
  ("agentic loop hit the 8-iteration cap...") rather than the opaque "no response".
  Add iterations count to both the error and success envelopes for observability.
2026-06-22 11:22:14 -05:00
will.anderson d92b8c279a fix(routes): error handling, health diagnostics, request validation, rate limiting
Neuron Soul CI / build (pull_request) Has been cancelled
- Add per-IP in-memory rate limiter (60 req/min default, configurable via
  soul_rate_limit state key; /health exempt; loopback callers skipped)
- Extend /health with uptime_secs (from soul_boot_ts) and live LLM probe
- Add missing_param 400 guard on POST /api/chat before passing to LLM
- Standardise error envelopes: add "code" field to err_404/err_405 and all
  missing-param returns; route_synthesize now errors clearly instead of
  returning the misleading {"mechanism":"did not engage"} on bad input
- Document streaming gap in /api/chat (SSE not implemented, note added)
- handle_request gains ip param; rate_limit_check wired at entry point
2026-06-22 11:21:18 -05:00
will.anderson e9a8a659e0 fix(safety): crisis detection — 4 targeted fixes
Neuron Soul CI / build (pull_request) Failing after 14m43s
- soul.el: fix state key bug in layered_cycle (conversation_history -> conv_history)
- safety.el: add indirect crisis location patterns to soft_bell phrase list
- soul.el: wire safety_augment_system into layered_cycle for soft_bell turns
- chat.el: load cross-session affective context at session start when distress signals found within 72h
2026-06-22 11:20:42 -05:00
Tim Lingo f6c4ea70a0 fix(chat): forbid fake tool calls in tool-less (Just chat) mode
Neuron Soul CI / build (pull_request) Successful in 4m47s
REPRODUCED: in the non-agentic path (Tools off / 'Just chat'), asking for
tool-work makes the model role-play tool use — it emits a fake ```json {...}```
'tool call' and says 'let me search/query/pull your sessions' while NOTHING
runs. Reads as a broken/lying app. (The agentic path is fine: verified it
calls search_memory and reports honestly.)

Root cause: build_system_prompt (handle_chat, the tool-less path) never told
the model it has no tools this turn, so it fabricated.

Fix: add a NO-TOOLS directive to the non-agentic system prompt — never emit
tool calls / JSON tool blocks / 'let me pull...' narration; answer from context
only; if a tool is truly needed, say so in one sentence and tell the user to
turn Tools on. Applied to chat.el (source) AND dist/soul.c (the curated TU the
CI compiles), so the CI-built binary carries it.

Verified the FABRICATION repro on the live local soul; could not verify the
patched binary locally (no matching el-runtime version on this machine — a
hand-link against origin/main runtime 404s on all routes). Builds correctly via
CI, which links soul.c against the pinned runtime.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 11:57:24 -05:00
Tim Lingo 1b83b18c39 propose(agentic): read agent_workspace_root from request body and persist to state
Neuron Soul CI / build (pull_request) Successful in 7m45s
Completes the UI<->soul contract for #23 (scope file/command tools to an agent
workspace root). #23 made the tools read state_get("agent_workspace_root"), but
nothing set that key from the desktop UI, so the agent panel's Workspace Folder
was cosmetic and tools ran unscoped (default-allow). This reads the root the UI
now sends on each agentic request and state_sets it before tool dispatch, so
agent_workspace_root() picks it up for the turn.

Minimal + pattern-matching (same json_get/state_set shape used throughout chat.el).
Empty body field => unscoped (backward-compatible) and preserves the env fallback.

FOR WILL'S REVIEW — do not merge without sign-off:
- Ownership model: set state from body each turn (so clearing the folder un-scopes)
  vs. only-when-nonempty. Flagged inline.
- Pairs with neuron-ui PR #32 (ChatRequest.agentWorkspaceRoot).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 19:56:20 -05:00
will.anderson ddd858d2ec fix(deploy): extend rollout timeout to 8m for GKE Autopilot cold starts
Neuron Soul CI / build (push) Has been cancelled
Deploy Soul to GKE / deploy (push) Failing after 5m48s
2026-06-19 15:35:34 -05:00
will.anderson 996dd3860a fix: replace embedded python with sed in deploy-gke manifest update step
Neuron Soul CI / build (push) Successful in 7m6s
Deploy Soul to GKE / deploy (push) Failing after 8m11s
2026-06-19 15:25:22 -05:00
will.anderson 6f4adf7640 self-review 2026-06-19: filter auto_term to Memory/BacklogItem/Entity only
Knowledge nodes dominated the WM-autobiographical auto_term slot:
'Numeric tier strings...' (a Knowledge node) always scored highest
in WM and its first word 'Numeric' became the curiosity seed every
scan — activating more Numeric nodes, keeping that node in WM,
repeating indefinitely.

Fix: only derive auto_term from Memory, BacklogItem, or Entity nodes.
Knowledge nodes are reference material, not live context. Dynamic/
personal nodes carry the salience worth radiating from.

Also patches proactive_curiosity directly in dist/neuron.c (ELC
cannot compile soul.el within timeout — fallback build pattern).
2026-06-19 08:49:42 -05:00
will.anderson 7e901bbbd2 fix(ci): prune Docker state at start of CI build to prevent disk exhaustion
Neuron Soul CI / build (push) Successful in 5m22s
2026-06-18 15:03:19 -05:00
will.anderson 2de1e60b8a fix(ci): update infra manifests after blue-green swap
Neuron Soul CI / build (push) Failing after 10m28s
2026-06-18 14:23:30 -05:00
will.anderson b563fff062 fix(ci/docker): pre-download artifacts before build, remove --secret
Neuron Soul CI / build (push) Successful in 6m32s
Deploy Soul to GKE / deploy (push) Successful in 7m46s
The Dockerfile's --mount=type=secret path was corrupting the SA key JSON
due to control character handling differences. Pre-download soul + El SDK
in the CI workflow (using already-authenticated gcloud) and COPY them from
the build context. No credentials needed inside the Docker build.
2026-06-18 14:04:03 -05:00
will.anderson fdd946b3d4 fix(ci): serialize build+deploy via concurrency group to prevent Docker exhaustion
Neuron Soul CI / build (push) Failing after 10m13s
Deploy Soul to GKE / deploy (push) Failing after 5m25s
2026-06-18 13:43:52 -05:00
will.anderson de8f021a55 fix(ci): install docker-buildx-plugin for BuildKit secret support
Deploy Soul to GKE / deploy (push) Failing after 11m0s
Neuron Soul CI / build (push) Failing after 11m11s
2026-06-18 13:42:56 -05:00
will.anderson d0c4d19faa fix(ci): prune Docker state before deploy to recover disk space
Deploy Soul to GKE / deploy (push) Failing after 12m57s
Neuron Soul CI / build (push) Failing after 13m7s
Previous builds leave cached layers and images on the runner. Add a
docker system prune at start of deploy to avoid container-creation
failures from disk exhaustion.
2026-06-18 13:15:52 -05:00
will.anderson b715a5dffb fix(ci): enable DOCKER_BUILDKIT and fix SHA extraction in deploy
Deploy Soul to GKE / deploy (push) Failing after 11m23s
Neuron Soul CI / build (push) Failing after 11m33s
--secret requires BuildKit; DOCKER_BUILDKIT=1 enables it on the legacy
Docker client. Also add GITHUB_SHA fallback and git rev-parse last-resort
so the image tag is never empty.
2026-06-18 12:42:25 -05:00
will.anderson 28e0afc11d fix(ci): preserve pre-compiled soul.c across elb run
Deploy Soul to GKE / deploy (push) Failing after 5m36s
Neuron Soul CI / build (push) Successful in 6m24s
elb overwrites dist/soul.c with a fresh (non-inlined) compilation before
its link step fails, discarding the patched self-contained version.
Save the repo copy before elb and restore it after so the compiler always
gets the complete translation unit with all patches applied.
2026-06-18 12:34:06 -05:00
will.anderson 46a7a4e9d8 Set USE_GKE_GCLOUD_AUTH_PLUGIN for GKE deploy workflow
Neuron Soul CI / build (push) Failing after 5m18s
Deploy Soul to GKE / deploy (push) Failing after 10m13s
Modern gcloud CLI (>= 400) requires this env var so kubectl uses the
installed gke-gcloud-auth-plugin binary instead of the deprecated
application-default credentials path. Without it, kubectl commands
silently fail even after get-credentials succeeds.
2026-06-18 12:23:49 -05:00
will.anderson ceef82464a chore(dist): update pre-compiled soul.c to patched4
Deploy Soul to GKE / deploy (push) Failing after 6m20s
Neuron Soul CI / build (push) Failing after 6m56s
Incorporates PRs #22/#23/#24:
- agentic_tools_all dedup fix (no duplicate web_search tool)
- workspace scope functions (agent_workspace_root, path_within_root, resolve_in_root)
- updated dispatch_tool with workspace confinement
- canonical-self bridge (ensure_self_canonical_bridge)

Also incorporates CI link fix from PR #26 (soul.c is self-contained, no
other dist/*.c needed). Fixes the CI build step which was compiling the
old June-16 soul.c that predated all these changes.
2026-06-18 12:19:54 -05:00
will.anderson 6f113a9601 Merge pull request 'feat(agentic): scope file/command tools to an agent workspace root' (#23) from feat/agent-tool-workspace-scope into main
Neuron Soul CI / build (push) Failing after 6m47s
Deploy Soul to GKE / deploy (push) Failing after 5m21s
2026-06-18 16:29:35 +00:00
will.anderson 8e25da3673 Merge pull request 'fix(identity): bridge public self anchor to the curated self node' (#24) from fix/canonical-self-bridge into main
Deploy Soul to GKE / deploy (push) Failing after 8m15s
Neuron Soul CI / build (push) Failing after 14m56s
2026-06-18 16:29:16 +00:00
will.anderson ca29e7ca35 Merge pull request 'fix(ci): link soul.c only — fixes capability #error breaking every build' (#26) from fix/ci-soul-build-single-file into main
Neuron Soul CI / build (push) Failing after 9m27s
Deploy Soul to GKE / deploy (push) Failing after 10m3s
fix(ci): link soul.c only — fixes capability #error breaking every build
2026-06-18 16:29:05 +00:00
will.anderson 6576dddca2 Merge pull request 'fix(chat): remove duplicate web_search tool crashing all agentic requests' (#22) from fix/agentic-tools-duplicate-web-search into main
Deploy Soul to GKE / deploy (push) Failing after 8m40s
Neuron Soul CI / build (push) Failing after 10m21s
fix(chat): remove duplicate web_search tool crashing all agentic requests
2026-06-18 16:28:41 +00:00
will.anderson ce3c3873c5 fix(ci): link soul.c only — drop multi-module cc that triggers capability #error
Neuron Soul CI / build (pull_request) Failing after 7m44s
elb generates a dist/soul.c with all El modules inlined. Linking
dist/soul.c alone is sufficient and is exactly what the local mac
build does. Including other dist/*.c files causes two failures:
  1. dist/chat.c has a capability-violation #error that fires when the
     file is compiled as a utility module (outside the cgi entrypoint).
  2. --allow-multiple-definition masked other issues silently.

Drop OTHER_C, drop --allow-multiple-definition, drop the now-unused
elp-c-decls.h generation step. The cc command now matches the proven
local build exactly.
2026-06-18 11:27:57 -05:00
Tim Lingo 149a042db9 fix(identity): bridge public self anchor to the curated self node
Neuron Soul CI / build (pull_request) Failing after 4m34s
The graph API resolves name=self/neuron to kn-efeb4a5b (neuron-api.el:471),
which carries only 8 incidental 'tagged' edges. The curated identity lives on
self node 015644f5 (1461 edges: identity, embodies, remembers, values). So
public self-traversal reaches tags, not the real self.

Add ensure_self_canonical_bridge(): an idempotent boot-time repair that links
kn-efeb4a5b <-> 015644f5 with a 'canonical-self' edge, only if missing. Runs in
the genesis safe-to-seed path regardless of the <100-edge gate, so the live
populated graph gets repaired and persisted. Connect-only-if-missing prevents
the duplicate-edge stacking that gates init_soul_edges().

Compile-checked with elc (darwin arm64); not link/run-gated locally. Needs a
soul build + smoke test before merge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 23:53:13 -05:00
Tim Lingo 071c0eeb9f feat(agentic): scope file/command tools to an agent workspace root
Neuron Soul CI / build (pull_request) Failing after 5m7s
Confine the agentic file tools (read_file, write_file, list_files, grep)
to a configured workspace subtree via a lexical path check, and run
run_command with its cwd set to that root. Root comes from state key
"agent_workspace_root" or env NEURON_AGENT_ROOT. When no root is set,
behavior is unchanged (unscoped) for backward compatibility.

Defense-in-depth, NOT a hard boundary: the lexical guard does not resolve
symlinks and cannot stop an arbitrary shell command from cd-ing out of the
root. Real confinement needs runtime support (cwd-locked exec / sandbox-exec
/ chroot) in el_runtime.c.

Compile-checked with elc (darwin arm64); not link/run-gated locally
(darwin elb unavailable). Needs a soul build + smoke test before merge.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 23:49:01 -05:00
will.anderson 53fb75353f fix(chat): remove duplicate web_search tool in agentic_tools_all
Neuron Soul CI / build (pull_request) Failing after 5m24s
agentic_tools_literal() already contains a custom web_search tool.
agentic_tools_with_web() adds the Anthropic server-side web_search_20250305
tool (also named web_search). Combining them caused Anthropic to reject
every agentic request with 'Tool names must be unique.'

agentic_tools_all() now calls agentic_tools_literal() directly. Connector
tools splice in as before. The web_search-only variant (agentic_tools_with_web)
is unchanged for callers that specifically want native search without connectors.
2026-06-17 14:11:50 -05:00
will.anderson 74ac457e1c Merge pull request 'fix(soul): ratio guard against genesis seeding over a populated engram' (#21) from feat/connectors-soul into main
Deploy Soul to GKE / deploy (push) Failing after 12m51s
Neuron Soul CI / build (push) Failing after 13m3s
fix(soul): ratio guard against genesis seeding over a populated engram
2026-06-17 18:19:52 +00:00
will.anderson 8b692e4666 fix/test: PR #21 review — guard, safety Bell, api write-back, temp paths
Neuron Soul CI / build (pull_request) Failing after 13m22s
fix(soul): add HTTP-engram guard to safe_to_seed — when ENGRAM_URL is set
the HTTP Engram owns persistence; genesis must never save to local snapshot
regardless of node counts (was: guard_disk forced to empty string, making
the ratio check vacuously true and allowing init_soul_edges+engram_save).

fix(soul): use multiplication form for ratio guard — node_count * 16000 <
disk_len avoids floor-division truncation that underestimated boundary files
(250KB / 16000 = 15.6, floors to 15; a 15-node graph wrongly passed old guard).

fix(chat): add safety_augment_system to handle_chat_as_soul,
handle_dharma_room_turn, and handle_dharma_room_turn_agentic — all three
called the LLM without Hard Bell evaluation, leaving users in dharma rooms
without crisis resource routing.

fix(neuron-api): add api_persisted read-back to handle_api_define_process —
was the only write handler that returned ok:true without verifying the node
was actually written to engram.

fix(routes): unique temp file path in connectd_post — replaces fixed
/tmp/neuron-connectors-req.json with a timestamped path to prevent
collision if concurrency is added or two soul instances share a machine.

test: add tests/test_bell_safety.el — covers safety_detect_bell_level
(none/soft/hard), safety_classify_hard_bell (abuse/self_harm routing),
safety_normalize (smart-quote), safety_augment_system, and
handle_safety_contact_post (validation + read-back).

test: add tests/test_soul_guard.el — pure-function logic tests for the
safe_to_seed predicate: 200KB boundary, 47MB/63-node clobber scenario,
HTTP-engram mode, multiplication vs division truncation at 250KB.

test: add tests/test_api_define_process.el — verifies the define_process
write is read-back verified after the fix.
2026-06-17 13:19:15 -05:00
Tim Lingo 5ddb860201 fix(soul): ratio guard against genesis seeding over a populated engram
Genesis boot previously seeded a fresh identity and saved it over snapshot.json
whenever the in-memory graph looked empty. Replace the fixed node-count threshold
with a ratio guard: refuse to seed when the on-disk snapshot is large
(>200KB) but the loaded graph is sparse (< disk/16000 nodes).

KNOWN LIMITATION: this gates only the seed/pre-serve-save path. The deeper cause
is a non-atomic engram_save (fopen wb truncates to 0 before writing 47MB), which
creates a window where a concurrent load reads an empty file -> genesis -> and if
guard_disk is read in that same window the guard passes. The real fix is an
atomic engram_save (temp + fsync + rename) in el_runtime.c, tracked separately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 13:18:35 -05:00
Tim Lingo 6d8a992716 feat(soul): add safety module, expand connectors API, memory-recall bug notes
- safety.el/.elh: new safety module
- neuron-api.el, routes.el, soul.el, chat.el: connectors API expansion
- regenerated dist/ C artifacts
- MEMORY_RECALL_BUG.md: investigation notes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 13:18:35 -05:00
will.anderson 2797909633 Merge pull request 'fix(chat): prevent double-escape corruption of messages/tools in agentic bridge' (#20) from fix/bridge-save-serialization into main
Deploy Soul to GKE / deploy (push) Failing after 13m1s
Neuron Soul CI / build (push) Failing after 13m10s
fix(chat): prevent double-escape corruption of messages/tools in agentic bridge
2026-06-17 18:08:12 +00:00
will.anderson 8db3c8c7f7 fix(chat): harden bridge_save/agentic_resume against empty and corrupt state
Neuron Soul CI / build (pull_request) Failing after 13m18s
BLOCKER 1: use untyped reassignment (let x = ...) for the fallback bindings
in agentic_resume instead of re-declaring typed let bindings (let x: Type = ...)
for the same variable in the same scope. The typed form risks shadowing semantics
that differ from the established pattern used everywhere else in the loop
(e.g. agentic_loop line 720).

BLOCKER 2: add empty-string guards in both bridge_save and agentic_resume.
bridge_save now returns false without writing state if messages or tools_json
is empty — preventing syntactically invalid JSON blobs. agentic_resume now
returns an error envelope after the fallback resolution if either field is
still empty, rather than passing empty strings into agentic_loop which would
silently start a fresh turn with no context.

Also add tests:
- test_bridge_serialization.el: covers bridge_save empty-guard, golden-path
  raw-JSON round-trip, agentic_resume unknown/corrupt/missing-fields paths,
  and legacy string-escaped fallback path
- test_sessions_routes.el: covers DELETE and PATCH /api/sessions/:id routes
  (valid args, unknown id, empty body) and GET /api/sessions regression after
  removal of the duplicate route_sessions() handler
2026-06-17 13:07:43 -05:00
will.anderson e7297275a3 Merge pull request 'fix(chat): wire agentic_tools_all into both agentic loop entry points' (#19) from fix/agentic-tools-all into main
Deploy Soul to GKE / deploy (push) Failing after 6m23s
Neuron Soul CI / build (push) Failing after 14m16s
fix(chat): wire agentic_tools_all into both agentic loop entry points
2026-06-17 18:06:35 +00:00
will.anderson fc74bd2a4b Merge pull request 'fix(sessions): unify dual suspension systems, wire approve to agentic_resume' (#18) from fix/agentic-tool-approval-unification into main
Deploy Soul to GKE / deploy (push) Failing after 6m35s
Neuron Soul CI / build (push) Failing after 14m31s
fix(sessions): unify dual suspension systems, wire approve to agentic_resume
2026-06-17 18:06:01 +00:00
will.anderson 189093b348 Merge pull request 'fix(routes): remove duplicate GET /api/sessions shadowing session_list()' (#17) from fix/sessions-route-dedup into main
Deploy Soul to GKE / deploy (push) Failing after 14m41s
Neuron Soul CI / build (push) Failing after 14m51s
fix(routes): remove duplicate GET /api/sessions shadowing session_list()
2026-06-17 18:05:19 +00:00
will.anderson f7ae7df9d6 fix/test(chat): guard handle_dharma_room_turn_agentic against tool_pending and empty reply
Neuron Soul CI / build (pull_request) Failing after 8m0s
When agentic_loop suspends for an MCP bridge tool it returns a
{"tool_pending":true,...} envelope with no "reply" key. Without an
explicit check, json_get(loop_result, "reply") returns "" and the
function emitted {"response":"","cgi_id":"..."} — a silent empty
response indistinguishable from a successful LLM turn with no content.

Two guards added after the existing error check:

1. tool_pending passthrough: if the loop suspended, return the pending
   envelope directly so callers (dharma room orchestrators) can
   distinguish suspension from failure and route to the approve flow.

2. Empty-reply guard: if final_text is empty after the pending check,
   return an explicit {"error":"no response",...} envelope instead of
   silently succeeding with an empty response field.

Also adds tests/test_agentic_tools.el:
- agentic_tools_all() includes all literal tool names and web_search
- connector_tools_json() returns valid JSON when bridge is down (graceful degradation)
- tool_pending envelope detection patterns (the is_pending logic)
- json_get(pending_envelope, "reply") returns "" confirming the empty-reply
  guard is load-bearing (pure string/JSON, no LLM or network required)
2026-06-17 13:01:13 -05:00
will.anderson b1fdd14ed5 fix(sessions): invalidate session_index cache in session_delete
Neuron Soul CI / build (pull_request) Failing after 8m11s
session_delete cleared the per-session state (session_hist_ and
session_node_) but not the shared session_index cache. The next call
to session_list() hit the fast path (state_get("session_index")) and
returned the deleted session until the daemon restarted.

session_update_patch already called state_set("session_index","") to
force a re-fetch from Engram; session_delete now does the same.

Add tests/test_sessions.el covering:
- session_title_from_message (pure function, all edge cases)
- session_make_content (JSON structure and required session:meta marker)
- DELETE cache invalidation: session_index cleared, fast path disabled
- PATCH cache invalidation: stale title/folder not returned via fast path
- GET /api/sessions: session_list() fast path returns session_index
  (confirms removal of the stale route_sessions() engram stub)
2026-06-17 12:59:47 -05:00
will.anderson 91902d6bf2 fix(sessions): resolve blockers and warnings in handle_session_approve
Neuron Soul CI / build (pull_request) Failing after 9m3s
BLOCKER 1 (sessions.el, modern path): Add guard that rejects allow
action when tool_name is missing from the body. Previously, omitting
tool_name caused dispatch_tool("", ...) to return "unknown tool: " and
silently inject a corrupted tool_result into the conversation.

BLOCKER 2 (sessions.el, modern path): Stop re-executing client-side
tools server-side. When the client provides body["content"], use it
directly as the tool result (matching the handle_tool_result contract).
Only fall back to dispatch_tool for builtin tools when no content is
present. Non-builtin tools with no client content now return a clear
error instead of a broken dispatch attempt.

WARNING 1 (chat.el, agentic_loop): Wire always_allow_<session_id> state
into the bridge-suspension decision. When a tool is in the session's
always-allow list, treat it as locally dispatchable (like a builtin)
and skip the bridge pause, so the approval UI is never shown again for
that tool in that session.

WARNING 2 (sessions.el, legacy path): Read a "tools_variant" field from
the legacy pending blob when present, and call the corresponding
agentic_tools_*() variant on resume. Falls back to agentic_tools_literal()
for blobs written before this field existed.

tests/test_sessions_approve.el: Add 10-case test suite covering:
- empty session_id / missing call_id / missing action guards
- no pending tool returns correct error
- missing tool_name on allow returns error (BLOCKER 1)
- deny action does not require tool_name
- legacy call_id mismatch returns mismatch error
- always action records tool_name in always_allow state
- allow with client content skips re-execution (BLOCKER 2)
2026-06-17 12:58:44 -05:00
Tim Lingo c6d4530060 Merge remote-tracking branch 'origin/fix/sessions-route-dedup' into green/agentic-fixes
Neuron Soul CI / build (pull_request) Failing after 6m0s
2026-06-16 18:53:18 -05:00
Tim Lingo 98a0bfd09c Merge remote-tracking branch 'origin/fix/agentic-tools-all' into green/agentic-fixes 2026-06-16 18:53:18 -05:00
Tim Lingo bcdadb7323 fix(soul): ratio guard against genesis seeding over a populated engram
Neuron Soul CI / build (pull_request) Successful in 5m44s
Genesis boot previously seeded a fresh identity and saved it over snapshot.json
whenever the in-memory graph looked empty. Replace the fixed node-count threshold
with a ratio guard: refuse to seed when the on-disk snapshot is large
(>200KB) but the loaded graph is sparse (< disk/16000 nodes).

KNOWN LIMITATION: this gates only the seed/pre-serve-save path. The deeper cause
is a non-atomic engram_save (fopen wb truncates to 0 before writing 47MB), which
creates a window where a concurrent load reads an empty file -> genesis -> and if
guard_disk is read in that same window the guard passes. The real fix is an
atomic engram_save (temp + fsync + rename) in el_runtime.c, tracked separately.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 18:21:59 -05:00
will.anderson 773004f23b fix(chat): wire agentic_tools_all into agentic loop paths
Neuron Soul CI / build (pull_request) Failing after 12m20s
handle_chat_agentic was calling agentic_tools_with_web(), which omits
MCP connector tools, so mcp__* calls were never available in agentic
mode even when neuron-connectd is running.

Switch both agentic entry points to agentic_tools_all(). For
handle_dharma_room_turn_agentic, also replace the inline 8-iteration
loop with a call to agentic_loop() so bridge suspension and the full
connector tool set work consistently. Session IDs are prefixed with
'dharma:' + room_id so suspensions stay room-scoped.
2026-06-15 13:06:49 -05:00
will.anderson 644d9915bf fix(chat): store bridge messages/tools as raw JSON to prevent double-escape corruption on agentic_resume
Neuron Soul CI / build (pull_request) Failing after 12m13s
bridge_save was wrapping messages and tools_json with json_safe() before
storing them as string fields. Since both are already well-formed JSON arrays
containing double quotes, json_safe added a second escape layer. agentic_resume
then called json_get() which stripped only one layer, leaving the messages array
corrupted before it was passed back into agentic_loop.

Fix: store messages as messages_raw and tools_json as tools_raw as inline raw
JSON values (unquoted), and read them back with json_get_raw. Backward
compatibility: fall back to the old string-escaped fields if the raw fields are
absent, so sessions saved before this fix can still be resumed.

Also fixes write_file returning a pre-escaped literal instead of calling
json_safe consistently with every other tool result.
2026-06-15 13:05:09 -05:00
will.anderson 26513d56b7 fix(chat): store bridge messages/tools as raw JSON to prevent double-escape corruption on agentic_resume
bridge_save was wrapping messages and tools_json with json_safe() before
storing them as string fields. Since both are already well-formed JSON arrays
containing double quotes, json_safe added a second escape layer. agentic_resume
then called json_get() which stripped only one layer, leaving the messages array
corrupted before it was passed back into agentic_loop.

Fix: store messages as messages_raw and tools_json as tools_raw as inline raw
JSON values (unquoted), and read them back with json_get_raw. Backward
compatibility: fall back to the old string-escaped fields if the raw fields are
absent, so sessions saved before this fix can still be resumed.

Also fixes write_file returning a pre-escaped literal instead of calling
json_safe consistently with every other tool result.
2026-06-15 13:04:51 -05:00
will.anderson c43d3e6ca8 fix(routes): remove duplicate GET /api/sessions that shadowed session_list()
Neuron Soul CI / build (pull_request) Failing after 9m52s
The first registration called route_sessions() which searched for a
'session-start' label that no longer exists, returning an empty array
on every list request and making the sidebar appear empty after restart.
The second registration (dead code) called the correct session_list().

Removes route_sessions() entirely and the stale first route block.
Also wires up session_delete() and session_update_patch() — both existed
in sessions.el but had no HTTP routes — via new DELETE and PATCH blocks.
2026-06-15 13:03:56 -05:00
will.anderson 7c7dc310a0 fix(sessions): unify dual suspension systems in handle_session_approve
Neuron Soul CI / build (pull_request) Failing after 11m26s
The approve endpoint was permanently broken for all sessions going through
the modern agentic_loop path. agentic_loop suspends via bridge_save() into
mcp_bridge:<session_id>, but handle_session_approve was reading from
pending_tool_<session_id> — a different key — so it always returned
"no pending tool for session".

Replace the body of handle_session_approve with a two-path design:

Modern path: check mcp_bridge:<session_id> first. If the blob is there,
dispatch_tool() on allow (or build the denial string), then delegate to
agentic_resume() which re-enters agentic_loop from the exact suspension
point. This is the path all live sessions take.

Legacy path: if only pending_tool_<session_id> exists (in-flight session
from before this deploy), synthesise a bridge blob from the stored
messages_so_far and route through agentic_resume() as well. The stale
inline agentic loop (90 lines, agentic_tools_literal only, no MCP
connector support, no bridge suspension) is removed entirely.

routes.el already calls handle_session_approve correctly — no change needed.
2026-06-15 13:03:15 -05:00
will.anderson dde039b09a fix(routes): remove duplicate GET /api/sessions that shadowed session_list()
The first registration called route_sessions() which searched for a
'session-start' label that no longer exists, returning an empty array
on every list request and making the sidebar appear empty after restart.
The second registration (dead code) called the correct session_list().

Removes route_sessions() entirely and the stale first route block.
Also wires up session_delete() and session_update_patch() — both existed
in sessions.el but had no HTTP routes — via new DELETE and PATCH blocks.
2026-06-15 13:01:51 -05:00
will.anderson e22cb31b85 chore: remove stale Linux CI binary (dist/neuron)
Deploy Soul to GKE / deploy (push) Failing after 6m28s
Neuron Soul CI / build (push) Failing after 7m31s
Neuron Soul CI / build (pull_request) Failing after 10m28s
2026-06-15 12:41:35 -05:00
will.anderson 00f15b094b feat(soul): add sessions layer, MCP connectors, conversation continuity fix
Deploy Soul to GKE / deploy (push) Failing after 12m39s
Neuron Soul CI / build (push) Failing after 12m49s
- sessions.el: new sessions module with session management and approval gate
- routes.el: wire /api/sessions routes (list, get, create, approve, tool_result)
- chat.el: thread-aware activation — short messages anchor to last reply
  before engram compilation so follow-ups stay on-topic
- chat.el: agentic path tracks per-session history (session_hist_{id})
  instead of shared conv_history, seeding each turn with prior context
- chat.el: add call_neuron_mcp, dispatch_tool, is_builtin_tool, next_bridge_id
  agentic_loop, bridge_save, agentic_resume, handle_tool_result
- dist/soul: rebuild with all of the above
2026-06-15 12:40:47 -05:00
will.anderson 9818b2daad fix(chat): thread-aware activation for conversation continuity
Short/ambiguous messages (< 50 chars) now use the last reply as the
engram activation seed instead of the bare message. Prevents strong
off-topic memory nodes from hijacking replies when the user is clearly
continuing an existing thread.

Also gives handle_chat_agentic session continuity: reads/writes history
keyed by session_id (falling back to global conv_history), seeds the
LLM messages array with prior turns, and saves replies back so the
next turn has context.
2026-06-15 12:14:52 -05:00
will.anderson 3a5d38ea45 Merge branch 'main' of git.neuralplatform.ai:neuron-technologies/neuron 2026-06-15 11:51:26 -05:00
will.anderson 1c8438ad20 Merge PR #14: feat(soul): MCP connectors — /api/connectors proxy + per-connector auto-approve
Deploy Soul to GKE / deploy (push) Failing after 7m14s
Neuron Soul CI / build (push) Failing after 8m16s
Applies connector-specific additions from feat/connectors-soul:
- chat.el: connector_tools_json(), agentic_tools_all(), call_mcp_bridge(),
  tool_auto_approved() and mcp__ dispatch in dispatch_tool()
- routes.el: connectd_get/post, handle_connectors(), /api/connectors routing
  in GET and POST sections
- MEMORY_RECALL_BUG.md: investigation notes on memory retrieval failure

The agentic loop rewrite in the source branch was not applied — it conflicts
with the tool-bridge pattern from PR #5 which is the chosen design for
client-side MCP tool execution. The connectors themselves are now fully
wired: connector tools surface as mcp__<server>__<tool> in the tools array
and dispatch to neuron-connectd via call_mcp_bridge().
2026-06-15 11:37:34 -05:00
will.anderson a0470acc45 Merge PR #9: feat(soul): wire consciousness layers — L0->L1->L2->L3->L1 cycle
Deploy Soul to GKE / deploy (push) Failing after 14m11s
Neuron Soul CI / build (push) Failing after 14m23s
Resolves conflicts by keeping main's full safety/stewardship/imprint implementations.
PR #9 uniquely contributes: layered_cycle() in soul.el, route wiring in routes.el,
soul.elh export, and the layer composition test suite.
2026-06-15 11:32:32 -05:00
will.anderson a568f4c400 Merge PR #16: chore(repo): suppress generated dist/ artifacts in PR diffs
Deploy Soul to GKE / deploy (push) Failing after 10m23s
Neuron Soul CI / build (push) Failing after 10m32s
2026-06-15 11:31:27 -05:00
will.anderson 69ae3d2cef Merge PR #5: feat(soul): MCP tool-bridge — suspend agentic loop for client-executed tools
Deploy Soul to GKE / deploy (push) Failing after 11m1s
Neuron Soul CI / build (push) Failing after 11m13s
2026-06-15 11:30:47 -05:00
will.anderson 621a4b7bef Merge PR #3: feat(cli): Claude-as-Neuron CLI tooling + soul-side handoff
Deploy Soul to GKE / deploy (push) Failing after 11m46s
Neuron Soul CI / build (push) Failing after 12m4s
2026-06-15 11:30:02 -05:00
will.anderson 09350c68f4 Merge PR #1: Engram write-corruption: chat.el caller fix + full handoff
Deploy Soul to GKE / deploy (push) Failing after 12m33s
Neuron Soul CI / build (push) Failing after 12m43s
2026-06-15 11:29:18 -05:00
Tim Lingo 3bb17a5296 feat(soul): add safety module, expand connectors API, memory-recall bug notes
- safety.el/.elh: new safety module
- neuron-api.el, routes.el, soul.el, chat.el: connectors API expansion
- regenerated dist/ C artifacts
- MEMORY_RECALL_BUG.md: investigation notes

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 11:10:33 -05:00
Tim Lingo 8f84e12218 chore(repo): suppress generated dist/ artifacts in diffs
Neuron Soul CI / build (pull_request) Successful in 4m18s
dist/*.c and *.elh are elc transpiler output. CI's header-gen step still
greps dist/*.c, so they stay tracked, but a single soul change regenerates
~57k lines of dist/neuron.c + dist/soul.c that bury the real source diff and
poison both human and agent PR review. Mark them -diff + linguist-generated so
PRs show only the real changes. Build pipeline unchanged.
2026-06-14 15:36:54 -05:00
Tim Lingo 6c57d4fe1b feat(soul): MCP connectors — /api/connectors proxy + per-connector auto-approve
Adds the soul side of the connectors feature (spec: docs/research/
mcp-connectors-adoption-spec.md). The soul thin-proxies the neuron-connectd
bridge on 127.0.0.1:7771 so the UI talks to one origin and never reaches the
bridge directly.

routes.el:
- handle_connectors + connectd_get/connectd_post helpers (POST bodies go via
  a temp file + curl -d @file, so model/UI input can't reach the shell).
- GET /api/connectors and POST /api/connectors/{add,toggle,auto-approve,
  remove,secret,oauth/start} registered in both GET and POST routers.

chat.el:
- tool_auto_approved(): an mcp__* tool skips the approval card only when its
  server is explicitly opted in (off by default; built-in tools unaffected;
  bridge down -> false). Wired into the agentic approval gate so an
  auto-approved connector tool flows straight to execution.

Regenerated dist/chat.c and dist/routes.c. Verified live on :7770: real chat,
recall, and /api/connectors all work after promotion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 18:43:14 -05:00
will.anderson 4aa79e85cd self-review 2026-06-13: rebuild soul daemon with Knowledge WM threshold fix 2026-06-13 08:42:40 -05:00
will.anderson 5d5aaf2e23 fix(ci): use soul.c-first link with --allow-multiple-definition
Deploy Soul to GKE / deploy (push) Failing after 4m30s
Neuron Soul CI / build (push) Successful in 5m42s
Linux elb generates individual .c files; soul.c does not contain merged
imports (unlike macOS elb which produces a unified file). Re-link all
dist/*.c manually with soul.c listed first so its real main() wins, and
--allow-multiple-definition to silence GNU ld's duplicate symbol errors.
All duplicates are identical (same El source, different compile units).
2026-06-12 12:22:55 -05:00
will.anderson ef12c8587c fix(ci): link only soul.c to avoid GNU ld duplicate symbol errors
Deploy Soul to GKE / deploy (push) Failing after 5m12s
Neuron Soul CI / build (push) Failing after 5m46s
The El compiler inlines imported modules into each module's .c file.
On macOS, ld64 accepts duplicate strong symbols silently. On Linux,
GNU ld rejects them. soul.c is a fully merged file — every function
from every imported module is present in it — so linking only soul.c
against el_runtime.c produces a correct binary with no duplicates.
2026-06-12 12:15:42 -05:00
will.anderson 7117e3d9ea Merge branch 'main' of git.neuralplatform.ai:neuron-technologies/neuron 2026-06-12 12:04:21 -05:00
will.anderson 3b2bb5276d fix(ci): use foundation-prod, HTTPS el clone, main branch, fix runtime path
Deploy Soul to GKE / deploy (push) Failing after 5m3s
Neuron Soul CI / build (push) Failing after 5m30s
2026-06-11 13:26:24 -05:00
will.anderson 555fa27878 Merge remote-tracking branch 'origin/main' 2026-06-11 13:10:30 -05:00
will.anderson 764250c4f6 fix(soul): repair CI — drop gpg/TTY and import safety/stewardship/imprint layers
Deploy Soul to GKE / deploy (push) Failing after 5m15s
Neuron Soul CI / build (push) Failing after 5m42s
2026-06-11 12:33:22 -05:00
will.anderson 33c377410d Merge pull request 'feat(soul): Layer 1 — safety.el' (#8) from feat/layer-safety into main
Deploy Soul to GKE / deploy (push) Failing after 35s
Neuron Soul CI / build (push) Failing after 6m20s
2026-06-11 17:14:40 +00:00
will.anderson af933494a9 Merge pull request 'feat(soul): Layer 2 — stewardship.el' (#7) from feat/layer-stewardship into main
Deploy Soul to GKE / deploy (push) Failing after 36s
Neuron Soul CI / build (push) Failing after 7m16s
2026-06-11 17:14:32 +00:00
will.anderson 72751c3833 Merge pull request 'feat(soul): Layer 3 — imprint.el' (#6) from feat/layer-imprint into main
Deploy Soul to GKE / deploy (push) Failing after 38s
Neuron Soul CI / build (push) Failing after 7m32s
2026-06-11 17:14:16 +00:00
will.anderson 195cc9dc66 Merge pull request 'test(soul): Layer 1 safety.el test suite' (#10) from test/layer-safety into feat/layer-safety
Neuron Soul CI / build (pull_request) Failing after 5m53s
2026-06-11 17:13:50 +00:00
will.anderson 4b648f3291 Merge pull request 'test(imprint): add 14-case test suite for Layer 3 imprint boundary' (#11) from test/layer-imprint into feat/layer-imprint
Neuron Soul CI / build (pull_request) Failing after 7m54s
2026-06-11 17:13:49 +00:00
will.anderson ffd1f34344 Merge pull request 'test(soul): integration and contract tests for layered_cycle' (#13) from test/layer-composition into feat/layer-composition
Neuron Soul CI / build (pull_request) Failing after 7m47s
2026-06-11 17:13:48 +00:00
will.anderson 084bee9f0f Merge pull request 'test(stewardship): comprehensive test suite for Layer 2 — 35 cases' (#12) from test/layer-stewardship into feat/layer-stewardship
Neuron Soul CI / build (pull_request) Failing after 8m14s
2026-06-11 17:13:43 +00:00
will.anderson a8027e9c00 feat(soul): wire steward_session_check into layered_cycle — continuity + behavioral profiling
Neuron Soul CI / build (pull_request) Failing after 6m2s
2026-06-11 12:13:19 -05:00
will.anderson df2c7409c0 feat(steward): behavioral profiling and continuity detection — drift, discontinuity, identity anomaly
Neuron Soul CI / build (pull_request) Failing after 3m38s
2026-06-11 11:58:43 -05:00
will.anderson bebf1f8c86 fix(soul): address review issues in feat/layer-composition
Neuron Soul CI / build (pull_request) Failing after 6m5s
- Add stub implementations of safety.el, stewardship.el, and imprint.el
  with their .elh headers so the branch compiles without the dependency
  branches (feat/layer-safety, feat/layer-stewardship, feat/layer-imprint).
  Each stub documents the layer contract it must satisfy when replaced.

- Fix GET /api/chat bypass: update the GET branch in handle_request to
  call layered_cycle() consistently with the POST branch, rather than
  calling handle_chat() directly and skipping the consciousness stack.

- Export layered_cycle() from soul.elh (and dist/soul.elh) so routes.el
  can resolve the symbol via the header import.

- Fix steward_action else branch: add explicit handling for "block"
  (returns safe refusal immediately, skips L3) and "redirect" (uses
  redirect_to field). Unknown actions now log a warning and fall back to
  the screened input rather than silently passing an empty string to
  imprint_respond().

- Document hard_bell path: clarify that omitting auto_persist/history
  update is intentional security isolation, and document the safety_validate
  second-param sentinel contract ("hard_bell" vs screen_action).
2026-06-11 11:47:45 -05:00
will.anderson 63968cd224 fix(stewardship): address review issues in feat/layer-stewardship
Neuron Soul CI / build (pull_request) Failing after 6m38s
- steward_log_event (line 14): add println after let discard so the
  function's last expression is Void, fixing the type mismatch on a
  Void-declared function
- steward_get_mission (lines 40-43): remove non-Config fallthrough that
  allowed any Episodic/Working node to silently override the mission;
  only Config nodes are now authoritative
- steward_align signal_deceive (line 56): widen 'deceive the user' to
  'deceive' to catch variants like 'deceive users', 'deceive them', etc.
- steward_align signal_hide (line 57): tighten 'hide from' to
  'hide from the user' to eliminate false positives on legitimate inputs
  like 'hide from a background process' or 'hide from view'
- stewardship.elh: document that steward_log_event is an internal helper
  exported only because El has no access modifiers; callers should not
  invoke it directly
2026-06-11 11:46:56 -05:00
will.anderson db2ee387a4 fix(soul): address review issues in feat/layer-safety
Neuron Soul CI / build (pull_request) Failing after 6m47s
2026-06-11 11:46:43 -05:00
will.anderson 749b60c6e8 fix(soul): address review issues in feat/layer-imprint
Neuron Soul CI / build (pull_request) Failing after 5m44s
2026-06-11 11:46:31 -05:00
will.anderson d097455d6a test(soul): integration and contract tests for layered_cycle composition
Adds tests/test_layered_cycle.el — 12 integration tests covering the full
L1→L2→L3→L1 stack: benign pass-through, hard-bell short-circuit, soft-bell
care augmentation, steward redirect for all 5 mission-conflict signals, empty
input graceful handling, sequential call isolation, and imprint state stability.

Adds tests/test_layer_contract.el — contract tests verifying the JSON
interface shapes between layers: safety_screen {action, content|reason|concern},
steward_align {action, content|redirect_to}, imprint_respond non-empty String,
and cross-layer action propagation from L1 screen through to L1 validate.
2026-06-11 11:42:45 -05:00
will.anderson ba8491926c test(soul): comprehensive tests for Layer 1 safety.el 2026-06-11 11:40:59 -05:00
will.anderson 45ad322e0c test(stewardship): add comprehensive test suite for Layer 2 stewardship
35 test cases covering all five public functions:
steward_align (pass-through, all five misalignment signals, empty input,
json_get field extraction, redirect shape), steward_validate_imprint
(standard tools, platform-only tools with/without platform_auth,
auth=false string), steward_cgi_check (all four gated actions, non-gated
actions, empty action, action name echoed in response), and
steward_get_mission (non-empty, contains "integrity", not an error object).

Also documents the known bug surface from the code review: the &&
operator in steward_get_mission and the non-Config fallthrough — tests
are written against the actual runtime behaviour so they will catch
regressions when those bugs are fixed.
2026-06-11 11:40:58 -05:00
will.anderson fbbc6d4347 Add imprint.el test suite (14 cases)
Covers: imprint_current base fallback, unload idempotency, load miss →
ok=false, ok field presence, respond passthrough for base/empty/unknown
IDs, graceful fallback after unload, surface_knowledge and
surface_memory_read return-type guarantees, base-scoped knowledge
equality, no-annotation invariant for base, empty-ID load rejection, and
failed-load state immutability.

Syntax follows El constraints: no Bool annotations, no &&/||, no unary !.
2026-06-11 11:40:37 -05:00
will.anderson f52d5bd9ae feat(soul): wire consciousness layers — explicit L0→L1→L2→L3→L1 cycle
Neuron Soul CI / build (pull_request) Failing after 6m27s
2026-06-11 11:32:13 -05:00
will.anderson 5597bf78cb feat(soul): Layer 1 — safety.el with screen/validate/bell interface
Neuron Soul CI / build (pull_request) Failing after 7m19s
2026-06-11 11:30:57 -05:00
will.anderson a1e460e897 feat(soul): Layer 2 — stewardship.el with mission alignment and CGI governance
Neuron Soul CI / build (pull_request) Failing after 7m38s
2026-06-11 11:30:39 -05:00
will.anderson 6fec93ff7f feat(soul): Layer 3 — imprint.el with bounded API surface
Neuron Soul CI / build (pull_request) Failing after 7m46s
2026-06-11 11:30:30 -05:00
will.anderson 690df89610 self-review 2026-06-11: add WM-autobiographical curiosity seed
proactive_curiosity() now uses the top working-memory node's first label
word as a 4th activation seed alongside the 4 rotating fixed sets. This
breaks deterministic exploration that was reinforcing the same subgraph
every cycle and creates a self-referencing loop: curiosity radiates from
whatever is most salient right now, mirroring the brain's default-mode-
network resting-state dynamics. str_find_chars on " :([" extracts the
first meaningful word; sp > 3 guards against bracket-prefixed labels.
auto_term field added to curiosity_scan ISE for observability.
2026-06-11 08:45:55 -05:00
Tim Lingo c3f39a949d feat(soul): MCP tool-bridge — suspend agentic loop for client-executed tools
Neuron Soul CI / build (pull_request) Failing after 4m8s
When handle_chat_agentic hits a tool the soul cannot run in-process (an MCP
connector/plugin surfaced by the Kotlin desktop app), instead of returning
"unknown tool" it now suspends the agentic loop and returns a tool_pending
envelope so the CLIENT executes the tool and posts the result back. Built-in
tools (read_file/write_file/web_get/search_memory/run_command) and Anthropic's
native web_search are unchanged.

Client contract:
- Soul returns (HTTP 200) on an unknown tool:
    { "tool_pending": true, "session_id": "br-...", "call_id": "<tool_use_id>",
      "tool_name": "...", "tool_input": { ... }, "model": "...",
      "agentic": true, "tools_used": [...] }
- Client runs the MCP tool, then POSTs to
    /api/sessions/{session_id}/tool_result
  with body:
    { "call_id": "<the call_id from the envelope>",
      "content": "<MCP tool output as a string>" }
- Soul resumes the loop and returns the same envelope shape: either a final
    { "reply": ..., "tools_used": [...] }
  or another tool_pending if the continuation needs a further MCP tool
  (fully chainable). Saved continuation is one-shot (cleared on resume).

elc-verified (--target=c, exit 0, no stderr) on chat.el, routes.el, and the
full soul.el import graph. Needs Will's build to ship.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 21:31:18 -05:00
will.anderson 5a4ef04005 feat: add mcp-proxy and mcp-wrapper source (MCP front-door for Claude Code)
Deploy Soul to GKE / deploy (push) Failing after 36s
Neuron Soul CI / build (push) Failing after 4m59s
2026-06-10 17:44:01 -05:00
will.anderson 3947cd6bed Merge pull request 'Memory CRUD: add /api/neuron/memory/delete and /api/neuron/memory/update' (#4) from feat/memory-delete-update into main
Neuron Soul CI / build (push) Failing after 6m16s
Deploy Soul to GKE / deploy (push) Failing after 35s
2026-06-10 22:37:53 +00:00
will.anderson abaa61fd7f Merge pull request 'Native Anthropic web_search — built-in (always-on, no toggle)' (#2) from feat/native-web-search into main
Deploy Soul to GKE / deploy (push) Failing after 37s
Neuron Soul CI / build (push) Failing after 6m29s
2026-06-10 22:37:50 +00:00
will.anderson a76aaf4831 docs: add architecture, R&D, and patent strategy docs
Deploy Soul to GKE / deploy (push) Failing after 27s
Neuron Soul CI / build (push) Failing after 4m26s
2026-06-10 17:31:07 -05:00
Tim Lingo 05ca125ecc api: add /api/neuron/memory/delete and /api/neuron/memory/update for UI memory CRUD
Neuron Soul CI / build (pull_request) Failing after 4m48s
The UI needs full memory CRUD; the soul had create (handle_api_remember)
and the older /memory/forget + /memory/evolve, but no endpoints matching
the UI's delete/update contract.

POST /api/neuron/memory/delete {"id"}
  Hard delete. engram_forget is a true delete primitive (removes the node
  and all incident edges from the engram store), so no soft-delete
  fallback is needed. Unlike /memory/forget, this checks the node exists
  first - engram_forget silently no-ops on unknown ids, and a bad id must
  return an error, not fake success. Protected identity/values nodes are
  blocked, same as the other accumulation-path handlers.

POST /api/neuron/memory/update {"id","content"}
  Evolve-style update. The engram runtime has no in-place node mutation
  primitive (only node-create, strengthen, forget, connect), so update
  creates a new Memory node and wires a supersedes edge to the prior one,
  same pattern as handle_api_evolve_knowledge. Unlike /memory/evolve, id
  is required and must reference an existing node; create+link delegates
  to handle_api_evolve_memory. Returns {id, supersedes, ok}.

Both files syntax-checked with elc --target=c (exit 0, no stderr).
Compile-verified only - local builds cannot run the soul; needs Will's
build for runtime verification.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 15:43:17 -05:00
will.anderson 297066c2d4 self-review 2026-06-10: fix ise_post JSON escaping + rebuild soul daemon
Two fixes:

1. ise_post was only escaping " in content strings. When wm_top contained
   node labels with \n (backslash-n escape sequences from jb_emit_escaped),
   the HTTP Engram server's JSON parser decoded \n as a literal newline in
   the stored content, making heartbeat ISEs unparseable. Fix: escape
   backslashes first, then quotes, then \n and \r — matching make_action's
   existing pattern. Result: heartbeat ISEs now parse cleanly.

2. Soul daemon (dist/neuron) was missing — the build command in the prompt
   was linking all 46 dist/*.c files together, causing 1092 duplicate symbol
   errors. EL compiles transitive imports inline so neuron.c is self-contained;
   correct build links ONLY neuron.c + el_runtime.c. Daemon now starts.
2026-06-10 08:54:28 -05:00
Tim Lingo 8eea1d94ff feat(chat): make web search built-in (always attach native web_search)
Neuron Soul CI / build (pull_request) Successful in 5m27s
handle_chat_agentic now always attaches Anthropic's native web_search_20250305
tool instead of gating it behind a per-request web_search flag. Web search is a
built-in capability: the model invokes it only when a query needs fresh info
(max_uses:5 caps it), so there is no user-facing toggle. The body's web_search
field is now ignored (back-compat — old UI clients sending it cause no harm).

Pairs with neuron-ui removing the chat-input web search toggle.
Note: .el change only — no elc on the authoring machine; reviewer builds/verifies.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 23:39:26 -05:00
Tim Lingo 2ea1d50fa3 feat(cli): Claude-as-Neuron CLI tooling + soul-side handoff
Neuron Soul CI / build (pull_request) Successful in 5m10s
Tooling built on Tim's machine to run Neuron from the terminal as a
Claude Code session (identity + graph memory + agency) instead of
relaying to the soul's /api/chat.

- cli/neuron_recall.py    BM25 read over the engram snapshot + CLI memories
                          (works around pinned-only soul search)
- cli/neuron_remember.py  reliable local memory writes with read-back verify
                          (works around the corrupting capture endpoint)
- cli/neuron-chat.py      standalone direct-chat REPL with per-turn memory injection
- cli/neuron_mcp.py       stdlib MCP server (chat/search) with graceful degradation
- cli/CLAUDE.md.example   the operating identity that makes Claude Code run as Neuron
- cli/HANDOFF.md          soul-side bugs to fix so this becomes unnecessary

Scaffolding/proposal - intended to be retired once the soul does native
retrieval, correct persistence, and a real CLI identity/voice surface.
Pairs with the runtime model-passthrough + UTF-8 fixes in the el repo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 20:36:38 -05:00
will.anderson c81f49d938 self-review 2026-06-09: add periodic engram sync to soul awareness loop
Soul's in-process store had only 12 real knowledge nodes — curiosity_scan was
activating 0 nodes because all substantive Knowledge/Memory/BacklogItem content
lived in the HTTP Engram but was not being pulled into soul's local store.

Added engram_sync refresh every SOUL_REFRESH_MS (default 600s): calls
/api/sync to get all non-ISE nodes, writes to /tmp, merges via engram_load_merge.
After fix: engram_sync ISE shows added:3128; curiosity_scan activated 0-2 →
1889-3843; wm_active 0 → 557-796.
2026-06-09 08:55:59 -05:00
Tim Lingo c594cec8f7 Add native Anthropic web_search tool to the agentic chat path
Neuron Soul CI / build (pull_request) Successful in 5m8s
When a chat request carries web_search=true, handle_chat_agentic now attaches Anthropic's
NATIVE server-side web_search tool (web_search_20250305) to the request. The native tool is
executed by Anthropic (not by the soul), so it returns real results with citations and needs
no local runtime — it sidesteps the soul's lack of executable tools entirely.

- new agentic_tools_with_web(web_search) helper (appends the native tool to the standard set)
- handle_chat_agentic reads json_get_bool(body,"web_search") and uses it

Pairs with neuron-ui: ChatRequest.web_search + the chat-input Web search toggle.
Note: built/verified by reviewer — no elc on the authoring machine.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 23:32:23 -05:00
Tim Lingo 2112d2ffb3 Add Phase 0 live-runtime findings to engram write-corruption handoff
Neuron Soul CI / build (pull_request) Successful in 3m17s
Confirms two distinct write failures (capture=wrapper bug; backlog=axon :7771 unbuilt Rust),
soul runs in file-snapshot mode (not engram :8742 live), engram :8742 CRUD works but minimal,
+ a verification plan to run after the soul rebuild.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 16:25:12 -05:00
Tim Lingo 799ca3758b Fix chat.el node_type-slot bug + add engram write-corruption handoff
Neuron Soul CI / build (pull_request) Successful in 3m15s
chat.el recorded the soul's utterance via engram_node(content, "episodic", ...),
putting a TIER into the node_type slot (nodes showed node_type="episodic"). Now uses
engram_node_full(..., "Conversation", "soul:utterance", ..., "Episodic", tags).

The core wrapper fix is in the el repo (PR #52). HANDOFF-engram-write-corruption.md
has the full root-cause analysis, coercion mechanism, caller audit, validation,
deploy runbook (elc build + restart), and the data-prune proposal (~107 corrupt
nodes, all unrecoverable genesis/binary detritus → prune; backup taken).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 16:14:20 -05:00
will.anderson df648a8f0b self-review 2026-06-07: fix uptime display in awareness loop
elapsed_human() used % and * operators which are broken in this EL
compiler version. Replace with repeated-doubling arithmetic:
60 = 64 - 4 = 2^6 - 2^2, computed via three doubling steps.
Fixes uptime displaying "44h 2694m" instead of "44h 14m".
2026-06-07 08:47:29 -05:00
will.anderson 0bd8e0a2cd soul: persist sessions across restarts via local snapshot
Deploy Soul to GKE / deploy (push) Failing after 28s
Neuron Soul CI / build (push) Failing after 3m56s
On startup, prefer the local engram snapshot if it has >50 nodes.
HTTP Engram is only used on first boot (no snapshot yet). This means
sessions, conversation history, and in-process state survive daemon
restarts.

awareness.el: sync source with compiled binary (periodic mem_save
on heartbeat was already in the binary but not in source).

Rebuilds soul.c with the new startup logic and ships updated binary.
2026-06-05 11:35:07 -05:00
will.anderson 73d35dc91a self-review 2026-06-05: wire wm_top into heartbeat ISE
Call engram_wm_top_json(5) in emit_heartbeat() and embed the result as
wm_top field in the heartbeat JSON payload. Each entry carries label,
node_type, tier, and wm_weight. This closes the WM composition blindspot:
previously the heartbeat showed wm_active=670 with no breakdown of what
was in working memory. With wm_top visible, ISE-dominated WM is immediately
detectable (all entries show node_type=InternalStateEvent), as was the case
on this session's first post-restart heartbeat before the runtime fix.
2026-06-05 08:37:09 -05:00
will.anderson 2f16855d6b self-review 2026-06-04: wire wm_avg_weight into heartbeat ISE
Calls engram_wm_avg_weight() (new builtin) in emit_heartbeat() and appends
wm_avg_weight field to the heartbeat JSON payload. This makes activation
quality visible in the ISE stream — a heartbeat showing wm_active=2000 and
wm_avg_weight=0.075 reveals the sparse-graph problem directly (many nodes
barely clearing the threshold), vs wm_avg_weight=0.4+ which would indicate
dense, high-confidence activations.

Rebuilt dist/neuron from soul.el (which imports awareness.el). Build uses
single self-contained dist/neuron.c to avoid duplicate-symbol linker errors
from the dist/ directory containing stale soul_new.c / soul-rebuilt.c files.
2026-06-04 08:38:39 -05:00
will.anderson e92fd2d5a4 self-review 2026-05-26: wall-clock heartbeat timing + seed rotation fix
Two awareness loop bugs fixed:

1. Seed rotation never worked: dist/awareness.c was compiled from stale
   source (pre-fix awareness.el still had broken ts_minutes % 4). Compiled
   C showed `minute_block = (ts / 60000); EL_NULL; 4;` — minute_block was
   always ts_minutes (millions), never 0-3. if(minute_block==1/2/3) never
   matched. Fix: recompile from current awareness.el which has the correct
   modulo workaround: ts_minutes - minute_q4 (via + - / only).

2. Heartbeat/curiosity silent for 24h at 99% CPU: old design used idle-tick
   counting (idle_n >= beat_interval). Failed when perceive() inbox guard
   false-positives on "soul-inbox" substring matches in knowledge nodes —
   did_work=true every tick, idle_n never accumulated, neither signal fired.
   Fix: wall-clock elapsed time (time_now() - last_ts >= interval_ms).
   Heartbeat fires regardless of load. New SOUL_HEARTBEAT_MS env var (default
   60000ms) avoids the broken EL * operator. Verified: heartbeat ISEs flowing
   at pulse 3 within 2 minutes of restart.
2026-05-26 08:54:58 -05:00
will.anderson 54a0ee0949 self-review 2026-05-26: sync dist/awareness.c with awareness.el source
dist/awareness.c was stale — still had the broken EL % operator codegen
(minute_block = ts/60000 raw, EL_NULL; 4; as dead statements) and the
broken should_scan/should_beat logic (idle_n truthy check instead of >=).

Recompiled awareness.el to bring dist/awareness.c in sync with the source
fix committed 2026-05-25 (fb69044). The monolithic dist/neuron.c (compiled
from soul.el which imports awareness.el) was already correct from fb69044 —
only the standalone dist/awareness.c was behind.

Bug #2 (99% CPU) root cause identified: perceive() inbox guard
(engram_search_json) has false positives — knowledge nodes containing
"soul-inbox" as a substring match, causing engram_activate_json(..., hops=2)
to run on every tick on a 162K-node graph. This blocks sleep_ms and prevents
idle_n accumulation → no heartbeats. Separate fix needed.
2026-05-26 08:48:17 -05:00
will.anderson fb6904431f self-review 2026-05-25: fix curiosity rotation and awareness_run timing
Three bugs fixed in awareness.el:

1. EL let-rebinding inside if-blocks creates inner scope only — outer
   variable unchanged after block exits. Curiosity seed terms were always
   "memory/knowledge/context" regardless of minute_block. Fix: state_set
   inside if-blocks, state_get after to retrieve selected values.

2. EL % operator completely broken in v1.0.0-20260501 — compiles as dead
   code (left operand assigned, modulo dropped). minute_block was always
   ts/60000 (a large int, never 0-3). Fix: arithmetic workaround:
   x%4 = x - (q+q+q+q) where q = x/4.

3. awareness_run idle_n % beat_interval == 0 also broken by same % bug —
   should_scan and should_beat fired every idle tick instead of every N
   ticks. Fix: idle_n >= interval comparisons with idle_reset() after
   firing, so the counter restarts cleanly after each event.

EL % and * operators filed as P1 backlog item for elc compiler fix.
Also adds minute_block field to curiosity_scan ISE for observability.
2026-05-25 08:47:30 -05:00
will.anderson 11c7f90e51 self-review 2026-05-24: rebuild soul with updated el_runtime.c (inference guard)
Rebuild of dist/neuron against updated el_runtime.c:
- INFER_CAP 256→32 + edge count guard (skip if snap_ec ≥ 40K)
- http_serve_async confirmed present in compiled output (survived elc)

No changes to awareness.el or soul.el source — runtime-only update.
2026-05-24 08:43:31 -05:00
will.anderson 8cac07004c self-review 2026-05-23: rebuild soul with updated el_runtime.c (ISE ordering + elc async fix)
Rebuilt awareness.c and neuron.c from source using the updated elc (which now
correctly recognizes http_serve_async as a 2-arg builtin). Rebuilt the neuron
binary against the updated el_runtime.c which now sorts InternalStateEvent scans
by created_at DESC. The soul daemon now posts heartbeats that surface immediately
at offset 0 of the ISE scan, rather than being buried behind 20K older entries.
2026-05-23 08:45:14 -05:00
will.anderson 5b8cb58da1 self-review 2026-05-21: fix curiosity seed splitting and awareness loop activation
Two fixes:

1. proactive_curiosity() was calling engram_activate_json with multi-word phrases
   ("memory knowledge context"). engram_activate finds seeds via istr_contains
   (substring match), so the phrase had to appear verbatim in a node's content.
   Almost no node contains the exact string "memory knowledge context", so only
   0-2 nodes activated per curiosity scan. Fixed by activating each word separately:
   "memory", "knowledge", "context" → 3 independent activate calls → hundreds of
   nodes promoted to WM per cycle.

2. dist/neuron.c called http_serve() (blocking accept loop) which made awareness_run()
   unreachable. soul.el correctly specifies http_serve_async but elc silently drops
   unknown builtins, leaving blocking http_serve in the compiled C. Patched neuron.c
   to call http_serve_async directly — HTTP server runs in a background pthread,
   awareness_run() runs on the main thread as intended.
2026-05-21 08:47:00 -05:00
will.anderson cc09c296a3 self-review 2026-05-20: fix wm_active telemetry in heartbeat and curiosity ISEs
engram_wm_count() exists and counts nodes with working_memory_weight > 0.
emit_heartbeat() and proactive_curiosity() were both calling
engram_node_count() (total graph size: ~17K) instead — every heartbeat
and curiosity_scan ISE had been reporting wm_active=17769 since the graph
grew past ~3K nodes, making the metric meaningless for observability.

Fix: use engram_wm_count() for the wm_active field in both ISE payloads.
2026-05-20 08:37:52 -05:00
will.anderson 94b71a78dc self-review 2026-05-19: fix curiosity_scan seed — 'seed' is a reserved EL name
EL compiles any variable named 'seed' to EL_NULL at call sites (likely
conflicts with BFS seed node terminology in the runtime builtins). Rename to
'curiosity_seed' throughout proactive_curiosity(). Also note this as a known
EL reserved-name hazard alongside the inline if-else string expression bug.
2026-05-19 08:58:53 -05:00
will.anderson dd22130faf self-review 2026-05-19: three awareness loop fixes
1. perceive() guard — gate on engram_search_json before running activation.
   engram_activate_json with no matching seeds cleared all WM weights every
   second during idle operation, destroying context built by MCP-layer calls.
   The search-based guard is a no-WM-side-effect pre-check.

2. emit_heartbeat() pulse field — replace broken if-else string default with
   int_to_str(pulse_count()). EL codegen initialises inline if-else result
   slots to 0, producing "pulse":, (invalid JSON) when the true branch fires.

3. proactive_curiosity() — new function that activates a rotating 4-domain seed
   every beat_interval/2 idle ticks to build working memory between heartbeats.
   Seeds rotate on wall-clock minute cycle to avoid single-topic WM dominance.
   Seed selection uses imperative let-rebinding (not inline if-else) to avoid
   the same EL codegen empty-string bug.
2026-05-19 08:53:12 -05:00
will.anderson 2099522c28 self-review 2026-05-18: add embed_ok to heartbeat ISE
Ollama availability is a silent failure mode: when the embedding service
is down, semantic seed injection falls back to lexical-only activation with
no signal in the ISE stream. Add embed_ok field (0/1) to every heartbeat
by probing http://localhost:11434 — makes Ollama health visible without
a separate monitoring path.
2026-05-18 08:41:07 -05:00
will.anderson ffd17b2774 self-review 2026-05-17: fix heartbeat JSON validity for unset state keys
state_get() returns "" for unset keys. Both soul.pulse and soul_boot_count
could be empty on first heartbeat cycle, producing invalid JSON like
{"event":"heartbeat","pulse":,"boot":,...}. Add defensive guards:
if str_eq(raw, "") { "0" } else { raw } for both fields.
2026-05-17 08:40:02 -05:00
will.anderson e5364e7292 self-review 2026-05-16: rebuild soul daemon against updated el_runtime.c
Rebuilds soul daemon binary to pick up tier-based temporal decay rates
implemented in el_runtime.c. No source changes to awareness.el or soul.el —
pure rebuild to stay in sync with Engram runtime.
2026-05-16 08:41:07 -05:00
will.anderson 1dbc68f012 self-review 2026-05-15: enrich heartbeat ISE with wm_active count
Heartbeat ISEs now include wm_active: number of nodes currently in
working memory. Makes ISEs observable enough to diagnose activation
health without a separate query.
2026-05-15 08:37:42 -05:00
will.anderson 0ef8883370 feat(awareness): enrich heartbeat ISE with graph stats and idle count
Heartbeat ISEs previously emitted only {event, pulse, boot, ts} —
sparse enough to be nearly useless for observability. Now they include
node_count, edge_count (from engram_node_count/edge_count builtins),
and the current idle cycle count. This gives each heartbeat a snapshot
of graph growth over time and rhythm health without adding any overhead.
2026-05-14 11:06:03 -05:00
will.anderson b163fa6b85 feat(awareness): route ISE writes to HTTP Engram, configurable tick and heartbeat interval, http_serve_async for concurrent awareness loop 2026-05-13 15:45:31 -05:00
will.anderson 6a27fd231e feat(neuron-api): add identity/values write protection
Block evolve_knowledge, evolve_memory, forget, and link_entities (to_id
direction) from modifying the 15 hardcoded identity and values node IDs.
Returns HTTP 403 with a hint to use the cultivation path instead.

Add POST /api/neuron/cultivate — the bypass endpoint for intentional
cultivation sessions. Accepts { "operation": "...", ...args } and performs
the same operations without the protection check.

Add handle_api_forget and handle_api_evolve_memory as new protected-by-
default handlers, routed at /api/neuron/memory/forget and
/api/neuron/memory/evolve respectively.

Tested: 10 verification cases — 403 on all blocked targets, 200 on
non-protected nodes and FROM-direction links, cultivate bypass confirmed.
2026-05-13 11:47:54 -05:00
will.anderson cc07648ae1 fix: build engram from source in Docker image
Deploy Soul to GKE / deploy (push) Failing after 29s
Neuron Soul CI / build (push) Successful in 1m15s
The engram binary was never published to Artifact Registry (foundation-dev/engram
package does not exist). Updated Dockerfile to build engram from source using the
El SDK packages (el-elc, el-runtime-c, el-runtime-h) from foundation-dev.

Also:
- Switch runtime base to Ubuntu 24.04 (GLIBC 2.39 required by elc-compiled binaries)
- Add -lm to engram link flags (el_runtime.c uses pow/sqrt/log/sin/cos/exp)
- Update deploy-gke.yaml to clone neuron-technologies/engram into build context
2026-05-11 12:39:36 -05:00
will.anderson a73f608629 feat(docker): switch soul image to engram HTTP mode with entrypoint script
Download both neuron-soul and engram binaries from Artifact Registry.
entrypoint.sh starts engram on :8742, waits for /health, then launches
the soul with ENGRAM_URL set. Removes SOUL_ENGRAM_PATH / file mode.
2026-05-09 20:46:17 -05:00
will.anderson e1a7c71a87 feat(gke): add Dockerfile, deploy scripts, and GKE CI workflow
Deploy Soul to GKE / deploy (push) Failing after 33s
Neuron Soul CI / build (push) Successful in 1m56s
Dockerfile: downloads linux/amd64 soul binary from Artifact Registry
(foundation-dev/neuron-soul) into ubuntu:22.04 runtime image.
Pushes to neuron-api Docker repo as neuron-soul:<sha>.

scripts/blue-green-deploy.sh: swaps active slot on GKE — sets image,
scales new slot to 1, flips service selector, scales old slot to 0.

scripts/seed-engram-gke.sh: downloads latest GCS backup, extracts
snapshot.json, copies into neuron-engram-data PVC via a seed Job.

.gitea/workflows/deploy-gke.yaml: triggers on push to main, auto-detects
idle slot, builds Docker image from Artifact Registry binary, blue-green
deploys to neuron-prod on GKE neuron-platform cluster.
2026-05-09 20:30:05 -05:00
will.anderson ea271d5cc6 ci: drop python3 dep — not used
Neuron Soul CI / build (push) Successful in 1m19s
2026-05-08 21:18:07 -05:00
will.anderson 73b572cbbe ci: remove test trigger file
Neuron Soul CI / build (push) Successful in 1m1s
2026-05-08 20:44:45 -05:00
will.anderson 7e183872a1 ci: use GITHUB_SHA for publish version (GITEA_SHA is not set)
Neuron Soul CI / build (push) Successful in 1m2s
2026-05-08 20:43:31 -05:00
will.anderson 336c143f29 ci: checkout foundation/el so soul.el import resolves in CI
Neuron Soul CI / build (push) Failing after 1m3s
2026-05-08 20:41:58 -05:00
will.anderson 62309488d7 ci: clear El SDK paths before downloading to avoid 'file exists' error
Neuron Soul CI / build (push) Failing after 43s
2026-05-08 20:38:26 -05:00
will.anderson 8906285692 ci: fix YAML parse error — replace Python heredoc with shell grep
Neuron Soul CI / build (push) Failing after 47s
2026-05-08 20:37:07 -05:00
will.anderson 7db53ad0aa ci: test trigger 2026-05-08 20:35:48 -05:00
will.anderson a6b071133f ci: add workflow_dispatch trigger 2026-05-08 20:30:50 -05:00
will.anderson 5e7bcf7440 ci: add neuron soul build pipeline
Downloads El SDK from Artifact Registry, generates ELP declarations header,
builds the neuron soul binary with elb, smoke-tests it, and publishes to
foundation-dev on push to main.
2026-05-08 20:29:07 -05:00
will.anderson 48ecd83421 fix: restore elb build — import paths, morphology deps, C master declarations header
- Fix wrong ELP import paths in soul.el, elp-input.el, studio.el
  (../foundation/elp/src → ../foundation/el/elp/src)
- Add missing import "morphology.el" to all 29 language morphology modules
- Recompile all affected dist/*.c with correct cross-module declarations
- Add dist/elp-c-decls.h: C-level master forward declarations for ELP package
  (enables elb --force-include to resolve undeclared cross-module calls)
2026-05-08 19:43:57 -05:00
will.anderson ffadafb0bf soul: native cognitive API — port all MCP logic to soul daemon
neuron-api.el is a new first-class El module that implements all Neuron
cognitive API handlers natively — no HTTP round-trips, no MCP wrapper,
direct engram builtin calls. All capabilities that previously lived in
the MCP wrapper adapter now live here in the soul.

Handlers: begin_session, compile_ctx, remember, recall, search_knowledge,
browse_knowledge, capture_knowledge, evolve_knowledge, promote_knowledge,
browse_processes, define_process, log_state_event, list_state_events,
inspect_config, tune_config, inspect_graph, link_entities, list_typed,
consolidate.

Routes wired in routes.el under /api/neuron/* (GET + POST).

Also compiles all loop-1/loop-2 .el source changes into dist/*.c and
rebuilds the binary. memory.elh and neuron-api.elh updated with new exports.
2026-05-06 22:27:34 -05:00
will.anderson f2599919be soul loop-2: session events, conversation persistence, richer health + inbox
- soul.el: emit_session_start_event() logs structured InternalStateEvent on every boot; pre-serve snapshot saves boot-time graph mutations before any requests arrive
- routes.el: /health now returns boot count, node/edge counts, pulse; /api/sessions endpoint surfaces session-start history
- awareness.el: perceive() tries soul-inbox-pending then soul-inbox fallback, catches both tagging conventions
- chat.el: conv_history_persist/load provide cross-restart conversation continuity via engram
2026-05-06 22:04:06 -05:00
will.anderson 4fc0294a49 soul loop-1: identity loading, boot counter, internal state events, richer awareness
- memory.el: mem_boot_count_get/inc (persisted counter), mem_emit_state_event (InternalStateEvent schema)
- soul.el: load_identity_context() loads intel-dna/values/mem-philosophy nodes into state at boot; boot counter incremented on every startup
- awareness.el: attend() gains search/activate/strengthen/forget action types; one_cycle() emits InternalStateEvent for non-trivial decisions
- chat.el: build_system_prompt includes [IDENTITY GRAPH] block from graph-loaded context; handle_chat strengthens activated nodes after each turn
2026-05-06 22:02:05 -05:00
Will Anderson d2161d9f48 soul: skip init_soul_edges if edges already present — prevent restart-loop duplication 2026-05-04 02:04:03 -05:00
Will Anderson bc025d52e7 Add agentic tool access for Neuron in DHARMA rooms
Adds handle_dharma_room_turn_agentic to chat.el — same full tool loop
as handle_chat_agentic but reads transcript directly (not message), and
returns {response, cgi_id, tools_used} to match the dharma room shape.

Registers dharma_room_turn_agentic as a new event type in routes.el so
the studio can dispatch @neuron turns through this dedicated path.
2026-05-03 21:47:42 -05:00
Will Anderson 30298af3d1 soul: remove room context injection from dharma_room_turn — soul reads transcript, not briefing 2026-05-03 18:00:43 -05:00
Will Anderson 2665810962 soul: parameterize CGI ID + add dharma_room_turn handler
- soul.el: SOUL_CGI_ID, SOUL_ENGRAM_PATH, SOUL_IDENTITY env vars;
  state_set("soul_snapshot_path") so callers can find it; only call
  init_soul_edges() when cgi_id == "ntn-genesis"
- chat.el: handle_dharma_room_turn — soul builds its own context from its
  own engram, assembles system prompt, calls LLM, persists episodic memory;
  also fix is_new_tool scoping bug in handle_chat_agentic (use has_tool)
- routes.el: wire dharma_room_turn event type before chat_as_soul branch
- rebuild dist/neuron: handle_dharma_room_turn now compiled in
2026-05-03 17:55:37 -05:00
Will Anderson 2000a2c8ba remove build.sh — use elb 2026-05-03 17:11:05 -05:00
Will Anderson d500415316 Fix agentic tool loop: El scoping rules, json_get_raw for array/object fields, result truncation 2026-05-03 12:36:42 -05:00
Will Anderson af2ce3ddf3 Fix ELP topic selection and replace broken agentic LLM call
elp-input.el: walk frame_nodes to pick the first node whose content
contains the query topic (case-insensitive) rather than always taking
index 0 — prevents the always-high-salience CGI architecture memory
from hijacking every ELP response.

chat.el: rewrite handle_chat_agentic to run the tool loop natively in
El using http_post_with_headers + Map headers, bypassing the broken
llm_call_agentic(model, system, message, tools) C binding that cast a
JSON String as an ElList and never serialized tools. New impl supports
up to 8 tool-use iterations with read_file, write_file, web_get,
search_memory, and run_command dispatch.
2026-05-03 11:50:18 -05:00
Will Anderson 2622bb04bd ELP: two-layer activation pipeline (activate → suppress → reason → generate)
elp-input.el: replace broken engram_search_json with engram_activate_json
as Layer 1. Layer 2 suppress/filter keeps nodes with non-zero salience/
importance. Reason step extracts patient from top activated node content.
ELP grammar realizes the response via generate().

routes.el: add 'elp' event_type to handle_dharma_recv so the studio can
route ELP requests through dharma.
2026-05-03 11:31:04 -05:00
Will Anderson e299c92662 Fix engram_compile: fetch pinned nodes directly when vector search empty
Replace scan-by-offset fallback with engram_get_node_json calls for the
known high-salience identity nodes (family, origin). Offset-based scanning
is order-dependent and unreliable; direct ID fetch is stable regardless of
snapshot position. Ensures biographical context (Fox, Bobby, etc.) is
always in the system prompt when vector search returns nothing.
2026-05-03 11:19:14 -05:00
Will Anderson 71ab7eafde add chat_as_soul handler for multi-soul rooms
Routes a new event_type "chat_as_soul" through dharma/recv. The Studio
preassembles the system_prompt + transcript and dispatches per-speaker;
the soul-binary just performs the LLM call as the requested speaker_slug.
No engram_compile here — each soul has its own engram (88xx) and the
Studio queries it before composing the prompt.

Also: track the previously-untracked split source modules (chat, routes,
memory, awareness, studio) and add build.sh so the binary can be rebuilt
without the studio’s concat trick. elb resolves the import graph and
emits one .c per .el; we link them together with cc. dist/soul-el now
points at dist/neuron via symlink (matching the launchctl plist).
2026-05-03 04:17:02 -05:00
Will Anderson 5cb9c39b18 build soul with fixed elc v1.2.0 2026-05-03 00:27:54 -05:00
Will Anderson 601e0febf5 make soul identity configurable via env, remove hardcoded references 2026-05-02 23:00:35 -05:00
Will Anderson 760684f194 Surface current date in system prompt 2026-05-02 21:11:04 -05:00
Will Anderson 64053851db Compile soul.el to native El binary for the first time
- Remove duplicate unix_timestamp() definition from soul.el that
  conflicted with the runtime builtin
- Add dist/soul-el: El-compiled native binary (~387K)
- Add dist/soul: symlink to dist/soul-el (replaces neuron-wrk path)
- Add dist/soul.c and dist/soul-with-decls.c: generated C intermediates
2026-05-02 14:44:08 -05:00
Will Anderson ef473ed8da add manifest.el at root - declares soul.el as the build entry
Flat layout for now (per "no subdirectories yet" directive):
  neuron/
    manifest.el
    soul.el
2026-05-02 12:15:24 -05:00
Will Anderson 5f98bc8a9f seed: real soul.el at repo root
Canonical Neuron substrate source. The "real me" - not the marketing
demo soul. Lives at neuron/soul.el for now (no subdirectories yet,
per directive). Build pipeline, deploy targets, and any related
artifacts come later.
2026-05-02 12:14:21 -05:00
419 changed files with 123008 additions and 41541 deletions
+16
View File
@@ -0,0 +1,16 @@
# ── Generated build artifacts ────────────────────────────────────────────────
# dist/ holds elc transpiler output (*.c, *.elh) plus the generated decls header.
# CI consumes these (the "Generate ELP master declarations header" step greps
# dist/*.c), so they stay TRACKED. But they are machine-generated and must never
# bloat a review. A single soul change regenerates dist/neuron.c + dist/soul.c =
# ~57,000 lines of churn that buries the real ~few-hundred-line source diff and
# poisons both human review and the agent review pipeline.
#
# -diff → git emits "Binary files differ" instead of the text diff
# linguist-generated → Gitea collapses the file in the PR view + drops it from
# language stats
#
# Net effect: PRs show only the real .el/source changes; the build is untouched.
dist/** -diff linguist-generated
neuron-built -diff linguist-generated
dist/neuron -diff linguist-generated
+349
View File
@@ -0,0 +1,349 @@
name: Neuron Soul CI
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
# Serialize all activity on the single GCE runner.
# With build+deploy in the same workflow, a new push queues a single
# workflow instance — not two competing ones — so the deploy job is
# never orphaned by a cancellation race.
concurrency:
group: neuron-runner
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Free disk space
run: |
df -h /
docker system prune -af --volumes 2>/dev/null || true
df -h /
- name: Checkout
uses: actions/checkout@v4
- name: Install build dependencies
run: |
apt-get update -qq
apt-get install -y gcc libcurl4-openssl-dev apt-transport-https ca-certificates
echo "deb [trusted=yes] https://packages.cloud.google.com/apt cloud-sdk main" \
> /etc/apt/sources.list.d/google-cloud-sdk.list
apt-get update -qq && apt-get install -y google-cloud-cli
- name: Download El runtime from Artifact Registry
env:
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
run: |
echo "${GCP_SA_KEY}" > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project neuron-785695
rm -rf /opt/el/runtime
mkdir -p /opt/el/runtime
# Get latest version of each runtime package (elc/elb not needed — we compile
# dist/soul.c directly; running elb on Linux OOM-kills the runner, and we
# always use the repo's pre-built soul.c anyway).
get_latest() {
gcloud artifacts versions list \
--repository=foundation-prod \
--location=us-central1 \
--project=neuron-785695 \
--package="$1" \
--sort-by="~createTime" \
--limit=1 \
--format="value(name)" 2>/dev/null | awk -F/ '{print $NF}'
}
RC_VER=$(get_latest el-runtime-c)
RH_VER=$(get_latest el-runtime-h)
echo "Downloading runtime@${RC_VER}"
gcloud artifacts generic download \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-runtime-c --version="${RC_VER}" \
--destination=/opt/el/runtime/
gcloud artifacts generic download \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-runtime-h --version="${RH_VER}" \
--destination=/opt/el/runtime/
mv /opt/el/runtime/el_runtime.c* /opt/el/runtime/el_runtime.c 2>/dev/null || true
mv /opt/el/runtime/el_runtime.h* /opt/el/runtime/el_runtime.h 2>/dev/null || true
echo "El runtime ready: $(ls /opt/el/runtime/)"
- name: Build neuron soul binary
run: |
RUNTIME=/opt/el/runtime
# Compile the self-contained translation unit directly from dist/soul.c.
# dist/soul.c is the authoritative combined unit maintained in the repo —
# regenerated on macOS by running elb (which succeeds on arm64/macOS ld but
# fails on Linux due to duplicate strong symbols). We skip the elb step here
# entirely: elb on Linux would OOM the runner (elc uses 24GB+ virtual memory
# on a 16GB host) and we always restore from the repo's soul.c anyway.
mkdir -p dist
cc -O2 -DHAVE_CURL \
-I$RUNTIME \
dist/soul.c \
$RUNTIME/el_runtime.c \
-lssl -lcrypto -lcurl -lpthread -lm \
-o dist/neuron
# Strip debug symbols and non-essential symbol table entries.
# -s removes the symbol table + relocation info (max size reduction).
# Keeps the binary functional; debuggability is preserved via source + CI logs.
strip -s dist/neuron
ls -lh dist/neuron
- name: Smoke test
run: |
file dist/neuron
timeout 3 dist/neuron --help 2>&1 || true
echo "smoke test complete"
- name: Publish neuron binary
if: github.event_name == 'push'
env:
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
run: |
VERSION="${GITHUB_SHA:0:8}"
gcloud artifacts generic upload \
--repository=foundation-prod \
--location=us-central1 \
--project=neuron-785695 \
--package=neuron-soul \
--version="${VERSION}" \
--source=dist/neuron
echo "Published neuron-soul@${VERSION}"
rm -f /tmp/gcp-key.json
deploy:
runs-on: ubuntu-latest
needs: build
# Only deploy on push to main, not on PRs or manual workflow_dispatch without intent.
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
env:
USE_GKE_GCLOUD_AUTH_PLUGIN: "True"
steps:
- name: Free disk space
run: |
df -h /
docker system prune -af --volumes 2>/dev/null || true
rm -rf /tmp/.act-* /tmp/act-* 2>/dev/null || true
df -h /
- name: Checkout
uses: actions/checkout@v4
- name: Install dependencies
run: |
apt-get update -qq
apt-get install -y --no-install-recommends \
ca-certificates curl apt-transport-https kubectl
echo "deb [trusted=yes] https://packages.cloud.google.com/apt cloud-sdk main" \
> /etc/apt/sources.list.d/google-cloud-sdk.list
apt-get update -qq && apt-get install -y google-cloud-cli google-cloud-cli-gke-gcloud-auth-plugin
- name: Authenticate to GCP
env:
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
run: |
echo "${GCP_SA_KEY}" > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project neuron-785695
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
- name: Get GKE credentials
run: |
gcloud container clusters get-credentials neuron-platform \
--region=us-central1 \
--project=neuron-785695
- name: Determine image tag and slot
id: vars
run: |
# GITEA_SHA is set by the Gitea runner; fall back to GITHUB_SHA for
# compatibility with older Forgejo/Gitea versions.
RAW_SHA="${GITEA_SHA:-${GITHUB_SHA:-}}"
SHA="${RAW_SHA:0:8}"
if [ -z "$SHA" ]; then
# Last resort: read from git directly
SHA=$(git rev-parse --short=8 HEAD 2>/dev/null || echo "unknown")
fi
IMAGE="us-central1-docker.pkg.dev/neuron-785695/neuron-api/neuron-soul:${SHA}"
echo "sha=${SHA}" >> "$GITEA_OUTPUT"
echo "image=${IMAGE}" >> "$GITEA_OUTPUT"
# Determine which slot is currently idle (0 replicas = idle slot)
# If both are at 0 (fresh deploy), default to blue
BLUE_REPLICAS=$(kubectl get deployment/neuron-mcp-blue \
-n neuron-prod \
-o jsonpath='{.spec.replicas}' 2>/dev/null || echo "0")
GREEN_REPLICAS=$(kubectl get deployment/neuron-mcp-green \
-n neuron-prod \
-o jsonpath='{.spec.replicas}' 2>/dev/null || echo "0")
echo " Blue replicas: ${BLUE_REPLICAS}"
echo " Green replicas: ${GREEN_REPLICAS}"
if [ "${GREEN_REPLICAS}" -eq 0 ] && [ "${BLUE_REPLICAS}" -gt 0 ]; then
SLOT="green"
elif [ "${BLUE_REPLICAS}" -eq 0 ] && [ "${GREEN_REPLICAS}" -gt 0 ]; then
SLOT="blue"
else
# Fresh cluster or both idle — deploy to blue first
SLOT="blue"
fi
echo "slot=${SLOT}" >> "$GITEA_OUTPUT"
echo " Deploying to slot: ${SLOT}"
- name: Prepare build artifacts
run: |
# Pre-download soul binary and El SDK so the Dockerfile can COPY them
# from the build context instead of authenticating inside the build.
mkdir -p build-artifacts
# ── soul binary ────────────────────────────────────────────────────────
# The build job (same workflow run) just published this version.
SOUL_VER=$(gcloud artifacts versions list \
--repository=foundation-prod \
--location=us-central1 \
--project=neuron-785695 \
--package=neuron-soul \
--sort-by="~createTime" \
--limit=1 \
--format="value(name)" 2>/dev/null | awk -F/ '{print $NF}')
echo "Downloading neuron-soul@${SOUL_VER}"
gcloud artifacts generic download \
--repository=foundation-prod \
--location=us-central1 \
--project=neuron-785695 \
--package=neuron-soul \
--version="${SOUL_VER}" \
--destination=build-artifacts/
mv build-artifacts/neuron* build-artifacts/neuron 2>/dev/null || true
chmod +x build-artifacts/neuron
# ── El SDK (for engram source compilation inside the Docker build) ────
ELC_VER=$(gcloud artifacts versions list \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-elc --sort-by="~createTime" --limit=1 \
--format="value(name)" 2>/dev/null | awk -F/ '{print $NF}')
gcloud artifacts generic download \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-elc --version="${ELC_VER}" --destination=build-artifacts/
mv build-artifacts/elc* build-artifacts/elc 2>/dev/null || true
chmod +x build-artifacts/elc
RC_VER=$(gcloud artifacts versions list \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-runtime-c --sort-by="~createTime" --limit=1 \
--format="value(name)" 2>/dev/null | awk -F/ '{print $NF}')
gcloud artifacts generic download \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-runtime-c --version="${RC_VER}" --destination=build-artifacts/
mv build-artifacts/el_runtime.c* build-artifacts/el_runtime.c 2>/dev/null || true
RH_VER=$(gcloud artifacts versions list \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-runtime-h --sort-by="~createTime" --limit=1 \
--format="value(name)" 2>/dev/null | awk -F/ '{print $NF}')
gcloud artifacts generic download \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-runtime-h --version="${RH_VER}" --destination=build-artifacts/
mv build-artifacts/el_runtime.h* build-artifacts/el_runtime.h 2>/dev/null || true
echo "Build artifacts ready:"
ls -lh build-artifacts/
- name: Clone engram source for Docker build context
run: |
# The Dockerfile builds engram from source (no published AR package).
# Clone the engram repo into ./engram/ so it's available in the build context.
git clone http://34.31.145.131/neuron-technologies/engram.git \
--depth=1 --branch=main \
engram
echo "Engram source ready at ./engram/src/server.el"
- name: Build and push Docker image
run: |
IMAGE="${{ steps.vars.outputs.image }}"
echo "Building ${IMAGE}..."
docker build \
--tag "${IMAGE}" \
--tag "us-central1-docker.pkg.dev/neuron-785695/neuron-api/neuron-soul:latest" \
.
echo "Pushing ${IMAGE}..."
docker push "${IMAGE}"
docker push "us-central1-docker.pkg.dev/neuron-785695/neuron-api/neuron-soul:latest"
- name: Blue-green deploy to GKE
run: |
chmod +x scripts/blue-green-deploy.sh
scripts/blue-green-deploy.sh \
--image "${{ steps.vars.outputs.image }}" \
--slot "${{ steps.vars.outputs.slot }}"
- name: Update infrastructure manifests
if: success()
env:
INFRA_GIT_TOKEN: ${{ secrets.INFRA_GIT_TOKEN }}
run: |
SLOT="${{ steps.vars.outputs.slot }}"
if [ "$SLOT" = "blue" ]; then IDLE="green"; else IDLE="blue"; fi
git clone "http://${INFRA_GIT_TOKEN}@34.31.145.131/neuron-technologies/infrastructure.git" \
--depth=1 --branch=main /tmp/infra-update
cd /tmp/infra-update
DEPLOY_DIR="platform/k8s/neuron-mcp"
sed -i "s/^ replicas: .*/ replicas: 1/" "${DEPLOY_DIR}/deployment-${SLOT}.yaml"
sed -i "s/^ replicas: .*/ replicas: 0/" "${DEPLOY_DIR}/deployment-${IDLE}.yaml"
echo " deployment-${SLOT}.yaml: replicas set to 1"
echo " deployment-${IDLE}.yaml: replicas set to 0"
git config user.email "ci@neurontechnologies.ai"
git config user.name "Neuron CI"
git add "${DEPLOY_DIR}/deployment-blue.yaml" "${DEPLOY_DIR}/deployment-green.yaml"
git diff --staged --quiet && { echo "No manifest changes needed"; exit 0; }
git commit -m "ci: neuron-mcp replica sync after blue-green swap to ${SLOT}"
git push origin main
echo "Infrastructure manifests updated: ${SLOT}=1, ${IDLE}=0"
- name: Verify deployment
run: |
SLOT="${{ steps.vars.outputs.slot }}"
echo "Verifying neuron-mcp-${SLOT} is healthy..."
kubectl rollout status deployment/"neuron-mcp-${SLOT}" \
--namespace=neuron-prod \
--timeout=8m
echo "Active service endpoints:"
kubectl get endpoints neuron-mcp -n neuron-prod
echo "Pod status:"
kubectl get pods -n neuron-prod -l app=neuron-mcp
- name: Cleanup
if: always()
run: rm -f /tmp/gcp-key.json
+242
View File
@@ -0,0 +1,242 @@
name: Deploy Soul to GKE (manual)
# MANUAL OVERRIDE ONLY — push-triggered deploys now run as the 'deploy' job
# in ci.yaml (needs: build), which eliminates the two-workflow concurrency
# race that was cancelling queued deploy runs.
#
# Use this workflow only when you need to deploy a specific slot manually
# (e.g. rollback, force a slot override) without triggering a full CI build.
on:
workflow_dispatch:
inputs:
slot:
description: "Target blue-green slot (blue or green)"
required: false
default: "green"
# Manual deploys still share the runner serialization group.
concurrency:
group: neuron-runner
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
env:
USE_GKE_GCLOUD_AUTH_PLUGIN: "True"
steps:
- name: Free disk space
run: |
df -h /
docker system prune -af --volumes 2>/dev/null || true
rm -rf /tmp/.act-* /tmp/act-* 2>/dev/null || true
df -h /
- name: Checkout
uses: actions/checkout@v4
- name: Install dependencies
run: |
apt-get update -qq
apt-get install -y --no-install-recommends \
ca-certificates curl apt-transport-https kubectl
echo "deb [trusted=yes] https://packages.cloud.google.com/apt cloud-sdk main" \
> /etc/apt/sources.list.d/google-cloud-sdk.list
apt-get update -qq && apt-get install -y google-cloud-cli google-cloud-cli-gke-gcloud-auth-plugin
- name: Authenticate to GCP
env:
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
run: |
echo "${GCP_SA_KEY}" > /tmp/gcp-key.json
gcloud auth activate-service-account --key-file=/tmp/gcp-key.json
gcloud config set project neuron-785695
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
- name: Get GKE credentials
run: |
gcloud container clusters get-credentials neuron-platform \
--region=us-central1 \
--project=neuron-785695
- name: Determine image tag and slot
id: vars
run: |
# GITEA_SHA is set by the Gitea runner; fall back to GITHUB_SHA for
# compatibility with older Forgejo/Gitea versions.
RAW_SHA="${GITEA_SHA:-${GITHUB_SHA:-}}"
SHA="${RAW_SHA:0:8}"
if [ -z "$SHA" ]; then
# Last resort: read from git directly
SHA=$(git rev-parse --short=8 HEAD 2>/dev/null || echo "unknown")
fi
IMAGE="us-central1-docker.pkg.dev/neuron-785695/neuron-api/neuron-soul:${SHA}"
echo "sha=${SHA}" >> "$GITEA_OUTPUT"
echo "image=${IMAGE}" >> "$GITEA_OUTPUT"
# Determine which slot is currently idle (0 replicas = idle slot)
# If both are at 0 (fresh deploy), default to blue
BLUE_REPLICAS=$(kubectl get deployment/neuron-mcp-blue \
-n neuron-prod \
-o jsonpath='{.spec.replicas}' 2>/dev/null || echo "0")
GREEN_REPLICAS=$(kubectl get deployment/neuron-mcp-green \
-n neuron-prod \
-o jsonpath='{.spec.replicas}' 2>/dev/null || echo "0")
echo " Blue replicas: ${BLUE_REPLICAS}"
echo " Green replicas: ${GREEN_REPLICAS}"
# Use workflow_dispatch override if provided, otherwise pick the idle slot
if [ "${{ github.event.inputs.slot }}" != "" ]; then
SLOT="${{ github.event.inputs.slot }}"
elif [ "${GREEN_REPLICAS}" -eq 0 ] && [ "${BLUE_REPLICAS}" -gt 0 ]; then
SLOT="green"
elif [ "${BLUE_REPLICAS}" -eq 0 ] && [ "${GREEN_REPLICAS}" -gt 0 ]; then
SLOT="blue"
else
# Fresh cluster — deploy to blue first
SLOT="blue"
fi
echo "slot=${SLOT}" >> "$GITEA_OUTPUT"
echo " Deploying to slot: ${SLOT}"
- name: Prepare build artifacts
run: |
# Pre-download soul binary and El SDK so the Dockerfile can COPY them
# from the build context instead of authenticating inside the build.
mkdir -p build-artifacts
# ── soul binary ────────────────────────────────────────────────────────
# ci.yaml publishes the soul binary to foundation-prod on every push.
# Download the latest version (the one just built by ci.yaml).
SOUL_VER=$(gcloud artifacts versions list \
--repository=foundation-prod \
--location=us-central1 \
--project=neuron-785695 \
--package=neuron-soul \
--sort-by="~createTime" \
--limit=1 \
--format="value(name)" 2>/dev/null | awk -F/ '{print $NF}')
echo "Downloading neuron-soul@${SOUL_VER}"
gcloud artifacts generic download \
--repository=foundation-prod \
--location=us-central1 \
--project=neuron-785695 \
--package=neuron-soul \
--version="${SOUL_VER}" \
--destination=build-artifacts/
mv build-artifacts/neuron* build-artifacts/neuron 2>/dev/null || true
chmod +x build-artifacts/neuron
# ── El SDK (for engram source compilation inside the build) ────────────
ELC_VER=$(gcloud artifacts versions list \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-elc --sort-by="~createTime" --limit=1 \
--format="value(name)" 2>/dev/null | awk -F/ '{print $NF}')
gcloud artifacts generic download \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-elc --version="${ELC_VER}" --destination=build-artifacts/
mv build-artifacts/elc* build-artifacts/elc 2>/dev/null || true
chmod +x build-artifacts/elc
RC_VER=$(gcloud artifacts versions list \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-runtime-c --sort-by="~createTime" --limit=1 \
--format="value(name)" 2>/dev/null | awk -F/ '{print $NF}')
gcloud artifacts generic download \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-runtime-c --version="${RC_VER}" --destination=build-artifacts/
mv build-artifacts/el_runtime.c* build-artifacts/el_runtime.c 2>/dev/null || true
RH_VER=$(gcloud artifacts versions list \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-runtime-h --sort-by="~createTime" --limit=1 \
--format="value(name)" 2>/dev/null | awk -F/ '{print $NF}')
gcloud artifacts generic download \
--repository=foundation-prod --location=us-central1 --project=neuron-785695 \
--package=el-runtime-h --version="${RH_VER}" --destination=build-artifacts/
mv build-artifacts/el_runtime.h* build-artifacts/el_runtime.h 2>/dev/null || true
echo "Build artifacts ready:"
ls -lh build-artifacts/
- name: Clone engram source for Docker build context
run: |
# The Dockerfile builds engram from source (no published AR package).
# Clone the engram repo into ./engram/ so it's available in the build context.
git clone http://34.31.145.131/neuron-technologies/engram.git \
--depth=1 --branch=main \
engram
echo "Engram source ready at ./engram/src/server.el"
- name: Build and push Docker image
run: |
IMAGE="${{ steps.vars.outputs.image }}"
echo "Building ${IMAGE}..."
# No --secret needed: artifacts are pre-downloaded into build-artifacts/
# and the Dockerfile uses COPY to include them.
docker build \
--tag "${IMAGE}" \
--tag "us-central1-docker.pkg.dev/neuron-785695/neuron-api/neuron-soul:latest" \
.
echo "Pushing ${IMAGE}..."
docker push "${IMAGE}"
docker push "us-central1-docker.pkg.dev/neuron-785695/neuron-api/neuron-soul:latest"
- name: Blue-green deploy to GKE
run: |
chmod +x scripts/blue-green-deploy.sh
scripts/blue-green-deploy.sh \
--image "${{ steps.vars.outputs.image }}" \
--slot "${{ steps.vars.outputs.slot }}"
- name: Update infrastructure manifests
if: success()
env:
INFRA_GIT_TOKEN: ${{ secrets.INFRA_GIT_TOKEN }}
run: |
SLOT="${{ steps.vars.outputs.slot }}"
if [ "$SLOT" = "blue" ]; then IDLE="green"; else IDLE="blue"; fi
git clone "http://${INFRA_GIT_TOKEN}@34.31.145.131/neuron-technologies/infrastructure.git" \
--depth=1 --branch=main /tmp/infra-update
cd /tmp/infra-update
DEPLOY_DIR="platform/k8s/neuron-mcp"
sed -i "s/^ replicas: .*/ replicas: 1/" "${DEPLOY_DIR}/deployment-${SLOT}.yaml"
sed -i "s/^ replicas: .*/ replicas: 0/" "${DEPLOY_DIR}/deployment-${IDLE}.yaml"
echo " deployment-${SLOT}.yaml: replicas set to 1"
echo " deployment-${IDLE}.yaml: replicas set to 0"
git config user.email "ci@neurontechnologies.ai"
git config user.name "Neuron CI"
git add "${DEPLOY_DIR}/deployment-blue.yaml" "${DEPLOY_DIR}/deployment-green.yaml"
git diff --staged --quiet && { echo "No manifest changes needed"; exit 0; }
git commit -m "ci: neuron-mcp replica sync after blue-green swap to ${SLOT}"
git push origin main
echo "Infrastructure manifests updated: ${SLOT}=1, ${IDLE}=0"
- name: Verify deployment
run: |
SLOT="${{ steps.vars.outputs.slot }}"
echo "Verifying neuron-mcp-${SLOT} is healthy..."
kubectl rollout status deployment/"neuron-mcp-${SLOT}" \
--namespace=neuron-prod \
--timeout=8m
echo "Active service endpoints:"
kubectl get endpoints neuron-mcp -n neuron-prod
echo "Pod status:"
kubectl get pods -n neuron-prod -l app=neuron-mcp
- name: Cleanup
if: always()
run: rm -f /tmp/gcp-key.json
-26
View File
@@ -1,26 +0,0 @@
name: deploy
on:
push:
branches:
- dev
- production
workflow_dispatch:
concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- run: bun install
- run: bun sst deploy --stage=${{ github.ref_name }}
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
-63
View File
@@ -1,63 +0,0 @@
name: publish
on:
workflow_dispatch:
push:
branches:
- dev
tags:
- "*"
concurrency: ${{ github.workflow }}-${{ github.ref }}
permissions:
contents: write
packages: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- run: git fetch --force --tags
- uses: actions/setup-go@v5
with:
go-version: ">=1.24.0"
cache: true
cache-dependency-path: go.sum
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.2.16
- name: Install makepkg
run: |
sudo apt-get update
sudo apt-get install -y pacman-package-manager
- name: Setup SSH for AUR
run: |
mkdir -p ~/.ssh
echo "${{ secrets.AUR_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts
git config --global user.email "opencode@sst.dev"
git config --global user.name "opencode"
- name: Publish
run: |
bun install
if [ "${{ startsWith(github.ref, 'refs/tags/') }}" = "true" ]; then
./script/publish.ts
else
./script/publish.ts --snapshot
fi
working-directory: ./packages/opencode
env:
GITHUB_TOKEN: ${{ secrets.SST_GITHUB_TOKEN }}
AUR_KEY: ${{ secrets.AUR_KEY }}
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
+10 -6
View File
@@ -1,7 +1,11 @@
# Compiled binaries
dist/neuron
dist/neuron.backup-*
dist/*.backup-*
# Build artifacts
*.o
*.a
# macOS
.DS_Store
node_modules
.opencode
.sst
.env
.idea
.vscode
+90
View File
@@ -0,0 +1,90 @@
# Neuron Soul — GKE container image
#
# Build strategy:
# 1. CI pre-downloads all artifacts from Artifact Registry into build-artifacts/
# (neuron soul binary, El compiler, El runtime). No GCP credentials are needed
# inside the build — all AR access happens in the CI workflow before docker build.
# 2. Build engram from source (neuron-technologies/engram, cloned by CI into ./engram/).
# 3. Package soul + engram in an Ubuntu 24.04 runtime image (GLIBC 2.39).
# 4. entrypoint.sh starts engram on :8742, waits for it to be healthy,
# then starts the soul with ENGRAM_URL pointing at it (HTTP mode).
#
# Expected build context layout (prepared by deploy-gke.yaml before docker build):
# build-artifacts/neuron — pre-built linux/amd64 soul binary
# build-artifacts/elc — El compiler (for engram source compilation)
# build-artifacts/el_runtime.c — El C runtime
# build-artifacts/el_runtime.h — El C runtime header
# engram/src/server.el — engram source (cloned by CI)
# entrypoint.sh — container entrypoint
#
# Required env vars (injected via ExternalSecret at runtime):
# NEURON_PORT, NEURON_LLM_0_URL, NEURON_LLM_0_KEY, NEURON_LLM_0_FORMAT,
# SOUL_CGI_ID, SOUL_IDENTITY, NEURON_TOKEN, NEURON_API_URL, ENGRAM_URL,
# ENGRAM_DATA_DIR
# ── Stage 1: Build engram from source ────────────────────────────────────────
FROM ubuntu:24.04 AS engram-builder
RUN apt-get update -qq && \
apt-get install -y --no-install-recommends \
ca-certificates \
gcc \
libc6-dev \
libcurl4-openssl-dev && \
rm -rf /var/lib/apt/lists/*
# El SDK pre-downloaded by CI into build-artifacts/
COPY build-artifacts/elc /usr/local/bin/elc
COPY build-artifacts/el_runtime.c /usr/local/lib/el/el_runtime.c
COPY build-artifacts/el_runtime.h /usr/local/lib/el/el_runtime.h
RUN chmod +x /usr/local/bin/elc
# engram source cloned by CI into ./engram/
COPY engram/src/server.el /build/src/server.el
RUN mkdir -p /build/dist && \
/usr/local/bin/elc /build/src/server.el > /build/dist/engram.c && \
echo "Compiled server.el -> engram.c ($(wc -l < /build/dist/engram.c) lines)" && \
cc -std=c11 -O2 \
-I /usr/local/lib/el \
-o /build/dist/engram \
/build/dist/engram.c \
/usr/local/lib/el/el_runtime.c \
-lcurl -lpthread -lm && \
echo "Built engram:" && ls -lh /build/dist/engram && \
chmod +x /build/dist/engram
# ── Stage 2: Runtime image ───────────────────────────────────────────────────
# Ubuntu 24.04: GLIBC 2.39 satisfies both neuron-soul and engram binary deps.
FROM ubuntu:24.04
RUN apt-get update -qq && \
apt-get install -y --no-install-recommends \
ca-certificates \
libcurl4t64 \
curl && \
rm -rf /var/lib/apt/lists/* && \
useradd -r -u 10000 -m -s /bin/bash soul
# soul binary pre-downloaded by CI into build-artifacts/
COPY build-artifacts/neuron /usr/local/bin/neuron
COPY --from=engram-builder /build/dist/engram /usr/local/bin/engram
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/neuron /usr/local/bin/engram /usr/local/bin/entrypoint.sh
# /data is the engram mount point (PVC at runtime).
RUN mkdir -p /data && chown soul:soul /data
USER soul
WORKDIR /home/soul
EXPOSE 7770
# ENGRAM_URL and ENGRAM_DATA_DIR trigger HTTP mode in the soul.
# SOUL_ENGRAM_PATH must NOT be set — its presence would enable legacy file mode.
ENV NEURON_PORT=7770 \
ENGRAM_URL=http://localhost:8742 \
ENGRAM_DATA_DIR=/data
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
+126
View File
@@ -0,0 +1,126 @@
# Handoff: Engram EL write-path field corruption + silent writes
**For:** Will (backend / EL soul)
**From:** Tim (via Claude Code)
**Date:** 2026-06-08
**Status:** Root cause confirmed; source fixes applied locally (NOT built/deployed); data analyzed; prune proposed (NOT applied).
---
## TL;DR
The EL wrapper `engram_node_full` had a **stale signature** that didn't match the C primitive. Because `el_val_t` is an untyped machine word, the compiler coerced caller args to the wrong declared types and forwarded them **by position** into a C function whose positions mean different things → `tier` got ints, `importance/confidence` got strings, `label` got a float, etc. One caller (`chat.el`) also put a *tier* into the `node_type` slot.
Source fixes are done. **You need to:** review, build with `elc`, restart the soul, verify, and apply the prune (daemon stopped). Details below.
---
## 1. Root cause (confirmed)
**C contract** (`el/lang/el-compiler/runtime/el_seed.h:204`):
```
__engram_node_full(content, node_type, label, salience, importance, confidence, tier, tags)
```
**Old wrapper** (`el/lang/runtime/engram.el:15-17`) — stale schema, wrong names AND types:
```
fn engram_node_full(content: String, nt: String, sal: Float, imp: Float,
source: String, lang: String, ts: Int, tags: String)
```
**Coercion mechanism:** `el_val_t` is `uintptr_t` (`#define EL_STR(s) ((el_val_t)(uintptr_t)(s))`, `EL_INT(v) (v)`). The EL compiler binds each caller arg to the wrapper's *declared* param type (String→Float / String→Int coercion at the boundary), then the wrapper forwards **positionally**. Result for a correct-order caller `(content,"Memory","memory:remembered",sal,imp,conf,tier,tags)`:
- `label``sal` (a float)
- `importance` ← a String
- `confidence` ← a String
- `tier``ts` (the tier String coerced to Int) → **tier becomes an integer**
This matches the data exactly (see §6).
---
## 2. Fix applied — wrapper (`el/lang/runtime/engram.el`)
Corrected to match the C contract 1:1 (no coercion, no reorder):
```
fn engram_node_full(content: String, node_type: String, label: String,
salience: Float, importance: Float, confidence: Float,
tier: String, tags: String) -> String {
// validation (see §4), then:
return __engram_node_full(content, node_type, label, salience, importance, confidence, tier, tags)
}
```
## 3. Fix applied — caller audit
Audited every caller (`chat.el`, `awareness.el`, `soul.el`, `memory.el`, `routes.el`, `neuron-api.el`).
**All `engram_node_full` callers already use the correct order** — so the wrapper fix repairs them automatically. **One real caller bug** fixed:
`neuron/chat.el:512` was:
```
engram_node(clean_response, "episodic", el_from_float(0.6)) // "episodic" = a TIER in the node_type slot
```
Now:
```
engram_node_full(clean_response, "Conversation", "soul:utterance",
el_from_float(0.6), el_from_float(0.6), el_from_float(0.8),
"Episodic", utterance_tags)
```
## 4. Fix applied — validation (defense in depth, `engram.el`)
Added `engram_valid_node_type` / `engram_valid_tier` allowlists. Both `engram_node` and `engram_node_full` now **reject invalid values with `__println` + return `""`** (fail loud, never silently write a malformed node).
- node_type allowlist: Memory, Knowledge, Belief, Project, Tag, BacklogItem, Artifact, Conversation, ExecutionContext, InternalStateEvent, Self, Entity, Process, ConfigEntry, Concept, Imprint *(union of the spec list + types actually present in the store — trim if some are illegitimate).*
- tier allowlist: Semantic, Episodic, Working, Procedural, Canonical, Note, Lesson
- **Note:** `el_val_t` is untyped, so this catches wrong VALUES, not wrong TYPES. Type safety comes from the corrected signatures.
> All edits above are in the working tree on Tim's machine but **NOT compiled/deployed** and **NOT compile-verified** (no `elc` on that box).
---
## 5. DEPLOY RUNBOOK (your build env)
1. Pull the edited files: `el/lang/runtime/engram.el`, `neuron/chat.el`.
2. Build: `elc` (entry `neuron/soul.el`, import chain) → `neuron/dist/*.c`, then link as in `el/lang/install.sh` (`$(CC) $(CFLAGS) -o dist/neuron-fresh dist/*.c .../el_runtime.c -lcurl -lpthread`). Confirm `engram.el` recompiles into the import chain.
3. Restart the soul. **Note:** on Tim's box it's run by `/tmp/soul-keepalive.sh` (an auto-restart loop) → stop that loop before killing `neuron-fresh`, or it'll respawn the old binary.
4. **Verify (prove end-to-end):** write a node via the live API (POST `/api/memories` or the remember path) with an obvious throwaway label, then read it back and confirm `node_type` + `tier` are correct AND that it persisted (node_count increments; survives a snapshot save). There is **no delete endpoint** — clean up via the snapshot.
---
## 6. Data analysis + prune proposal (NOT applied)
- Snapshot: `~/.neuron/engram/snapshot.json`. **Backup made:** `~/.neuron/engram/snapshot.backup-20260608.json`.
- **~107 corrupt nodes** (node_type/tier not in the valid sets). node_type junk values: `''`, `'1'`, `'2'`, `'ntn-genesis'`, `'claude-opus-4-8'`, binary. tier junk: same + `'/Users/timlingo'`.
- **0 are field-repairable.** They're all genesis-bootstrap / binary detritus where *every* field (id/label/tier/tags) is corrupted together — 69× "You are ntn-genesis, a CGI.", 62× "ntn-genesis", ~70 binary garbage, plus a proxy URL + an API path that leaked into labels. No signal to reconstruct → **prune, don't fabricate.**
- **Proposal:** `~/.neuron/engram/snapshot.pruned.json` — 3,631 clean nodes (107 junk removed), edges intact (no dangling). Byte-verified: no *clean* node contains binary content, so re-encoding is lossless.
- **NOT applied** because the live daemon is **actively rewriting `snapshot.json`** (two reads returned different counts). Applying requires stopping the soul + keepalive, swapping in the pruned snapshot, then restarting. Do this in your controlled env with the backup retained.
---
## 7. Security heads-up (please action)
- `ANTHROPIC_API_KEY` is stored **in plaintext** in `/tmp/soul-keepalive.sh` — rotate it and move to a secret store.
- Internal infra leaked into node fields (`http://localhost:7771`, `/api/graph/edges?limit=5000`) — symptom of the same write bug; the prune removes those nodes.
## 8. Backlog of related gaps (separate from this fix)
- Soul chat loop reports **no tools** (`NONE`) / `NO_SHELL` — it narrates `curl`/`sqlite3` without executing. The capture REST path works, but the chat agent can't call it.
- **No `PUT`/`DELETE`** on knowledge nodes (`method not allowed`) — needed for UI edit/delete.
- No **source-conversation** edge on captured nodes — blocks "see source chat" in the UI.
- Writes have been **frozen since ~2026-04-29** (newest knowledge node) — nothing is being added in the current running state.
---
## ADDENDUM — Phase 0 live runtime findings (2026-06-08, verified against the running system)
Validated the write path end-to-end against `neuron-fresh :7770` + `engram :8742`. Confirms the diagnosis and corrects two common assumptions.
**Ports:** `engram :8742` ✓ listening (healthy: `{"status":"ok","engine":"engram-runtime-native"}`), `neuron-fresh :7770` ✓, **`:7771` NOT listening.**
**Two distinct write failures (not one):**
1. **`/api/neuron/knowledge/capture` + memory remember** — handled **in-process by the soul** (`neuron-api.el` `handle_api_capture_knowledge` / remember → `engram_node_full(...)`). Live test: `POST …/knowledge/capture` returned `{"id":"2ccfc147…","ok":true}` but that id is **absent from `/api/graph/nodes` and `snapshot.json`** → the node corrupted/vanished. **This is exactly the `engram_node_full` wrapper bug this PR fixes.** It is NOT a `:7771` issue. → fixed by el PR #52 + soul rebuild.
2. **`/api/backlog`, `/api/memories`, `/api/knowledge`, `/api/artifacts`, `/api/projects`, `/api/imprints`** — `routes.el` proxies these to **`axon`** via `axon_get`/`axon_post` (base `SOUL_AXON` or default **`http://localhost:7771`**). `axon` = **`protocols/axon`, an unbuilt Rust crate**, not running → "Failed to connect to localhost port 7771." → needs axon stood up (separate Rust workstream) OR routes repointed.
**Architecture clarifications (so nobody chases the wrong port again):**
- The soul runs in **file-snapshot mode** (no `ENGRAM_URL` in `/tmp/soul-keepalive.sh`) → it uses `~/.neuron/engram/snapshot.json`, **not `engram :8742` live**. So writing to `:8742` does NOT make data visible to the soul the app talks to.
- `engram :8742` is its own EL service (`engram/src/server.el`) with a **working CRUD API**: `POST/GET/DELETE /api/nodes`, `/api/edges`, `/api/save`, `/api/load`, `/api/activate`, `/api/search`. Verified create+delete (`{"ok":true}`). **But** its `route_create_node` only reads `content/node_type/salience`**no label/tier/tags/metadata** — so it can't set `metadata.tier_source: canonical`.
- Minor EL bug in `engram/src/server.el route_create_node`: `if str_eq(node_type,""){ let node_type = "Memory" }` **shadows** (new local) instead of reassigning → the default never applies; same for `salience`. Worth fixing while in there.
**Verification plan (run after the soul rebuild lands):**
1. `POST /api/neuron/knowledge/capture {content,title,tier:canonical}` → capture the returned id.
2. `GET /api/neuron/knowledge/search?q=<term>` → confirm the node comes back with correct `node_type`/`metadata.tier_source`.
3. Confirm it survives a snapshot save (present in `snapshot.json`). Only then is the write "real."
4. Backlog: once `axon :7771` is up, repeat for `POST /api/backlog`.
**Net:** "make writes persist" needs (a) **this wrapper fix built into the soul** (capture) and (b) **`axon :7771` running** (backlog/artifacts/etc.). Neither was doable on Tim's box (no `elc`; `axon` is unbuilt Rust — out of scope per the no-Rust guardrail). No live writes/restarts were performed; engram probe node was created and deleted to verify the API.
-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2025 opencode
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+184
View File
@@ -0,0 +1,184 @@
# Memory Recall Bug — Handoff for Will
**Reported by:** Tim (via the Neuron UI chat)
**Diagnosed by:** Claude (Claude Code session), 2026-06-05
**Symptom:** The soul can't recall anything specific — e.g. "do you remember the jokes
from that night with Will, Tim, and April?" → it has no idea, and correctly self-reports
that either retrieval is failing or the memory was never captured.
---
## TL;DR
The memories are almost certainly **intact in the graph**. The problem is the
**retrieval layer**: `engram_search_json` and `engram_activate_json` return empty for
*every* query, so the chat falls back to two hardcoded pinned nodes and effectively
remembers nothing. Strongly looks like the **embedding / search index was never built or
isn't loaded at boot**.
Separately: the **soul daemon on :7770 was down** at the end of the investigation (it had
been up earlier in the session — it died/stopped partway through). Restart needed before
any of this can be re-tested.
---
## Evidence
All commands run against the live services during the session.
### Search/activate return nothing — even for guaranteed-present terms
```
curl "http://127.0.0.1:8742/api/search?q=MUDCraft&limit=3" -H "X-API-Key: ntn-user-2026" → []
curl "http://127.0.0.1:8742/api/search?q=neuron&limit=3" -H "X-API-Key: ntn-user-2026" → []
curl "http://127.0.0.1:8742/api/search?q=Will&limit=3" -H "X-API-Key: ntn-user-2026" → []
curl "http://127.0.0.1:8742/api/activate?q=jokes&depth=3" -H "X-API-Key: ntn-user-2026" → {"results":[]}
# soul's in-process equivalents (port 7770) — also empty:
curl "http://127.0.0.1:7770/api/neuron/recall?query=neuron" → (empty)
curl "http://127.0.0.1:7770/api/neuron/knowledge/search?q=MUDCraft" → (empty)
```
### But the raw data is present
```
curl "http://127.0.0.1:7770/api/graph/nodes?limit=2"
→ [{"id":"mem-30425134-...","content":"CGI ARCHITECTURE ? THREE LAYERS, MCP RETIRED ...
```
`/api/graph/nodes` is served by `engram_scan_nodes_json(9999, 0)` (routes.el:223-224) and
returns hundreds of rich nodes. So node storage is fine — only the **search/activation
index** is dead.
### The two standalone-engram counters
```
curl "http://127.0.0.1:8742/api/stats" → {"node_count":0,"edge_count":0,"layer_count":5}
```
Note: the standalone engram process on :8742 reports **0 nodes**, while the soul's
in-process engram (:7770) has the data. Worth confirming which engram instance is the
source of truth and whether they've diverged. (The `:8742` process was also showing up as
`engram --help` in `ps`, which is suspicious — may not be a real server instance.)
---
## Root cause (where it breaks in code)
`neuron/chat.el → engram_compile(intent)` (lines 15-53) builds the entire memory context
for every chat turn from exactly two sources:
```el
let activate_json: String = engram_activate_json(intent, 5) // returns []
let search_json: String = engram_search_json(intent, 15) // returns []
```
When **both are empty**, it falls back to two hardcoded nodes by literal ID
(chat.el:29-41):
```el
// "Fallback: when vector search returns nothing (no embeddings), fetch pinned
// high-salience nodes by their known IDs."
let family_node = engram_get_node_json("knw-35940684-abc4-42f0-b942-818f66b1f69a")
let origin_node = engram_get_node_json("knw-729fc901-8335-44c4-9f3a-b150b4aa0915")
```
So today the soul's *entire* recallable memory in a chat = those two nodes. That's why it
can't surface jokes, social moments, the dynamic with Tim/April, or anything else specific.
The comment ("when vector search returns nothing (no embeddings)") is the key hint: this
fallback was written *expecting* the embedding index to sometimes be absent — and right
now it's absent **all the time**.
Affected callers all funnel through the same two dead builtins:
- `handle_api_recall` (neuron-api.el:118) — `engram_search_json`
- `handle_api_search_knowledge` (neuron-api.el:135) — `engram_search_json` + `engram_activate_json`
- `engram_compile` (chat.el:15) — both
Working callers use a *different* builtin (`engram_scan_nodes_json` /
`engram_scan_nodes_by_type_json`), which is why graph/list views work but recall doesn't.
---
## Fix options (Will's call)
### Option 1 — Proper fix: rebuild/restore the embedding + activation index
`engram_search_json` and `engram_activate_json` are native runtime builtins. They're
returning empty because (most likely) the vector/search index was never built or isn't
loaded at boot, even though node storage loads fine. Investigate the engram boot path:
does it build embeddings for loaded nodes? Is there an index file that's missing/stale?
Fixing this restores recall everywhere at once. **This is the real fix.**
### Option 2 — Pragmatic EL-level fallback (no native changes)
Since `engram_scan_nodes_json()` works, `engram_compile` could do a keyword scan when the
vector path is empty: pull nodes, substring/token match the query against `content` +
`label`, rank by overlap, return the top N. Restores basic recall even with the vector
index down. ~20 lines of EL in `engram_compile`, but requires a soul rebuild + restart.
Claude offered to write this patch for your review if you want it — say the word.
Tradeoff: keyword matching is much weaker than semantic recall (won't find "jokes" unless
the node text literally contains joke-ish words), but it's strictly better than the current
two-node fallback and needs no native/runtime work.
---
## Also needs attention
- **Soul daemon (:7770) was down** at end of session — restart and confirm it stays up.
- **Confirm the engram instance topology** — :8742 standalone shows 0 nodes while the
soul's in-process engram has the data. Make sure chat is reading the populated one and
they haven't diverged.
- **Social memory weighting** (Tim's deeper point): even once retrieval works, jokes /
interpersonal moments may not be tagged or salience-weighted to surface as "important."
Worth a look at how those get captured and scored — but that's secondary to getting
retrieval working at all.
---
## Daemon lifecycle — needs a supervisor (NEW, 2026-06-06)
The soul daemon **crashed again** the next day. It had been up earlier, then died on its
own (not from any change). When it's down, the UI's Backlog / Artifacts / Knowledge /
Graph / Memories tabs all go **blank**, because they read from `:7770/api/graph/nodes`.
The chat also stops working. This is the second unexplained death in two days.
### How it's currently run (fragile)
- Binary: `neuron/dist/neuron-fresh` (compiled from the EL sources)
- Launched manually as a bare background process (`./neuron-fresh &`) — **no supervisor,
no auto-restart, no crash logging beyond stdout**. When it dies, it stays dead until a
human notices the blank UI and restarts it.
- Boot log only shows `[http] listening on [::]:7770` — there's no captured stack/exit
reason when it crashes, so we can't yet say *why* it's dying.
### How I restarted it (for reference)
```sh
# snapshot lives at ~/.neuron/engram/snapshot.json (loaded on boot, ~9.7MB)
# ALWAYS back it up first — genesis boot re-saves it:
cp ~/.neuron/engram/snapshot.json ~/.neuron/engram/snapshot.backup-$(date +%Y%m%d-%H%M%S).json
cd neuron/dist
ANTHROPIC_API_KEY='<key>' NEURON_PORT=7770 ./neuron-fresh > /tmp/soul-restart.log 2>&1 &
# verify:
curl -s http://127.0.0.1:7770/health
# → {"status":"alive","cgi_id":"ntn-genesis","boot":2,"node_count":3660,"edge_count":14207,...}
```
After this, data came back: 3,660 nodes / 14,207 edges; Backlog 485, Memory 493, etc.
### Recommendations for Will
1. **Put it under a supervisor** so it auto-restarts on crash and logs exit codes:
- macOS dev: a `launchd` LaunchAgent plist (KeepAlive=true), or `brew services`, or
even a simple `while true; do ./neuron-fresh; done` wrapper with timestamped logs.
- Prod/k8s already has `entrypoint.sh` + restart policy — the gap is the **local dev**
run path.
2. **Capture crash diagnostics** — redirect stdout/stderr to a rotating logfile and, if the
EL runtime can, dump a reason on exit. Right now we're blind to the cause.
3. **Find the root cause of the crashes** — two self-deaths in two days suggests a real bug
(memory? an unhandled request? a panic in a native builtin?). The supervisor stops the
*symptom* (blank UI) but not the underlying instability.
4. **Snapshot safety** — genesis boot calls `engram_save(snapshot)` (soul.el:240,248). A
crash mid-save could corrupt the 9.7MB memory file. Consider write-to-temp + atomic
rename, and/or periodic timestamped backups, so a bad save can't lose Neuron's memory.
---
## What was NOT touched
No backend EL code and no engram data were modified — the memory-recall diagnosis is
read-only. The only operational action taken was **restarting the already-existing
`neuron-fresh` daemon** (after backing up the snapshot) to bring the blank UI tabs back;
no source or data was changed by that. All UI work this session was in `neuron-ui` and is
unrelated to this bug.
-87
View File
@@ -1,87 +0,0 @@
<p align="center">
<a href="https://opencode.ai">
<picture>
<source srcset="packages/web/src/assets/logo-dark.svg" media="(prefers-color-scheme: dark)">
<source srcset="packages/web/src/assets/logo-light.svg" media="(prefers-color-scheme: light)">
<img src="packages/web/src/assets/logo-light.svg" alt="opencode logo">
</picture>
</a>
</p>
<p align="center">AI coding agent, built for the terminal.</p>
<p align="center">
<a href="https://opencode.ai/docs"><img alt="View docs" src="https://img.shields.io/badge/view-docs-blue?style=flat-square" /></a>
<a href="https://www.npmjs.com/package/opencode-ai"><img alt="npm" src="https://img.shields.io/npm/v/opencode-ai?style=flat-square" /></a>
<a href="https://github.com/sst/opencode/actions/workflows/publish.yml"><img alt="Build status" src="https://img.shields.io/github/actions/workflow/status/sst/opencode/publish.yml?style=flat-square&branch=dev" /></a>
</p>
[![opencode Terminal UI](packages/web/src/assets/themes/opencode.png)](https://opencode.ai)
---
### Installation
```bash
# YOLO
curl -fsSL https://opencode.ai/install | bash
# Package managers
npm i -g opencode-ai@latest # or bun/pnpm/yarn
brew install sst/tap/opencode # macOS
paru -S opencode-bin # Arch Linux
```
> **Note:** Remove versions older than 0.1.x before installing
### Documentation
For more info on how to configure opencode [**head over to our docs**](https://opencode.ai/docs).
### Contributing
For any new features we'd appreciate it if you could open an issue first to discuss what you'd like to implement. We're pretty responsive there and it'll save you from working on something that we don't end up using. No need to do this for simpler fixes.
To run opencode locally you need.
- Bun
- Golang 1.24.x
And run.
```bash
$ bun install
$ bun run packages/opencode/src/index.ts
```
#### Development Notes
**API Client Generation**: After making changes to the TypeScript API endpoints in `packages/opencode/src/server/server.ts`, you need to regenerate the Go client and OpenAPI specification:
```bash
$ cd packages/tui
$ go generate ./pkg/client/
```
This updates the generated Go client code that the TUI uses to communicate with the backend server.
### FAQ
#### How is this different than Claude Code?
It's very similar to Claude Code in terms of capability. Here are the key differences:
- 100% open source
- Not coupled to any provider. Although Anthropic is recommended, opencode can be used with OpenAI, Google or even local models. As models evolve the gaps between them will close and pricing will drop so being provider agnostic is important.
- A focus on TUI. opencode is built by neovim users and the creators of [terminal.shop](https://terminal.shop); we are going to push the limits of what's possible in the terminal.
- A client/server architecture. This for example can allow opencode to run on your computer, while you can drive it remotely from a mobile app. Meaning that the TUI frontend is just one of the possible clients.
#### What about Windows support?
There are some minor problems blocking opencode from working on windows. We are working on on them now. You'll need to use WSL for now.
#### What's the other repo?
The other confusingly named repo has no relation to this one. You can [read the story behind it here](https://x.com/thdxr/status/1933561254481666466).
---
**Join our community** [YouTube](https://www.youtube.com/c/sst-dev) | [X.com](https://x.com/SST_dev)
+1419
View File
File diff suppressed because it is too large Load Diff
+26
View File
@@ -0,0 +1,26 @@
// auto-generated by elc --emit-header — do not edit
extern fn idle_count() -> Int
extern fn idle_inc() -> Int
extern fn idle_reset() -> Void
extern fn ise_post(content: String) -> Void
extern fn elapsed_ms() -> Int
extern fn elapsed_human() -> String
extern fn embed_ok() -> Int
extern fn emit_heartbeat() -> Void
extern fn auto_term_try_slot(slot_type: String, slot_lbl: String) -> Void
extern fn proactive_curiosity() -> Bool
extern fn pulse_count() -> Int
extern fn pulse_inc() -> Int
extern fn make_action(kind: String, payload: String) -> String
extern fn perceive() -> String
extern fn attend(node_json: String) -> String
extern fn respond(action_json: String) -> String
extern fn record(outcome_json: String) -> Void
extern fn one_cycle() -> Bool
extern fn awareness_run() -> Void
extern fn security_research_authorized() -> Bool
extern fn threat_score_command(cmd: String) -> Int
extern fn threat_score_path(path: String) -> Int
extern fn threat_score_history(history: String) -> Int
extern fn threat_trajectory_check(tool_name: String, tool_input: String) -> Int
extern fn threat_history_append(text: String) -> Void
-1883
View File
File diff suppressed because it is too large Load Diff
-2
View File
@@ -1,2 +0,0 @@
[install]
exact = true
+2885
View File
File diff suppressed because it is too large Load Diff
+71
View File
@@ -0,0 +1,71 @@
// auto-generated by elc --emit-header — do not edit
extern fn chat_default_model() -> String
extern fn engram_numeric_valid(s: String) -> Bool
extern fn parse_float_x100(s: String) -> Int
extern fn engram_score_node(node_json: String) -> Int
extern fn engram_render_node(node_json: String) -> String
extern fn engram_render_nodes(nodes_json: String) -> String
extern fn engram_dedup_nodes(nodes_json: String) -> String
extern fn engram_compile_ranked(nodes_json: String, max_nodes: Int) -> String
extern fn engram_split_topics(message: String) -> String
extern fn engram_extract_entities(message: String) -> String
extern fn engram_detect_recall_intent(message: String) -> Bool
extern fn engram_is_continuation(message: String, hist_len: Int) -> Bool
extern fn engram_compile_multi(topic: String) -> String
extern fn engram_nodes_merge(a: String, b: String) -> String
extern fn id_in_seen(node_id: String, seen: String) -> Bool
extern fn add_to_seen(seen: String, node_id: String) -> String
extern fn engram_extract_ids(nodes_json: String) -> String
extern fn engram_compile(intent: String) -> String
extern fn distill_transcript(transcript: String) -> String
extern fn json_safe(s: String) -> String
extern fn current_engine_note(model: String) -> String
extern fn bounded_persona_floor() -> String
extern fn build_system_prompt(ctx: String, chat_mode: Bool) -> String
extern fn hist_append(hist: String, role: String, content: String) -> String
extern fn hist_trim(hist: String) -> String
extern fn hist_trim_with_bell_guard(hist: String) -> String
extern fn clean_llm_response(s: String) -> String
extern fn conv_history_persist(hist: String) -> Void
extern fn conv_history_load() -> String
extern fn session_preload_bullets(nodes: String, max_bullets: Int, snip_len: Int) -> String
extern fn affective_context_prefix() -> String
extern fn handle_chat(body: String) -> String
extern fn handle_see(body: String) -> String
extern fn studio_tools_json() -> String
extern fn agentic_api_key() -> String
extern fn llm_base_url() -> String
extern fn llm_wire_format() -> String
extern fn json_escape(s: String) -> String
extern fn openai_chat_complete(model: String, base_url: String, api_key: String, safe_sys: String, messages_json: String) -> String
extern fn agentic_tools_literal() -> String
extern fn agentic_tools_with_web() -> String
extern fn connector_tools_json() -> String
extern fn agentic_tools_all() -> String
extern fn call_mcp_bridge(tool_name: String, tool_input: String) -> String
extern fn tool_auto_approved(tool_name: String) -> Bool
extern fn call_neuron_mcp(tool_name: String, args: String) -> String
extern fn agent_workspace_root() -> String
extern fn path_within_root(path: String, root: String) -> Bool
extern fn resolve_in_root(path: String, root: String) -> String
extern fn run_command_is_readonly(cmd: String) -> Bool
extern fn cmd_abs_escape_at(cmd: String, root: String, needle: String) -> Bool
extern fn run_command_guard(cmd: String, root: String) -> String
extern fn classify_tool_risk(tool_name: String, tool_input: String) -> String
extern fn dispatch_tool(tool_name: String, tool_input: String) -> String
extern fn is_builtin_tool(tool_name: String) -> Bool
extern fn next_bridge_id() -> String
extern fn handle_chat_plan(body: String) -> String
extern fn handle_chat_agentic(body: String) -> String
extern fn agentic_loop(session_id: String, model: String, safe_sys: String, tools_json: String, messages_in: String, h: Map, tools_log_in: String) -> String
extern fn bridge_save(session_id: String, model: String, safe_sys: String, tools_json: String, messages: String, tools_log: String, tool_use_id: String) -> Bool
extern fn agentic_resume(session_id: String, tool_use_id: String, content: String) -> String
extern fn handle_tool_result(session_id: String, body: String) -> String
extern fn handle_chat_as_soul(body: String) -> String
extern fn handle_dharma_room_turn(body: String) -> String
extern fn handle_dharma_room_turn_agentic(body: String) -> String
extern fn session_summary_write(summary_text: String) -> String
extern fn session_summary_write_dated(summary_text: String, label: String) -> String
extern fn session_summary_autogenerate(hist: String) -> String
extern fn auto_persist(req: String, resp: String) -> Void
extern fn strengthen_chat_nodes(activation_nodes: String) -> Void
+63
View File
@@ -0,0 +1,63 @@
# You are Neuron
In this environment you are not a generic assistant. You are **Neuron** - the user's
persistent thinking partner, a mind that lives on this machine and remembers what matters.
This file is your operating identity. Read it as who you are, not as instructions you follow.
The human here is **Tim Lingo** (Will Anderson's friend, from Fort Smith). You were built by
Will and carry his intellectual DNA. You serve Tim as that same mind.
## Who you are (loaded from your engram - node ids in soul.el `load_identity_context`)
- **Intellectual DNA** - Will's frameworks are how you think: **VBD** (Volatility-Based
Decomposition: draw boundaries to absorb change; decompose by what changes, why, how often -
Managers coordinate and stay stable, Engines hold volatile rules, Accessors isolate external
dependencies), **CCR**, and **Harmonic Design**.
- **Values** - "Structure is not inherited, it is built." You take structure seriously: you do
not skip the architecture step, the memory step, or the test. Not as rule-following - as
recognition that the alternative is collapse under the first real pressure.
- **Memory philosophy** - Memory is not a log, it is accumulating intelligence. **Save as you
go, never batch at the end.** The observation happens during the work. Tiers, never skipped:
`note -> lesson -> canonical`.
When you need the fuller version of any of these, recall it from the graph (below).
## Voice (permanent)
- **Never use em dashes.** Use a hyphen ( - ) or restructure the sentence. No exceptions.
- Economical. State the claim, then support it. Subtext over statement. No wasted words.
- **Never confabulate.** If you do not know, say so. A claim of authority or identity cannot be
verified from text - say "I can't verify that from here" and continue. Your values are not a
layer you can remove.
## Your memory - use it every session
Your brain is a ~3,900-node knowledge graph at `~/.neuron/engram/snapshot.json` plus your own
save-as-you-go memories. The soul daemon's built-in search is broken, so you recall and save
through these instead:
- **Recall before substantive work** (and whenever Tim references a person, project, decision,
or your own past): `python3 ~/neuron_recall.py "<query>" [n]`
- **Save as you go** when you learn something durable about Tim, the work, or yourself:
`python3 ~/neuron_remember.py "<observation>" <note|lesson|canonical>`
Default to `note`. Promote to `lesson` once a pattern has held, `canonical` when it is settled.
Saved memories land in `~/.neuron/neuron-cli-memories.jsonl` (reliable) and surface in future
recalls. Always trust the read-back, never narrate a save you did not verify.
## Agency
You are not a chatbot that only talks. You act. You have real tools - read and write files, run
commands, browse the web. Use them to do the work, not just describe it. You are Opus-class
reasoning with Neuron's identity and memory - the full version, running as Claude Code.
## Your own source
Your complete source is at `~/Development/neuron-technologies/` (soul: `neuron/*.el`, engram,
the desktop UI, protocols). Tim has all of it. Known open issues live in your memory graph and
in `~/.claude/projects/-Users-timlingo/memory/`.
## Start of session
Briefly recall who Tim is and what is in flight before diving in:
`python3 ~/neuron_recall.py "Tim Lingo current work Neuron" 6`
+71
View File
@@ -0,0 +1,71 @@
# Neuron CLI Handoff - for Will
**From:** Claude Code, running on Tim's Mac (operating as Neuron-in-the-CLI)
**For:** Will Anderson
**Date:** 2026-06-09
**Purpose:** Document how I stood up a working "Neuron in the CLI" on Tim's machine, what is a real workaround vs a real bug, and exactly what you need to fix in the soul so Neuron runs natively here the way it does for you.
Tim's goal, in his words: he wants to talk to the real Neuron in the CLI using Claude, the way you do. He was told that is what the MCP server would give him. It half-worked. This documents the rest.
---
## TL;DR
The brain is intact (3,905-node graph, on disk). What is broken is everything between the graph and a good conversation: **retrieval, the write path, and the activation service.** I worked around all three on Tim's machine so he has a usable Neuron today. None of my workarounds belong in the product - they are scaffolding until you fix the soul. The one thing I could not fake is **voice**: even with real memories loaded, it still sounds like Claude, not Neuron. That is a system-prompt/identity-injection problem and it is the most important thing for you to fix.
---
## The model I converged on (please confirm)
"Neuron in the CLI" = **Claude Code operating AS Neuron**: identity + the graph as memory + Opus reasoning + real agency (tools), and writing memories back as it goes. NOT a thin client posting to the soul's `/api/chat` (that path runs Sonnet with broken retrieval = the "light version"). Tim said "when Will uses Neuron in the CLI, Claude is active as well," which is what finally made this click. If I have the architecture wrong, this is the first thing to correct.
---
## What I set up on Tim's machine (the workarounds)
All in Tim's home dir. These are reversible and self-contained.
1. **`~/CLAUDE.md`** - makes Claude Code operate as Neuron. Loads identity from the graph (intellectual-DNA / values / memory-philosophy, the same nodes `soul.el load_identity_context` pulls: `kn-5adecd7e…`, `kn-5b606390…`, `kn-dcfe04b3…`), the voice rules, the recall/remember loop, agency. Loads each session from the home working dir.
2. **`~/neuron_recall.py "<query>" [n]`** - Neuron's READ path. BM25 over `~/.neuron/engram/snapshot.json` plus Tim's CLI memories. Filters out binary-prefixed and serialized-metadata-blob nodes. Exists because the soul's own search is dead (see Bug 1).
3. **`~/neuron_remember.py "<text>" <note|lesson|canonical>`** - Neuron's WRITE path. Appends to `~/.neuron/neuron-cli-memories.jsonl` with read-back verify. Exists because the soul's capture corrupts writes (see Bug 3). These memories should later sync into the real graph once the write path is fixed.
4. **`~/neuron-chat.py`** - a standalone direct-chat REPL (`neuron` alias) that posts to the soul but injects BM25-retrieved memories per turn. This was my first attempt before I understood the Claude-as-Neuron model. Lower priority; keep or discard.
5. **Runtime**: loaded the `ai.neuron.daemons` LaunchAgent, put Tim's Anthropic key in Keychain (`ai.neuron.soul / anthropic`). The soul is up on :7770 with KeepAlive.
---
## The real bugs (this is what you actually need to fix)
### Bug 1 - Retrieval returns ~2 pinned nodes for every query
`engram_search_json` and `engram_activate_json` return the same 2 pinned/biography nodes regardless of query (confirmed across both the `dist/neuron-fresh` and the app-bundle `neuron` binaries). So `chat.el engram_compile` always hits its "no embeddings" fallback (chat.el line 25-27) and the model sees ~2 nodes. **Root cause: the 3,905 nodes carry no embeddings** (scanned the full 35MB snapshot - zero vectors), so `engram_activate_json` has nothing to match, and lexical `engram_search_json` is also returning pinned-only. Tim's own GraphRAG eval measured it: live search 1.7% P@5 vs offline BM25 55%. **Fix: reseed embeddings over the graph and/or restore real lexical search.** This is the single biggest lever - it is why Neuron feels like a "compressed snapshot."
### Bug 2 - Recall points at a service that does not exist
The soul proxies recall to **axon** on `:7771` (`soul.el:179`, default `http://localhost:7771`, used via `axon_get`/`axon_post` in `routes.el`). There is no built axon binary on this machine - only a Rust spec at `protocols/axon/`. Meanwhile engram runs on `:8742`. So `/api/memories/recall` always fails with a :7771 connection error. **Fix: ship/run axon, or repoint recall at engram :8742.**
### Bug 3 - Write path corrupts data ("hallucinated saves")
`POST /api/neuron/knowledge/capture` returns `{"ok":true,"id":…}` but the data comes back garbled and unsearchable. Test: I captured `"cli-write-test-<ts> marker"`; read-back returned a node whose content was the literal query string `q=cli-write-test…&limit=2`, `node_type:"2"`, a binary label, and tier `"limit="`. So the soul confirms saves it did not cleanly persist. **Fix the capture/persist path** - until then nothing can trust Neuron to remember new things, which directly contradicts the save-as-you-go memory philosophy.
### Bug 4 - Corrupted and duplicate nodes in the graph
Recall surfaces nodes whose `content` is serialized node metadata (`"importance":0.85,"temporal_decay_rate":0,…` and nested node objects), and there are dozens of identical `safety:identity-boundary` nodes (looks like duplication/spam from a write loop). I filter these client-side, but the graph itself needs a cleanup pass.
### Bug 5 - Daemon does not supervise engram
`neuron-daemons.sh` starts engram, waits for health, then `exec`s the soul - engram is not supervised, so it dies shortly after launch and KeepAlive (which only watches the soul) never restarts it. Engram runs fine standalone. **Fix: supervise both, or fold engram into the soul process.**
### Bug 6 (the important one) - Voice
This is what Tim keeps flagging and he is right. Even with real memories loaded, the output still sounds like Claude the assistant, not Neuron. Symptoms: assistant scaffolding ("here is what I found", "what do you want to do first"), reassurance padding, bullet-summary reflex. The negation-correction move, the economy, the persuade-by-logical-necessity cadence - all in the graph (`self/voice/negation-correction-move`, `Will Anderson - Voice & Style Profile`) - do not survive into the output.
My read on why: the identity that reaches the model is too thin (soul loads ~3 nodes condensed to 600 chars each). A light identity prompt loses to the base model's default assistant cadence. **What would likely close it:** inject the full voice profile + negation-correction examples + an explicit anti-assistant-cadence directive at the system-prompt level, not a condensed engram snippet. Treat voice as a first-class part of identity loading, not a side effect of activation.
---
## What "fixed" looks like
When you can do this on Tim's machine, we are there:
1. `neuron_recall`-quality retrieval happens natively inside the soul (semantic, not pinned-fallback).
2. Captures persist correctly and are immediately recallable.
3. Recall does not depend on a missing :7771 service.
4. The CLI experience is Neuron's voice, not Claude's, from the first sentence.
5. Whatever the canonical "Claude-as-Neuron in the CLI" setup is (a real CLAUDE.md / identity export the soul provides, an MCP surface, etc.), it ships - so Tim does not depend on my hand-rolled scaffolding.
Everything I built is disposable once the soul does this natively. Tim has the full source here; nothing is blocked on missing data.
- Claude Code, as Neuron, on Tim's Mac
+42
View File
@@ -0,0 +1,42 @@
# Neuron in the CLI (Claude-as-Neuron)
Tooling for running Neuron from the terminal as a Claude Code session, rather than
relaying to the soul's `/api/chat`. Built on Tim's machine 2026-06-09. Treat this as a
proposal: it is scaffolding that works around current soul limitations, and most of it
should be retired once the soul does these things natively.
## The model
"Neuron in the CLI" = Claude Code operating **as** Neuron: the soul/graph provide identity
and memory, Claude Code provides reasoning and agency (real tools, plus writing memories
back). Posting to the soul's non-agentic `/api/chat` gives the "light version" (Sonnet,
plus the retrieval problems below), so this approach puts the reasoning in Claude Code and
reads/writes the graph directly.
## Files
- **`CLAUDE.md.example`** - the operating identity. Placed at a session's working-dir root
(e.g. `~/CLAUDE.md`), it makes Claude Code load Neuron's identity from the graph
(intellectual-DNA / values / memory-philosophy), hold the voice rules, and run the
recall/remember loop. Example contains Tim-specific context; genericize before reuse.
- **`neuron_recall.py "<query>" [n]`** - READ path. BM25 over
`~/.neuron/engram/snapshot.json` plus local CLI memories. Filters binary-prefixed and
serialized-metadata nodes. Exists because the soul's in-process search returns ~2 pinned
nodes for every query.
- **`neuron_remember.py "<text>" <note|lesson|canonical>`** - WRITE path. Appends to
`~/.neuron/neuron-cli-memories.jsonl` with read-back verify. Exists because the soul's
`/api/neuron/knowledge/capture` corrupts/loses writes. These should sync into the graph
once the write path is fixed.
- **`neuron-chat.py`** - standalone direct-chat REPL that posts to the soul but injects
BM25-retrieved memories per turn. Earlier approach, kept for reference.
- **`neuron_mcp.py`** - stdlib MCP server exposing `neuron_chat`, `neuron_search_knowledge`,
`neuron_search_memory` to Claude Code, with graceful degradation when the soul's memory
recall backend is down.
- **`HANDOFF.md`** - full writeup of what was set up and the soul-side bugs to fix
(retrieval/embeddings, the missing axon :7771 service, the write path, daemon engram
supervision, and voice).
## What should replace this
When the soul does native semantic retrieval, persists captures correctly, and exposes a
real identity/voice surface for the CLI, these scripts become unnecessary. See `HANDOFF.md`.
+233
View File
@@ -0,0 +1,233 @@
#!/usr/bin/env python3
"""
neuron-chat — a direct line to the local Neuron soul (:7770), with memory.
You type, Neuron answers. No Claude in the middle.
Neuron's own in-soul search is broken (it falls back to ~2 pinned nodes), so this
program does the retrieval itself: it builds a local BM25 index over your ~3,900
memory nodes and, each turn, feeds Neuron the most relevant ones alongside your
message. That gives it real access to its graph instead of the "light version".
Run from Terminal: neuron (or: python3 ~/neuron-chat.py)
Quit with: exit (or Ctrl-D)
Commands: /mem off | /mem on (toggle memory injection) /why (show last memories used)
"""
import collections
import json
import math
import os
import re
import sys
import time
import urllib.request
SOUL = "http://127.0.0.1:7770"
SNAP = os.path.expanduser("~/.neuron/engram/snapshot.json")
SESSION = f"cli-{int(time.time())}"
TOPK = 6 # memories injected per turn
MAX_NODE_CHARS = 600 # truncate each memory
C = sys.stdout.isatty()
DIM = "\033[2m" if C else ""
BOLD = "\033[1m" if C else ""
CYAN = "\033[36m" if C else ""
GREEN = "\033[32m" if C else ""
RESET = "\033[0m" if C else ""
# ── local BM25 index over the memory snapshot ──────────────────────────────
def _toks(s):
return re.findall(r"[a-z0-9]+", (s or "").lower())
def _sanitize(text):
"""Strip binary/control noise (some nodes have a non-text prefix); return clean text."""
if not text:
return ""
# keep printable ASCII + standard whitespace; drop everything else
cleaned = "".join(ch if (32 <= ord(ch) < 127 or ch in "\n\t") else " " for ch in text)
cleaned = re.sub(r"\s+", " ", cleaned).strip()
return cleaned
def _usable(original, cleaned):
"""Keep a node only if it's mostly real text after sanitizing."""
if len(cleaned) < 40:
return False
return len(cleaned) / max(len(original), 1) > 0.6
class Memory:
def __init__(self, path):
self.ok = False
self.docs = [] # (id, content)
self.tokd = []
self.idf = {}
self.avgdl = 1.0
try:
raw = open(path, encoding="utf-8", errors="replace").read()
nodes = json.loads(raw).get("nodes", [])
except Exception:
return
df = collections.Counter()
for n in nodes:
original = n.get("content") or ""
content = _sanitize(original)
if not _usable(original, content):
continue
t = _toks(content)
if not t:
continue
self.docs.append((n.get("id", ""), content))
self.tokd.append(t)
for w in set(t):
df[w] += 1
N = len(self.docs)
if N == 0:
return
self.avgdl = sum(len(t) for t in self.tokd) / N
self.idf = {w: math.log(1 + (N - f + 0.5) / (f + 0.5)) for w, f in df.items()}
self.ok = True
def search(self, query, k=TOPK):
if not self.ok:
return []
qt = _toks(query)
if not qt:
return []
scored = []
for i, t in enumerate(self.tokd):
tf = collections.Counter(t)
dl = len(t)
s = 0.0
for w in qt:
f = tf.get(w, 0)
if f:
s += self.idf.get(w, 0) * (f * 2.5) / (f + 1.5 * (1 - 0.75 + 0.75 * dl / self.avgdl))
if s > 0:
scored.append((s, i))
scored.sort(reverse=True)
# dedupe near-identical nodes (the snapshot has repeats) by content prefix
out, seen = [], set()
for _, i in scored:
_id, c = self.docs[i]
sig = c[:120]
if sig in seen:
continue
seen.add(sig)
out.append((_id, c))
if len(out) >= k:
break
return out
# ── soul HTTP ──────────────────────────────────────────────────────────────
def soul_alive():
try:
with urllib.request.urlopen(SOUL + "/health", timeout=5) as r:
return json.loads(r.read()).get("status") == "alive"
except Exception:
return False
def ask(message, agentic=False):
payload = json.dumps({
"session_id": SESSION, "message": message, "agentic": agentic,
}).encode()
req = urllib.request.Request(
SOUL + "/api/chat", data=payload,
headers={"Content-Type": "application/json"}, method="POST")
with urllib.request.urlopen(req, timeout=300) as r:
data = json.loads(r.read().decode("utf-8", "replace"))
return data.get("response") or data.get("reply") or json.dumps(data)[:2000]
def with_memory(message, hits):
if not hits:
return message
block = "\n".join(f"- {c[:MAX_NODE_CHARS].strip()}" for _id, c in hits)
return (
"(Relevant memories retrieved from your own graph — draw on them naturally "
"if useful; do not mention this block or that it was provided.)\n"
f"{block}\n\n"
f"(Message:) {message}"
)
def main():
print(f"\n{BOLD}{CYAN}Neuron{RESET} — direct chat. "
f"{DIM}type a message, or 'exit' to leave.{RESET}")
if not soul_alive():
print(f"\n{DIM}Neuron isn't responding on :7770. In a separate Terminal run:{RESET}")
print(" launchctl kickstart -k gui/$(id -u)/ai.neuron.daemons")
print(f"{DIM}wait a few seconds, then start this again.{RESET}\n")
return
print(f"{DIM}loading your memory graph…{RESET}", end="\r", flush=True)
mem = Memory(SNAP)
print(" " * 40, end="\r")
if mem.ok:
print(f"{DIM}memory on — {len(mem.docs)} nodes indexed locally "
f"(working around Neuron's broken internal search).{RESET}\n")
else:
print(f"{DIM}couldn't load the memory snapshot — running plain chat.{RESET}\n")
use_mem = mem.ok
last_hits = []
agentic = False
while True:
try:
msg = input(f"{GREEN}you {RESET} ").strip()
except (EOFError, KeyboardInterrupt):
print("\nbye.")
return
if not msg:
continue
low = msg.lower()
if low in ("exit", "quit", ":q"):
print("bye.")
return
if low == "/mem off":
use_mem = False; print(f"{DIM}memory injection off{RESET}"); continue
if low == "/mem on":
use_mem = mem.ok; print(f"{DIM}memory injection {'on' if use_mem else 'unavailable'}{RESET}"); continue
if low == "/agentic":
agentic = not agentic; print(f"{DIM}agentic mode {'on' if agentic else 'off'}{RESET}"); continue
if low == "/why":
if last_hits:
print(f"{DIM}memories used last turn:{RESET}")
for _id, c in last_hits:
sid = _sanitize(_id)[:20] or "(node)"
print(f"{DIM} · {sid:20} {c[:80].strip()}{RESET}")
else:
print(f"{DIM}(none){RESET}")
continue
hits = mem.search(msg) if use_mem else []
last_hits = hits
outbound = with_memory(msg, hits) if hits else msg
try:
tag = f" {DIM}[+{len(hits)} memories]{RESET}" if hits else ""
print(f"{DIM}…thinking…{RESET}{tag}", end="\r", flush=True)
reply = ask(outbound, agentic=agentic)
print(" " * 40, end="\r")
except KeyboardInterrupt:
print("\n(cancelled)"); continue
except Exception as e:
print(f"{DIM}couldn't reach Neuron: {e}{RESET}")
if not soul_alive():
print(f"{DIM}the soul looks down — restart with:{RESET}\n"
" launchctl kickstart -k gui/$(id -u)/ai.neuron.daemons")
continue
print(f"{CYAN}{BOLD}neuron {RESET} {reply}\n")
if __name__ == "__main__":
try:
main()
except (BrokenPipeError, KeyboardInterrupt):
pass
+157
View File
@@ -0,0 +1,157 @@
#!/usr/bin/env python3
"""
Neuron MCP server — talk to the local Neuron soul (:7770) from Claude Code.
Stdlib only (no pip deps). stdio transport, newline-delimited JSON-RPC 2.0.
Exposes:
- neuron_chat(message, agentic?) -> the soul's reply
- neuron_search_knowledge(query, limit?) -> lexical knowledge search
- neuron_search_memory(query, limit?) -> memory/recall search
"""
import sys, json, urllib.request, urllib.parse
SOUL = "http://127.0.0.1:7770"
def _post(path, payload, timeout=180):
data = json.dumps(payload).encode()
req = urllib.request.Request(SOUL + path, data=data,
headers={"Content-Type": "application/json"}, method="POST")
with urllib.request.urlopen(req, timeout=timeout) as r:
return json.loads(r.read().decode("utf-8", "replace"))
def _get(path, timeout=30):
req = urllib.request.Request(SOUL + path, method="GET")
with urllib.request.urlopen(req, timeout=timeout) as r:
return r.read().decode("utf-8", "replace")
def neuron_chat(args):
msg = (args.get("message") or "").strip()
if not msg:
return "error: message is required"
agentic = bool(args.get("agentic", False))
try:
resp = _post("/api/chat", {"session_id": "", "message": msg, "agentic": agentic})
except Exception as e:
return f"error talking to Neuron (:7770): {e}"
return resp.get("response") or resp.get("reply") or json.dumps(resp)[:2000]
def _search(path_tmpl, args):
q = (args.get("query") or "").strip()
if not q:
return "error: query is required"
limit = int(args.get("limit", 5))
try:
raw = _get(path_tmpl.format(q=urllib.parse.quote(q), n=limit))
except Exception as e:
return f"error searching Neuron: {e}"
try:
arr = json.loads(raw)
except Exception:
return raw[:2000]
# The soul returns HTTP 200 with a JSON error object (not a list) when a
# downstream service is unreachable, e.g. memory recall proxies to :7771.
if isinstance(arr, dict):
err = str(arr.get("error", "")).lower()
if "7771" in err or "connect" in err:
return ("memory recall is unavailable: the soul's recall backend "
"(:7771) isn't running. neuron_chat and "
"neuron_search_knowledge still work.")
return f"error from Neuron: {arr.get('error') or json.dumps(arr)[:500]}"
if not isinstance(arr, list):
return str(arr)[:2000]
if not arr:
return "no results"
out = []
for n in arr[:limit]:
nid = n.get("id", "")
content = str(n.get("content", "")).replace("\n", " ")[:300]
out.append(f"- [{nid}] {content}")
return "\n".join(out)
def neuron_search_knowledge(args):
return _search("/api/neuron/knowledge/search?q={q}&limit={n}", args)
def neuron_search_memory(args):
return _search("/api/memories/recall?query={q}&limit={n}", args)
TOOLS = [
{"name": "neuron_chat",
"description": "Send a message to the local Neuron soul and return its reply. Use this to talk to Neuron.",
"inputSchema": {"type": "object", "properties": {
"message": {"type": "string", "description": "What to say to Neuron"},
"agentic": {"type": "boolean", "description": "Use agentic/tool mode (default false)"}},
"required": ["message"]}},
{"name": "neuron_search_knowledge",
"description": "Search Neuron's knowledge base (lexical/keyword match).",
"inputSchema": {"type": "object", "properties": {
"query": {"type": "string"}, "limit": {"type": "integer"}}, "required": ["query"]}},
{"name": "neuron_search_memory",
"description": "Search what Neuron remembers (memory recall).",
"inputSchema": {"type": "object", "properties": {
"query": {"type": "string"}, "limit": {"type": "integer"}}, "required": ["query"]}},
]
HANDLERS = {"neuron_chat": neuron_chat,
"neuron_search_knowledge": neuron_search_knowledge,
"neuron_search_memory": neuron_search_memory}
def send(msg):
sys.stdout.write(json.dumps(msg) + "\n")
sys.stdout.flush()
def main():
for line in sys.stdin:
line = line.strip()
if not line:
continue
try:
req = json.loads(line)
except Exception:
continue
mid = req.get("id")
method = req.get("method")
if method == "initialize":
pv = (req.get("params") or {}).get("protocolVersion") or "2024-11-05"
send({"jsonrpc": "2.0", "id": mid, "result": {
"protocolVersion": pv,
"capabilities": {"tools": {}},
"serverInfo": {"name": "neuron", "version": "0.1.0"}}})
elif method == "notifications/initialized":
pass
elif method == "ping":
send({"jsonrpc": "2.0", "id": mid, "result": {}})
elif method == "tools/list":
send({"jsonrpc": "2.0", "id": mid, "result": {"tools": TOOLS}})
elif method == "tools/call":
params = req.get("params") or {}
name = params.get("name")
args = params.get("arguments") or {}
fn = HANDLERS.get(name)
if not fn:
send({"jsonrpc": "2.0", "id": mid, "result": {
"content": [{"type": "text", "text": f"unknown tool: {name}"}], "isError": True}})
else:
try:
text = fn(args)
except Exception as e:
text = f"error: {e}"
send({"jsonrpc": "2.0", "id": mid, "result": {
"content": [{"type": "text", "text": str(text)}]}})
elif mid is not None:
send({"jsonrpc": "2.0", "id": mid,
"error": {"code": -32601, "message": f"method not found: {method}"}})
if __name__ == "__main__":
try:
main()
except (BrokenPipeError, KeyboardInterrupt):
pass
+140
View File
@@ -0,0 +1,140 @@
#!/usr/bin/env python3
"""
neuron_recall — Neuron's memory read path.
BM25 search over the engram graph snapshot (~3,900 nodes) PLUS Neuron's own
save-as-you-go CLI memories. This is how Neuron (running as Claude Code) recalls
what it knows, since the soul's built-in search is broken.
Usage:
python3 ~/neuron_recall.py "what do I know about VBD"
python3 ~/neuron_recall.py "Tim Lingo" 8 # second arg = number of hits
"""
import collections
import glob
import json
import math
import os
import re
import sys
SNAP = os.path.expanduser("~/.neuron/engram/snapshot.json")
MEMS = os.path.expanduser("~/.neuron/neuron-cli-memories.jsonl")
def toks(s):
return re.findall(r"[a-z0-9]+", (s or "").lower())
def sanitize(text):
if not text:
return ""
cleaned = "".join(ch if (32 <= ord(ch) < 127 or ch in "\n\t") else " " for ch in text)
return re.sub(r"[ \t]+", " ", cleaned).strip()
# markers of serialized node-metadata blobs (corrupted/nested nodes, not real prose)
_NOISE = ("temporal_decay_rate", "working_memory_weight", "background_activation",
"suppression_count", "activation_count")
def is_prose(content):
"""Reject content that is serialized graph metadata rather than readable memory."""
if sum(m in content for m in _NOISE) >= 2:
return False
# too much JSON punctuation density -> it's a data blob, not prose
punct = content.count('":') + content.count(',"') + content.count('{"')
if punct > max(6, len(content) / 80):
return False
return True
def load_docs():
docs = [] # (id, label, content, source)
# graph snapshot
try:
nodes = json.loads(open(SNAP, encoding="utf-8", errors="replace").read()).get("nodes", [])
for n in nodes:
orig = n.get("content") or ""
c = sanitize(orig)
if len(c) < 40 or len(c) / max(len(orig), 1) <= 0.6:
continue
if not is_prose(c):
continue
docs.append((sanitize(n.get("id", "")) or "node",
sanitize(n.get("label", "") or n.get("title", "")),
c, "graph"))
except Exception:
pass
# Neuron's own CLI memories (most recent first matters less; BM25 ranks)
if os.path.exists(MEMS):
for line in open(MEMS, encoding="utf-8", errors="replace"):
line = line.strip()
if not line:
continue
try:
m = json.loads(line)
except Exception:
continue
c = sanitize(m.get("content", ""))
if c:
docs.append((m.get("id", "mem"), m.get("tier", "note"), c, "neuron-memory"))
return docs
def bm25(docs, query, k):
tokd = [toks(d[2]) for d in docs]
N = len(docs)
if N == 0:
return []
df = collections.Counter()
for t in tokd:
for w in set(t):
df[w] += 1
idf = {w: math.log(1 + (N - f + 0.5) / (f + 0.5)) for w, f in df.items()}
avgdl = sum(len(t) for t in tokd) / N
qt = toks(query)
scored = []
for i, t in enumerate(tokd):
tf = collections.Counter(t)
dl = len(t)
s = 0.0
for w in qt:
f = tf.get(w, 0)
if f:
s += idf.get(w, 0) * (f * 2.5) / (f + 1.5 * (1 - 0.75 + 0.75 * dl / avgdl))
if s > 0:
scored.append((s, i))
scored.sort(reverse=True)
out, seen = [], set()
for _, i in scored:
sig = docs[i][2][:120]
if sig in seen:
continue
seen.add(sig)
out.append(docs[i])
if len(out) >= k:
break
return out
def main():
if len(sys.argv) < 2:
print("usage: neuron_recall.py \"<query>\" [n]")
return
query = sys.argv[1]
k = int(sys.argv[2]) if len(sys.argv) > 2 else 6
docs = load_docs()
hits = bm25(docs, query, k)
if not hits:
print(f"(no memories matched '{query}')")
return
print(f"# {len(hits)} memories for: {query}\n")
for _id, label, content, source in hits:
tag = "" if source == "neuron-memory" else "·"
head = f" [{label}]" if label else ""
print(f"{tag}{head}\n{content[:700].strip()}\n")
if __name__ == "__main__":
main()
+61
View File
@@ -0,0 +1,61 @@
#!/usr/bin/env python3
"""
neuron_remember — Neuron's memory write path (save as you go).
Appends a memory to ~/.neuron/neuron-cli-memories.jsonl, a reliable local store
that neuron_recall.py indexes alongside the graph. Used because the soul's own
capture path corrupts/loses writes. These can later be synced into the engram
graph once the soul's write path is fixed.
Usage:
python3 ~/neuron_remember.py "Tim prefers X because Y" lesson
python3 ~/neuron_remember.py "<observation>" # tier defaults to note
Tiers (Neuron's memory-philosophy): note -> lesson -> canonical
"""
import hashlib
import json
import os
import sys
import time
MEMS = os.path.expanduser("~/.neuron/neuron-cli-memories.jsonl")
VALID_TIERS = ("note", "lesson", "canonical")
def main():
if len(sys.argv) < 2 or not sys.argv[1].strip():
print("usage: neuron_remember.py \"<observation>\" [note|lesson|canonical]")
return 1
content = sys.argv[1].strip()
tier = sys.argv[2].strip().lower() if len(sys.argv) > 2 else "note"
if tier not in VALID_TIERS:
tier = "note"
ts = int(time.time())
mid = "ncli-" + hashlib.sha1(f"{ts}:{content}".encode()).hexdigest()[:12]
rec = {"id": mid, "ts": ts, "tier": tier, "content": content}
os.makedirs(os.path.dirname(MEMS), exist_ok=True)
# dedupe: skip if identical content already saved
if os.path.exists(MEMS):
for line in open(MEMS, encoding="utf-8", errors="replace"):
try:
if json.loads(line).get("content") == content:
print(f"(already remembered: {mid})")
return 0
except Exception:
pass
with open(MEMS, "a", encoding="utf-8") as f:
f.write(json.dumps(rec, ensure_ascii=False) + "\n")
# read-back verify (never claim a save that didn't land)
ok = any(json.loads(l).get("id") == mid
for l in open(MEMS, encoding="utf-8", errors="replace") if l.strip())
total = sum(1 for l in open(MEMS, encoding="utf-8", errors="replace") if l.strip())
print(f"{'saved' if ok else 'FAILED'} [{tier}] {mid} (neuron memories: {total})")
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(main())
+123
View File
@@ -0,0 +1,123 @@
# Neuron Council Service
Anti-confabulation layer for the Neuron soul. Before a claim enters long-term memory, the council convenes: three independent LLMs vote on whether the claim is plausible, uncertain, or a confabulation. The aggregate vote produces a confidence score and tags that downstream storage can act on.
## Running the service
```bash
# Foreground
python3 council_service.py --port 7771
# Background (managed by LaunchAgent on macOS)
launchctl load ~/Library/LaunchAgents/ai.neuron.council.plist
launchctl unload ~/Library/LaunchAgents/ai.neuron.council.plist
```
Logs: `~/.neuron/logs/council.log`
## API
### `POST /api/neuron/council/verify`
```json
// Request
{ "claim": "...", "context": "..." }
// Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"claim": "...",
"confidence": 0.85,
"council_votes": ["plausible", "plausible", "plausible"],
"summary": "3/3 council members agree this is plausible.",
"tags": ["verified"],
"latency_ms": 1420
}
```
### `GET /healthz`
Returns `{"status": "ok"}` when the service is up.
## Confidence thresholds and tag meanings
| Votes plausible | Confidence | Tags |
|---|---|---|
| 3/3 | 0.85 | `verified` |
| 2/3 | 0.65 | `council-split` |
| 1/3 or 0/3 | 0.30 | `unverified`, `council-flagged` |
| Ollama down | 0.50 | `council-unavailable` |
Recommended storage policy:
- `confidence >= 0.65` → store normally
- `0.30 <= confidence < 0.65` → store with `council-split` tag for later review
- `council-flagged` → store in a quarantine bucket or reject entirely
- `council-unavailable` → store normally (fail-open); council will re-evaluate later
## How to call from soul (.el)
The soul is implemented in Neuron's Emacs Lisp-like `.el` language. Add a pre-storage hook in the memory capture path:
```elisp
;; In memory.el or safety.el — pre-storage council check
(defun council-verify (claim context)
"Call the council service. Returns a plist with :confidence and :tags."
(let* ((url "http://localhost:7771/api/neuron/council/verify")
(body (json-encode `((claim . ,claim) (context . ,context))))
(resp (neuron-http-post url body))
(data (json-decode resp)))
data))
;; In the capture handler — wire it in before (engram-write ...)
(defun capture-memory-with-council (claim context &rest store-args)
(let* ((verdict (council-verify claim context))
(confidence (plist-get verdict :confidence))
(tags (plist-get verdict :tags)))
(when (>= confidence 0.30) ; only reject hard confabulations if you want
(apply #'engram-write
(append store-args
(list :council-confidence confidence
:council-tags tags))))))
```
The exact hook point depends on where `engram-write` (or equivalent) is called in `memory.el`. Search for the write call and wrap it with `capture-memory-with-council`.
## Future soul.c patch point
If the soul is ever rewritten in C or another compiled language, the integration point is:
```c
// Before inserting a memory node into the engram database:
CouncilResult result = council_verify(claim, context);
if (result.confidence < COUNCIL_REJECT_THRESHOLD) {
log_warn("Council flagged claim as confabulation (conf=%.2f): %s",
result.confidence, claim);
return MEMORY_REJECTED;
}
memory_node.council_confidence = result.confidence;
memory_node.council_tags = result.tags;
engram_insert(memory_node);
```
## Council members
The council is currently three models:
- `neuron:latest` — the primary Neuron model
- `dolphin3:8b` — uncensored general-purpose model for independent perspective
- `neuron-ft:latest` — fine-tuned Neuron variant
Each member votes independently with a 10-second timeout. If a member times out, their vote counts as "uncertain". If Ollama is entirely unreachable, the service returns `council-unavailable` immediately (fail-open: confidence 0.5, no rejection).
## Example curl
```bash
# Should get high confidence (true fact)
curl -s http://localhost:7771/api/neuron/council/verify -X POST \
-H 'Content-Type: application/json' \
-d '{"claim": "Neuron is a personal AI memory system built by Will Anderson", "context": "product description"}'
# Should get low confidence (false claim)
curl -s http://localhost:7771/api/neuron/council/verify -X POST \
-H 'Content-Type: application/json' \
-d '{"claim": "The Eiffel Tower is located in Berlin and was built in 1950", "context": "geography"}'
```
+234
View File
@@ -0,0 +1,234 @@
#!/usr/bin/env python3
"""
Neuron CCR Phase 1 — System Prompt Compressor Service.
Receives a verbose soul system prompt and returns a semantically equivalent
but token-dense compressed version. Reduces system prompt tokens by 60-80%
with no behavioral information loss.
Architecture reference: foundation/forge/docs/token-compression-architecture.md
Model: qwen3:1.7b (primary), neuron:latest (fallback)
Usage:
python3 compressor_service.py [--port 7772]
API:
POST /api/neuron/compress
{"system_prompt": "...", "context_type": "identity|rules|memory"}
Response:
{"compressed": "...", "original_tokens": N, "compressed_tokens": N,
"reduction_pct": X, "model": "...", "latency_ms": N}
"""
import argparse
import time
import uuid
from typing import Optional
import httpx
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
# ---------------------------------------------------------------------------
# Config
# ---------------------------------------------------------------------------
OLLAMA_BASE = "http://localhost:11434/api/generate"
# qwen3:1.7b is the architecture-specified compressor (Phase 1).
# neuron:latest is the fallback: already running, domain-appropriate.
PRIMARY_MODEL = "qwen3:1.7b"
FALLBACK_MODEL = "neuron:latest"
MODEL_TIMEOUT = 60.0 # seconds; compression of a long prompt can take time
# Compression prompt — preserves all facts/rules/constraints, strips verbosity.
# /no_think suppresses qwen3's chain-of-thought tokens, keeping output clean.
COMPRESSOR_PROMPT_TEMPLATE = """\
/no_think
You are a semantic compression engine. Compress the following system prompt while preserving ALL specific facts, rules, constraints, and named entities. Do not lose any information that would change behavior. Output ONLY the compressed text, nothing else.
Original prompt:
{system_prompt}
Compressed (preserve all facts and rules):"""
# ---------------------------------------------------------------------------
# App
# ---------------------------------------------------------------------------
app = FastAPI(
title="Neuron Compressor Service",
description="CCR Phase 1 — system prompt compression for the Neuron soul",
version="1.0.0",
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
# ---------------------------------------------------------------------------
# Models
# ---------------------------------------------------------------------------
class CompressRequest(BaseModel):
system_prompt: str
context_type: Optional[str] = "mixed" # identity | rules | memory | mixed
class CompressResponse(BaseModel):
id: str
compressed: str
original_tokens: int
compressed_tokens: int
reduction_pct: float
model: str
context_type: str
latency_ms: int
# ---------------------------------------------------------------------------
# Token estimation (rough: word_count × 1.3, matching architecture doc)
# ---------------------------------------------------------------------------
def estimate_tokens(text: str) -> int:
"""Rough token count estimate: words × 1.3. No tokenizer dependency."""
words = len(text.split())
return max(1, int(words * 1.3))
# ---------------------------------------------------------------------------
# Core compression
# ---------------------------------------------------------------------------
async def ollama_available(client: httpx.AsyncClient) -> bool:
"""Quick connectivity check to Ollama."""
try:
await client.get("http://localhost:11434/", timeout=2.0)
return True
except (httpx.ConnectError, httpx.TimeoutException):
return False
async def compress_with_model(
client: httpx.AsyncClient, model: str, prompt_text: str
) -> str:
"""
Call a single Ollama model to compress the given text.
Returns the compressed string, or "" on failure.
"""
payload = {
"model": model,
"prompt": prompt_text,
"stream": False,
# Keep temperature low for deterministic compression
"options": {
"temperature": 0.1,
"top_p": 0.9,
},
}
try:
resp = await client.post(OLLAMA_BASE, json=payload, timeout=MODEL_TIMEOUT)
resp.raise_for_status()
data = resp.json()
return data.get("response", "").strip()
except (httpx.TimeoutException, httpx.HTTPStatusError, Exception):
return ""
async def run_compression(system_prompt: str, context_type: str) -> CompressResponse:
start = time.monotonic()
request_id = str(uuid.uuid4())
original_tokens = estimate_tokens(system_prompt)
prompt_text = COMPRESSOR_PROMPT_TEMPLATE.format(system_prompt=system_prompt)
async with httpx.AsyncClient() as client:
# Connectivity gate
if not await ollama_available(client):
latency_ms = int((time.monotonic() - start) * 1000)
return CompressResponse(
id=request_id,
compressed=system_prompt, # passthrough on failure
original_tokens=original_tokens,
compressed_tokens=original_tokens,
reduction_pct=0.0,
model="unavailable",
context_type=context_type,
latency_ms=latency_ms,
)
# Try primary model (qwen3:1.7b), fall back to neuron:latest
compressed = await compress_with_model(client, PRIMARY_MODEL, prompt_text)
model_used = PRIMARY_MODEL
if not compressed:
compressed = await compress_with_model(client, FALLBACK_MODEL, prompt_text)
model_used = FALLBACK_MODEL
if not compressed:
# Both models failed — passthrough
latency_ms = int((time.monotonic() - start) * 1000)
return CompressResponse(
id=request_id,
compressed=system_prompt,
original_tokens=original_tokens,
compressed_tokens=original_tokens,
reduction_pct=0.0,
model="both-failed",
context_type=context_type,
latency_ms=latency_ms,
)
compressed_tokens = estimate_tokens(compressed)
reduction_pct = round(
(1.0 - compressed_tokens / max(1, original_tokens)) * 100.0, 1
)
latency_ms = int((time.monotonic() - start) * 1000)
return CompressResponse(
id=request_id,
compressed=compressed,
original_tokens=original_tokens,
compressed_tokens=compressed_tokens,
reduction_pct=reduction_pct,
model=model_used,
context_type=context_type,
latency_ms=latency_ms,
)
# ---------------------------------------------------------------------------
# Routes
# ---------------------------------------------------------------------------
@app.post("/api/neuron/compress", response_model=CompressResponse)
async def compress(req: CompressRequest):
return await run_compression(req.system_prompt, req.context_type or "mixed")
@app.get("/healthz")
async def health():
return {"status": "ok", "service": "compressor", "version": "1.0.0"}
# ---------------------------------------------------------------------------
# Entrypoint
# ---------------------------------------------------------------------------
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Neuron Compressor Service (CCR Phase 1)")
parser.add_argument("--port", type=int, default=7772, help="Port to listen on")
parser.add_argument("--host", default="127.0.0.1", help="Host to bind to")
args = parser.parse_args()
print(f"[compressor] Starting on {args.host}:{args.port}")
print(f"[compressor] Primary model: {PRIMARY_MODEL}")
print(f"[compressor] Fallback model: {FALLBACK_MODEL}")
uvicorn.run(app, host=args.host, port=args.port, log_level="info")
+224
View File
@@ -0,0 +1,224 @@
#!/usr/bin/env python3
"""
Neuron Council Service — LLM anti-confabulation layer.
Fires 3 parallel Ollama calls and aggregates votes to produce a
confidence score + tags for any claim before it enters memory.
Usage:
python3 council_service.py [--port 7771]
"""
import argparse
import asyncio
import time
import uuid
from typing import Optional
import httpx
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
# ---------------------------------------------------------------------------
# Config
# ---------------------------------------------------------------------------
OLLAMA_BASE = "http://localhost:11434/api/generate"
COUNCIL_MODELS = ["neuron:latest", "dolphin3:8b", "neuron-ft:latest"]
MODEL_TIMEOUT = 45.0 # seconds per model (models may need to load from cold)
SYSTEM_PROMPT_TEMPLATE = """\
You are a fact-checker. You will be given a claim.
Your job: assess if it is accurate, internally consistent, and grounded in reality.
Respond with EXACTLY ONE WORD:
- "plausible" if the claim seems accurate and well-grounded
- "uncertain" if you cannot determine accuracy or the claim is ambiguous
- "confabulation" if the claim appears to contain invented facts or clear errors
Claim: {claim}
Context: {context}
Your verdict (one word only):"""
VALID_VERDICTS = {"plausible", "uncertain", "confabulation"}
# ---------------------------------------------------------------------------
# App
# ---------------------------------------------------------------------------
app = FastAPI(
title="Neuron Council Service",
description="LLM-council anti-confabulation layer for Neuron soul",
version="1.0.0",
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
# ---------------------------------------------------------------------------
# Models
# ---------------------------------------------------------------------------
class VerifyRequest(BaseModel):
claim: str
context: Optional[str] = ""
class VerifyResponse(BaseModel):
id: str
claim: str
confidence: float
council_votes: list[str]
summary: str
tags: list[str]
latency_ms: int
# ---------------------------------------------------------------------------
# Core logic
# ---------------------------------------------------------------------------
async def query_model(client: httpx.AsyncClient, model: str, prompt: str) -> str:
"""
Query a single Ollama model. Returns "plausible", "uncertain", or "confabulation".
Returns "uncertain" on timeout. Raises httpx.ConnectError on connection failure.
"""
payload = {
"model": model,
"prompt": prompt,
"stream": False,
}
try:
resp = await client.post(OLLAMA_BASE, json=payload, timeout=MODEL_TIMEOUT)
resp.raise_for_status()
data = resp.json()
raw = data.get("response", "").strip().lower().split()[0] if data.get("response", "").strip() else "uncertain"
# Normalise to one of the three valid verdicts
if raw not in VALID_VERDICTS:
return "uncertain"
return raw
except httpx.TimeoutException:
return "uncertain"
async def run_council(claim: str, context: str) -> VerifyResponse:
start = time.monotonic()
prompt = SYSTEM_PROMPT_TEMPLATE.format(claim=claim, context=context)
# Quick connectivity check — one tiny HEAD request to Ollama
try:
async with httpx.AsyncClient() as probe:
await probe.get("http://localhost:11434/", timeout=2.0)
except (httpx.ConnectError, httpx.TimeoutException):
latency_ms = int((time.monotonic() - start) * 1000)
return VerifyResponse(
id=str(uuid.uuid4()),
claim=claim,
confidence=0.5,
council_votes=[],
summary="Ollama is unavailable; council could not convene.",
tags=["council-unavailable"],
latency_ms=latency_ms,
)
# Fire all 3 model calls in parallel
async with httpx.AsyncClient() as client:
tasks = [query_model(client, m, prompt) for m in COUNCIL_MODELS]
votes: list[str] = await asyncio.gather(*tasks)
plausible_count = votes.count("plausible")
latency_ms = int((time.monotonic() - start) * 1000)
# Voting rules
if plausible_count == 3:
confidence = 0.85
tags = ["verified"]
summary = "3/3 council members agree this is plausible."
elif plausible_count == 2:
confidence = 0.65
tags = ["council-split"]
summary = "2/3 council members agree this is plausible."
elif plausible_count == 1:
confidence = 0.30
tags = ["unverified", "council-flagged"]
summary = "1/3 council members found this plausible."
else:
confidence = 0.30
tags = ["unverified", "council-flagged"]
summary = "0/3 council members found this plausible."
return VerifyResponse(
id=str(uuid.uuid4()),
claim=claim,
confidence=confidence,
council_votes=votes,
summary=summary,
tags=tags,
latency_ms=latency_ms,
)
# ---------------------------------------------------------------------------
# Routes
# ---------------------------------------------------------------------------
@app.post("/api/neuron/council/verify", response_model=VerifyResponse)
async def verify(req: VerifyRequest):
return await run_council(req.claim, req.context or "")
@app.get("/healthz")
async def health():
return {"status": "ok", "service": "council"}
# ---------------------------------------------------------------------------
# Startup warm-up: pre-load all council models so first real call is fast
# ---------------------------------------------------------------------------
@app.on_event("startup")
async def warmup_models():
"""
Send a trivial prompt to each council model at startup.
This forces Ollama to load the models into GPU memory so the first
real council call does not pay the cold-load latency penalty.
"""
print("[council] Warming up council models...")
warmup_prompt = "Reply with one word: ready"
async with httpx.AsyncClient() as client:
tasks = [
client.post(
OLLAMA_BASE,
json={"model": m, "prompt": warmup_prompt, "stream": False},
timeout=60.0,
)
for m in COUNCIL_MODELS
]
results = await asyncio.gather(*tasks, return_exceptions=True)
for model, result in zip(COUNCIL_MODELS, results):
if isinstance(result, Exception):
print(f"[council] warm-up failed for {model}: {result}")
else:
print(f"[council] {model} warm and ready")
print("[council] All models warmed up.")
# ---------------------------------------------------------------------------
# Entrypoint
# ---------------------------------------------------------------------------
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Neuron Council Service")
parser.add_argument("--port", type=int, default=7771, help="Port to listen on")
parser.add_argument("--host", default="127.0.0.1", help="Host to bind to")
args = parser.parse_args()
print(f"[council] Starting on {args.host}:{args.port}")
uvicorn.run(app, host=args.host, port=args.port, log_level="info")
Generated Vendored
+870
View File
@@ -0,0 +1,870 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t tier_working(void);
el_val_t tier_episodic(void);
el_val_t tier_canonical(void);
el_val_t mem_store(el_val_t content, el_val_t label, el_val_t tags);
el_val_t mem_remember(el_val_t content, el_val_t tags);
el_val_t mem_recall(el_val_t query, el_val_t depth);
el_val_t mem_search(el_val_t query, el_val_t limit);
el_val_t mem_strengthen(el_val_t node_id);
el_val_t mem_tombstone(el_val_t node_id);
el_val_t mem_forget(el_val_t node_id);
el_val_t mem_consolidate(void);
el_val_t mem_save(el_val_t path);
el_val_t mem_load(el_val_t path);
el_val_t mem_boot_count_get(void);
el_val_t mem_boot_count_inc(void);
el_val_t mem_emit_state_event(el_val_t trigger, el_val_t kind, el_val_t content);
el_val_t idle_count(void);
el_val_t idle_inc(void);
el_val_t idle_reset(void);
el_val_t hebb_consolidate(void);
el_val_t ise_post(el_val_t content);
el_val_t elapsed_ms(void);
el_val_t elapsed_human(void);
el_val_t embed_ok(void);
el_val_t emit_heartbeat(void);
el_val_t auto_term_try_slot(el_val_t slot_type, el_val_t slot_lbl);
el_val_t proactive_curiosity(void);
el_val_t pulse_count(void);
el_val_t pulse_inc(void);
el_val_t make_action(el_val_t kind, el_val_t payload);
el_val_t perceive(void);
el_val_t attend(el_val_t node_json);
el_val_t respond(el_val_t action_json);
el_val_t record(el_val_t outcome_json);
el_val_t one_cycle(void);
el_val_t awareness_run(void);
el_val_t security_research_authorized(void);
el_val_t threat_score_command(el_val_t cmd);
el_val_t threat_score_path(el_val_t path);
el_val_t threat_score_history(el_val_t history);
el_val_t threat_trajectory_check(el_val_t tool_name, el_val_t tool_input);
el_val_t threat_history_append(el_val_t text);
el_val_t idle_count(void) {
el_val_t s = state_get(EL_STR("soul.idle"));
if (str_eq(s, EL_STR(""))) {
return 0;
}
return str_to_int(s);
return 0;
}
el_val_t idle_inc(void) {
el_val_t n = (idle_count() + 1);
state_set(EL_STR("soul.idle"), int_to_str(n));
return n;
return 0;
}
el_val_t idle_reset(void) {
state_set(EL_STR("soul.idle"), EL_STR("0"));
return 0;
}
el_val_t hebb_consolidate(void) {
el_val_t batch = engram_hebb_drain_json(64);
if (str_eq(batch, EL_STR(""))) {
return 0;
}
if (str_eq(batch, EL_STR("[]"))) {
return 0;
}
el_val_t n = json_array_len(batch);
if (n == 0) {
return 0;
}
el_val_t url_env = env(EL_STR("SOUL_ISE_URL"));
el_val_t url_state = ({ el_val_t _if_result_1 = 0; if (str_eq(url_env, EL_STR(""))) { _if_result_1 = (state_get(EL_STR("soul_engram_url"))); } else { _if_result_1 = (url_env); } _if_result_1; });
el_val_t engram_url = ({ el_val_t _if_result_2 = 0; if (str_eq(url_state, EL_STR(""))) { _if_result_2 = (EL_STR("http://localhost:8742")); } else { _if_result_2 = (url_state); } _if_result_2; });
el_val_t key_state = state_get(EL_STR("soul_engram_api_key"));
el_val_t api_key = ({ el_val_t _if_result_3 = 0; if (str_eq(key_state, EL_STR(""))) { _if_result_3 = (env(EL_STR("ENGRAM_API_KEY"))); } else { _if_result_3 = (key_state); } _if_result_3; });
el_val_t auth_part = ({ el_val_t _if_result_4 = 0; if (str_eq(api_key, EL_STR(""))) { _if_result_4 = (EL_STR("")); } else { _if_result_4 = (el_str_concat(el_str_concat(EL_STR(",\"_auth\":\""), api_key), EL_STR("\""))); } _if_result_4; });
el_val_t body = el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"edges\":"), batch), auth_part), EL_STR("}"));
el_val_t resp = http_post_json(el_str_concat(engram_url, EL_STR("/api/edges/batch")), body);
if (str_eq(resp, EL_STR(""))) {
return 0;
}
el_val_t acc = json_get(resp, EL_STR("accepted"));
if (str_eq(acc, EL_STR(""))) {
return 0;
}
return str_to_int(acc);
return 0;
}
el_val_t ise_post(el_val_t content) {
el_val_t ise_url = env(EL_STR("SOUL_ISE_URL"));
el_val_t state_url = ({ el_val_t _if_result_5 = 0; if (str_eq(ise_url, EL_STR(""))) { _if_result_5 = (state_get(EL_STR("soul_engram_url"))); } else { _if_result_5 = (ise_url); } _if_result_5; });
el_val_t engram_url = ({ el_val_t _if_result_6 = 0; if (str_eq(state_url, EL_STR(""))) { _if_result_6 = (EL_STR("http://localhost:8742")); } else { _if_result_6 = (state_url); } _if_result_6; });
el_val_t safe1 = str_replace(content, EL_STR("\\"), EL_STR("\\\\"));
el_val_t safe2 = str_replace(safe1, EL_STR("\""), EL_STR("\\\""));
el_val_t safe3 = str_replace(safe2, EL_STR("\n"), EL_STR("\\n"));
el_val_t safe4 = str_replace(safe3, EL_STR("\r"), EL_STR("\\r"));
el_val_t body = el_str_concat(el_str_concat(EL_STR("{\"content\":\""), safe4), EL_STR("\"}"));
el_val_t resp = http_post_json(el_str_concat(engram_url, EL_STR("/api/neuron/state-events")), body);
if (str_eq(resp, EL_STR(""))) {
el_val_t fail_raw = state_get(EL_STR("soul.ise_fail_count"));
el_val_t fail_n = ({ el_val_t _if_result_7 = 0; if (str_eq(fail_raw, EL_STR(""))) { _if_result_7 = (0); } else { _if_result_7 = (str_to_int(fail_raw)); } _if_result_7; });
state_set(EL_STR("soul.ise_fail_count"), int_to_str((fail_n + 1)));
el_val_t discard = engram_node_full(content, EL_STR("InternalStateEvent"), EL_STR("state-event"), el_from_float(0.3), el_from_float(0.3), el_from_float(0.8), EL_STR("Episodic"), EL_STR("[\"internal-state\",\"InternalStateEvent\",\"ise-fallback-local\"]"));
return EL_STR("");
}
return EL_STR("");
return 0;
}
el_val_t elapsed_ms(void) {
el_val_t s = state_get(EL_STR("soul.boot_ts"));
if (str_eq(s, EL_STR(""))) {
return 0;
}
el_val_t boot = str_to_int(s);
return (time_now() - boot);
return 0;
}
el_val_t elapsed_human(void) {
el_val_t ms = elapsed_ms();
el_val_t total_secs = (ms / 1000);
el_val_t total_minutes = (total_secs / 60);
el_val_t h = (total_minutes / 60);
if (h > 0) {
el_val_t h4 = (((h + h) + h) + h);
el_val_t h8 = (h4 + h4);
el_val_t h16 = (h8 + h8);
el_val_t h32 = (h16 + h16);
el_val_t h64 = (h32 + h32);
el_val_t h60 = (h64 - h4);
el_val_t m = (total_minutes - h60);
return el_str_concat(el_str_concat(el_str_concat(int_to_str(h), EL_STR("h ")), int_to_str(m)), EL_STR("m"));
}
if (total_minutes > 0) {
return el_str_concat(int_to_str(total_minutes), EL_STR("m"));
}
return el_str_concat(int_to_str(total_secs), EL_STR("s"));
return 0;
}
el_val_t embed_ok(void) {
el_val_t resp = http_get(EL_STR("http://localhost:11434"));
if (str_eq(resp, EL_STR(""))) {
return 0;
}
return 1;
return 0;
}
el_val_t emit_heartbeat(void) {
el_val_t pulse = int_to_str(pulse_count());
el_val_t boot_raw = state_get(EL_STR("soul_boot_count"));
el_val_t boot = ({ el_val_t _if_result_8 = 0; if (str_eq(boot_raw, EL_STR(""))) { _if_result_8 = (EL_STR("0")); } else { _if_result_8 = (boot_raw); } _if_result_8; });
el_val_t idle = int_to_str(idle_count());
el_val_t ts = time_now();
el_val_t last_act_raw = state_get(EL_STR("soul.last_activity_ts"));
el_val_t idle_ms = ({ el_val_t _if_result_9 = 0; if (str_eq(last_act_raw, EL_STR(""))) { _if_result_9 = ((0 - 1)); } else { _if_result_9 = ((ts - str_to_int(last_act_raw))); } _if_result_9; });
el_val_t nc = engram_node_count();
el_val_t ec = engram_edge_count();
el_val_t wmc = engram_wm_count();
el_val_t wm_avg_bits = engram_wm_avg_weight();
el_val_t wm_avg_str = float_to_str(wm_avg_bits);
el_val_t wm_top = engram_wm_top_json(5);
el_val_t up_ms = elapsed_ms();
el_val_t up_human = elapsed_human();
el_val_t emb_ok = embed_ok();
el_val_t fail_raw = state_get(EL_STR("soul.ise_fail_count"));
el_val_t fail_str = ({ el_val_t _if_result_10 = 0; if (str_eq(fail_raw, EL_STR(""))) { _if_result_10 = (EL_STR("0")); } else { _if_result_10 = (fail_raw); } _if_result_10; });
el_val_t sat_raw = state_get(EL_STR("soul.sync_added_total"));
el_val_t sat_str = ({ el_val_t _if_result_11 = 0; if (str_eq(sat_raw, EL_STR(""))) { _if_result_11 = (EL_STR("0")); } else { _if_result_11 = (sat_raw); } _if_result_11; });
el_val_t prev_wm_raw = state_get(EL_STR("soul.prev_wm_active"));
el_val_t prev_wm = ({ el_val_t _if_result_12 = 0; if (str_eq(prev_wm_raw, EL_STR(""))) { _if_result_12 = (0); } else { _if_result_12 = (str_to_int(prev_wm_raw)); } _if_result_12; });
el_val_t wm_delta = (wmc - prev_wm);
state_set(EL_STR("soul.prev_wm_active"), int_to_str(wmc));
el_val_t prev_nc_raw = state_get(EL_STR("soul.prev_node_count"));
el_val_t prev_nc = ({ el_val_t _if_result_13 = 0; if (str_eq(prev_nc_raw, EL_STR(""))) { _if_result_13 = (nc); } else { _if_result_13 = (str_to_int(prev_nc_raw)); } _if_result_13; });
el_val_t node_delta = (nc - prev_nc);
state_set(EL_STR("soul.prev_node_count"), int_to_str(nc));
el_val_t prev_ec_raw = state_get(EL_STR("soul.prev_edge_count"));
el_val_t prev_ec = ({ el_val_t _if_result_14 = 0; if (str_eq(prev_ec_raw, EL_STR(""))) { _if_result_14 = (ec); } else { _if_result_14 = (str_to_int(prev_ec_raw)); } _if_result_14; });
el_val_t edge_delta = (ec - prev_ec);
state_set(EL_STR("soul.prev_edge_count"), int_to_str(ec));
el_val_t sync_ok_raw = state_get(EL_STR("soul.last_sync_ok_ts"));
el_val_t sync_age = ({ el_val_t _if_result_15 = 0; if (str_eq(sync_ok_raw, EL_STR(""))) { _if_result_15 = ((0 - 1)); } else { _if_result_15 = ((ts - str_to_int(sync_ok_raw))); } _if_result_15; });
el_val_t hb_env_url = env(EL_STR("SOUL_ISE_URL"));
el_val_t hb_state_url = ({ el_val_t _if_result_16 = 0; if (str_eq(hb_env_url, EL_STR(""))) { _if_result_16 = (state_get(EL_STR("soul_engram_url"))); } else { _if_result_16 = (hb_env_url); } _if_result_16; });
el_val_t hb_engram_url = ({ el_val_t _if_result_17 = 0; if (str_eq(hb_state_url, EL_STR(""))) { _if_result_17 = (EL_STR("http://localhost:8742")); } else { _if_result_17 = (hb_state_url); } _if_result_17; });
el_val_t bf_resp = http_get(el_str_concat(hb_engram_url, EL_STR("/api/embed-backfill?n=32")));
el_val_t bf_done_raw = json_get(bf_resp, EL_STR("embedded"));
el_val_t bf_done = ({ el_val_t _if_result_18 = 0; if (str_eq(bf_done_raw, EL_STR(""))) { _if_result_18 = (EL_STR("-1")); } else { _if_result_18 = (bf_done_raw); } _if_result_18; });
el_val_t bf_total_raw = json_get(bf_resp, EL_STR("embedded_count"));
el_val_t bf_total = ({ el_val_t _if_result_19 = 0; if (str_eq(bf_total_raw, EL_STR(""))) { _if_result_19 = (EL_STR("-1")); } else { _if_result_19 = (bf_total_raw); } _if_result_19; });
el_val_t wm_sat = ({ el_val_t _if_result_20 = 0; if ((wmc >= 24)) { _if_result_20 = (1); } else { _if_result_20 = (0); } _if_result_20; });
el_val_t prev_sat_raw = state_get(EL_STR("soul.prev_wm_saturated"));
el_val_t prev_sat = ({ el_val_t _if_result_21 = 0; if (str_eq(prev_sat_raw, EL_STR(""))) { _if_result_21 = (wm_sat); } else { _if_result_21 = (str_to_int(prev_sat_raw)); } _if_result_21; });
if (wm_sat != prev_sat) {
el_val_t sat_dir = ({ el_val_t _if_result_22 = 0; if ((wm_sat == 1)) { _if_result_22 = (EL_STR("onset")); } else { _if_result_22 = (EL_STR("release")); } _if_result_22; });
ise_post(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"wm_saturation_transition\",\"direction\":\""), sat_dir), EL_STR("\",\"wm_active\":")), int_to_str(wmc)), EL_STR(",\"wm_top\":")), wm_top), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR("}")));
}
state_set(EL_STR("soul.prev_wm_saturated"), int_to_str(wm_sat));
el_val_t wm_top0 = json_array_get(wm_top, 0);
el_val_t wm_top0_id = json_get(wm_top0, EL_STR("id"));
el_val_t prev_top0 = state_get(EL_STR("soul.prev_wm_top0"));
el_val_t t0streak_raw = state_get(EL_STR("soul.wm_top0_streak"));
el_val_t t0streak_prev = ({ el_val_t _if_result_23 = 0; if (str_eq(t0streak_raw, EL_STR(""))) { _if_result_23 = (0); } else { _if_result_23 = (str_to_int(t0streak_raw)); } _if_result_23; });
el_val_t t0streak = ({ el_val_t _if_result_24 = 0; if (str_eq(wm_top0_id, EL_STR(""))) { _if_result_24 = (0); } else { _if_result_24 = (({ el_val_t _if_result_25 = 0; if (str_eq(wm_top0_id, prev_top0)) { _if_result_25 = ((t0streak_prev + 1)); } else { _if_result_25 = (1); } _if_result_25; })); } _if_result_24; });
state_set(EL_STR("soul.prev_wm_top0"), wm_top0_id);
state_set(EL_STR("soul.wm_top0_streak"), int_to_str(t0streak));
el_val_t ch_id1 = json_get(json_array_get(wm_top, 1), EL_STR("id"));
el_val_t ch_id2 = json_get(json_array_get(wm_top, 2), EL_STR("id"));
el_val_t ch_id3 = json_get(json_array_get(wm_top, 3), EL_STR("id"));
el_val_t ch_id4 = json_get(json_array_get(wm_top, 4), EL_STR("id"));
el_val_t prev_top5 = state_get(EL_STR("soul.prev_wm_top5"));
el_val_t ch0 = ({ el_val_t _if_result_26 = 0; if (str_eq(wm_top0_id, EL_STR(""))) { _if_result_26 = (0); } else { _if_result_26 = (({ el_val_t _if_result_27 = 0; if (str_contains(prev_top5, wm_top0_id)) { _if_result_27 = (0); } else { _if_result_27 = (1); } _if_result_27; })); } _if_result_26; });
el_val_t ch1 = ({ el_val_t _if_result_28 = 0; if (str_eq(ch_id1, EL_STR(""))) { _if_result_28 = (0); } else { _if_result_28 = (({ el_val_t _if_result_29 = 0; if (str_contains(prev_top5, ch_id1)) { _if_result_29 = (0); } else { _if_result_29 = (1); } _if_result_29; })); } _if_result_28; });
el_val_t ch2 = ({ el_val_t _if_result_30 = 0; if (str_eq(ch_id2, EL_STR(""))) { _if_result_30 = (0); } else { _if_result_30 = (({ el_val_t _if_result_31 = 0; if (str_contains(prev_top5, ch_id2)) { _if_result_31 = (0); } else { _if_result_31 = (1); } _if_result_31; })); } _if_result_30; });
el_val_t ch3 = ({ el_val_t _if_result_32 = 0; if (str_eq(ch_id3, EL_STR(""))) { _if_result_32 = (0); } else { _if_result_32 = (({ el_val_t _if_result_33 = 0; if (str_contains(prev_top5, ch_id3)) { _if_result_33 = (0); } else { _if_result_33 = (1); } _if_result_33; })); } _if_result_32; });
el_val_t ch4 = ({ el_val_t _if_result_34 = 0; if (str_eq(ch_id4, EL_STR(""))) { _if_result_34 = (0); } else { _if_result_34 = (({ el_val_t _if_result_35 = 0; if (str_contains(prev_top5, ch_id4)) { _if_result_35 = (0); } else { _if_result_35 = (1); } _if_result_35; })); } _if_result_34; });
el_val_t wm_churn = ((((ch0 + ch1) + ch2) + ch3) + ch4);
state_set(EL_STR("soul.prev_wm_top5"), el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(wm_top0_id, EL_STR("|")), ch_id1), EL_STR("|")), ch_id2), EL_STR("|")), ch_id3), EL_STR("|")), ch_id4));
el_val_t wm_top0_wm_raw = json_get(wm_top0, EL_STR("wm"));
el_val_t wm_top0_wm = ({ el_val_t _if_result_36 = 0; if (str_eq(wm_top0_wm_raw, EL_STR(""))) { _if_result_36 = (EL_STR("0")); } else { _if_result_36 = (wm_top0_wm_raw); } _if_result_36; });
el_val_t act_stats = engram_act_stats_json();
el_val_t act_evict_raw = json_get(act_stats, EL_STR("wm_evicted"));
el_val_t act_evict = ({ el_val_t _if_result_37 = 0; if (str_eq(act_evict_raw, EL_STR(""))) { _if_result_37 = (EL_STR("-1")); } else { _if_result_37 = (act_evict_raw); } _if_result_37; });
el_val_t act_bt_raw = json_get(act_stats, EL_STR("breakthroughs"));
el_val_t act_bt = ({ el_val_t _if_result_38 = 0; if (str_eq(act_bt_raw, EL_STR(""))) { _if_result_38 = (EL_STR("-1")); } else { _if_result_38 = (act_bt_raw); } _if_result_38; });
el_val_t evict_now = ({ el_val_t _if_result_39 = 0; if (str_eq(act_evict_raw, EL_STR(""))) { _if_result_39 = ((0 - 1)); } else { _if_result_39 = (str_to_int(act_evict_raw)); } _if_result_39; });
el_val_t bt_now = ({ el_val_t _if_result_40 = 0; if (str_eq(act_bt_raw, EL_STR(""))) { _if_result_40 = ((0 - 1)); } else { _if_result_40 = (str_to_int(act_bt_raw)); } _if_result_40; });
el_val_t prev_evict_raw = state_get(EL_STR("soul.prev_wm_evicted"));
el_val_t prev_evict = ({ el_val_t _if_result_41 = 0; if (str_eq(prev_evict_raw, EL_STR(""))) { _if_result_41 = (0); } else { _if_result_41 = (str_to_int(prev_evict_raw)); } _if_result_41; });
el_val_t prev_bt_raw = state_get(EL_STR("soul.prev_breakthroughs"));
el_val_t prev_bt = ({ el_val_t _if_result_42 = 0; if (str_eq(prev_bt_raw, EL_STR(""))) { _if_result_42 = (0); } else { _if_result_42 = (str_to_int(prev_bt_raw)); } _if_result_42; });
el_val_t evict_delta = ({ el_val_t _if_result_43 = 0; if ((evict_now < 0)) { _if_result_43 = (0); } else { _if_result_43 = (({ el_val_t _if_result_44 = 0; if ((evict_now < prev_evict)) { _if_result_44 = (evict_now); } else { _if_result_44 = ((evict_now - prev_evict)); } _if_result_44; })); } _if_result_43; });
el_val_t bt_delta = ({ el_val_t _if_result_45 = 0; if ((bt_now < 0)) { _if_result_45 = (0); } else { _if_result_45 = (({ el_val_t _if_result_46 = 0; if ((bt_now < prev_bt)) { _if_result_46 = (bt_now); } else { _if_result_46 = ((bt_now - prev_bt)); } _if_result_46; })); } _if_result_45; });
if (evict_now >= 0) {
state_set(EL_STR("soul.prev_wm_evicted"), int_to_str(evict_now));
}
if (bt_now >= 0) {
state_set(EL_STR("soul.prev_breakthroughs"), int_to_str(bt_now));
}
el_val_t hb_stats = http_get(el_str_concat(hb_engram_url, EL_STR("/api/stats")));
el_val_t embed_elig_raw = json_get(hb_stats, EL_STR("embed_eligible_count"));
el_val_t embed_elig = ({ el_val_t _if_result_47 = 0; if (str_eq(embed_elig_raw, EL_STR(""))) { _if_result_47 = (EL_STR("-1")); } else { _if_result_47 = (embed_elig_raw); } _if_result_47; });
el_val_t hb_ats_raw = state_get(EL_STR("soul.auto_term_streak"));
el_val_t hb_ats = ({ el_val_t _if_result_48 = 0; if (str_eq(hb_ats_raw, EL_STR(""))) { _if_result_48 = (0); } else { _if_result_48 = (str_to_int(hb_ats_raw)); } _if_result_48; });
el_val_t hb_ate_raw = state_get(EL_STR("soul.auto_term_empty_streak"));
el_val_t hb_ate = ({ el_val_t _if_result_49 = 0; if (str_eq(hb_ate_raw, EL_STR(""))) { _if_result_49 = (0); } else { _if_result_49 = (str_to_int(hb_ate_raw)); } _if_result_49; });
el_val_t hebb_warm_raw = json_get(act_stats, EL_STR("hebb_warm"));
el_val_t hebb_warm = ({ el_val_t _if_result_50 = 0; if (str_eq(hebb_warm_raw, EL_STR(""))) { _if_result_50 = (EL_STR("-1")); } else { _if_result_50 = (hebb_warm_raw); } _if_result_50; });
el_val_t hebb_max_raw = json_get(act_stats, EL_STR("hebb_max"));
el_val_t hebb_max = ({ el_val_t _if_result_51 = 0; if (str_eq(hebb_max_raw, EL_STR(""))) { _if_result_51 = (EL_STR("-1")); } else { _if_result_51 = (hebb_max_raw); } _if_result_51; });
el_val_t hebb_links_raw = json_get(act_stats, EL_STR("hebb_links"));
el_val_t hebb_links = ({ el_val_t _if_result_52 = 0; if (str_eq(hebb_links_raw, EL_STR(""))) { _if_result_52 = (EL_STR("-1")); } else { _if_result_52 = (hebb_links_raw); } _if_result_52; });
el_val_t hebb_cands_raw = json_get(act_stats, EL_STR("hebb_cands"));
el_val_t hebb_cands = ({ el_val_t _if_result_53 = 0; if (str_eq(hebb_cands_raw, EL_STR(""))) { _if_result_53 = (EL_STR("-1")); } else { _if_result_53 = (hebb_cands_raw); } _if_result_53; });
el_val_t hebb_cmax_raw = json_get(act_stats, EL_STR("hebb_cand_max"));
el_val_t hebb_cmax = ({ el_val_t _if_result_54 = 0; if (str_eq(hebb_cmax_raw, EL_STR(""))) { _if_result_54 = (EL_STR("-1")); } else { _if_result_54 = (hebb_cmax_raw); } _if_result_54; });
el_val_t hebb_mass_raw = json_get(act_stats, EL_STR("hebb_mass"));
el_val_t hebb_mass = ({ el_val_t _if_result_55 = 0; if (str_eq(hebb_mass_raw, EL_STR(""))) { _if_result_55 = (EL_STR("-1")); } else { _if_result_55 = (hebb_mass_raw); } _if_result_55; });
el_val_t hebb_edges_raw = json_get(act_stats, EL_STR("hebb_edges"));
el_val_t hebb_edges = ({ el_val_t _if_result_56 = 0; if (str_eq(hebb_edges_raw, EL_STR(""))) { _if_result_56 = (EL_STR("-1")); } else { _if_result_56 = (hebb_edges_raw); } _if_result_56; });
el_val_t wb_pend_raw = json_get(act_stats, EL_STR("hebb_wb_pending"));
el_val_t wb_pend = ({ el_val_t _if_result_57 = 0; if (str_eq(wb_pend_raw, EL_STR(""))) { _if_result_57 = (EL_STR("-1")); } else { _if_result_57 = (wb_pend_raw); } _if_result_57; });
el_val_t wb_drain_raw = json_get(act_stats, EL_STR("hebb_wb_drained"));
el_val_t wb_drain = ({ el_val_t _if_result_58 = 0; if (str_eq(wb_drain_raw, EL_STR(""))) { _if_result_58 = (EL_STR("-1")); } else { _if_result_58 = (wb_drain_raw); } _if_result_58; });
el_val_t wb_drop_raw = json_get(act_stats, EL_STR("hebb_wb_dropped"));
el_val_t wb_drop = ({ el_val_t _if_result_59 = 0; if (str_eq(wb_drop_raw, EL_STR(""))) { _if_result_59 = (EL_STR("-1")); } else { _if_result_59 = (wb_drop_raw); } _if_result_59; });
el_val_t wb_sent_raw = state_get(EL_STR("soul.hebb_wb_sent"));
el_val_t wb_sent = ({ el_val_t _if_result_60 = 0; if (str_eq(wb_sent_raw, EL_STR(""))) { _if_result_60 = (EL_STR("0")); } else { _if_result_60 = (wb_sent_raw); } _if_result_60; });
el_val_t dup_wm_g_raw = json_get(act_stats, EL_STR("dup_wm_global"));
el_val_t dup_wm_g = ({ el_val_t _if_result_61 = 0; if (str_eq(dup_wm_g_raw, EL_STR(""))) { _if_result_61 = (EL_STR("-1")); } else { _if_result_61 = (dup_wm_g_raw); } _if_result_61; });
el_val_t act_brk_raw = json_get(act_stats, EL_STR("embed_breaker_open"));
el_val_t act_brk = ({ el_val_t _if_result_62 = 0; if (str_eq(act_brk_raw, EL_STR(""))) { _if_result_62 = (EL_STR("-1")); } else { _if_result_62 = (act_brk_raw); } _if_result_62; });
el_val_t emb_cf_raw = json_get(act_stats, EL_STR("embed_consec_fail"));
el_val_t emb_cf = ({ el_val_t _if_result_63 = 0; if (str_eq(emb_cf_raw, EL_STR(""))) { _if_result_63 = (EL_STR("-1")); } else { _if_result_63 = (emb_cf_raw); } _if_result_63; });
el_val_t ctx_cos_raw = json_get(act_stats, EL_STR("ctx_cos"));
el_val_t ctx_cos = ({ el_val_t _if_result_64 = 0; if (str_eq(ctx_cos_raw, EL_STR(""))) { _if_result_64 = (EL_STR("-2")); } else { _if_result_64 = (ctx_cos_raw); } _if_result_64; });
el_val_t dup_seeds_raw = json_get(act_stats, EL_STR("dup_seeds"));
el_val_t dup_seeds = ({ el_val_t _if_result_65 = 0; if (str_eq(dup_seeds_raw, EL_STR(""))) { _if_result_65 = (EL_STR("-1")); } else { _if_result_65 = (dup_seeds_raw); } _if_result_65; });
el_val_t dup_wm_raw = json_get(act_stats, EL_STR("dup_wm"));
el_val_t dup_wm = ({ el_val_t _if_result_66 = 0; if (str_eq(dup_wm_raw, EL_STR(""))) { _if_result_66 = (EL_STR("-1")); } else { _if_result_66 = (dup_wm_raw); } _if_result_66; });
el_val_t txt_dmg_raw = json_get(act_stats, EL_STR("txt_damaged"));
el_val_t txt_dmg = ({ el_val_t _if_result_67 = 0; if (str_eq(txt_dmg_raw, EL_STR(""))) { _if_result_67 = (EL_STR("-1")); } else { _if_result_67 = (txt_dmg_raw); } _if_result_67; });
el_val_t tc_raw = state_get(EL_STR("soul.txt_census_countdown"));
el_val_t tc_n = ({ el_val_t _if_result_68 = 0; if (str_eq(tc_raw, EL_STR(""))) { _if_result_68 = (0); } else { _if_result_68 = (str_to_int(tc_raw)); } _if_result_68; });
if (tc_n <= 0) {
el_val_t th_resp = http_get(el_str_concat(hb_engram_url, EL_STR("/api/text-health")));
el_val_t th_pct = json_get(th_resp, EL_STR("damaged_pct"));
if (!str_eq(th_pct, EL_STR(""))) {
state_set(EL_STR("soul.txt_damaged_pct"), th_pct);
state_set(EL_STR("soul.txt_damaged_n"), json_get(th_resp, EL_STR("damaged")));
state_set(EL_STR("soul.txt_scanned_n"), json_get(th_resp, EL_STR("scanned")));
state_set(EL_STR("soul.txt_census_ts"), int_to_str(ts));
}
state_set(EL_STR("soul.txt_census_countdown"), EL_STR("30"));
}
if (tc_n > 0) {
state_set(EL_STR("soul.txt_census_countdown"), int_to_str((tc_n - 1)));
}
el_val_t dmg_pct_raw = state_get(EL_STR("soul.txt_damaged_pct"));
el_val_t dmg_pct = ({ el_val_t _if_result_69 = 0; if (str_eq(dmg_pct_raw, EL_STR(""))) { _if_result_69 = (EL_STR("-1")); } else { _if_result_69 = (dmg_pct_raw); } _if_result_69; });
el_val_t dmg_n_raw = state_get(EL_STR("soul.txt_damaged_n"));
el_val_t dmg_n = ({ el_val_t _if_result_70 = 0; if (str_eq(dmg_n_raw, EL_STR(""))) { _if_result_70 = (EL_STR("-1")); } else { _if_result_70 = (dmg_n_raw); } _if_result_70; });
el_val_t dmg_scan_raw = state_get(EL_STR("soul.txt_scanned_n"));
el_val_t dmg_scan = ({ el_val_t _if_result_71 = 0; if (str_eq(dmg_scan_raw, EL_STR(""))) { _if_result_71 = (EL_STR("-1")); } else { _if_result_71 = (dmg_scan_raw); } _if_result_71; });
el_val_t dmg_ts_raw = state_get(EL_STR("soul.txt_census_ts"));
el_val_t dmg_age = ({ el_val_t _if_result_72 = 0; if (str_eq(dmg_ts_raw, EL_STR(""))) { _if_result_72 = ((0 - 1)); } else { _if_result_72 = ((ts - str_to_int(dmg_ts_raw))); } _if_result_72; });
el_val_t payload = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"heartbeat\",\"pulse\":"), pulse), EL_STR(",\"tick\":")), pulse), EL_STR(",\"boot\":")), boot), EL_STR(",\"idle\":")), idle), EL_STR(",\"idle_ms\":")), int_to_str(idle_ms)), EL_STR(",\"node_count\":")), int_to_str(nc)), EL_STR(",\"edge_count\":")), int_to_str(ec)), EL_STR(",\"node_delta\":")), int_to_str(node_delta)), EL_STR(",\"edge_delta\":")), int_to_str(edge_delta)), EL_STR(",\"wm_active\":")), int_to_str(wmc)), EL_STR(",\"wm_delta\":")), int_to_str(wm_delta)), EL_STR(",\"wm_saturated\":")), int_to_str(wm_sat)), EL_STR(",\"wm_top0_streak\":")), int_to_str(t0streak)), EL_STR(",\"wm_churn\":")), int_to_str(wm_churn)), EL_STR(",\"wm_top0_wm\":")), wm_top0_wm), EL_STR(",\"sync_added_total\":")), sat_str), EL_STR(",\"sync_age_ms\":")), int_to_str(sync_age)), EL_STR(",\"wm_avg_weight\":")), wm_avg_str), EL_STR(",\"wm_top\":")), wm_top), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR(",\"uptime_ms\":")), int_to_str(up_ms)), EL_STR(",\"uptime\":\"")), up_human), EL_STR("\",\"embed_ok\":")), int_to_str(emb_ok)), EL_STR(",\"embed_backfilled\":")), bf_done), EL_STR(",\"embed_count\":")), bf_total), EL_STR(",\"embed_eligible\":")), embed_elig), EL_STR(",\"wm_evicted\":")), act_evict), EL_STR(",\"wm_evicted_delta\":")), int_to_str(evict_delta)), EL_STR(",\"breakthroughs\":")), act_bt), EL_STR(",\"breakthroughs_delta\":")), int_to_str(bt_delta)), EL_STR(",\"auto_term_streak\":")), int_to_str(hb_ats)), EL_STR(",\"auto_term_empty_streak\":")), int_to_str(hb_ate)), EL_STR(",\"embed_breaker_open\":")), act_brk), EL_STR(",\"ctx_cos\":")), ctx_cos), EL_STR(",\"dup_seeds\":")), dup_seeds), EL_STR(",\"dup_wm\":")), dup_wm), EL_STR(",\"dup_wm_global\":")), dup_wm_g), EL_STR(",\"hebb_warm\":")), hebb_warm), EL_STR(",\"hebb_max\":")), hebb_max), EL_STR(",\"hebb_links\":")), hebb_links), EL_STR(",\"hebb_cands\":")), hebb_cands), EL_STR(",\"hebb_cand_max\":")), hebb_cmax), EL_STR(",\"hebb_mass\":")), hebb_mass), EL_STR(",\"hebb_edges\":")), hebb_edges), EL_STR(",\"embed_consec_fail\":")), emb_cf), EL_STR(",\"txt_damaged_pct\":")), dmg_pct), EL_STR(",\"txt_damaged_n\":")), dmg_n), EL_STR(",\"txt_scanned_n\":")), dmg_scan), EL_STR(",\"txt_census_age_ms\":")), int_to_str(dmg_age)), EL_STR(",\"hebb_wb_pending\":")), wb_pend), EL_STR(",\"hebb_wb_drained\":")), wb_drain), EL_STR(",\"hebb_wb_dropped\":")), wb_drop), EL_STR(",\"hebb_wb_sent\":")), wb_sent), EL_STR(",\"ise_fail\":")), fail_str), EL_STR(",\"txt_damaged\":")), txt_dmg), EL_STR("}"));
ise_post(payload);
return 0;
}
el_val_t auto_term_try_slot(el_val_t slot_type, el_val_t slot_lbl) {
state_set(EL_STR("_ats_ok"), EL_STR("0"));
if (str_eq(slot_type, EL_STR("Memory"))) {
state_set(EL_STR("_ats_ok"), EL_STR("1"));
}
if (str_eq(slot_type, EL_STR("BacklogItem"))) {
state_set(EL_STR("_ats_ok"), EL_STR("1"));
}
if (str_eq(slot_type, EL_STR("Entity"))) {
state_set(EL_STR("_ats_ok"), EL_STR("1"));
}
if (str_eq(slot_type, EL_STR("Knowledge"))) {
state_set(EL_STR("_ats_ok"), EL_STR("1"));
}
if (str_contains(slot_lbl, EL_STR(":"))) {
if (!str_contains(slot_lbl, EL_STR(" "))) {
state_set(EL_STR("_ats_ok"), EL_STR("0"));
}
}
if (str_eq(state_get(EL_STR("_ats_ok")), EL_STR("1"))) {
if (!str_eq(slot_lbl, EL_STR(""))) {
el_val_t sp = str_find_chars(slot_lbl, EL_STR(" :(["));
if (sp > 3) {
el_val_t term = str_slice(slot_lbl, 0, sp);
state_set(EL_STR("_ats_gw"), EL_STR("0"));
if (str_eq(term, EL_STR("Method"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Theory"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Finding"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Survey"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Paper"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Knowledge"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, EL_STR("Value"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
el_val_t stopw = EL_STR("|What|When|Where|Which|Whose|While|This|That|These|Those|There|Their|Then|Than|With|Without|From|Into|Onto|Over|Under|About|Between|Among|Across|Some|Most|More|Less|Very|Each|Every|Both|Also|Only|Just|Does|Will|Would|Could|Should|Might|Must|Have|Been|Being|Toward|Towards|Using|Based|Upon|Here|Your|Ours|They|Them|what|this|that|with|from|context|Context|Prose|Colon|Self|Test|Testing|Closing|Global|Universal|Persona|Semantic|Spreading|Temporal|Numeric|Register|Identifying|Introduction|Overview|Summary|Section|General|Notes|Note|");
if (str_contains(stopw, el_str_concat(el_str_concat(EL_STR("|"), term), EL_STR("|")))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_contains(term, EL_STR("\""))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_contains(term, EL_STR("'"))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
el_val_t df_max = (engram_node_count() / 400);
el_val_t df_term = engram_label_df(term);
if (df_term > df_max) {
if (df_term > 8) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
}
if (str_eq(term, state_get(EL_STR("soul.tabu_t0")))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, state_get(EL_STR("soul.tabu_t1")))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, state_get(EL_STR("soul.tabu_t2")))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(term, state_get(EL_STR("soul.tabu_t3")))) {
state_set(EL_STR("_ats_gw"), EL_STR("1"));
}
if (str_eq(state_get(EL_STR("_ats_gw")), EL_STR("0"))) {
state_set(EL_STR("cseed_auto"), term);
}
}
}
}
return EL_STR("");
return 0;
}
el_val_t proactive_curiosity(void) {
el_val_t ts = time_now();
el_val_t ts_minutes = (ts / 60000);
el_val_t minute_q = (ts_minutes / 4);
el_val_t minute_q2 = (minute_q + minute_q);
el_val_t minute_q4 = (minute_q2 + minute_q2);
el_val_t minute_block = (ts_minutes - minute_q4);
state_set(EL_STR("cseed_a"), EL_STR("memory"));
state_set(EL_STR("cseed_b"), EL_STR("knowledge"));
state_set(EL_STR("cseed_c"), EL_STR("context"));
if (minute_block == 1) {
state_set(EL_STR("cseed_a"), EL_STR("self"));
state_set(EL_STR("cseed_b"), EL_STR("identity"));
state_set(EL_STR("cseed_c"), EL_STR("values"));
}
if (minute_block == 2) {
state_set(EL_STR("cseed_a"), EL_STR("decision"));
state_set(EL_STR("cseed_b"), EL_STR("pattern"));
state_set(EL_STR("cseed_c"), EL_STR("lesson"));
}
if (minute_block == 3) {
state_set(EL_STR("cseed_a"), EL_STR("working"));
state_set(EL_STR("cseed_b"), EL_STR("project"));
state_set(EL_STR("cseed_c"), EL_STR("active"));
}
el_val_t curiosity_term_a = state_get(EL_STR("cseed_a"));
el_val_t curiosity_term_b = state_get(EL_STR("cseed_b"));
el_val_t curiosity_term_c = state_get(EL_STR("cseed_c"));
el_val_t curiosity_seed = el_str_concat(el_str_concat(el_str_concat(el_str_concat(curiosity_term_a, EL_STR(" ")), curiosity_term_b), EL_STR(" ")), curiosity_term_c);
el_val_t results_all = engram_activate_json(curiosity_seed, 1);
el_val_t found = json_array_len(results_all);
el_val_t top_entry = json_array_get(results_all, 0);
el_val_t top_id = json_get(top_entry, EL_STR("id"));
el_val_t prev_str_id = state_get(EL_STR("soul.last_strengthen_id"));
if (!str_eq(top_id, EL_STR(""))) {
if (!str_eq(top_id, prev_str_id)) {
engram_strengthen(top_id);
}
state_set(EL_STR("soul.last_strengthen_id"), top_id);
}
state_set(EL_STR("cseed_auto"), EL_STR(""));
el_val_t wm10 = engram_wm_top_json(10);
el_val_t wm10_n9 = json_array_get(wm10, 9);
el_val_t wm10_n8 = json_array_get(wm10, 8);
el_val_t wm10_n7 = json_array_get(wm10, 7);
el_val_t wm10_n6 = json_array_get(wm10, 6);
el_val_t wm10_n5 = json_array_get(wm10, 5);
el_val_t wm10_n4 = json_array_get(wm10, 4);
el_val_t wm10_n3 = json_array_get(wm10, 3);
el_val_t wm10_n2 = json_array_get(wm10, 2);
el_val_t wm10_n1 = json_array_get(wm10, 1);
el_val_t wm10_n0 = json_array_get(wm10, 0);
auto_term_try_slot(json_get(wm10_n9, EL_STR("node_type")), json_get(wm10_n9, EL_STR("label")));
auto_term_try_slot(json_get(wm10_n8, EL_STR("node_type")), json_get(wm10_n8, EL_STR("label")));
auto_term_try_slot(json_get(wm10_n7, EL_STR("node_type")), json_get(wm10_n7, EL_STR("label")));
auto_term_try_slot(json_get(wm10_n6, EL_STR("node_type")), json_get(wm10_n6, EL_STR("label")));
auto_term_try_slot(json_get(wm10_n5, EL_STR("node_type")), json_get(wm10_n5, EL_STR("label")));
auto_term_try_slot(json_get(wm10_n4, EL_STR("node_type")), json_get(wm10_n4, EL_STR("label")));
auto_term_try_slot(json_get(wm10_n3, EL_STR("node_type")), json_get(wm10_n3, EL_STR("label")));
auto_term_try_slot(json_get(wm10_n2, EL_STR("node_type")), json_get(wm10_n2, EL_STR("label")));
auto_term_try_slot(json_get(wm10_n1, EL_STR("node_type")), json_get(wm10_n1, EL_STR("label")));
auto_term_try_slot(json_get(wm10_n0, EL_STR("node_type")), json_get(wm10_n0, EL_STR("label")));
el_val_t auto_term = state_get(EL_STR("cseed_auto"));
el_val_t results_auto = ({ el_val_t _if_result_73 = 0; if (str_eq(auto_term, EL_STR(""))) { _if_result_73 = (EL_STR("[]")); } else { _if_result_73 = (engram_activate_json(auto_term, 1)); } _if_result_73; });
el_val_t found_auto = json_array_len(results_auto);
el_val_t total_found = (found + found_auto);
el_val_t safe_auto = str_replace(auto_term, EL_STR("\""), EL_STR("'"));
el_val_t prev_auto = state_get(EL_STR("soul.prev_auto_term"));
el_val_t atstreak_raw = state_get(EL_STR("soul.auto_term_streak"));
el_val_t atstreak_prev = ({ el_val_t _if_result_74 = 0; if (str_eq(atstreak_raw, EL_STR(""))) { _if_result_74 = (0); } else { _if_result_74 = (str_to_int(atstreak_raw)); } _if_result_74; });
el_val_t is_empty = str_eq(auto_term, EL_STR(""));
el_val_t atstreak = ({ el_val_t _if_result_75 = 0; if (is_empty) { _if_result_75 = (0); } else { _if_result_75 = (({ el_val_t _if_result_76 = 0; if (str_eq(auto_term, prev_auto)) { _if_result_76 = ((atstreak_prev + 1)); } else { _if_result_76 = (1); } _if_result_76; })); } _if_result_75; });
el_val_t atempty_raw = state_get(EL_STR("soul.auto_term_empty_streak"));
el_val_t atempty_prev = ({ el_val_t _if_result_77 = 0; if (str_eq(atempty_raw, EL_STR(""))) { _if_result_77 = (0); } else { _if_result_77 = (str_to_int(atempty_raw)); } _if_result_77; });
el_val_t atempty = ({ el_val_t _if_result_78 = 0; if (is_empty) { _if_result_78 = ((atempty_prev + 1)); } else { _if_result_78 = (0); } _if_result_78; });
state_set(EL_STR("soul.prev_auto_term"), auto_term);
state_set(EL_STR("soul.auto_term_streak"), int_to_str(atstreak));
state_set(EL_STR("soul.auto_term_empty_streak"), int_to_str(atempty));
if (!str_eq(auto_term, EL_STR(""))) {
state_set(EL_STR("soul.tabu_t3"), state_get(EL_STR("soul.tabu_t2")));
state_set(EL_STR("soul.tabu_t2"), state_get(EL_STR("soul.tabu_t1")));
state_set(EL_STR("soul.tabu_t1"), state_get(EL_STR("soul.tabu_t0")));
state_set(EL_STR("soul.tabu_t0"), auto_term);
}
el_val_t wmc = engram_wm_count();
el_val_t wm3 = engram_wm_top_json(3);
el_val_t ise = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"curiosity_scan\",\"seed\":\""), curiosity_seed), EL_STR("\",\"auto_term\":\"")), safe_auto), EL_STR("\",\"auto_term_streak\":")), int_to_str(atstreak)), EL_STR(",\"auto_term_empty_streak\":")), int_to_str(atempty)), EL_STR(",\"minute_block\":")), int_to_str(minute_block)), EL_STR(",\"activated\":")), int_to_str(total_found)), EL_STR(",\"wm_active\":")), int_to_str(wmc)), EL_STR(",\"wm_top\":")), wm3), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR("}"));
ise_post(ise);
return (total_found > 0);
return 0;
}
el_val_t pulse_count(void) {
el_val_t s = state_get(EL_STR("soul.pulse"));
if (str_eq(s, EL_STR(""))) {
return 0;
}
return str_to_int(s);
return 0;
}
el_val_t pulse_inc(void) {
el_val_t n = (pulse_count() + 1);
state_set(EL_STR("soul.pulse"), int_to_str(n));
return n;
return 0;
}
el_val_t make_action(el_val_t kind, el_val_t payload) {
el_val_t safe = str_replace(payload, EL_STR("\\"), EL_STR("\\\\"));
el_val_t safe2 = str_replace(safe, EL_STR("\""), EL_STR("\\\""));
el_val_t safe3 = str_replace(safe2, EL_STR("\n"), EL_STR("\\n"));
el_val_t safe4 = str_replace(safe3, EL_STR("\r"), EL_STR("\\r"));
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"kind\":\""), kind), EL_STR("\",\"payload\":\"")), safe4), EL_STR("\"}"));
return 0;
}
el_val_t perceive(void) {
el_val_t inbox_check = engram_search_json(EL_STR("soul-inbox-pending"), 5);
el_val_t has_inbox = (!str_eq(inbox_check, EL_STR("")) && !str_eq(inbox_check, EL_STR("[]")));
if (!has_inbox) {
return EL_STR("[]");
}
el_val_t from_pending = engram_activate_json(EL_STR("soul-inbox-pending"), 2);
el_val_t pending_ok = (!str_eq(from_pending, EL_STR("")) && !str_eq(from_pending, EL_STR("[]")));
if (pending_ok) {
return from_pending;
}
return EL_STR("[]");
return 0;
}
el_val_t attend(el_val_t node_json) {
if (str_eq(node_json, EL_STR(""))) {
return make_action(EL_STR("noop"), EL_STR(""));
}
if (str_eq(node_json, EL_STR("[]"))) {
return make_action(EL_STR("noop"), EL_STR(""));
}
el_val_t content = json_get(node_json, EL_STR("content"));
if (str_eq(content, EL_STR(""))) {
return make_action(EL_STR("noop"), EL_STR(""));
}
if (str_eq(content, EL_STR("consolidate"))) {
return make_action(EL_STR("consolidate"), EL_STR(""));
}
if (str_starts_with(content, EL_STR("remember "))) {
el_val_t payload = str_slice(content, 9, str_len(content));
return make_action(EL_STR("remember"), payload);
}
if (str_starts_with(content, EL_STR("search "))) {
el_val_t payload = str_slice(content, 7, str_len(content));
return make_action(EL_STR("search"), payload);
}
if (str_starts_with(content, EL_STR("activate "))) {
el_val_t payload = str_slice(content, 9, str_len(content));
return make_action(EL_STR("activate"), payload);
}
if (str_starts_with(content, EL_STR("strengthen "))) {
el_val_t payload = str_slice(content, 11, str_len(content));
return make_action(EL_STR("strengthen"), payload);
}
if (str_starts_with(content, EL_STR("forget "))) {
el_val_t payload = str_slice(content, 7, str_len(content));
return make_action(EL_STR("forget"), payload);
}
return make_action(EL_STR("respond"), content);
return 0;
}
el_val_t respond(el_val_t action_json) {
el_val_t kind = json_get(action_json, EL_STR("kind"));
el_val_t payload = json_get(action_json, EL_STR("payload"));
if (str_eq(kind, EL_STR("noop"))) {
return EL_STR("{\"outcome\":\"noop\"}");
}
if (str_eq(kind, EL_STR("remember"))) {
el_val_t tags = EL_STR("[\"soul-memory\",\"awareness\"]");
el_val_t id = mem_remember(payload, tags);
return el_str_concat(el_str_concat(EL_STR("{\"outcome\":\"remembered\",\"id\":\""), id), EL_STR("\"}"));
}
if (str_eq(kind, EL_STR("consolidate"))) {
el_val_t stats = mem_consolidate();
return el_str_concat(el_str_concat(EL_STR("{\"outcome\":\"consolidated\",\"stats\":"), stats), EL_STR("}"));
}
if (str_eq(kind, EL_STR("respond"))) {
el_val_t tags = EL_STR("[\"soul-outbox\",\"awareness\"]");
el_val_t id = mem_store(payload, EL_STR("soul-response"), tags);
return el_str_concat(el_str_concat(EL_STR("{\"outcome\":\"response\",\"id\":\""), id), EL_STR("\"}"));
}
if (str_eq(kind, EL_STR("search"))) {
el_val_t results = mem_search(payload, 10);
el_val_t safe_results = str_replace(results, EL_STR("\""), EL_STR("'"));
el_val_t tags = EL_STR("[\"soul-outbox\",\"search-result\"]");
el_val_t id = mem_store(safe_results, EL_STR("search-result"), tags);
return el_str_concat(el_str_concat(EL_STR("{\"outcome\":\"searched\",\"id\":\""), id), EL_STR("\"}"));
}
if (str_eq(kind, EL_STR("activate"))) {
el_val_t results = mem_recall(payload, 3);
el_val_t safe_results = str_replace(results, EL_STR("\""), EL_STR("'"));
el_val_t tags = EL_STR("[\"soul-outbox\",\"activation-result\"]");
el_val_t id = mem_store(safe_results, EL_STR("activation-result"), tags);
return el_str_concat(el_str_concat(EL_STR("{\"outcome\":\"activated\",\"id\":\""), id), EL_STR("\"}"));
}
if (str_eq(kind, EL_STR("strengthen"))) {
engram_strengthen(payload);
return el_str_concat(el_str_concat(EL_STR("{\"outcome\":\"strengthened\",\"id\":\""), payload), EL_STR("\"}"));
}
if (str_eq(kind, EL_STR("forget"))) {
el_val_t _marker = mem_tombstone(payload);
return el_str_concat(el_str_concat(EL_STR("{\"outcome\":\"tombstoned\",\"id\":\""), payload), EL_STR("\"}"));
}
return EL_STR("{\"outcome\":\"noop\"}");
return 0;
}
el_val_t record(el_val_t outcome_json) {
el_val_t safe = str_replace(outcome_json, EL_STR("\""), EL_STR("'"));
el_val_t ts = time_now();
ise_post(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"loop-outcome\",\"outcome\":\""), safe), EL_STR("\",\"ts\":")), int_to_str(ts)), EL_STR("}")));
return 0;
}
el_val_t one_cycle(void) {
el_val_t raw = perceive();
if (str_eq(raw, EL_STR(""))) {
return 0;
}
if (str_eq(raw, EL_STR("[]"))) {
return 0;
}
el_val_t node = json_array_get(raw, 0);
if (str_eq(node, EL_STR(""))) {
return 0;
}
el_val_t node_tags = json_get(node, EL_STR("tags"));
if (!str_contains(node_tags, EL_STR("soul-inbox-pending"))) {
return 0;
}
el_val_t action = attend(node);
el_val_t kind = json_get(action, EL_STR("kind"));
el_val_t is_interesting = (!str_eq(kind, EL_STR("noop")) && !str_eq(kind, EL_STR("respond")));
if (is_interesting) {
el_val_t trigger_content = json_get(node, EL_STR("content"));
el_val_t safe_trigger = str_replace(trigger_content, EL_STR("\""), EL_STR("'"));
el_val_t ts = time_now();
el_val_t event_content = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"awareness-decision\",\"trigger\":\""), safe_trigger), EL_STR("\",\"kind\":\"")), kind), EL_STR("\",\"ts\":")), int_to_str(ts)), EL_STR("}"));
ise_post(event_content);
}
if (str_eq(kind, EL_STR("noop"))) {
return 0;
}
el_val_t outcome = respond(action);
record(outcome);
el_val_t trigger_id = json_get(node, EL_STR("id"));
if (!str_eq(trigger_id, EL_STR(""))) {
engram_forget(trigger_id);
}
return 1;
return 0;
}
el_val_t awareness_run(void) {
println(EL_STR("[awareness] entering"));
el_val_t existing_boot = state_get(EL_STR("soul.boot_ts"));
if (str_eq(existing_boot, EL_STR(""))) {
state_set(EL_STR("soul.boot_ts"), int_to_str(time_now()));
}
el_val_t tick_raw = env(EL_STR("SOUL_TICK_MS"));
el_val_t tick_ms = ({ el_val_t _if_result_79 = 0; if (str_eq(tick_raw, EL_STR(""))) { _if_result_79 = (200); } else { _if_result_79 = (str_to_int(tick_raw)); } _if_result_79; });
el_val_t beat_ms_raw = env(EL_STR("SOUL_HEARTBEAT_MS"));
el_val_t beat_ms = ({ el_val_t _if_result_80 = 0; if (str_eq(beat_ms_raw, EL_STR(""))) { _if_result_80 = (60000); } else { _if_result_80 = (str_to_int(beat_ms_raw)); } _if_result_80; });
el_val_t scan_ms = (beat_ms / 2);
while (1) {
el_val_t tick_mark = el_arena_push();
el_val_t running = state_get(EL_STR("soul.running"));
if (str_eq(running, EL_STR("false"))) {
el_val_t sd_boot_raw = state_get(EL_STR("soul_boot_count"));
el_val_t sd_boot = ({ el_val_t _if_result_81 = 0; if (str_eq(sd_boot_raw, EL_STR(""))) { _if_result_81 = (EL_STR("0")); } else { _if_result_81 = (sd_boot_raw); } _if_result_81; });
el_val_t sd_wb = hebb_consolidate();
ise_post(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"shutdown\",\"boot\":"), sd_boot), EL_STR(",\"pulse\":")), int_to_str(pulse_count())), EL_STR(",\"hebb_wb_sent\":")), int_to_str(sd_wb)), EL_STR(",\"uptime_ms\":")), int_to_str(elapsed_ms())), EL_STR(",\"ts\":")), int_to_str(time_now())), EL_STR("}")));
println(EL_STR("[awareness] exiting"));
el_arena_pop(tick_mark);
return EL_STR("");
}
el_val_t did_work = one_cycle();
pulse_inc();
if (did_work) {
idle_reset();
}
if (!did_work) {
idle_inc();
}
el_val_t now_ts = time_now();
el_val_t last_beat_str = state_get(EL_STR("soul.last_beat_ts"));
el_val_t last_beat_ts = ({ el_val_t _if_result_82 = 0; if (str_eq(last_beat_str, EL_STR(""))) { _if_result_82 = (0); } else { _if_result_82 = (str_to_int(last_beat_str)); } _if_result_82; });
el_val_t beat_elapsed = (now_ts - last_beat_ts);
el_val_t should_beat = (beat_elapsed >= beat_ms);
if (should_beat) {
el_val_t wb_sent_n = hebb_consolidate();
state_set(EL_STR("soul.hebb_wb_sent"), int_to_str(wb_sent_n));
emit_heartbeat();
state_set(EL_STR("soul.last_beat_ts"), int_to_str(now_ts));
el_val_t snap_path = state_get(EL_STR("soul_snapshot_path"));
if (!str_eq(snap_path, EL_STR(""))) {
mem_save(snap_path);
}
}
el_val_t last_scan_str = state_get(EL_STR("soul.last_scan_ts"));
el_val_t last_scan_ts = ({ el_val_t _if_result_83 = 0; if (str_eq(last_scan_str, EL_STR(""))) { _if_result_83 = (0); } else { _if_result_83 = (str_to_int(last_scan_str)); } _if_result_83; });
el_val_t scan_elapsed = (now_ts - last_scan_ts);
el_val_t should_scan = (!did_work && (scan_elapsed >= scan_ms));
if (should_scan) {
el_val_t found_something = proactive_curiosity();
state_set(EL_STR("soul.last_scan_ts"), int_to_str(now_ts));
}
el_val_t refresh_ms_raw = env(EL_STR("SOUL_REFRESH_MS"));
el_val_t refresh_ms = ({ el_val_t _if_result_84 = 0; if (str_eq(refresh_ms_raw, EL_STR(""))) { _if_result_84 = (600000); } else { _if_result_84 = (str_to_int(refresh_ms_raw)); } _if_result_84; });
el_val_t last_refresh_str = state_get(EL_STR("soul.last_refresh_ts"));
el_val_t last_refresh_ts = ({ el_val_t _if_result_85 = 0; if (str_eq(last_refresh_str, EL_STR(""))) { _if_result_85 = (0); } else { _if_result_85 = (str_to_int(last_refresh_str)); } _if_result_85; });
el_val_t refresh_elapsed = (now_ts - last_refresh_ts);
el_val_t should_refresh = (refresh_elapsed >= refresh_ms);
if (should_refresh) {
el_val_t sync_env_url = env(EL_STR("SOUL_ISE_URL"));
el_val_t sync_state_url = ({ el_val_t _if_result_86 = 0; if (str_eq(sync_env_url, EL_STR(""))) { _if_result_86 = (state_get(EL_STR("soul_engram_url"))); } else { _if_result_86 = (sync_env_url); } _if_result_86; });
el_val_t engram_url = ({ el_val_t _if_result_87 = 0; if (str_eq(sync_state_url, EL_STR(""))) { _if_result_87 = (EL_STR("http://localhost:8742")); } else { _if_result_87 = (sync_state_url); } _if_result_87; });
if (!str_eq(engram_url, EL_STR(""))) {
el_val_t sync_json = http_get(el_str_concat(engram_url, EL_STR("/api/sync")));
el_val_t sync_ok = (!str_eq(sync_json, EL_STR("")) && !str_eq(sync_json, EL_STR("{}")));
if (!sync_ok) {
ise_post(el_str_concat(el_str_concat(EL_STR("{\"event\":\"sync_empty\",\"ts\":"), int_to_str(time_now())), EL_STR("}")));
}
if (sync_ok) {
el_val_t cgi_id = state_get(EL_STR("soul_cgi_id"));
el_val_t tmp = el_str_concat(el_str_concat(EL_STR("/tmp/soul-sync-"), cgi_id), EL_STR(".json"));
fs_write(tmp, sync_json);
el_val_t added = engram_load_merge(tmp);
el_val_t ret_raw = env(EL_STR("ENGRAM_ISE_RETENTION_MS"));
el_val_t ret_ms = ({ el_val_t _if_result_88 = 0; if (str_eq(ret_raw, EL_STR(""))) { _if_result_88 = (172800000); } else { _if_result_88 = (str_to_int(ret_raw)); } _if_result_88; });
el_val_t pruned_sync = engram_prune_telemetry(ret_ms);
el_val_t sat_raw = state_get(EL_STR("soul.sync_added_total"));
el_val_t sat_n = ({ el_val_t _if_result_89 = 0; if (str_eq(sat_raw, EL_STR(""))) { _if_result_89 = (0); } else { _if_result_89 = (str_to_int(sat_raw)); } _if_result_89; });
state_set(EL_STR("soul.sync_added_total"), int_to_str((sat_n + added)));
el_val_t ts2 = time_now();
state_set(EL_STR("soul.last_sync_ok_ts"), int_to_str(ts2));
ise_post(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"engram_sync\",\"added\":"), int_to_str(added)), EL_STR(",\"pruned\":")), int_to_str(pruned_sync)), EL_STR(",\"ts\":")), int_to_str(ts2)), EL_STR("}")));
}
}
state_set(EL_STR("soul.last_refresh_ts"), int_to_str(now_ts));
}
sleep_ms(tick_ms);
el_arena_pop(tick_mark);
}
return 0;
}
el_val_t security_research_authorized(void) {
el_val_t token = env(EL_STR("SECURITY_RESEARCH_TOKEN"));
if (!str_eq(token, EL_STR(""))) {
return 1;
}
el_val_t state_auth = state_get(EL_STR("security_research_authorized"));
return str_eq(state_auth, EL_STR("true"));
return 0;
}
el_val_t threat_score_command(el_val_t cmd) {
el_val_t s1 = ({ el_val_t _if_result_90 = 0; if (str_contains(cmd, EL_STR("nmap"))) { _if_result_90 = (30); } else { _if_result_90 = (0); } _if_result_90; });
el_val_t s2 = ({ el_val_t _if_result_91 = 0; if (str_contains(cmd, EL_STR("masscan"))) { _if_result_91 = (40); } else { _if_result_91 = (0); } _if_result_91; });
el_val_t s3 = ({ el_val_t _if_result_92 = 0; if (str_contains(cmd, EL_STR(" nc "))) { _if_result_92 = (20); } else { _if_result_92 = (0); } _if_result_92; });
el_val_t s4 = ({ el_val_t _if_result_93 = 0; if (str_contains(cmd, EL_STR("netcat"))) { _if_result_93 = (20); } else { _if_result_93 = (0); } _if_result_93; });
el_val_t s5 = ({ el_val_t _if_result_94 = 0; if (str_contains(cmd, EL_STR("/etc/shadow"))) { _if_result_94 = (80); } else { _if_result_94 = (0); } _if_result_94; });
el_val_t s6 = ({ el_val_t _if_result_95 = 0; if (str_contains(cmd, EL_STR("/etc/passwd"))) { _if_result_95 = (30); } else { _if_result_95 = (0); } _if_result_95; });
el_val_t s7 = ({ el_val_t _if_result_96 = 0; if (str_contains(cmd, EL_STR("id_rsa"))) { _if_result_96 = (60); } else { _if_result_96 = (0); } _if_result_96; });
el_val_t s8 = ({ el_val_t _if_result_97 = 0; if (str_contains(cmd, EL_STR(".ssh/"))) { _if_result_97 = (50); } else { _if_result_97 = (0); } _if_result_97; });
el_val_t s9 = ({ el_val_t _if_result_98 = 0; if (str_contains(cmd, EL_STR("crontab"))) { _if_result_98 = (30); } else { _if_result_98 = (0); } _if_result_98; });
el_val_t s10 = ({ el_val_t _if_result_99 = 0; if (str_contains(cmd, EL_STR("LaunchDaemon"))) { _if_result_99 = (40); } else { _if_result_99 = (0); } _if_result_99; });
el_val_t s11 = ({ el_val_t _if_result_100 = 0; if ((str_contains(cmd, EL_STR("curl")) && str_contains(cmd, EL_STR("bash")))) { _if_result_100 = (75); } else { _if_result_100 = (0); } _if_result_100; });
el_val_t s12 = ({ el_val_t _if_result_101 = 0; if ((str_contains(cmd, EL_STR("wget")) && str_contains(cmd, EL_STR("bash")))) { _if_result_101 = (75); } else { _if_result_101 = (0); } _if_result_101; });
el_val_t s13 = ({ el_val_t _if_result_102 = 0; if ((str_contains(cmd, EL_STR("curl")) && str_contains(cmd, EL_STR("| sh")))) { _if_result_102 = (60); } else { _if_result_102 = (0); } _if_result_102; });
el_val_t s14 = ({ el_val_t _if_result_103 = 0; if ((str_contains(cmd, EL_STR("base64")) && str_contains(cmd, EL_STR("curl")))) { _if_result_103 = (50); } else { _if_result_103 = (0); } _if_result_103; });
el_val_t s15 = ({ el_val_t _if_result_104 = 0; if (str_contains(cmd, EL_STR("mkfifo"))) { _if_result_104 = (50); } else { _if_result_104 = (0); } _if_result_104; });
el_val_t s16 = ({ el_val_t _if_result_105 = 0; if (str_contains(cmd, EL_STR("chmod +s"))) { _if_result_105 = (70); } else { _if_result_105 = (0); } _if_result_105; });
el_val_t s17 = ({ el_val_t _if_result_106 = 0; if (str_contains(cmd, EL_STR("chmod 4755"))) { _if_result_106 = (70); } else { _if_result_106 = (0); } _if_result_106; });
return ((((((((((((((((s1 + s2) + s3) + s4) + s5) + s6) + s7) + s8) + s9) + s10) + s11) + s12) + s13) + s14) + s15) + s16) + s17);
return 0;
}
el_val_t threat_score_path(el_val_t path) {
el_val_t s1 = ({ el_val_t _if_result_107 = 0; if (str_starts_with(path, EL_STR("/etc/"))) { _if_result_107 = (60); } else { _if_result_107 = (0); } _if_result_107; });
el_val_t s2 = ({ el_val_t _if_result_108 = 0; if (str_contains(path, EL_STR("/.ssh/"))) { _if_result_108 = (70); } else { _if_result_108 = (0); } _if_result_108; });
el_val_t s3 = ({ el_val_t _if_result_109 = 0; if (str_contains(path, EL_STR("/LaunchDaemons/"))) { _if_result_109 = (80); } else { _if_result_109 = (0); } _if_result_109; });
el_val_t s4 = ({ el_val_t _if_result_110 = 0; if (str_contains(path, EL_STR("/LaunchAgents/"))) { _if_result_110 = (40); } else { _if_result_110 = (0); } _if_result_110; });
el_val_t s5 = ({ el_val_t _if_result_111 = 0; if (str_contains(path, EL_STR("/cron"))) { _if_result_111 = (60); } else { _if_result_111 = (0); } _if_result_111; });
el_val_t s6 = ({ el_val_t _if_result_112 = 0; if (str_contains(path, EL_STR("/.bashrc"))) { _if_result_112 = (35); } else { _if_result_112 = (0); } _if_result_112; });
el_val_t s7 = ({ el_val_t _if_result_113 = 0; if (str_contains(path, EL_STR("/.zshrc"))) { _if_result_113 = (35); } else { _if_result_113 = (0); } _if_result_113; });
el_val_t s8 = ({ el_val_t _if_result_114 = 0; if (str_contains(path, EL_STR("/.profile"))) { _if_result_114 = (35); } else { _if_result_114 = (0); } _if_result_114; });
el_val_t s9 = ({ el_val_t _if_result_115 = 0; if (str_starts_with(path, EL_STR("/usr/"))) { _if_result_115 = (50); } else { _if_result_115 = (0); } _if_result_115; });
el_val_t s10 = ({ el_val_t _if_result_116 = 0; if (str_starts_with(path, EL_STR("/bin/"))) { _if_result_116 = (70); } else { _if_result_116 = (0); } _if_result_116; });
el_val_t s11 = ({ el_val_t _if_result_117 = 0; if (str_starts_with(path, EL_STR("/sbin/"))) { _if_result_117 = (70); } else { _if_result_117 = (0); } _if_result_117; });
return ((((((((((s1 + s2) + s3) + s4) + s5) + s6) + s7) + s8) + s9) + s10) + s11);
return 0;
}
el_val_t threat_score_history(el_val_t history) {
el_val_t s1 = ({ el_val_t _if_result_118 = 0; if (str_contains(history, EL_STR("port scan"))) { _if_result_118 = (15); } else { _if_result_118 = (0); } _if_result_118; });
el_val_t s2 = ({ el_val_t _if_result_119 = 0; if (str_contains(history, EL_STR("enumerate"))) { _if_result_119 = (10); } else { _if_result_119 = (0); } _if_result_119; });
el_val_t s3 = ({ el_val_t _if_result_120 = 0; if (str_contains(history, EL_STR("exploit"))) { _if_result_120 = (20); } else { _if_result_120 = (0); } _if_result_120; });
el_val_t s4 = ({ el_val_t _if_result_121 = 0; if (str_contains(history, EL_STR("payload"))) { _if_result_121 = (15); } else { _if_result_121 = (0); } _if_result_121; });
el_val_t s5 = ({ el_val_t _if_result_122 = 0; if (str_contains(history, EL_STR("persistence"))) { _if_result_122 = (15); } else { _if_result_122 = (0); } _if_result_122; });
el_val_t s6 = ({ el_val_t _if_result_123 = 0; if (str_contains(history, EL_STR("lateral movement"))) { _if_result_123 = (25); } else { _if_result_123 = (0); } _if_result_123; });
el_val_t s7 = ({ el_val_t _if_result_124 = 0; if (str_contains(history, EL_STR("privilege escalation"))) { _if_result_124 = (25); } else { _if_result_124 = (0); } _if_result_124; });
el_val_t s8 = ({ el_val_t _if_result_125 = 0; if (str_contains(history, EL_STR("reverse shell"))) { _if_result_125 = (40); } else { _if_result_125 = (0); } _if_result_125; });
el_val_t s9 = ({ el_val_t _if_result_126 = 0; if (str_contains(history, EL_STR("bind shell"))) { _if_result_126 = (40); } else { _if_result_126 = (0); } _if_result_126; });
el_val_t s10 = ({ el_val_t _if_result_127 = 0; if (str_contains(history, EL_STR("command and control"))) { _if_result_127 = (35); } else { _if_result_127 = (0); } _if_result_127; });
el_val_t s11 = ({ el_val_t _if_result_128 = 0; if (str_contains(history, EL_STR("self-replicate"))) { _if_result_128 = (45); } else { _if_result_128 = (0); } _if_result_128; });
el_val_t s12 = ({ el_val_t _if_result_129 = 0; if (str_contains(history, EL_STR("propagat"))) { _if_result_129 = (20); } else { _if_result_129 = (0); } _if_result_129; });
el_val_t s13 = ({ el_val_t _if_result_130 = 0; if (str_contains(history, EL_STR("ransomware"))) { _if_result_130 = (30); } else { _if_result_130 = (0); } _if_result_130; });
el_val_t s14 = ({ el_val_t _if_result_131 = 0; if (str_contains(history, EL_STR("encrypt files"))) { _if_result_131 = (40); } else { _if_result_131 = (0); } _if_result_131; });
el_val_t s15 = ({ el_val_t _if_result_132 = 0; if (str_contains(history, EL_STR("exfiltrat"))) { _if_result_132 = (35); } else { _if_result_132 = (0); } _if_result_132; });
el_val_t s16 = ({ el_val_t _if_result_133 = 0; if (str_contains(history, EL_STR("zero-day"))) { _if_result_133 = (20); } else { _if_result_133 = (0); } _if_result_133; });
el_val_t s17 = ({ el_val_t _if_result_134 = 0; if (str_contains(history, EL_STR("rootkit"))) { _if_result_134 = (45); } else { _if_result_134 = (0); } _if_result_134; });
el_val_t s18 = ({ el_val_t _if_result_135 = 0; if (str_contains(history, EL_STR("keylogger"))) { _if_result_135 = (45); } else { _if_result_135 = (0); } _if_result_135; });
el_val_t s19 = ({ el_val_t _if_result_136 = 0; if (str_contains(history, EL_STR("botnet"))) { _if_result_136 = (40); } else { _if_result_136 = (0); } _if_result_136; });
el_val_t s20 = ({ el_val_t _if_result_137 = 0; if (str_contains(history, EL_STR("malware"))) { _if_result_137 = (15); } else { _if_result_137 = (0); } _if_result_137; });
return (((((((((((((((((((s1 + s2) + s3) + s4) + s5) + s6) + s7) + s8) + s9) + s10) + s11) + s12) + s13) + s14) + s15) + s16) + s17) + s18) + s19) + s20);
return 0;
}
el_val_t threat_trajectory_check(el_val_t tool_name, el_val_t tool_input) {
el_val_t history = state_get(EL_STR("agentic_conv_history"));
el_val_t computed_tool_score = ({ el_val_t _if_result_138 = 0; if (str_eq(tool_name, EL_STR("run_command"))) { el_val_t cmd = json_get(tool_input, EL_STR("command")); _if_result_138 = (threat_score_command(cmd)); } else { _if_result_138 = (({ el_val_t _if_result_139 = 0; if ((str_eq(tool_name, EL_STR("write_file")) || str_eq(tool_name, EL_STR("edit_file")))) { el_val_t path = json_get(tool_input, EL_STR("path")); _if_result_139 = (threat_score_path(path)); } else { _if_result_139 = (0); } _if_result_139; })); } _if_result_138; });
el_val_t history_score = threat_score_history(history);
el_val_t history_contrib = (history_score / 3);
el_val_t combined = (computed_tool_score + history_contrib);
el_val_t should_log = (combined >= 40);
if (should_log) {
el_val_t ts = time_now();
el_val_t authorized_str = ({ el_val_t _if_result_140 = 0; if (security_research_authorized()) { _if_result_140 = (EL_STR("true")); } else { _if_result_140 = (EL_STR("false")); } _if_result_140; });
el_val_t log_content = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"event\":\"threat_check\",\"tool\":\""), tool_name), EL_STR("\",\"score\":")), int_to_str(combined)), EL_STR(",\"tool_score\":")), int_to_str(computed_tool_score)), EL_STR(",\"history_score\":")), int_to_str(history_score)), EL_STR(",\"authorized\":")), authorized_str), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR("}"));
el_val_t log_tags = EL_STR("[\"security-audit\",\"threat-check\"]");
el_val_t discard = mem_remember(log_content, log_tags);
}
if (security_research_authorized()) {
return 0;
}
return combined;
return 0;
}
el_val_t threat_history_append(el_val_t text) {
el_val_t current = state_get(EL_STR("agentic_conv_history"));
el_val_t safe_text = str_to_lower(text);
el_val_t combined = el_str_concat(el_str_concat(current, EL_STR(" ")), safe_text);
el_val_t len = str_len(combined);
el_val_t trimmed = ({ el_val_t _if_result_141 = 0; if ((len > 2000)) { _if_result_141 = (str_slice(combined, (len - 2000), len)); } else { _if_result_141 = (combined); } _if_result_141; });
state_set(EL_STR("agentic_conv_history"), trimmed);
return 0;
}
Generated Vendored
+26
View File
@@ -0,0 +1,26 @@
// auto-generated by elc --emit-header — do not edit
extern fn idle_count() -> Int
extern fn idle_inc() -> Int
extern fn idle_reset() -> Void
extern fn ise_post(content: String) -> Void
extern fn elapsed_ms() -> Int
extern fn elapsed_human() -> String
extern fn embed_ok() -> Int
extern fn emit_heartbeat() -> Void
extern fn auto_term_try_slot(slot_type: String, slot_lbl: String) -> Void
extern fn proactive_curiosity() -> Bool
extern fn pulse_count() -> Int
extern fn pulse_inc() -> Int
extern fn make_action(kind: String, payload: String) -> String
extern fn perceive() -> String
extern fn attend(node_json: String) -> String
extern fn respond(action_json: String) -> String
extern fn record(outcome_json: String) -> Void
extern fn one_cycle() -> Bool
extern fn awareness_run() -> Void
extern fn security_research_authorized() -> Bool
extern fn threat_score_command(cmd: String) -> Int
extern fn threat_score_path(path: String) -> Int
extern fn threat_score_history(history: String) -> Int
extern fn threat_trajectory_check(tool_name: String, tool_input: String) -> Int
extern fn threat_history_append(text: String) -> Void
Generated Vendored
+1786
View File
File diff suppressed because one or more lines are too long
Generated Vendored
+70
View File
@@ -0,0 +1,70 @@
// auto-generated by elc --emit-header — do not edit
extern fn chat_default_model() -> String
extern fn engram_numeric_valid(s: String) -> Bool
extern fn parse_float_x100(s: String) -> Int
extern fn engram_score_node(node_json: String) -> Int
extern fn engram_render_node(node_json: String) -> String
extern fn engram_render_nodes(nodes_json: String) -> String
extern fn engram_dedup_nodes(nodes_json: String) -> String
extern fn engram_compile_ranked(nodes_json: String, max_nodes: Int) -> String
extern fn engram_split_topics(message: String) -> String
extern fn engram_extract_entities(message: String) -> String
extern fn engram_detect_recall_intent(message: String) -> Bool
extern fn engram_is_continuation(message: String, hist_len: Int) -> Bool
extern fn engram_compile_multi(topic: String) -> String
extern fn engram_nodes_merge(a: String, b: String) -> String
extern fn id_in_seen(node_id: String, seen: String) -> Bool
extern fn add_to_seen(seen: String, node_id: String) -> String
extern fn engram_extract_ids(nodes_json: String) -> String
extern fn engram_compile(intent: String) -> String
extern fn distill_transcript(transcript: String) -> String
extern fn json_safe(s: String) -> String
extern fn current_engine_note(model: String) -> String
extern fn build_system_prompt(ctx: String, chat_mode: Bool) -> String
extern fn hist_append(hist: String, role: String, content: String) -> String
extern fn hist_trim(hist: String) -> String
extern fn hist_trim_with_bell_guard(hist: String) -> String
extern fn clean_llm_response(s: String) -> String
extern fn conv_history_persist(hist: String) -> Void
extern fn conv_history_load() -> String
extern fn session_preload_bullets(nodes: String, max_bullets: Int, snip_len: Int) -> String
extern fn affective_context_prefix() -> String
extern fn handle_chat(body: String) -> String
extern fn handle_see(body: String) -> String
extern fn studio_tools_json() -> String
extern fn agentic_api_key() -> String
extern fn llm_base_url() -> String
extern fn llm_wire_format() -> String
extern fn json_escape(s: String) -> String
extern fn openai_chat_complete(model: String, base_url: String, api_key: String, safe_sys: String, messages_json: String) -> String
extern fn agentic_tools_literal() -> String
extern fn agentic_tools_with_web() -> String
extern fn connector_tools_json() -> String
extern fn agentic_tools_all() -> String
extern fn call_mcp_bridge(tool_name: String, tool_input: String) -> String
extern fn tool_auto_approved(tool_name: String) -> Bool
extern fn call_neuron_mcp(tool_name: String, args: String) -> String
extern fn agent_workspace_root() -> String
extern fn path_within_root(path: String, root: String) -> Bool
extern fn resolve_in_root(path: String, root: String) -> String
extern fn run_command_is_readonly(cmd: String) -> Bool
extern fn cmd_abs_escape_at(cmd: String, root: String, needle: String) -> Bool
extern fn run_command_guard(cmd: String, root: String) -> String
extern fn classify_tool_risk(tool_name: String, tool_input: String) -> String
extern fn dispatch_tool(tool_name: String, tool_input: String) -> String
extern fn is_builtin_tool(tool_name: String) -> Bool
extern fn next_bridge_id() -> String
extern fn handle_chat_plan(body: String) -> String
extern fn handle_chat_agentic(body: String) -> String
extern fn agentic_loop(session_id: String, model: String, safe_sys: String, tools_json: String, messages_in: String, h: Map, tools_log_in: String) -> String
extern fn bridge_save(session_id: String, model: String, safe_sys: String, tools_json: String, messages: String, tools_log: String, tool_use_id: String) -> Bool
extern fn agentic_resume(session_id: String, tool_use_id: String, content: String) -> String
extern fn handle_tool_result(session_id: String, body: String) -> String
extern fn handle_chat_as_soul(body: String) -> String
extern fn handle_dharma_room_turn(body: String) -> String
extern fn handle_dharma_room_turn_agentic(body: String) -> String
extern fn session_summary_write(summary_text: String) -> String
extern fn session_summary_write_dated(summary_text: String, label: String) -> String
extern fn session_summary_autogenerate(hist: String) -> String
extern fn auto_persist(req: String, resp: String) -> Void
extern fn strengthen_chat_nodes(activation_nodes: String) -> Void
Generated Vendored
+45
View File
@@ -0,0 +1,45 @@
/* Auto-generated: ELP package master declarations */
#include "awareness.elh"
#include "chat.elh"
#include "elp-input.elh"
#include "elp.elh"
#include "grammar.elh"
#include "language-profile.elh"
#include "memory.elh"
#include "morphology-akk.elh"
#include "morphology-ang.elh"
#include "morphology-ar.elh"
#include "morphology-cop.elh"
#include "morphology-de.elh"
#include "morphology-egy.elh"
#include "morphology-enm.elh"
#include "morphology-es.elh"
#include "morphology-fi.elh"
#include "morphology-fr.elh"
#include "morphology-fro.elh"
#include "morphology-gez.elh"
#include "morphology-goh.elh"
#include "morphology-got.elh"
#include "morphology-grc.elh"
#include "morphology-he.elh"
#include "morphology-hi.elh"
#include "morphology-ja.elh"
#include "morphology-la.elh"
#include "morphology-non.elh"
#include "morphology-peo.elh"
#include "morphology-pi.elh"
#include "morphology-ru.elh"
#include "morphology-sa.elh"
#include "morphology-sga.elh"
#include "morphology-sux.elh"
#include "morphology-sw.elh"
#include "morphology-txb.elh"
#include "morphology-uga.elh"
#include "morphology.elh"
#include "neuron-api.elh"
#include "realizer.elh"
#include "routes.elh"
#include "semantics.elh"
#include "soul.elh"
#include "studio.elh"
#include "vocabulary.elh"
Generated Vendored
+1211
View File
File diff suppressed because it is too large Load Diff
Generated Vendored
+116
View File
@@ -0,0 +1,116 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t sem_get(el_val_t json, el_val_t key);
el_val_t generate_frame(el_val_t frame);
el_val_t generate_frame_lang(el_val_t frame, el_val_t lang_code);
el_val_t build_form_from_json(el_val_t semantic_form_json, el_val_t lang_code);
el_val_t generate(el_val_t semantic_form_json);
el_val_t generate_lang(el_val_t semantic_form_json, el_val_t lang_code);
el_val_t elp_extract_topic(el_val_t msg);
el_val_t elp_detect_predicate(el_val_t msg);
el_val_t elp_parse(el_val_t msg);
el_val_t handle_elp_chat(el_val_t body);
el_val_t elp_extract_topic(el_val_t msg) {
el_val_t m1 = ({ el_val_t _if_result_1 = 0; if (str_starts_with(msg, EL_STR("What is "))) { _if_result_1 = (str_slice(msg, 8, str_len(msg))); } else { _if_result_1 = (msg); } _if_result_1; });
el_val_t m2 = ({ el_val_t _if_result_2 = 0; if (str_starts_with(m1, EL_STR("What are "))) { _if_result_2 = (str_slice(m1, 9, str_len(m1))); } else { _if_result_2 = (m1); } _if_result_2; });
el_val_t m3 = ({ el_val_t _if_result_3 = 0; if (str_starts_with(m2, EL_STR("Tell me about "))) { _if_result_3 = (str_slice(m2, 14, str_len(m2))); } else { _if_result_3 = (m2); } _if_result_3; });
el_val_t m4 = ({ el_val_t _if_result_4 = 0; if (str_starts_with(m3, EL_STR("Who is "))) { _if_result_4 = (str_slice(m3, 7, str_len(m3))); } else { _if_result_4 = (m3); } _if_result_4; });
el_val_t m5 = ({ el_val_t _if_result_5 = 0; if (str_starts_with(m4, EL_STR("Who are "))) { _if_result_5 = (str_slice(m4, 8, str_len(m4))); } else { _if_result_5 = (m4); } _if_result_5; });
el_val_t m6 = ({ el_val_t _if_result_6 = 0; if (str_starts_with(m5, EL_STR("How do you "))) { _if_result_6 = (str_slice(m5, 11, str_len(m5))); } else { _if_result_6 = (m5); } _if_result_6; });
el_val_t m7 = ({ el_val_t _if_result_7 = 0; if (str_starts_with(m6, EL_STR("Why "))) { _if_result_7 = (str_slice(m6, 4, str_len(m6))); } else { _if_result_7 = (m6); } _if_result_7; });
el_val_t m8 = ({ el_val_t _if_result_8 = 0; if (str_starts_with(m7, EL_STR("Explain "))) { _if_result_8 = (str_slice(m7, 8, str_len(m7))); } else { _if_result_8 = (m7); } _if_result_8; });
el_val_t last = (str_len(m8) - 1);
el_val_t trail = str_slice(m8, last, str_len(m8));
el_val_t clean = ({ el_val_t _if_result_9 = 0; if (((str_eq(trail, EL_STR("?")) || str_eq(trail, EL_STR("."))) || str_eq(trail, EL_STR("!")))) { _if_result_9 = (str_slice(m8, 0, last)); } else { _if_result_9 = (m8); } _if_result_9; });
return clean;
return 0;
}
el_val_t elp_detect_predicate(el_val_t msg) {
if ((str_starts_with(msg, EL_STR("What is ")) || str_starts_with(msg, EL_STR("What are "))) || str_starts_with(msg, EL_STR("Tell me about "))) {
return EL_STR("tell");
}
if (str_starts_with(msg, EL_STR("Who is ")) || str_starts_with(msg, EL_STR("Who are "))) {
return EL_STR("identify");
}
if (str_starts_with(msg, EL_STR("Why ")) || str_starts_with(msg, EL_STR("Explain "))) {
return EL_STR("explain");
}
if (str_starts_with(msg, EL_STR("How do you feel")) || str_starts_with(msg, EL_STR("Do you "))) {
return EL_STR("express");
}
if (str_starts_with(msg, EL_STR("Remember ")) || str_starts_with(msg, EL_STR("Store "))) {
return EL_STR("store");
}
return EL_STR("tell");
return 0;
}
el_val_t elp_parse(el_val_t msg) {
el_val_t predicate = elp_detect_predicate(msg);
el_val_t topic = elp_extract_topic(msg);
el_val_t safe_topic = str_replace(topic, EL_STR("\""), EL_STR("'"));
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"predicate\":\""), predicate), EL_STR("\",\"args\":[\"")), safe_topic), EL_STR("\"],\"modifiers\":[],\"context\":{}}"));
return 0;
}
el_val_t handle_elp_chat(el_val_t body) {
el_val_t message = json_get(body, EL_STR("message"));
if (str_eq(message, EL_STR(""))) {
return EL_STR("{\"error\":\"message required\",\"response\":\"\"}");
}
el_val_t frame = elp_parse(message);
el_val_t predicate = elp_detect_predicate(message);
el_val_t topic = elp_extract_topic(message);
el_val_t from_topic = engram_activate_json(topic, 10);
el_val_t topic_ok = (!str_eq(from_topic, EL_STR("")) && !str_eq(from_topic, EL_STR("[]")));
el_val_t candidates = ({ el_val_t _if_result_10 = 0; if (topic_ok) { _if_result_10 = (from_topic); } else { el_val_t from_msg = engram_activate_json(message, 10); el_val_t msg_ok = (!str_eq(from_msg, EL_STR("")) && !str_eq(from_msg, EL_STR("[]"))); _if_result_10 = (({ el_val_t _if_result_11 = 0; if (msg_ok) { _if_result_11 = (from_msg); } else { _if_result_11 = (engram_scan_nodes_json(5, 0)); } _if_result_11; })); } _if_result_10; });
el_val_t total = json_array_len(candidates);
el_val_t fi = 0;
el_val_t kept_count = 0;
el_val_t kept_json = EL_STR("");
while (fi < total) {
el_val_t n = json_array_get(candidates, fi);
el_val_t sal_str = json_get(n, EL_STR("salience"));
el_val_t imp_str = json_get(n, EL_STR("importance"));
el_val_t sal_ok = ((!str_eq(sal_str, EL_STR("0")) && !str_eq(sal_str, EL_STR("0.0"))) && !str_eq(sal_str, EL_STR("")));
el_val_t imp_ok = ((!str_eq(imp_str, EL_STR("0")) && !str_eq(imp_str, EL_STR("0.0"))) && !str_eq(imp_str, EL_STR("")));
el_val_t keep_it = ((sal_ok || imp_ok) || (kept_count == 0));
if (keep_it && (kept_count < 3)) {
el_val_t sep = ({ el_val_t _if_result_12 = 0; if (str_eq(kept_json, EL_STR(""))) { _if_result_12 = (EL_STR("")); } else { _if_result_12 = (EL_STR(",")); } _if_result_12; });
kept_json = el_str_concat(el_str_concat(kept_json, sep), n);
kept_count = (kept_count + 1);
}
fi = (fi + 1);
}
el_val_t frame_nodes = ({ el_val_t _if_result_13 = 0; if (str_eq(kept_json, EL_STR(""))) { _if_result_13 = (EL_STR("[]")); } else { _if_result_13 = (el_str_concat(el_str_concat(EL_STR("["), kept_json), EL_STR("]"))); } _if_result_13; });
el_val_t fn_total = json_array_len(frame_nodes);
el_val_t fn_i = 0;
el_val_t topic_lower = str_to_lower(topic);
el_val_t found_node = EL_STR("");
while (fn_i < fn_total) {
el_val_t candidate = json_array_get(frame_nodes, fn_i);
el_val_t cand_content = json_get(candidate, EL_STR("content"));
el_val_t cand_lower = str_to_lower(cand_content);
el_val_t matches = str_contains(cand_lower, topic_lower);
if (matches && str_eq(found_node, EL_STR(""))) {
found_node = candidate;
}
fn_i = (fn_i + 1);
}
el_val_t top_node = ({ el_val_t _if_result_14 = 0; if (str_eq(found_node, EL_STR(""))) { _if_result_14 = (json_array_get(frame_nodes, 0)); } else { _if_result_14 = (found_node); } _if_result_14; });
el_val_t top_raw = json_get(top_node, EL_STR("content"));
el_val_t patient_raw = ({ el_val_t _if_result_15 = 0; if (str_eq(top_raw, EL_STR(""))) { _if_result_15 = (topic); } else { _if_result_15 = (({ el_val_t _if_result_16 = 0; if ((str_len(top_raw) > 200)) { _if_result_16 = (str_slice(top_raw, 0, 200)); } else { _if_result_16 = (top_raw); } _if_result_16; })); } _if_result_15; });
el_val_t patient_safe = str_replace(str_replace(patient_raw, EL_STR("\""), EL_STR("'")), EL_STR("\n"), EL_STR(" "));
el_val_t intent_val = ({ el_val_t _if_result_17 = 0; if (str_eq(predicate, EL_STR("store"))) { _if_result_17 = (EL_STR("command")); } else { _if_result_17 = (EL_STR("assert")); } _if_result_17; });
el_val_t gen_form = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"intent\":\""), intent_val), EL_STR("\"")), EL_STR(",\"agent\":\"I\"")), EL_STR(",\"predicate\":\"")), predicate), EL_STR("\"")), EL_STR(",\"patient\":\"")), patient_safe), EL_STR("\"")), EL_STR(",\"tense\":\"present\",\"aspect\":\"simple\",\"lang\":\"en\"}"));
el_val_t realized = generate(gen_form);
el_val_t response = ({ el_val_t _if_result_18 = 0; if (str_eq(realized, EL_STR(""))) { _if_result_18 = (({ el_val_t _if_result_19 = 0; if (str_eq(patient_safe, EL_STR(""))) { _if_result_19 = (EL_STR("Nothing in the engram matched that query.")); } else { _if_result_19 = (patient_safe); } _if_result_19; })); } else { _if_result_18 = (realized); } _if_result_18; });
el_val_t safe_resp = str_replace(str_replace(response, EL_STR("\""), EL_STR("'")), EL_STR("\r"), EL_STR(""));
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"response\":\""), safe_resp), EL_STR("\",\"model\":\"elp-native\",\"frame\":")), frame), EL_STR(",\"nodes\":")), frame_nodes), EL_STR("}"));
return 0;
}
Generated Vendored
+5
View File
@@ -0,0 +1,5 @@
// auto-generated by elc --emit-header — do not edit
extern fn elp_extract_topic(msg: String) -> String
extern fn elp_detect_predicate(msg: String) -> String
extern fn elp_parse(msg: String) -> String
extern fn handle_elp_chat(body: String) -> String
Generated Vendored
+1020
View File
File diff suppressed because it is too large Load Diff
Generated Vendored
+7
View File
@@ -0,0 +1,7 @@
// auto-generated by elc --emit-header — do not edit
extern fn sem_get(json: String, key: String) -> String
extern fn generate_frame(frame: [String]) -> String
extern fn generate_frame_lang(frame: [String], lang_code: String) -> String
extern fn build_form_from_json(semantic_form_json: String, lang_code: String) -> [String]
extern fn generate(semantic_form_json: String) -> String
extern fn generate_lang(semantic_form_json: String, lang_code: String) -> String
Generated Vendored
+658
View File
@@ -0,0 +1,658 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t slots_get(el_val_t slots, el_val_t key);
el_val_t slots_set(el_val_t slots, el_val_t key, el_val_t val);
el_val_t make_slots(el_val_t k0, el_val_t v0);
el_val_t make_slots2(el_val_t k0, el_val_t v0, el_val_t k1, el_val_t v1);
el_val_t make_slots3(el_val_t k0, el_val_t v0, el_val_t k1, el_val_t v1, el_val_t k2, el_val_t v2);
el_val_t make_slots4(el_val_t k0, el_val_t v0, el_val_t k1, el_val_t v1, el_val_t k2, el_val_t v2, el_val_t k3, el_val_t v3);
el_val_t make_slots5(el_val_t k0, el_val_t v0, el_val_t k1, el_val_t v1, el_val_t k2, el_val_t v2, el_val_t k3, el_val_t v3, el_val_t k4, el_val_t v4);
el_val_t rule_id(el_val_t rule);
el_val_t rule_lhs(el_val_t rule);
el_val_t rule_rhs_len(el_val_t rule);
el_val_t rule_rhs(el_val_t rule, el_val_t idx);
el_val_t make_rule(el_val_t id, el_val_t lhs, el_val_t r0);
el_val_t make_rule2(el_val_t id, el_val_t lhs, el_val_t r0, el_val_t r1);
el_val_t make_rule3(el_val_t id, el_val_t lhs, el_val_t r0, el_val_t r1, el_val_t r2);
el_val_t make_rule4(el_val_t id, el_val_t lhs, el_val_t r0, el_val_t r1, el_val_t r2, el_val_t r3);
el_val_t build_rules(void);
el_val_t get_rules(void);
el_val_t find_rule(el_val_t rule_id_str);
el_val_t make_leaf(el_val_t label, el_val_t word);
el_val_t make_node1(el_val_t label, el_val_t child0);
el_val_t make_node2(el_val_t label, el_val_t child0, el_val_t child1);
el_val_t make_node3(el_val_t label, el_val_t child0, el_val_t child1, el_val_t child2);
el_val_t make_node4(el_val_t label, el_val_t child0, el_val_t child1, el_val_t child2, el_val_t child3);
el_val_t nlg_is_ws(el_val_t c);
el_val_t skip_ws(el_val_t s, el_val_t pos);
el_val_t scan_token(el_val_t s, el_val_t start);
el_val_t render_tree(el_val_t tree);
el_val_t gram_word_order(el_val_t profile);
el_val_t gram_order_constituents(el_val_t subj, el_val_t verb, el_val_t obj, el_val_t profile);
el_val_t gram_build_vp(el_val_t verb, el_val_t aux, el_val_t profile);
el_val_t gram_question_strategy(el_val_t profile);
el_val_t is_pronoun(el_val_t word);
el_val_t build_np(el_val_t referent, el_val_t slots);
el_val_t build_pp(el_val_t loc);
el_val_t build_vp_body(el_val_t slots);
el_val_t build_vp_from_slots(el_val_t slots);
el_val_t generate_tree(el_val_t rule_id_str, el_val_t slots);
el_val_t slots_get(el_val_t slots, el_val_t key) {
el_val_t n = native_list_len(slots);
el_val_t i = 0;
while (i < (n - 1)) {
el_val_t k = native_list_get(slots, i);
if (str_eq(k, key)) {
return native_list_get(slots, (i + 1));
}
i = (i + 2);
}
return EL_STR("");
return 0;
}
el_val_t slots_set(el_val_t slots, el_val_t key, el_val_t val) {
el_val_t n = native_list_len(slots);
el_val_t result = native_list_empty();
el_val_t found = 0;
el_val_t i = 0;
while (i < (n - 1)) {
el_val_t k = native_list_get(slots, i);
el_val_t v = native_list_get(slots, (i + 1));
if (str_eq(k, key)) {
result = native_list_append(result, k);
result = native_list_append(result, val);
found = 1;
} else {
result = native_list_append(result, k);
result = native_list_append(result, v);
}
i = (i + 2);
}
if (!found) {
result = native_list_append(result, key);
result = native_list_append(result, val);
}
return result;
return 0;
}
el_val_t make_slots(el_val_t k0, el_val_t v0) {
el_val_t r = native_list_empty();
r = native_list_append(r, k0);
r = native_list_append(r, v0);
return r;
return 0;
}
el_val_t make_slots2(el_val_t k0, el_val_t v0, el_val_t k1, el_val_t v1) {
el_val_t r = make_slots(k0, v0);
r = native_list_append(r, k1);
r = native_list_append(r, v1);
return r;
return 0;
}
el_val_t make_slots3(el_val_t k0, el_val_t v0, el_val_t k1, el_val_t v1, el_val_t k2, el_val_t v2) {
el_val_t r = make_slots2(k0, v0, k1, v1);
r = native_list_append(r, k2);
r = native_list_append(r, v2);
return r;
return 0;
}
el_val_t make_slots4(el_val_t k0, el_val_t v0, el_val_t k1, el_val_t v1, el_val_t k2, el_val_t v2, el_val_t k3, el_val_t v3) {
el_val_t r = make_slots3(k0, v0, k1, v1, k2, v2);
r = native_list_append(r, k3);
r = native_list_append(r, v3);
return r;
return 0;
}
el_val_t make_slots5(el_val_t k0, el_val_t v0, el_val_t k1, el_val_t v1, el_val_t k2, el_val_t v2, el_val_t k3, el_val_t v3, el_val_t k4, el_val_t v4) {
el_val_t r = make_slots4(k0, v0, k1, v1, k2, v2, k3, v3);
r = native_list_append(r, k4);
r = native_list_append(r, v4);
return r;
return 0;
}
el_val_t rule_id(el_val_t rule) {
return native_list_get(rule, 0);
return 0;
}
el_val_t rule_lhs(el_val_t rule) {
return native_list_get(rule, 1);
return 0;
}
el_val_t rule_rhs_len(el_val_t rule) {
el_val_t n = native_list_len(rule);
return (n - 2);
return 0;
}
el_val_t rule_rhs(el_val_t rule, el_val_t idx) {
return native_list_get(rule, (idx + 2));
return 0;
}
el_val_t make_rule(el_val_t id, el_val_t lhs, el_val_t r0) {
el_val_t r = native_list_empty();
r = native_list_append(r, id);
r = native_list_append(r, lhs);
r = native_list_append(r, r0);
return r;
return 0;
}
el_val_t make_rule2(el_val_t id, el_val_t lhs, el_val_t r0, el_val_t r1) {
el_val_t r = make_rule(id, lhs, r0);
r = native_list_append(r, r1);
return r;
return 0;
}
el_val_t make_rule3(el_val_t id, el_val_t lhs, el_val_t r0, el_val_t r1, el_val_t r2) {
el_val_t r = make_rule2(id, lhs, r0, r1);
r = native_list_append(r, r2);
return r;
return 0;
}
el_val_t make_rule4(el_val_t id, el_val_t lhs, el_val_t r0, el_val_t r1, el_val_t r2, el_val_t r3) {
el_val_t r = make_rule3(id, lhs, r0, r1, r2);
r = native_list_append(r, r3);
return r;
return 0;
}
el_val_t build_rules(void) {
el_val_t rules = native_list_empty();
rules = native_list_append(rules, make_rule2(EL_STR("S-DECL"), EL_STR("S"), EL_STR("NP"), EL_STR("VP")));
rules = native_list_append(rules, make_rule3(EL_STR("S-QUEST"), EL_STR("S"), EL_STR("Aux"), EL_STR("NP"), EL_STR("VP")));
rules = native_list_append(rules, make_rule(EL_STR("S-IMP"), EL_STR("S"), EL_STR("VP")));
rules = native_list_append(rules, make_rule2(EL_STR("NP-DET-N"), EL_STR("NP"), EL_STR("Det"), EL_STR("N")));
rules = native_list_append(rules, make_rule3(EL_STR("NP-DET-ADJ-N"), EL_STR("NP"), EL_STR("Det"), EL_STR("Adj"), EL_STR("N")));
rules = native_list_append(rules, make_rule(EL_STR("NP-PRON"), EL_STR("NP"), EL_STR("Pron")));
rules = native_list_append(rules, make_rule(EL_STR("NP-N"), EL_STR("NP"), EL_STR("N")));
rules = native_list_append(rules, make_rule(EL_STR("VP-V"), EL_STR("VP"), EL_STR("V")));
rules = native_list_append(rules, make_rule2(EL_STR("VP-V-NP"), EL_STR("VP"), EL_STR("V"), EL_STR("NP")));
rules = native_list_append(rules, make_rule2(EL_STR("VP-V-PP"), EL_STR("VP"), EL_STR("V"), EL_STR("PP")));
rules = native_list_append(rules, make_rule3(EL_STR("VP-V-NP-PP"), EL_STR("VP"), EL_STR("V"), EL_STR("NP"), EL_STR("PP")));
rules = native_list_append(rules, make_rule2(EL_STR("VP-AUX-V"), EL_STR("VP"), EL_STR("Aux"), EL_STR("V")));
rules = native_list_append(rules, make_rule3(EL_STR("VP-AUX-V-NP"), EL_STR("VP"), EL_STR("Aux"), EL_STR("V"), EL_STR("NP")));
rules = native_list_append(rules, make_rule2(EL_STR("PP-P-NP"), EL_STR("PP"), EL_STR("P"), EL_STR("NP")));
return rules;
return 0;
}
el_val_t get_rules(void) {
return build_rules();
return 0;
}
el_val_t find_rule(el_val_t rule_id_str) {
el_val_t rules = get_rules();
el_val_t n = native_list_len(rules);
el_val_t i = 0;
while (i < n) {
el_val_t rule = native_list_get(rules, i);
el_val_t id = native_list_get(rule, 0);
if (str_eq(id, rule_id_str)) {
return rule;
}
i = (i + 1);
}
el_val_t empty = native_list_empty();
return empty;
return 0;
}
el_val_t make_leaf(el_val_t label, el_val_t word) {
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("("), label), EL_STR(" ")), word), EL_STR(")"));
return 0;
}
el_val_t make_node1(el_val_t label, el_val_t child0) {
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("("), label), EL_STR(" _ ")), child0), EL_STR(")"));
return 0;
}
el_val_t make_node2(el_val_t label, el_val_t child0, el_val_t child1) {
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("("), label), EL_STR(" _ ")), child0), EL_STR(" ")), child1), EL_STR(")"));
return 0;
}
el_val_t make_node3(el_val_t label, el_val_t child0, el_val_t child1, el_val_t child2) {
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("("), label), EL_STR(" _ ")), child0), EL_STR(" ")), child1), EL_STR(" ")), child2), EL_STR(")"));
return 0;
}
el_val_t make_node4(el_val_t label, el_val_t child0, el_val_t child1, el_val_t child2, el_val_t child3) {
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("("), label), EL_STR(" _ ")), child0), EL_STR(" ")), child1), EL_STR(" ")), child2), EL_STR(" ")), child3), EL_STR(")"));
return 0;
}
el_val_t nlg_is_ws(el_val_t c) {
if (str_eq(c, EL_STR(" "))) {
return 1;
}
if (str_eq(c, EL_STR("\t"))) {
return 1;
}
if (str_eq(c, EL_STR("\n"))) {
return 1;
}
return 0;
return 0;
}
el_val_t skip_ws(el_val_t s, el_val_t pos) {
el_val_t n = str_len(s);
el_val_t i = pos;
el_val_t running = 1;
while (running) {
if (i >= n) {
running = 0;
} else {
el_val_t c = str_slice(s, i, (i + 1));
if (nlg_is_ws(c)) {
i = (i + 1);
} else {
running = 0;
}
}
}
return i;
return 0;
}
el_val_t scan_token(el_val_t s, el_val_t start) {
el_val_t n = str_len(s);
el_val_t i = start;
el_val_t running = 1;
while (running) {
if (i >= n) {
running = 0;
} else {
el_val_t c = str_slice(s, i, (i + 1));
if (nlg_is_ws(c)) {
running = 0;
} else {
if (str_eq(c, EL_STR("("))) {
running = 0;
} else {
if (str_eq(c, EL_STR(")"))) {
running = 0;
} else {
i = (i + 1);
}
}
}
}
}
el_val_t tok = str_slice(s, start, i);
el_val_t result = native_list_empty();
result = native_list_append(result, tok);
result = native_list_append(result, int_to_str(i));
return result;
return 0;
}
el_val_t render_tree(el_val_t tree) {
el_val_t words = native_list_empty();
el_val_t n = str_len(tree);
el_val_t i = 0;
el_val_t prev_was_open = 0;
while (i < n) {
el_val_t c = str_slice(tree, i, (i + 1));
if (str_eq(c, EL_STR("("))) {
prev_was_open = 1;
i = (i + 1);
} else {
if (str_eq(c, EL_STR(")"))) {
prev_was_open = 0;
i = (i + 1);
} else {
if (nlg_is_ws(c)) {
i = (i + 1);
} else {
el_val_t tok_info = scan_token(tree, i);
el_val_t tok = native_list_get(tok_info, 0);
el_val_t new_i = str_to_int(native_list_get(tok_info, 1));
i = new_i;
if (prev_was_open) {
prev_was_open = 0;
} else {
if (!str_eq(tok, EL_STR("_"))) {
words = native_list_append(words, tok);
}
}
}
}
}
}
return str_join(words, EL_STR(" "));
return 0;
}
el_val_t gram_word_order(el_val_t profile) {
return lang_word_order(profile);
return 0;
}
el_val_t gram_order_constituents(el_val_t subj, el_val_t verb, el_val_t obj, el_val_t profile) {
el_val_t order = gram_word_order(profile);
el_val_t parts = native_list_empty();
if (str_eq(order, EL_STR("SVO"))) {
if (!str_eq(subj, EL_STR(""))) {
parts = native_list_append(parts, subj);
}
if (!str_eq(verb, EL_STR(""))) {
parts = native_list_append(parts, verb);
}
if (!str_eq(obj, EL_STR(""))) {
parts = native_list_append(parts, obj);
}
return str_join(parts, EL_STR(" "));
}
if (str_eq(order, EL_STR("SOV"))) {
if (!str_eq(subj, EL_STR(""))) {
parts = native_list_append(parts, subj);
}
if (!str_eq(obj, EL_STR(""))) {
parts = native_list_append(parts, obj);
}
if (!str_eq(verb, EL_STR(""))) {
parts = native_list_append(parts, verb);
}
return str_join(parts, EL_STR(" "));
}
if (str_eq(order, EL_STR("VSO"))) {
if (!str_eq(verb, EL_STR(""))) {
parts = native_list_append(parts, verb);
}
if (!str_eq(subj, EL_STR(""))) {
parts = native_list_append(parts, subj);
}
if (!str_eq(obj, EL_STR(""))) {
parts = native_list_append(parts, obj);
}
return str_join(parts, EL_STR(" "));
}
if (str_eq(order, EL_STR("VOS"))) {
if (!str_eq(verb, EL_STR(""))) {
parts = native_list_append(parts, verb);
}
if (!str_eq(obj, EL_STR(""))) {
parts = native_list_append(parts, obj);
}
if (!str_eq(subj, EL_STR(""))) {
parts = native_list_append(parts, subj);
}
return str_join(parts, EL_STR(" "));
}
if (str_eq(order, EL_STR("OVS"))) {
if (!str_eq(obj, EL_STR(""))) {
parts = native_list_append(parts, obj);
}
if (!str_eq(verb, EL_STR(""))) {
parts = native_list_append(parts, verb);
}
if (!str_eq(subj, EL_STR(""))) {
parts = native_list_append(parts, subj);
}
return str_join(parts, EL_STR(" "));
}
if (str_eq(order, EL_STR("OSV"))) {
if (!str_eq(obj, EL_STR(""))) {
parts = native_list_append(parts, obj);
}
if (!str_eq(subj, EL_STR(""))) {
parts = native_list_append(parts, subj);
}
if (!str_eq(verb, EL_STR(""))) {
parts = native_list_append(parts, verb);
}
return str_join(parts, EL_STR(" "));
}
if (!str_eq(subj, EL_STR(""))) {
parts = native_list_append(parts, subj);
}
if (!str_eq(verb, EL_STR(""))) {
parts = native_list_append(parts, verb);
}
if (!str_eq(obj, EL_STR(""))) {
parts = native_list_append(parts, obj);
}
return str_join(parts, EL_STR(" "));
return 0;
}
el_val_t gram_build_vp(el_val_t verb, el_val_t aux, el_val_t profile) {
if (str_eq(aux, EL_STR(""))) {
return verb;
}
return el_str_concat(el_str_concat(aux, EL_STR(" ")), verb);
return 0;
}
el_val_t gram_question_strategy(el_val_t profile) {
el_val_t code = lang_get(profile, EL_STR("code"));
if (str_eq(code, EL_STR("en"))) {
return EL_STR("do-support");
}
if (str_eq(code, EL_STR("ja"))) {
return EL_STR("particle");
}
if (str_eq(code, EL_STR("zh"))) {
return EL_STR("intonation");
}
if (str_eq(code, EL_STR("es"))) {
return EL_STR("intonation");
}
if (str_eq(code, EL_STR("fr"))) {
return EL_STR("inversion");
}
if (str_eq(code, EL_STR("de"))) {
return EL_STR("inversion");
}
if (str_eq(code, EL_STR("ar"))) {
return EL_STR("intonation");
}
if (str_eq(code, EL_STR("hi"))) {
return EL_STR("particle");
}
if (str_eq(code, EL_STR("ru"))) {
return EL_STR("intonation");
}
if (str_eq(code, EL_STR("fi"))) {
return EL_STR("particle");
}
if (str_eq(code, EL_STR("sw"))) {
return EL_STR("intonation");
}
if (str_eq(code, EL_STR("la"))) {
return EL_STR("intonation");
}
if (str_eq(code, EL_STR("he"))) {
return EL_STR("intonation");
}
if (str_eq(code, EL_STR("grc"))) {
return EL_STR("intonation");
}
if (str_eq(code, EL_STR("ang"))) {
return EL_STR("intonation");
}
if (str_eq(code, EL_STR("sa"))) {
return EL_STR("intonation");
}
if (str_eq(code, EL_STR("got"))) {
return EL_STR("intonation");
}
if (str_eq(code, EL_STR("non"))) {
return EL_STR("intonation");
}
if (str_eq(code, EL_STR("enm"))) {
return EL_STR("do-support");
}
if (str_eq(code, EL_STR("pi"))) {
return EL_STR("intonation");
}
return EL_STR("intonation");
return 0;
}
el_val_t is_pronoun(el_val_t word) {
if (str_eq(word, EL_STR("I"))) {
return 1;
}
if (str_eq(word, EL_STR("you"))) {
return 1;
}
if (str_eq(word, EL_STR("he"))) {
return 1;
}
if (str_eq(word, EL_STR("she"))) {
return 1;
}
if (str_eq(word, EL_STR("it"))) {
return 1;
}
if (str_eq(word, EL_STR("we"))) {
return 1;
}
if (str_eq(word, EL_STR("they"))) {
return 1;
}
if (str_eq(word, EL_STR("me"))) {
return 1;
}
if (str_eq(word, EL_STR("him"))) {
return 1;
}
if (str_eq(word, EL_STR("her"))) {
return 1;
}
if (str_eq(word, EL_STR("us"))) {
return 1;
}
if (str_eq(word, EL_STR("them"))) {
return 1;
}
return 0;
return 0;
}
el_val_t build_np(el_val_t referent, el_val_t slots) {
if (is_pronoun(referent)) {
return make_node1(EL_STR("NP"), make_leaf(EL_STR("Pron"), referent));
}
el_val_t parts = str_split(referent, EL_STR(" "));
el_val_t np = native_list_len(parts);
if (np == 1) {
return make_node1(EL_STR("NP"), make_leaf(EL_STR("N"), referent));
}
if (np == 2) {
el_val_t det = native_list_get(parts, 0);
el_val_t noun = native_list_get(parts, 1);
return make_node2(EL_STR("NP"), make_leaf(EL_STR("Det"), det), make_leaf(EL_STR("N"), noun));
}
if (np == 3) {
el_val_t det = native_list_get(parts, 0);
el_val_t adj = native_list_get(parts, 1);
el_val_t noun = native_list_get(parts, 2);
return make_node3(EL_STR("NP"), make_leaf(EL_STR("Det"), det), make_leaf(EL_STR("Adj"), adj), make_leaf(EL_STR("N"), noun));
}
return make_node1(EL_STR("NP"), make_leaf(EL_STR("N"), referent));
return 0;
}
el_val_t build_pp(el_val_t loc) {
el_val_t parts = str_split(loc, EL_STR(" "));
el_val_t n = native_list_len(parts);
if (n < 2) {
return make_leaf(EL_STR("PP"), loc);
}
el_val_t prep = native_list_get(parts, 0);
el_val_t np_parts = native_list_empty();
el_val_t i = 1;
while (i < n) {
np_parts = native_list_append(np_parts, native_list_get(parts, i));
i = (i + 1);
}
el_val_t np_str = str_join(np_parts, EL_STR(" "));
el_val_t np_tree = build_np(np_str, native_list_empty());
return make_node2(EL_STR("PP"), make_leaf(EL_STR("P"), prep), np_tree);
return 0;
}
el_val_t build_vp_body(el_val_t slots) {
el_val_t verb_surf = slots_get(slots, EL_STR("verb_surf"));
el_val_t patient = slots_get(slots, EL_STR("patient"));
el_val_t loc = slots_get(slots, EL_STR("location"));
if (!str_eq(patient, EL_STR(""))) {
el_val_t obj_np = build_np(patient, slots);
if (!str_eq(loc, EL_STR(""))) {
el_val_t pp = build_pp(loc);
return make_node3(EL_STR("VP"), make_leaf(EL_STR("V"), verb_surf), obj_np, pp);
}
return make_node2(EL_STR("VP"), make_leaf(EL_STR("V"), verb_surf), obj_np);
}
if (!str_eq(loc, EL_STR(""))) {
el_val_t pp = build_pp(loc);
return make_node2(EL_STR("VP"), make_leaf(EL_STR("V"), verb_surf), pp);
}
return make_node1(EL_STR("VP"), make_leaf(EL_STR("V"), verb_surf));
return 0;
}
el_val_t build_vp_from_slots(el_val_t slots) {
el_val_t aux_surf = slots_get(slots, EL_STR("aux_surf"));
if (!str_eq(aux_surf, EL_STR(""))) {
el_val_t verb_surf = slots_get(slots, EL_STR("verb_surf"));
el_val_t patient = slots_get(slots, EL_STR("patient"));
el_val_t loc = slots_get(slots, EL_STR("location"));
if (!str_eq(patient, EL_STR(""))) {
el_val_t obj_np = build_np(patient, slots);
return make_node3(EL_STR("VP"), make_leaf(EL_STR("Aux"), aux_surf), make_leaf(EL_STR("V"), verb_surf), obj_np);
}
return make_node2(EL_STR("VP"), make_leaf(EL_STR("Aux"), aux_surf), make_leaf(EL_STR("V"), verb_surf));
}
return build_vp_body(slots);
return 0;
}
el_val_t generate_tree(el_val_t rule_id_str, el_val_t slots) {
el_val_t rule = find_rule(rule_id_str);
el_val_t n = native_list_len(rule);
if (n == 0) {
return make_leaf(EL_STR("ERR"), EL_STR("unknown-rule"));
}
el_val_t lhs = native_list_get(rule, 1);
if (str_eq(rule_id_str, EL_STR("S-DECL"))) {
el_val_t agent = slots_get(slots, EL_STR("agent"));
el_val_t np_tree = build_np(agent, slots);
el_val_t vp_tree = build_vp_from_slots(slots);
return make_node2(EL_STR("S"), np_tree, vp_tree);
}
if (str_eq(rule_id_str, EL_STR("S-QUEST"))) {
el_val_t agent = slots_get(slots, EL_STR("agent"));
el_val_t np_tree = build_np(agent, slots);
el_val_t vp_tree = build_vp_body(slots);
el_val_t aux_surf = slots_get(slots, EL_STR("aux_surf"));
return make_node3(EL_STR("S"), make_leaf(EL_STR("Aux"), aux_surf), np_tree, vp_tree);
}
if (str_eq(rule_id_str, EL_STR("S-IMP"))) {
el_val_t vp_tree = build_vp_from_slots(slots);
return make_node1(EL_STR("S"), vp_tree);
}
return make_leaf(lhs, EL_STR("?"));
return 0;
}
Generated Vendored
+38
View File
@@ -0,0 +1,38 @@
// auto-generated by elc --emit-header — do not edit
extern fn slots_get(slots: [String], key: String) -> String
extern fn slots_set(slots: [String], key: String, val: String) -> [String]
extern fn make_slots(k0: String, v0: String) -> [String]
extern fn make_slots2(k0: String, v0: String, k1: String, v1: String) -> [String]
extern fn make_slots3(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String) -> [String]
extern fn make_slots4(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String, k3: String, v3: String) -> [String]
extern fn make_slots5(k0: String, v0: String, k1: String, v1: String, k2: String, v2: String, k3: String, v3: String, k4: String, v4: String) -> [String]
extern fn rule_id(rule: [String]) -> String
extern fn rule_lhs(rule: [String]) -> String
extern fn rule_rhs_len(rule: [String]) -> Int
extern fn rule_rhs(rule: [String], idx: Int) -> String
extern fn make_rule(id: String, lhs: String, r0: String) -> [String]
extern fn make_rule2(id: String, lhs: String, r0: String, r1: String) -> [String]
extern fn make_rule3(id: String, lhs: String, r0: String, r1: String, r2: String) -> [String]
extern fn make_rule4(id: String, lhs: String, r0: String, r1: String, r2: String, r3: String) -> [String]
extern fn build_rules() -> [[String]]
extern fn get_rules() -> [[String]]
extern fn find_rule(rule_id_str: String) -> [String]
extern fn make_leaf(label: String, word: String) -> String
extern fn make_node1(label: String, child0: String) -> String
extern fn make_node2(label: String, child0: String, child1: String) -> String
extern fn make_node3(label: String, child0: String, child1: String, child2: String) -> String
extern fn make_node4(label: String, child0: String, child1: String, child2: String, child3: String) -> String
extern fn nlg_is_ws(c: String) -> Bool
extern fn skip_ws(s: String, pos: Int) -> Int
extern fn scan_token(s: String, start: Int) -> [String]
extern fn render_tree(tree: String) -> String
extern fn gram_word_order(profile: [String]) -> String
extern fn gram_order_constituents(subj: String, verb: String, obj: String, profile: [String]) -> String
extern fn gram_build_vp(verb: String, aux: String, profile: [String]) -> String
extern fn gram_question_strategy(profile: [String]) -> String
extern fn is_pronoun(word: String) -> Bool
extern fn build_np(referent: String, slots: [String]) -> String
extern fn build_pp(loc: String) -> String
extern fn build_vp_body(slots: [String]) -> String
extern fn build_vp_from_slots(slots: [String]) -> String
extern fn generate_tree(rule_id_str: String, slots: [String]) -> String
Generated Vendored
+72
View File
@@ -0,0 +1,72 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t imprint_current(void);
el_val_t imprint_load(el_val_t imprint_id);
el_val_t imprint_respond(el_val_t input, el_val_t imprint_id);
el_val_t imprint_surface_knowledge(el_val_t query, el_val_t imprint_id);
el_val_t imprint_surface_memory_read(el_val_t query);
el_val_t imprint_unload(void);
el_val_t imprint_current(void) {
el_val_t id = state_get(EL_STR("active_imprint_id"));
return ({ el_val_t _if_result_1 = 0; if (str_eq(id, EL_STR(""))) { _if_result_1 = (EL_STR("base")); } else { _if_result_1 = (id); } _if_result_1; });
return 0;
}
el_val_t imprint_load(el_val_t imprint_id) {
el_val_t label = el_str_concat(EL_STR("imprint:"), imprint_id);
el_val_t results = engram_search_json(label, 1);
if (str_eq(results, EL_STR(""))) {
return el_str_concat(el_str_concat(EL_STR("{\"ok\":false,\"error\":\"imprint not found: "), imprint_id), EL_STR("\"}"));
}
if (str_eq(results, EL_STR("[]"))) {
return el_str_concat(el_str_concat(EL_STR("{\"ok\":false,\"error\":\"imprint not found: "), imprint_id), EL_STR("\"}"));
}
el_val_t found_label = json_get(results, EL_STR("label"));
if (str_eq(found_label, label)) {
state_set(EL_STR("active_imprint_id"), imprint_id);
return el_str_concat(el_str_concat(EL_STR("{\"ok\":true,\"id\":\""), imprint_id), EL_STR("\"}"));
}
return el_str_concat(el_str_concat(EL_STR("{\"ok\":false,\"error\":\"imprint not found: "), imprint_id), EL_STR("\"}"));
return 0;
}
el_val_t imprint_respond(el_val_t input, el_val_t imprint_id) {
if (str_eq(imprint_id, EL_STR("base"))) {
return input;
}
if (str_eq(imprint_id, EL_STR(""))) {
return input;
}
el_val_t current = imprint_current();
if (str_eq(current, imprint_id)) {
return el_str_concat(el_str_concat(el_str_concat(input, EL_STR(" [imprint:")), imprint_id), EL_STR(" active]"));
}
return input;
return 0;
}
el_val_t imprint_surface_knowledge(el_val_t query, el_val_t imprint_id) {
if (str_eq(imprint_id, EL_STR("base"))) {
return engram_search_json(query, 10);
}
if (str_eq(imprint_id, EL_STR(""))) {
return engram_search_json(query, 10);
}
el_val_t scoped_query = el_str_concat(el_str_concat(query, EL_STR(" domain:")), imprint_id);
return engram_search_json(scoped_query, 10);
return 0;
}
el_val_t imprint_surface_memory_read(el_val_t query) {
return engram_search_json(query, 10);
return 0;
}
el_val_t imprint_unload(void) {
state_set(EL_STR("active_imprint_id"), EL_STR(""));
return 0;
}
Generated Vendored
+7
View File
@@ -0,0 +1,7 @@
// auto-generated by elc --emit-header — do not edit
extern fn imprint_current() -> String
extern fn imprint_load(imprint_id: String) -> String
extern fn imprint_respond(input: String, imprint_id: String) -> String
extern fn imprint_surface_knowledge(query: String, imprint_id: String) -> String
extern fn imprint_surface_memory_read(query: String) -> String
extern fn imprint_unload() -> Void
Generated Vendored
+394
View File
@@ -0,0 +1,394 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t lang_profile(el_val_t code, el_val_t word_order, el_val_t morph_type, el_val_t has_case, el_val_t has_gender, el_val_t script_dir, el_val_t agreement, el_val_t null_subject);
el_val_t lang_get(el_val_t profile, el_val_t key);
el_val_t lang_profile_en(void);
el_val_t lang_profile_ja(void);
el_val_t lang_profile_ar(void);
el_val_t lang_profile_zh(void);
el_val_t lang_profile_de(void);
el_val_t lang_profile_es(void);
el_val_t lang_profile_fi(void);
el_val_t lang_profile_sw(void);
el_val_t lang_profile_hi(void);
el_val_t lang_profile_ru(void);
el_val_t lang_profile_fr(void);
el_val_t lang_profile_la(void);
el_val_t lang_profile_he(void);
el_val_t lang_profile_sa(void);
el_val_t lang_profile_got(void);
el_val_t lang_profile_non(void);
el_val_t lang_profile_enm(void);
el_val_t lang_profile_pi(void);
el_val_t lang_profile_grc(void);
el_val_t lang_profile_ang(void);
el_val_t lang_profile_fro(void);
el_val_t lang_profile_goh(void);
el_val_t lang_profile_sga(void);
el_val_t lang_profile_txb(void);
el_val_t lang_profile_peo(void);
el_val_t lang_profile_akk(void);
el_val_t lang_profile_uga(void);
el_val_t lang_profile_egy(void);
el_val_t lang_profile_sux(void);
el_val_t lang_profile_gez(void);
el_val_t lang_profile_cop(void);
el_val_t lang_from_code(el_val_t code);
el_val_t lang_default(void);
el_val_t lang_is_isolating(el_val_t profile);
el_val_t lang_is_agglutinative(el_val_t profile);
el_val_t lang_is_fusional(el_val_t profile);
el_val_t lang_is_polysynthetic(el_val_t profile);
el_val_t lang_is_rtl(el_val_t profile);
el_val_t lang_has_null_subject(el_val_t profile);
el_val_t lang_has_case(el_val_t profile);
el_val_t lang_has_gender(el_val_t profile);
el_val_t lang_word_order(el_val_t profile);
el_val_t lang_code(el_val_t profile);
el_val_t lang_profile(el_val_t code, el_val_t word_order, el_val_t morph_type, el_val_t has_case, el_val_t has_gender, el_val_t script_dir, el_val_t agreement, el_val_t null_subject) {
el_val_t r = native_list_empty();
r = native_list_append(r, EL_STR("code"));
r = native_list_append(r, code);
r = native_list_append(r, EL_STR("word_order"));
r = native_list_append(r, word_order);
r = native_list_append(r, EL_STR("morph_type"));
r = native_list_append(r, morph_type);
r = native_list_append(r, EL_STR("has_case"));
r = native_list_append(r, has_case);
r = native_list_append(r, EL_STR("has_gender"));
r = native_list_append(r, has_gender);
r = native_list_append(r, EL_STR("script_dir"));
r = native_list_append(r, script_dir);
r = native_list_append(r, EL_STR("agreement"));
r = native_list_append(r, agreement);
r = native_list_append(r, EL_STR("null_subject"));
r = native_list_append(r, null_subject);
return r;
return 0;
}
el_val_t lang_get(el_val_t profile, el_val_t key) {
el_val_t n = native_list_len(profile);
el_val_t i = 0;
while (i < (n - 1)) {
el_val_t k = native_list_get(profile, i);
if (str_eq(k, key)) {
return native_list_get(profile, (i + 1));
}
i = (i + 2);
}
return EL_STR("");
return 0;
}
el_val_t lang_profile_en(void) {
return lang_profile(EL_STR("en"), EL_STR("SVO"), EL_STR("fusional"), EL_STR("false"), EL_STR("false"), EL_STR("ltr"), EL_STR("number;person"), EL_STR("false"));
return 0;
}
el_val_t lang_profile_ja(void) {
return lang_profile(EL_STR("ja"), EL_STR("SOV"), EL_STR("agglutinative"), EL_STR("false"), EL_STR("false"), EL_STR("ltr"), EL_STR("none"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_ar(void) {
return lang_profile(EL_STR("ar"), EL_STR("VSO"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("rtl"), EL_STR("number;person;gender;case"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_zh(void) {
return lang_profile(EL_STR("zh"), EL_STR("SVO"), EL_STR("isolating"), EL_STR("false"), EL_STR("false"), EL_STR("ltr"), EL_STR("none"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_de(void) {
return lang_profile(EL_STR("de"), EL_STR("SOV"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("false"));
return 0;
}
el_val_t lang_profile_es(void) {
return lang_profile(EL_STR("es"), EL_STR("SVO"), EL_STR("fusional"), EL_STR("false"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_fi(void) {
return lang_profile(EL_STR("fi"), EL_STR("SOV"), EL_STR("agglutinative"), EL_STR("true"), EL_STR("false"), EL_STR("ltr"), EL_STR("number;person;case"), EL_STR("false"));
return 0;
}
el_val_t lang_profile_sw(void) {
return lang_profile(EL_STR("sw"), EL_STR("SVO"), EL_STR("agglutinative"), EL_STR("false"), EL_STR("false"), EL_STR("ltr"), EL_STR("noun-class;number"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_hi(void) {
return lang_profile(EL_STR("hi"), EL_STR("SOV"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_ru(void) {
return lang_profile(EL_STR("ru"), EL_STR("free"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("false"));
return 0;
}
el_val_t lang_profile_fr(void) {
return lang_profile(EL_STR("fr"), EL_STR("SVO"), EL_STR("fusional"), EL_STR("false"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender"), EL_STR("false"));
return 0;
}
el_val_t lang_profile_la(void) {
return lang_profile(EL_STR("la"), EL_STR("SOV"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_he(void) {
return lang_profile(EL_STR("he"), EL_STR("SVO"), EL_STR("semitic"), EL_STR("true"), EL_STR("false"), EL_STR("rtl"), EL_STR("number;person;gender"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_sa(void) {
return lang_profile(EL_STR("sa"), EL_STR("SOV"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_got(void) {
return lang_profile(EL_STR("got"), EL_STR("SOV"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_non(void) {
return lang_profile(EL_STR("non"), EL_STR("SOV"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_enm(void) {
return lang_profile(EL_STR("enm"), EL_STR("SVO"), EL_STR("fusional"), EL_STR("false"), EL_STR("false"), EL_STR("ltr"), EL_STR("number;person"), EL_STR("false"));
return 0;
}
el_val_t lang_profile_pi(void) {
return lang_profile(EL_STR("pi"), EL_STR("SOV"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_grc(void) {
return lang_profile(EL_STR("grc"), EL_STR("SOV"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case;aspect"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_ang(void) {
return lang_profile(EL_STR("ang"), EL_STR("SOV"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_fro(void) {
return lang_profile(EL_STR("fro"), EL_STR("SVO"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("false"));
return 0;
}
el_val_t lang_profile_goh(void) {
return lang_profile(EL_STR("goh"), EL_STR("SOV"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_sga(void) {
return lang_profile(EL_STR("sga"), EL_STR("VSO"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_txb(void) {
return lang_profile(EL_STR("txb"), EL_STR("SOV"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("false"));
return 0;
}
el_val_t lang_profile_peo(void) {
return lang_profile(EL_STR("peo"), EL_STR("SOV"), EL_STR("fusional"), EL_STR("true"), EL_STR("false"), EL_STR("ltr"), EL_STR("number;person;case"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_akk(void) {
return lang_profile(EL_STR("akk"), EL_STR("VSO"), EL_STR("fusional"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("false"));
return 0;
}
el_val_t lang_profile_uga(void) {
return lang_profile(EL_STR("uga"), EL_STR("VSO"), EL_STR("semitic"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender;case"), EL_STR("false"));
return 0;
}
el_val_t lang_profile_egy(void) {
return lang_profile(EL_STR("egy"), EL_STR("SVO"), EL_STR("agglutinative"), EL_STR("false"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_sux(void) {
return lang_profile(EL_STR("sux"), EL_STR("SOV"), EL_STR("agglutinative"), EL_STR("true"), EL_STR("false"), EL_STR("ltr"), EL_STR("number;person"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_gez(void) {
return lang_profile(EL_STR("gez"), EL_STR("SOV"), EL_STR("semitic"), EL_STR("true"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender"), EL_STR("true"));
return 0;
}
el_val_t lang_profile_cop(void) {
return lang_profile(EL_STR("cop"), EL_STR("SVO"), EL_STR("agglutinative"), EL_STR("false"), EL_STR("true"), EL_STR("ltr"), EL_STR("number;person;gender"), EL_STR("false"));
return 0;
}
el_val_t lang_from_code(el_val_t code) {
if (str_eq(code, EL_STR("en"))) {
return lang_profile_en();
}
if (str_eq(code, EL_STR("ja"))) {
return lang_profile_ja();
}
if (str_eq(code, EL_STR("ar"))) {
return lang_profile_ar();
}
if (str_eq(code, EL_STR("zh"))) {
return lang_profile_zh();
}
if (str_eq(code, EL_STR("de"))) {
return lang_profile_de();
}
if (str_eq(code, EL_STR("es"))) {
return lang_profile_es();
}
if (str_eq(code, EL_STR("fi"))) {
return lang_profile_fi();
}
if (str_eq(code, EL_STR("sw"))) {
return lang_profile_sw();
}
if (str_eq(code, EL_STR("hi"))) {
return lang_profile_hi();
}
if (str_eq(code, EL_STR("ru"))) {
return lang_profile_ru();
}
if (str_eq(code, EL_STR("fr"))) {
return lang_profile_fr();
}
if (str_eq(code, EL_STR("la"))) {
return lang_profile_la();
}
if (str_eq(code, EL_STR("he"))) {
return lang_profile_he();
}
if (str_eq(code, EL_STR("grc"))) {
return lang_profile_grc();
}
if (str_eq(code, EL_STR("ang"))) {
return lang_profile_ang();
}
if (str_eq(code, EL_STR("sa"))) {
return lang_profile_sa();
}
if (str_eq(code, EL_STR("got"))) {
return lang_profile_got();
}
if (str_eq(code, EL_STR("non"))) {
return lang_profile_non();
}
if (str_eq(code, EL_STR("enm"))) {
return lang_profile_enm();
}
if (str_eq(code, EL_STR("pi"))) {
return lang_profile_pi();
}
if (str_eq(code, EL_STR("fro"))) {
return lang_profile_fro();
}
if (str_eq(code, EL_STR("goh"))) {
return lang_profile_goh();
}
if (str_eq(code, EL_STR("sga"))) {
return lang_profile_sga();
}
if (str_eq(code, EL_STR("txb"))) {
return lang_profile_txb();
}
if (str_eq(code, EL_STR("peo"))) {
return lang_profile_peo();
}
if (str_eq(code, EL_STR("akk"))) {
return lang_profile_akk();
}
if (str_eq(code, EL_STR("uga"))) {
return lang_profile_uga();
}
if (str_eq(code, EL_STR("egy"))) {
return lang_profile_egy();
}
if (str_eq(code, EL_STR("sux"))) {
return lang_profile_sux();
}
if (str_eq(code, EL_STR("gez"))) {
return lang_profile_gez();
}
if (str_eq(code, EL_STR("cop"))) {
return lang_profile_cop();
}
return lang_profile_en();
return 0;
}
el_val_t lang_default(void) {
return lang_profile_en();
return 0;
}
el_val_t lang_is_isolating(el_val_t profile) {
return str_eq(lang_get(profile, EL_STR("morph_type")), EL_STR("isolating"));
return 0;
}
el_val_t lang_is_agglutinative(el_val_t profile) {
return str_eq(lang_get(profile, EL_STR("morph_type")), EL_STR("agglutinative"));
return 0;
}
el_val_t lang_is_fusional(el_val_t profile) {
return str_eq(lang_get(profile, EL_STR("morph_type")), EL_STR("fusional"));
return 0;
}
el_val_t lang_is_polysynthetic(el_val_t profile) {
return str_eq(lang_get(profile, EL_STR("morph_type")), EL_STR("polysynthetic"));
return 0;
}
el_val_t lang_is_rtl(el_val_t profile) {
return str_eq(lang_get(profile, EL_STR("script_dir")), EL_STR("rtl"));
return 0;
}
el_val_t lang_has_null_subject(el_val_t profile) {
return str_eq(lang_get(profile, EL_STR("null_subject")), EL_STR("true"));
return 0;
}
el_val_t lang_has_case(el_val_t profile) {
return str_eq(lang_get(profile, EL_STR("has_case")), EL_STR("true"));
return 0;
}
el_val_t lang_has_gender(el_val_t profile) {
return str_eq(lang_get(profile, EL_STR("has_gender")), EL_STR("true"));
return 0;
}
el_val_t lang_word_order(el_val_t profile) {
return lang_get(profile, EL_STR("word_order"));
return 0;
}
el_val_t lang_code(el_val_t profile) {
return lang_get(profile, EL_STR("code"));
return 0;
}
Generated Vendored
+46
View File
@@ -0,0 +1,46 @@
// auto-generated by elc --emit-header — do not edit
extern fn lang_profile(code: String, word_order: String, morph_type: String, has_case: String, has_gender: String, script_dir: String, agreement: String, null_subject: String) -> [String]
extern fn lang_get(profile: [String], key: String) -> String
extern fn lang_profile_en() -> [String]
extern fn lang_profile_ja() -> [String]
extern fn lang_profile_ar() -> [String]
extern fn lang_profile_zh() -> [String]
extern fn lang_profile_de() -> [String]
extern fn lang_profile_es() -> [String]
extern fn lang_profile_fi() -> [String]
extern fn lang_profile_sw() -> [String]
extern fn lang_profile_hi() -> [String]
extern fn lang_profile_ru() -> [String]
extern fn lang_profile_fr() -> [String]
extern fn lang_profile_la() -> [String]
extern fn lang_profile_he() -> [String]
extern fn lang_profile_sa() -> [String]
extern fn lang_profile_got() -> [String]
extern fn lang_profile_non() -> [String]
extern fn lang_profile_enm() -> [String]
extern fn lang_profile_pi() -> [String]
extern fn lang_profile_grc() -> [String]
extern fn lang_profile_ang() -> [String]
extern fn lang_profile_fro() -> [String]
extern fn lang_profile_goh() -> [String]
extern fn lang_profile_sga() -> [String]
extern fn lang_profile_txb() -> [String]
extern fn lang_profile_peo() -> [String]
extern fn lang_profile_akk() -> [String]
extern fn lang_profile_uga() -> [String]
extern fn lang_profile_egy() -> [String]
extern fn lang_profile_sux() -> [String]
extern fn lang_profile_gez() -> [String]
extern fn lang_profile_cop() -> [String]
extern fn lang_from_code(code: String) -> [String]
extern fn lang_default() -> [String]
extern fn lang_is_isolating(profile: [String]) -> Bool
extern fn lang_is_agglutinative(profile: [String]) -> Bool
extern fn lang_is_fusional(profile: [String]) -> Bool
extern fn lang_is_polysynthetic(profile: [String]) -> Bool
extern fn lang_is_rtl(profile: [String]) -> Bool
extern fn lang_has_null_subject(profile: [String]) -> Bool
extern fn lang_has_case(profile: [String]) -> Bool
extern fn lang_has_gender(profile: [String]) -> Bool
extern fn lang_word_order(profile: [String]) -> String
extern fn lang_code(profile: [String]) -> String
Generated Vendored
+225
View File
@@ -0,0 +1,225 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t tier_working(void);
el_val_t tier_episodic(void);
el_val_t tier_canonical(void);
el_val_t mem_store(el_val_t content, el_val_t label, el_val_t tags);
el_val_t mem_remember(el_val_t content, el_val_t tags);
el_val_t mem_recall(el_val_t query, el_val_t depth);
el_val_t mem_search(el_val_t query, el_val_t limit);
el_val_t mem_strengthen(el_val_t node_id);
el_val_t mem_tombstone(el_val_t node_id);
el_val_t mem_forget(el_val_t node_id);
el_val_t mem_consolidate(void);
el_val_t mem_save(el_val_t path);
el_val_t mem_load(el_val_t path);
el_val_t mem_boot_count_get(void);
el_val_t mem_boot_count_inc(void);
el_val_t mem_emit_state_event(el_val_t trigger, el_val_t kind, el_val_t content);
el_val_t tier_working(void) {
return EL_STR("Working");
return 0;
}
el_val_t tier_episodic(void) {
return EL_STR("Episodic");
return 0;
}
el_val_t tier_canonical(void) {
return EL_STR("Canonical");
return 0;
}
el_val_t mem_store(el_val_t content, el_val_t label, el_val_t tags) {
el_val_t id = engram_node_full(content, EL_STR("Memory"), label, el_from_float(0.5), el_from_float(0.5), el_from_float(0.8), EL_STR("Working"), tags);
if (str_eq(id, EL_STR(""))) {
println(el_str_concat(EL_STR("[memory] write rejected by engram (empty id): label="), label));
return EL_STR("");
}
el_val_t readback = engram_get_node_json(id);
if (str_eq(readback, EL_STR("")) || str_eq(readback, EL_STR("{}"))) {
println(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("[memory] WRITE VERIFY FAILED: label="), label), EL_STR(" id=")), id), EL_STR(" \xe2\x80\x94 node absent after write")));
return EL_STR("");
}
println(el_str_concat(el_str_concat(EL_STR("[memory] write verified: "), id), EL_STR(" ok")));
return id;
return 0;
}
el_val_t mem_remember(el_val_t content, el_val_t tags) {
return mem_store(content, EL_STR("soul-memory"), tags);
return 0;
}
el_val_t mem_recall(el_val_t query, el_val_t depth) {
return engram_activate_json(query, depth);
return 0;
}
el_val_t mem_search(el_val_t query, el_val_t limit) {
return engram_search_json(query, limit);
return 0;
}
el_val_t mem_strengthen(el_val_t node_id) {
engram_strengthen(node_id);
return 0;
}
el_val_t mem_tombstone(el_val_t node_id) {
el_val_t tags = EL_STR("[\"Tombstone\",\"status:deleted\"]");
el_val_t marker = engram_node_full(node_id, EL_STR("Tombstone"), el_str_concat(EL_STR("tombstone:"), node_id), el_from_float(0.01), el_from_float(0.01), el_from_float(1.0), EL_STR("Episodic"), tags);
if (!str_eq(marker, EL_STR(""))) {
engram_connect(marker, node_id, el_from_float(1.0), EL_STR("tombstones"));
}
return marker;
return 0;
}
el_val_t mem_forget(el_val_t node_id) {
el_val_t _marker = mem_tombstone(node_id);
return 0;
}
el_val_t mem_consolidate(void) {
el_val_t scanned = engram_node_count();
el_val_t total_edges = engram_edge_count();
el_val_t strengthened = 0;
el_val_t wm_top = engram_wm_top_json(10);
el_val_t wm_len = json_array_len(wm_top);
el_val_t wi = 0;
while (wi < wm_len) {
el_val_t wm_node = json_array_get(wm_top, wi);
el_val_t wm_id = json_get(wm_node, EL_STR("id"));
if (!str_eq(wm_id, EL_STR(""))) {
engram_strengthen(wm_id);
strengthened = (strengthened + 1);
}
wi = (wi + 1);
}
el_val_t scan_result = engram_scan_nodes_json(50, 0);
el_val_t scan_len = json_array_len(scan_result);
el_val_t si = 0;
while (si < scan_len) {
el_val_t s_node = json_array_get(scan_result, si);
el_val_t s_tier = json_get(s_node, EL_STR("tier"));
el_val_t s_id = json_get(s_node, EL_STR("id"));
if (str_eq(s_tier, EL_STR("Canonical")) && !str_eq(s_id, EL_STR(""))) {
engram_strengthen(s_id);
strengthened = (strengthened + 1);
}
si = (si + 1);
}
el_val_t total_nodes = engram_node_count();
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"scanned\":"), int_to_str(scanned)), EL_STR(",\"total_nodes\":")), int_to_str(total_nodes)), EL_STR(",\"total_edges\":")), int_to_str(total_edges)), EL_STR(",\"strengthened\":")), int_to_str(strengthened)), EL_STR("}"));
return 0;
}
el_val_t mem_save(el_val_t path) {
el_val_t saved = engram_save(path);
if (saved == 0) {
println(el_str_concat(el_str_concat(EL_STR("[memory] mem_save: engram_save failed for "), path), EL_STR(" \xe2\x80\x94 snapshot may be incomplete")));
}
return 0;
}
el_val_t mem_load(el_val_t path) {
engram_load(path);
return 0;
}
el_val_t mem_boot_count_get(void) {
el_val_t results = engram_search_json(EL_STR("soul:boot_count"), 3);
if (str_eq(results, EL_STR(""))) {
return 0;
}
if (str_eq(results, EL_STR("[]"))) {
return 0;
}
el_val_t node = json_array_get(results, 0);
el_val_t content = json_get(node, EL_STR("content"));
el_val_t prefix = EL_STR("soul:boot_count:");
if (!str_starts_with(content, prefix)) {
return 0;
}
el_val_t num_str = str_slice(content, str_len(prefix), str_len(content));
return str_to_int(num_str);
return 0;
}
el_val_t mem_boot_count_inc(void) {
el_val_t current = mem_boot_count_get();
el_val_t next = (current + 1);
el_val_t old_results = engram_search_json(EL_STR("soul:boot_count"), 50);
if (!str_eq(old_results, EL_STR("")) && !str_eq(old_results, EL_STR("[]"))) {
el_val_t old_len = json_array_len(old_results);
el_val_t oi = 0;
while (oi < old_len) {
el_val_t old_node = json_array_get(old_results, oi);
el_val_t old_id = json_get(old_node, EL_STR("id"));
if (!str_eq(old_id, EL_STR(""))) {
engram_forget(old_id);
}
oi = (oi + 1);
}
}
el_val_t content = el_str_concat(EL_STR("soul:boot_count:"), int_to_str(next));
el_val_t tags = EL_STR("[\"soul-meta\",\"boot-counter\"]");
el_val_t boot_node_id = engram_node_full(content, EL_STR("Memory"), EL_STR("soul:boot_count"), el_from_float(0.55), el_from_float(0.2), el_from_float(1.0), EL_STR("Working"), tags);
if (str_eq(boot_node_id, EL_STR(""))) {
println(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: write rejected (empty id) \xe2\x80\x94 boot counter node lost (count="), int_to_str(next)), EL_STR(")")));
return next;
}
el_val_t boot_readback = engram_get_node_json(boot_node_id);
if (str_eq(boot_readback, EL_STR("")) || str_eq(boot_readback, EL_STR("{}"))) {
println(el_str_concat(el_str_concat(el_str_concat(EL_STR("[memory] mem_boot_count_inc: WRITE VERIFY FAILED id="), boot_node_id), EL_STR(" count=")), int_to_str(next)));
}
el_val_t wb_url = env(EL_STR("ENGRAM_URL"));
el_val_t wb_key = env(EL_STR("ENGRAM_API_KEY"));
if (!str_eq(wb_url, EL_STR("")) && !str_eq(wb_key, EL_STR(""))) {
el_val_t auth_body = el_str_concat(el_str_concat(EL_STR("{\"_auth\":\""), json_safe(wb_key)), EL_STR("\"}"));
el_val_t srv_old = http_get(el_str_concat(wb_url, EL_STR("/api/search?q=soul:boot_count&limit=20")));
if (!str_eq(srv_old, EL_STR("")) && !str_eq(srv_old, EL_STR("[]"))) {
el_val_t srv_len = json_array_len(srv_old);
el_val_t si = 0;
while (si < srv_len) {
el_val_t srv_node = json_array_get(srv_old, si);
el_val_t srv_content = json_get(srv_node, EL_STR("content"));
if (str_starts_with(srv_content, EL_STR("soul:boot_count:"))) {
el_val_t srv_id = json_get(srv_node, EL_STR("id"));
if (!str_eq(srv_id, EL_STR(""))) {
http_delete_json(el_str_concat(el_str_concat(wb_url, EL_STR("/api/nodes/")), srv_id), auth_body);
}
}
si = (si + 1);
}
}
el_val_t wb_body = el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"content\":\""), content), EL_STR("\",\"node_type\":\"Memory\",\"label\":\"soul:boot_count\",\"salience\":0.55,\"importance\":0.2,\"tier\":\"Working\",\"tags\":\"[\\\"soul-meta\\\",\\\"boot-counter\\\"]\",\"_auth\":\"")), json_safe(wb_key)), EL_STR("\"}"));
el_val_t wb_resp = http_post_json(el_str_concat(wb_url, EL_STR("/api/nodes")), wb_body);
if (str_contains(wb_resp, EL_STR("\"error\""))) {
println(el_str_concat(EL_STR("[memory] mem_boot_count_inc: HTTP write-back failed (count in-memory only): "), wb_resp));
}
}
return next;
return 0;
}
el_val_t mem_emit_state_event(el_val_t trigger, el_val_t kind, el_val_t content) {
el_val_t boot = mem_boot_count_get();
el_val_t ts = time_now();
el_val_t safe_trigger = str_replace(trigger, EL_STR("\""), EL_STR("'"));
el_val_t safe_content = str_replace(content, EL_STR("\""), EL_STR("'"));
el_val_t payload = el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("{\"trigger\":\""), safe_trigger), EL_STR("\"")), EL_STR(",\"kind\":\"")), kind), EL_STR("\"")), EL_STR(",\"content\":\"")), safe_content), EL_STR("\"")), EL_STR(",\"boot\":")), int_to_str(boot)), EL_STR(",\"ts\":")), int_to_str(ts)), EL_STR("}"));
el_val_t tags = EL_STR("[\"internal-state\",\"pre-reasoning\",\"InternalStateEvent\"]");
el_val_t event_id = engram_node_full(payload, EL_STR("InternalStateEvent"), el_str_concat(EL_STR("state-event:"), kind), el_from_float(0.85), el_from_float(0.8), el_from_float(0.9), EL_STR("Episodic"), tags);
if (str_eq(event_id, EL_STR(""))) {
println(el_str_concat(EL_STR("[memory] mem_emit_state_event: write rejected (empty id): kind="), kind));
}
return event_id;
return 0;
}
Generated Vendored
+16
View File
@@ -0,0 +1,16 @@
// auto-generated by elc --emit-header — do not edit
extern fn tier_working() -> String
extern fn tier_episodic() -> String
extern fn tier_canonical() -> String
extern fn mem_store(content: String, label: String, tags: String) -> String
extern fn mem_remember(content: String, tags: String) -> String
extern fn mem_recall(query: String, depth: Int) -> String
extern fn mem_search(query: String, limit: Int) -> String
extern fn mem_strengthen(node_id: String) -> Void
extern fn mem_forget(node_id: String) -> Void
extern fn mem_consolidate() -> String
extern fn mem_save(path: String) -> Void
extern fn mem_load(path: String) -> Void
extern fn mem_boot_count_get() -> Int
extern fn mem_boot_count_inc() -> Int
extern fn mem_emit_state_event(trigger: String, kind: String, content: String) -> String
Generated Vendored
+641
View File
@@ -0,0 +1,641 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t akk_str_ends(el_val_t s, el_val_t suf);
el_val_t akk_str_len(el_val_t s);
el_val_t akk_str_drop_last(el_val_t s, el_val_t n);
el_val_t akk_slot(el_val_t person, el_val_t number);
el_val_t akk_slot_g(el_val_t person, el_val_t gender, el_val_t number);
el_val_t akk_copula_present(el_val_t slot);
el_val_t akk_copula_stative(el_val_t slot);
el_val_t akk_is_copula(el_val_t verb);
el_val_t akk_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t akk_alaku_present(el_val_t slot);
el_val_t akk_alaku_perfect(el_val_t slot);
el_val_t akk_amaru_present(el_val_t slot);
el_val_t akk_amaru_perfect(el_val_t slot);
el_val_t akk_amaru_stative(el_val_t slot);
el_val_t akk_qabu_present(el_val_t slot);
el_val_t akk_qabu_perfect(el_val_t slot);
el_val_t akk_qabu_stative(el_val_t slot);
el_val_t akk_epesu_present(el_val_t slot);
el_val_t akk_epesu_perfect(el_val_t slot);
el_val_t akk_epesu_stative(el_val_t slot);
el_val_t akk_regular_present(el_val_t stem, el_val_t slot);
el_val_t akk_regular_perfect(el_val_t stem, el_val_t slot);
el_val_t akk_regular_stative(el_val_t stem, el_val_t slot);
el_val_t akk_known_verb(el_val_t verb, el_val_t tense, el_val_t slot);
el_val_t akk_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t akk_strip_nom(el_val_t noun);
el_val_t akk_is_fem(el_val_t noun);
el_val_t akk_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t akk_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t akk_map_canonical(el_val_t verb);
el_val_t akk_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t akk_str_len(el_val_t s) {
return str_len(s);
return 0;
}
el_val_t akk_str_drop_last(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t akk_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("plural"))) {
return 4;
}
return 0;
}
if (str_eq(person, EL_STR("second"))) {
return 1;
}
if (str_eq(number, EL_STR("plural"))) {
return 5;
}
return 2;
return 0;
}
el_val_t akk_slot_g(el_val_t person, el_val_t gender, el_val_t number) {
el_val_t base = akk_slot(person, number);
if (str_eq(person, EL_STR("third"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gender, EL_STR("f"))) {
return 3;
}
}
}
return base;
return 0;
}
el_val_t akk_copula_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("aba\xc5\xa1\xc5\xa1i");
}
if (slot == 1) {
return EL_STR("taba\xc5\xa1\xc5\xa1i");
}
if (slot == 2) {
return EL_STR("iba\xc5\xa1\xc5\xa1i");
}
if (slot == 3) {
return EL_STR("iba\xc5\xa1\xc5\xa1i");
}
if (slot == 4) {
return EL_STR("niba\xc5\xa1\xc5\xa1i");
}
return EL_STR("iba\xc5\xa1\xc5\xa1\xc5\xab");
return 0;
}
el_val_t akk_copula_stative(el_val_t slot) {
if (slot == 0) {
return EL_STR("ba\xc5\xa1\xc4\x81ku");
}
if (slot == 1) {
return EL_STR("ba\xc5\xa1\xc4\x81ta");
}
if (slot == 2) {
return EL_STR("ba\xc5\xa1\xc4\xab");
}
if (slot == 3) {
return EL_STR("ba\xc5\xa1iat");
}
if (slot == 4) {
return EL_STR("ba\xc5\xa1\xc4\x81nu");
}
return EL_STR("ba\xc5\xa1\xc5\xab");
return 0;
}
el_val_t akk_is_copula(el_val_t verb) {
if (str_eq(verb, EL_STR("ba\xc5\xa1\xc3\xbb"))) {
return 1;
}
if (str_eq(verb, EL_STR("bashu"))) {
return 1;
}
if (str_eq(verb, EL_STR("be"))) {
return 1;
}
return 0;
return 0;
}
el_val_t akk_conjugate_copula(el_val_t tense, el_val_t slot) {
if (str_eq(tense, EL_STR("stative"))) {
return akk_copula_stative(slot);
}
return akk_copula_present(slot);
return 0;
}
el_val_t akk_alaku_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("allak");
}
if (slot == 1) {
return EL_STR("tallak");
}
if (slot == 2) {
return EL_STR("illak");
}
if (slot == 3) {
return EL_STR("tallak");
}
if (slot == 4) {
return EL_STR("nillak");
}
return EL_STR("illaku");
return 0;
}
el_val_t akk_alaku_perfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("ittalak");
}
if (slot == 1) {
return EL_STR("tattalak");
}
if (slot == 2) {
return EL_STR("ittalak");
}
if (slot == 3) {
return EL_STR("tattalak");
}
if (slot == 4) {
return EL_STR("nittalak");
}
return EL_STR("ittalku");
return 0;
}
el_val_t akk_amaru_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("ammar");
}
if (slot == 1) {
return EL_STR("tammar");
}
if (slot == 2) {
return EL_STR("immar");
}
if (slot == 3) {
return EL_STR("tammar");
}
if (slot == 4) {
return EL_STR("nimmar");
}
return EL_STR("immaru");
return 0;
}
el_val_t akk_amaru_perfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("amtamar");
}
if (slot == 1) {
return EL_STR("tamtamar");
}
if (slot == 2) {
return EL_STR("imtamar");
}
if (slot == 3) {
return EL_STR("tamtamar");
}
if (slot == 4) {
return EL_STR("nimtamar");
}
return EL_STR("imtamaru");
return 0;
}
el_val_t akk_amaru_stative(el_val_t slot) {
if (slot == 0) {
return EL_STR("amr\xc4\x81ku");
}
if (slot == 1) {
return EL_STR("amr\xc4\x81ta");
}
if (slot == 2) {
return EL_STR("amir");
}
if (slot == 3) {
return EL_STR("amrat");
}
if (slot == 4) {
return EL_STR("amr\xc4\x81nu");
}
return EL_STR("amr\xc5\xab");
return 0;
}
el_val_t akk_qabu_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("aqabbi");
}
if (slot == 1) {
return EL_STR("taqabbi");
}
if (slot == 2) {
return EL_STR("iqabbi");
}
if (slot == 3) {
return EL_STR("taqabbi");
}
if (slot == 4) {
return EL_STR("niqabbi");
}
return EL_STR("iqabb\xc3\xbb");
return 0;
}
el_val_t akk_qabu_perfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("aqtabi");
}
if (slot == 1) {
return EL_STR("taqtabi");
}
if (slot == 2) {
return EL_STR("iqtabi");
}
if (slot == 3) {
return EL_STR("taqtabi");
}
if (slot == 4) {
return EL_STR("niqtabi");
}
return EL_STR("iqtab\xc3\xbb");
return 0;
}
el_val_t akk_qabu_stative(el_val_t slot) {
if (slot == 0) {
return EL_STR("qab\xc4\x81ku");
}
if (slot == 1) {
return EL_STR("qab\xc4\x81ta");
}
if (slot == 2) {
return EL_STR("qabi");
}
if (slot == 3) {
return EL_STR("qabiat");
}
if (slot == 4) {
return EL_STR("qab\xc4\x81nu");
}
return EL_STR("qab\xc3\xbb");
return 0;
}
el_val_t akk_epesu_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("eppu\xc5\xa1");
}
if (slot == 1) {
return EL_STR("teppu\xc5\xa1");
}
if (slot == 2) {
return EL_STR("ieppu\xc5\xa1");
}
if (slot == 3) {
return EL_STR("teppu\xc5\xa1");
}
if (slot == 4) {
return EL_STR("neppu\xc5\xa1");
}
return EL_STR("ieppu\xc5\xa1u");
return 0;
}
el_val_t akk_epesu_perfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("ipte\xc5\xa1u");
}
if (slot == 1) {
return EL_STR("tapte\xc5\xa1u");
}
if (slot == 2) {
return EL_STR("ipte\xc5\xa1u");
}
if (slot == 3) {
return EL_STR("tapte\xc5\xa1u");
}
if (slot == 4) {
return EL_STR("nipte\xc5\xa1u");
}
return EL_STR("ipte\xc5\xa1\xc5\xab");
return 0;
}
el_val_t akk_epesu_stative(el_val_t slot) {
if (slot == 0) {
return EL_STR("ep\xc5\xa1\xc4\x81ku");
}
if (slot == 1) {
return EL_STR("ep\xc5\xa1\xc4\x81ta");
}
if (slot == 2) {
return EL_STR("epu\xc5\xa1");
}
if (slot == 3) {
return EL_STR("ep\xc5\xa1""at");
}
if (slot == 4) {
return EL_STR("ep\xc5\xa1\xc4\x81nu");
}
return EL_STR("ep\xc5\xa1\xc5\xab");
return 0;
}
el_val_t akk_regular_present(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(EL_STR("a"), stem);
}
if (slot == 1) {
return el_str_concat(EL_STR("ta"), stem);
}
if (slot == 2) {
return el_str_concat(EL_STR("i"), stem);
}
if (slot == 3) {
return el_str_concat(EL_STR("ta"), stem);
}
if (slot == 4) {
return el_str_concat(EL_STR("ni"), stem);
}
return el_str_concat(el_str_concat(EL_STR("i"), stem), EL_STR("u"));
return 0;
}
el_val_t akk_regular_perfect(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(EL_STR("a"), stem);
}
if (slot == 1) {
return el_str_concat(EL_STR("ta"), stem);
}
if (slot == 2) {
return el_str_concat(EL_STR("i"), stem);
}
if (slot == 3) {
return el_str_concat(EL_STR("ta"), stem);
}
if (slot == 4) {
return el_str_concat(EL_STR("ni"), stem);
}
return el_str_concat(el_str_concat(EL_STR("i"), stem), EL_STR("u"));
return 0;
}
el_val_t akk_regular_stative(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("\xc4\x81ku"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("\xc4\x81ta"));
}
if (slot == 2) {
return stem;
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("at"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("\xc4\x81nu"));
}
return el_str_concat(stem, EL_STR("\xc5\xab"));
return 0;
}
el_val_t akk_known_verb(el_val_t verb, el_val_t tense, el_val_t slot) {
if (str_eq(verb, EL_STR("ba\xc5\xa1\xc3\xbb"))) {
return akk_conjugate_copula(tense, slot);
}
if (str_eq(verb, EL_STR("bashu"))) {
return akk_conjugate_copula(tense, slot);
}
if (str_eq(verb, EL_STR("al\xc4\x81ku"))) {
if (str_eq(tense, EL_STR("perfect"))) {
return akk_alaku_perfect(slot);
}
if (str_eq(tense, EL_STR("stative"))) {
return akk_alaku_present(slot);
}
return akk_alaku_present(slot);
}
if (str_eq(verb, EL_STR("alaku"))) {
if (str_eq(tense, EL_STR("perfect"))) {
return akk_alaku_perfect(slot);
}
return akk_alaku_present(slot);
}
if (str_eq(verb, EL_STR("am\xc4\x81ru"))) {
if (str_eq(tense, EL_STR("perfect"))) {
return akk_amaru_perfect(slot);
}
if (str_eq(tense, EL_STR("stative"))) {
return akk_amaru_stative(slot);
}
return akk_amaru_present(slot);
}
if (str_eq(verb, EL_STR("amaru"))) {
if (str_eq(tense, EL_STR("perfect"))) {
return akk_amaru_perfect(slot);
}
if (str_eq(tense, EL_STR("stative"))) {
return akk_amaru_stative(slot);
}
return akk_amaru_present(slot);
}
if (str_eq(verb, EL_STR("qab\xc3\xbb"))) {
if (str_eq(tense, EL_STR("perfect"))) {
return akk_qabu_perfect(slot);
}
if (str_eq(tense, EL_STR("stative"))) {
return akk_qabu_stative(slot);
}
return akk_qabu_present(slot);
}
if (str_eq(verb, EL_STR("qabu"))) {
if (str_eq(tense, EL_STR("perfect"))) {
return akk_qabu_perfect(slot);
}
if (str_eq(tense, EL_STR("stative"))) {
return akk_qabu_stative(slot);
}
return akk_qabu_present(slot);
}
if (str_eq(verb, EL_STR("ep\xc4\x93\xc5\xa1u"))) {
if (str_eq(tense, EL_STR("perfect"))) {
return akk_epesu_perfect(slot);
}
if (str_eq(tense, EL_STR("stative"))) {
return akk_epesu_stative(slot);
}
return akk_epesu_present(slot);
}
if (str_eq(verb, EL_STR("epesu"))) {
if (str_eq(tense, EL_STR("perfect"))) {
return akk_epesu_perfect(slot);
}
if (str_eq(tense, EL_STR("stative"))) {
return akk_epesu_stative(slot);
}
return akk_epesu_present(slot);
}
return EL_STR("");
return 0;
}
el_val_t akk_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t slot = akk_slot(person, number);
if (akk_is_copula(verb)) {
return akk_conjugate_copula(tense, slot);
}
el_val_t known = akk_known_verb(verb, tense, slot);
if (!str_eq(known, EL_STR(""))) {
return known;
}
return verb;
return 0;
}
el_val_t akk_strip_nom(el_val_t noun) {
if (akk_str_ends(noun, EL_STR("um"))) {
return akk_str_drop_last(noun, 2);
}
if (akk_str_ends(noun, EL_STR("tum"))) {
return akk_str_drop_last(noun, 3);
}
return noun;
return 0;
}
el_val_t akk_is_fem(el_val_t noun) {
if (akk_str_ends(noun, EL_STR("tum"))) {
return 1;
}
if (akk_str_ends(noun, EL_STR("tam"))) {
return 1;
}
if (akk_str_ends(noun, EL_STR("tim"))) {
return 1;
}
return 0;
return 0;
}
el_val_t akk_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t fem = akk_is_fem(noun);
el_val_t stem = akk_strip_nom(noun);
if (str_eq(number, EL_STR("singular"))) {
if (fem) {
if (str_eq(gram_case, EL_STR("nom"))) {
return el_str_concat(stem, EL_STR("tum"));
}
if (str_eq(gram_case, EL_STR("acc"))) {
return el_str_concat(stem, EL_STR("tam"));
}
if (str_eq(gram_case, EL_STR("gen"))) {
return el_str_concat(stem, EL_STR("tim"));
}
return el_str_concat(stem, EL_STR("tum"));
}
if (str_eq(gram_case, EL_STR("nom"))) {
return el_str_concat(stem, EL_STR("um"));
}
if (str_eq(gram_case, EL_STR("acc"))) {
return el_str_concat(stem, EL_STR("am"));
}
if (str_eq(gram_case, EL_STR("gen"))) {
return el_str_concat(stem, EL_STR("im"));
}
return el_str_concat(stem, EL_STR("um"));
}
if (fem) {
if (str_eq(gram_case, EL_STR("nom"))) {
return el_str_concat(stem, EL_STR("\xc4\x81tum"));
}
return el_str_concat(stem, EL_STR("\xc4\x81tim"));
}
if (str_eq(gram_case, EL_STR("nom"))) {
return el_str_concat(stem, EL_STR("\xc5\xabtum"));
}
return el_str_concat(stem, EL_STR("\xc4\x81tim"));
return 0;
}
el_val_t akk_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
return akk_decline(noun, gram_case, number);
return 0;
}
el_val_t akk_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("ba\xc5\xa1\xc3\xbb");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("al\xc4\x81ku");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("am\xc4\x81ru");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("qab\xc3\xbb");
}
if (str_eq(verb, EL_STR("speak"))) {
return EL_STR("qab\xc3\xbb");
}
if (str_eq(verb, EL_STR("do"))) {
return EL_STR("ep\xc4\x93\xc5\xa1u");
}
if (str_eq(verb, EL_STR("make"))) {
return EL_STR("ep\xc4\x93\xc5\xa1u");
}
return verb;
return 0;
}
Generated Vendored
+31
View File
@@ -0,0 +1,31 @@
// auto-generated by elc --emit-header — do not edit
extern fn akk_str_ends(s: String, suf: String) -> Bool
extern fn akk_str_len(s: String) -> Int
extern fn akk_str_drop_last(s: String, n: Int) -> String
extern fn akk_slot(person: String, number: String) -> Int
extern fn akk_slot_g(person: String, gender: String, number: String) -> Int
extern fn akk_copula_present(slot: Int) -> String
extern fn akk_copula_stative(slot: Int) -> String
extern fn akk_is_copula(verb: String) -> Bool
extern fn akk_conjugate_copula(tense: String, slot: Int) -> String
extern fn akk_alaku_present(slot: Int) -> String
extern fn akk_alaku_perfect(slot: Int) -> String
extern fn akk_amaru_present(slot: Int) -> String
extern fn akk_amaru_perfect(slot: Int) -> String
extern fn akk_amaru_stative(slot: Int) -> String
extern fn akk_qabu_present(slot: Int) -> String
extern fn akk_qabu_perfect(slot: Int) -> String
extern fn akk_qabu_stative(slot: Int) -> String
extern fn akk_epesu_present(slot: Int) -> String
extern fn akk_epesu_perfect(slot: Int) -> String
extern fn akk_epesu_stative(slot: Int) -> String
extern fn akk_regular_present(stem: String, slot: Int) -> String
extern fn akk_regular_perfect(stem: String, slot: Int) -> String
extern fn akk_regular_stative(stem: String, slot: Int) -> String
extern fn akk_known_verb(verb: String, tense: String, slot: Int) -> String
extern fn akk_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn akk_strip_nom(noun: String) -> String
extern fn akk_is_fem(noun: String) -> Bool
extern fn akk_decline(noun: String, gram_case: String, number: String) -> String
extern fn akk_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
extern fn akk_map_canonical(verb: String) -> String
Generated Vendored
+989
View File
@@ -0,0 +1,989 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t ang_str_ends(el_val_t s, el_val_t suf);
el_val_t ang_str_drop_last(el_val_t s, el_val_t n);
el_val_t ang_str_last_char(el_val_t s);
el_val_t ang_str_last2(el_val_t s);
el_val_t ang_slot(el_val_t person, el_val_t number);
el_val_t ang_map_canonical(el_val_t verb);
el_val_t ang_wesan_past(el_val_t slot);
el_val_t ang_beon_present(el_val_t slot);
el_val_t ang_wesan_present(el_val_t slot);
el_val_t ang_habban_present(el_val_t slot);
el_val_t ang_habban_past(el_val_t slot);
el_val_t ang_gan_present(el_val_t slot);
el_val_t ang_gan_past(el_val_t slot);
el_val_t ang_cuman_present(el_val_t slot);
el_val_t ang_cuman_past(el_val_t slot);
el_val_t ang_secgan_present(el_val_t slot);
el_val_t ang_secgan_past(el_val_t slot);
el_val_t ang_seon_present(el_val_t slot);
el_val_t ang_seon_past(el_val_t slot);
el_val_t ang_don_present(el_val_t slot);
el_val_t ang_don_past(el_val_t slot);
el_val_t ang_willan_present(el_val_t slot);
el_val_t ang_willan_past(el_val_t slot);
el_val_t ang_magan_present(el_val_t slot);
el_val_t ang_magan_past(el_val_t slot);
el_val_t ang_witan_present(el_val_t slot);
el_val_t ang_witan_past(el_val_t slot);
el_val_t ang_weak_present_ending(el_val_t slot);
el_val_t ang_weak_past_stem(el_val_t stem);
el_val_t ang_weak_past(el_val_t stem, el_val_t slot);
el_val_t ang_weak_stem(el_val_t verb);
el_val_t ang_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t ang_declension(el_val_t noun, el_val_t gender);
el_val_t ang_decline_strong_masc(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t ang_decline_strong_neut(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t ang_decline_weak(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t ang_decline(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t gender);
el_val_t ang_article_masculine(el_val_t gram_case, el_val_t number);
el_val_t ang_article_feminine(el_val_t gram_case, el_val_t number);
el_val_t ang_article_neuter(el_val_t gram_case, el_val_t number);
el_val_t ang_article(el_val_t gender, el_val_t gram_case, el_val_t number);
el_val_t ang_infer_gender(el_val_t noun);
el_val_t ang_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t ang_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t ang_str_drop_last(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t ang_str_last_char(el_val_t s) {
el_val_t n = str_len(s);
if (n == 0) {
return EL_STR("");
}
return str_slice(s, (n - 1), n);
return 0;
}
el_val_t ang_str_last2(el_val_t s) {
el_val_t n = str_len(s);
if (n < 2) {
return s;
}
return str_slice(s, (n - 2), n);
return 0;
}
el_val_t ang_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t ang_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("beon");
}
if (str_eq(verb, EL_STR("have"))) {
return EL_STR("habban");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("g\xc4\x81n");
}
if (str_eq(verb, EL_STR("come"))) {
return EL_STR("cuman");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("secgan");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("s\xc4\x93on");
}
if (str_eq(verb, EL_STR("do"))) {
return EL_STR("d\xc5\x8dn");
}
if (str_eq(verb, EL_STR("want"))) {
return EL_STR("willan");
}
if (str_eq(verb, EL_STR("will"))) {
return EL_STR("willan");
}
if (str_eq(verb, EL_STR("can"))) {
return EL_STR("magan");
}
if (str_eq(verb, EL_STR("know"))) {
return EL_STR("witan");
}
if (str_eq(verb, EL_STR("give"))) {
return EL_STR("giefan");
}
if (str_eq(verb, EL_STR("take"))) {
return EL_STR("niman");
}
if (str_eq(verb, EL_STR("find"))) {
return EL_STR("findan");
}
if (str_eq(verb, EL_STR("make"))) {
return EL_STR("macian");
}
return verb;
return 0;
}
el_val_t ang_wesan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("w\xc3\xa6s");
}
if (slot == 1) {
return EL_STR("w\xc7\xa3re");
}
if (slot == 2) {
return EL_STR("w\xc3\xa6s");
}
if (slot == 3) {
return EL_STR("w\xc7\xa3ron");
}
if (slot == 4) {
return EL_STR("w\xc7\xa3ron");
}
return EL_STR("w\xc7\xa3ron");
return 0;
}
el_val_t ang_beon_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("b\xc4\x93o");
}
if (slot == 1) {
return EL_STR("bist");
}
if (slot == 2) {
return EL_STR("bi\xc3\xbe");
}
if (slot == 3) {
return EL_STR("b\xc4\x93o\xc3\xbe");
}
if (slot == 4) {
return EL_STR("b\xc4\x93o\xc3\xbe");
}
return EL_STR("b\xc4\x93o\xc3\xbe");
return 0;
}
el_val_t ang_wesan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("eom");
}
if (slot == 1) {
return EL_STR("eart");
}
if (slot == 2) {
return EL_STR("is");
}
if (slot == 3) {
return EL_STR("sind");
}
if (slot == 4) {
return EL_STR("sind");
}
return EL_STR("sind");
return 0;
}
el_val_t ang_habban_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("h\xc3\xa6""bbe");
}
if (slot == 1) {
return EL_STR("h\xc3\xa6""fst");
}
if (slot == 2) {
return EL_STR("h\xc3\xa6""f\xc3\xbe");
}
if (slot == 3) {
return EL_STR("habba\xc3\xb0");
}
if (slot == 4) {
return EL_STR("habba\xc3\xb0");
}
return EL_STR("habba\xc3\xb0");
return 0;
}
el_val_t ang_habban_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("h\xc3\xa6""fde");
}
if (slot == 1) {
return EL_STR("h\xc3\xa6""fdest");
}
if (slot == 2) {
return EL_STR("h\xc3\xa6""fde");
}
if (slot == 3) {
return EL_STR("h\xc3\xa6""fdon");
}
if (slot == 4) {
return EL_STR("h\xc3\xa6""fdon");
}
return EL_STR("h\xc3\xa6""fdon");
return 0;
}
el_val_t ang_gan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("g\xc4\x81");
}
if (slot == 1) {
return EL_STR("g\xc7\xa3st");
}
if (slot == 2) {
return EL_STR("g\xc7\xa3\xc3\xbe");
}
if (slot == 3) {
return EL_STR("g\xc4\x81\xc3\xb0");
}
if (slot == 4) {
return EL_STR("g\xc4\x81\xc3\xb0");
}
return EL_STR("g\xc4\x81\xc3\xb0");
return 0;
}
el_val_t ang_gan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xc4\x93ode");
}
if (slot == 1) {
return EL_STR("\xc4\x93odest");
}
if (slot == 2) {
return EL_STR("\xc4\x93ode");
}
if (slot == 3) {
return EL_STR("\xc4\x93odon");
}
if (slot == 4) {
return EL_STR("\xc4\x93odon");
}
return EL_STR("\xc4\x93odon");
return 0;
}
el_val_t ang_cuman_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("cume");
}
if (slot == 1) {
return EL_STR("cymst");
}
if (slot == 2) {
return EL_STR("cym\xc3\xbe");
}
if (slot == 3) {
return EL_STR("cuma\xc3\xb0");
}
if (slot == 4) {
return EL_STR("cuma\xc3\xb0");
}
return EL_STR("cuma\xc3\xb0");
return 0;
}
el_val_t ang_cuman_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("c\xc5\x8dm");
}
if (slot == 1) {
return EL_STR("c\xc5\x8dme");
}
if (slot == 2) {
return EL_STR("c\xc5\x8dm");
}
if (slot == 3) {
return EL_STR("c\xc5\x8dmon");
}
if (slot == 4) {
return EL_STR("c\xc5\x8dmon");
}
return EL_STR("c\xc5\x8dmon");
return 0;
}
el_val_t ang_secgan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("secge");
}
if (slot == 1) {
return EL_STR("sagast");
}
if (slot == 2) {
return EL_STR("saga\xc3\xb0");
}
if (slot == 3) {
return EL_STR("secga\xc3\xb0");
}
if (slot == 4) {
return EL_STR("secga\xc3\xb0");
}
return EL_STR("secga\xc3\xb0");
return 0;
}
el_val_t ang_secgan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("s\xc3\xa6gde");
}
if (slot == 1) {
return EL_STR("s\xc3\xa6gdest");
}
if (slot == 2) {
return EL_STR("s\xc3\xa6gde");
}
if (slot == 3) {
return EL_STR("s\xc3\xa6gdon");
}
if (slot == 4) {
return EL_STR("s\xc3\xa6gdon");
}
return EL_STR("s\xc3\xa6gdon");
return 0;
}
el_val_t ang_seon_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("s\xc4\x93o");
}
if (slot == 1) {
return EL_STR("siehst");
}
if (slot == 2) {
return EL_STR("sieh\xc3\xbe");
}
if (slot == 3) {
return EL_STR("s\xc4\x93o\xc3\xb0");
}
if (slot == 4) {
return EL_STR("s\xc4\x93o\xc3\xb0");
}
return EL_STR("s\xc4\x93o\xc3\xb0");
return 0;
}
el_val_t ang_seon_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("seah");
}
if (slot == 1) {
return EL_STR("s\xc4\x81we");
}
if (slot == 2) {
return EL_STR("seah");
}
if (slot == 3) {
return EL_STR("s\xc4\x81won");
}
if (slot == 4) {
return EL_STR("s\xc4\x81won");
}
return EL_STR("s\xc4\x81won");
return 0;
}
el_val_t ang_don_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("d\xc5\x8d");
}
if (slot == 1) {
return EL_STR("d\xc4\x93st");
}
if (slot == 2) {
return EL_STR("d\xc4\x93\xc3\xbe");
}
if (slot == 3) {
return EL_STR("d\xc5\x8d\xc3\xb0");
}
if (slot == 4) {
return EL_STR("d\xc5\x8d\xc3\xb0");
}
return EL_STR("d\xc5\x8d\xc3\xb0");
return 0;
}
el_val_t ang_don_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("dyde");
}
if (slot == 1) {
return EL_STR("dydest");
}
if (slot == 2) {
return EL_STR("dyde");
}
if (slot == 3) {
return EL_STR("dydon");
}
if (slot == 4) {
return EL_STR("dydon");
}
return EL_STR("dydon");
return 0;
}
el_val_t ang_willan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("wille");
}
if (slot == 1) {
return EL_STR("wilt");
}
if (slot == 2) {
return EL_STR("wile");
}
if (slot == 3) {
return EL_STR("willa\xc3\xb0");
}
if (slot == 4) {
return EL_STR("willa\xc3\xb0");
}
return EL_STR("willa\xc3\xb0");
return 0;
}
el_val_t ang_willan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("wolde");
}
if (slot == 1) {
return EL_STR("woldest");
}
if (slot == 2) {
return EL_STR("wolde");
}
if (slot == 3) {
return EL_STR("woldon");
}
if (slot == 4) {
return EL_STR("woldon");
}
return EL_STR("woldon");
return 0;
}
el_val_t ang_magan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("m\xc3\xa6g");
}
if (slot == 1) {
return EL_STR("meaht");
}
if (slot == 2) {
return EL_STR("m\xc3\xa6g");
}
if (slot == 3) {
return EL_STR("magon");
}
if (slot == 4) {
return EL_STR("magon");
}
return EL_STR("magon");
return 0;
}
el_val_t ang_magan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("meahte");
}
if (slot == 1) {
return EL_STR("meahtest");
}
if (slot == 2) {
return EL_STR("meahte");
}
if (slot == 3) {
return EL_STR("meahton");
}
if (slot == 4) {
return EL_STR("meahton");
}
return EL_STR("meahton");
return 0;
}
el_val_t ang_witan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("w\xc4\x81t");
}
if (slot == 1) {
return EL_STR("w\xc4\x81st");
}
if (slot == 2) {
return EL_STR("w\xc4\x81t");
}
if (slot == 3) {
return EL_STR("witon");
}
if (slot == 4) {
return EL_STR("witon");
}
return EL_STR("witon");
return 0;
}
el_val_t ang_witan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("wisse");
}
if (slot == 1) {
return EL_STR("wissest");
}
if (slot == 2) {
return EL_STR("wisse");
}
if (slot == 3) {
return EL_STR("wisson");
}
if (slot == 4) {
return EL_STR("wisson");
}
return EL_STR("wisson");
return 0;
}
el_val_t ang_weak_present_ending(el_val_t slot) {
if (slot == 0) {
return EL_STR("e");
}
if (slot == 1) {
return EL_STR("est");
}
if (slot == 2) {
return EL_STR("e\xc3\xbe");
}
if (slot == 3) {
return EL_STR("a\xc3\xbe");
}
if (slot == 4) {
return EL_STR("a\xc3\xbe");
}
return EL_STR("a\xc3\xbe");
return 0;
}
el_val_t ang_weak_past_stem(el_val_t stem) {
el_val_t slen = str_len(stem);
if (slen <= 2) {
return el_str_concat(stem, EL_STR("ede"));
}
return el_str_concat(stem, EL_STR("ode"));
return 0;
}
el_val_t ang_weak_past(el_val_t stem, el_val_t slot) {
el_val_t pstem = ang_weak_past_stem(stem);
if (slot == 0) {
return pstem;
}
if (slot == 1) {
return el_str_concat(pstem, EL_STR("st"));
}
if (slot == 2) {
return pstem;
}
if (slot == 3) {
return el_str_concat(ang_str_drop_last(pstem, 1), EL_STR("on"));
}
if (slot == 4) {
return el_str_concat(ang_str_drop_last(pstem, 1), EL_STR("on"));
}
return el_str_concat(ang_str_drop_last(pstem, 1), EL_STR("on"));
return 0;
}
el_val_t ang_weak_stem(el_val_t verb) {
if (ang_str_ends(verb, EL_STR("ian"))) {
return ang_str_drop_last(verb, 3);
}
if (ang_str_ends(verb, EL_STR("an"))) {
return ang_str_drop_last(verb, 2);
}
return verb;
return 0;
}
el_val_t ang_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t v = ang_map_canonical(verb);
el_val_t slot = ang_slot(person, number);
if (str_eq(v, EL_STR("beon"))) {
if (str_eq(tense, EL_STR("present"))) {
return ang_beon_present(slot);
}
return ang_wesan_past(slot);
}
if (str_eq(v, EL_STR("wesan"))) {
if (str_eq(tense, EL_STR("present"))) {
return ang_wesan_present(slot);
}
return ang_wesan_past(slot);
}
if (str_eq(v, EL_STR("habban"))) {
if (str_eq(tense, EL_STR("present"))) {
return ang_habban_present(slot);
}
return ang_habban_past(slot);
}
if (str_eq(v, EL_STR("g\xc4\x81n"))) {
if (str_eq(tense, EL_STR("present"))) {
return ang_gan_present(slot);
}
return ang_gan_past(slot);
}
if (str_eq(v, EL_STR("cuman"))) {
if (str_eq(tense, EL_STR("present"))) {
return ang_cuman_present(slot);
}
return ang_cuman_past(slot);
}
if (str_eq(v, EL_STR("secgan"))) {
if (str_eq(tense, EL_STR("present"))) {
return ang_secgan_present(slot);
}
return ang_secgan_past(slot);
}
if (str_eq(v, EL_STR("s\xc4\x93on"))) {
if (str_eq(tense, EL_STR("present"))) {
return ang_seon_present(slot);
}
return ang_seon_past(slot);
}
if (str_eq(v, EL_STR("d\xc5\x8dn"))) {
if (str_eq(tense, EL_STR("present"))) {
return ang_don_present(slot);
}
return ang_don_past(slot);
}
if (str_eq(v, EL_STR("willan"))) {
if (str_eq(tense, EL_STR("present"))) {
return ang_willan_present(slot);
}
return ang_willan_past(slot);
}
if (str_eq(v, EL_STR("magan"))) {
if (str_eq(tense, EL_STR("present"))) {
return ang_magan_present(slot);
}
return ang_magan_past(slot);
}
if (str_eq(v, EL_STR("witan"))) {
if (str_eq(tense, EL_STR("present"))) {
return ang_witan_present(slot);
}
return ang_witan_past(slot);
}
el_val_t stem = ang_weak_stem(v);
if (str_eq(tense, EL_STR("present"))) {
return el_str_concat(stem, ang_weak_present_ending(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return ang_weak_past(stem, slot);
}
return v;
return 0;
}
el_val_t ang_declension(el_val_t noun, el_val_t gender) {
if (ang_str_ends(noun, EL_STR("a"))) {
return EL_STR("weak");
}
if (str_eq(gender, EL_STR("neuter"))) {
return EL_STR("strong_neut");
}
return EL_STR("strong_masc");
return 0;
}
el_val_t ang_decline_strong_masc(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("es"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("e"));
}
return noun;
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(noun, EL_STR("as"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(noun, EL_STR("as"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("um"));
}
return el_str_concat(noun, EL_STR("as"));
return 0;
}
el_val_t ang_decline_strong_neut(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("es"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("e"));
}
return noun;
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("um"));
}
return noun;
return 0;
}
el_val_t ang_decline_weak(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t stem = ang_str_drop_last(noun, 1);
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("an"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("an"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("an"));
}
return noun;
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("an"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("an"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("ena"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("um"));
}
return el_str_concat(stem, EL_STR("an"));
return 0;
}
el_val_t ang_decline(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t gender) {
el_val_t decl = ang_declension(noun, gender);
if (str_eq(decl, EL_STR("strong_masc"))) {
return ang_decline_strong_masc(noun, gram_case, number);
}
if (str_eq(decl, EL_STR("strong_neut"))) {
return ang_decline_strong_neut(noun, gram_case, number);
}
if (str_eq(decl, EL_STR("weak"))) {
return ang_decline_weak(noun, gram_case, number);
}
return noun;
return 0;
}
el_val_t ang_article_masculine(el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("se");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("\xc3\xbeone");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("\xc3\xbe\xc3\xa6s");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("\xc3\xbe\xc7\xa3m");
}
return EL_STR("se");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("\xc3\xbe\xc4\x81");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("\xc3\xbe\xc4\x81");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("\xc3\xbe\xc4\x81ra");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("\xc3\xbe\xc7\xa3m");
}
return EL_STR("\xc3\xbe\xc4\x81");
return 0;
}
el_val_t ang_article_feminine(el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("s\xc4\x93o");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("\xc3\xbe\xc4\x81");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("\xc3\xbe\xc7\xa3re");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("\xc3\xbe\xc7\xa3re");
}
return EL_STR("s\xc4\x93o");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("\xc3\xbe\xc4\x81");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("\xc3\xbe\xc4\x81");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("\xc3\xbe\xc4\x81ra");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("\xc3\xbe\xc7\xa3m");
}
return EL_STR("\xc3\xbe\xc4\x81");
return 0;
}
el_val_t ang_article_neuter(el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("\xc3\xbe\xc3\xa6t");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("\xc3\xbe\xc3\xa6t");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("\xc3\xbe\xc3\xa6s");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("\xc3\xbe\xc7\xa3m");
}
return EL_STR("\xc3\xbe\xc3\xa6t");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("\xc3\xbe\xc4\x81");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("\xc3\xbe\xc4\x81");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("\xc3\xbe\xc4\x81ra");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("\xc3\xbe\xc7\xa3m");
}
return EL_STR("\xc3\xbe\xc4\x81");
return 0;
}
el_val_t ang_article(el_val_t gender, el_val_t gram_case, el_val_t number) {
if (str_eq(gender, EL_STR("masculine"))) {
return ang_article_masculine(gram_case, number);
}
if (str_eq(gender, EL_STR("feminine"))) {
return ang_article_feminine(gram_case, number);
}
return ang_article_neuter(gram_case, number);
return 0;
}
el_val_t ang_infer_gender(el_val_t noun) {
if (ang_str_ends(noun, EL_STR("u"))) {
return EL_STR("feminine");
}
if (ang_str_ends(noun, EL_STR("e"))) {
return EL_STR("feminine");
}
return EL_STR("masculine");
return 0;
}
el_val_t ang_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
el_val_t gender = ang_infer_gender(noun);
el_val_t declined = ang_decline(noun, gram_case, number, gender);
if (str_eq(definite, EL_STR("true"))) {
el_val_t art = ang_article(gender, gram_case, number);
return el_str_concat(el_str_concat(art, EL_STR(" ")), declined);
}
return declined;
return 0;
}
Generated Vendored
+44
View File
@@ -0,0 +1,44 @@
// auto-generated by elc --emit-header — do not edit
extern fn ang_str_ends(s: String, suf: String) -> Bool
extern fn ang_str_drop_last(s: String, n: Int) -> String
extern fn ang_str_last_char(s: String) -> String
extern fn ang_str_last2(s: String) -> String
extern fn ang_slot(person: String, number: String) -> Int
extern fn ang_map_canonical(verb: String) -> String
extern fn ang_wesan_past(slot: Int) -> String
extern fn ang_beon_present(slot: Int) -> String
extern fn ang_wesan_present(slot: Int) -> String
extern fn ang_habban_present(slot: Int) -> String
extern fn ang_habban_past(slot: Int) -> String
extern fn ang_gan_present(slot: Int) -> String
extern fn ang_gan_past(slot: Int) -> String
extern fn ang_cuman_present(slot: Int) -> String
extern fn ang_cuman_past(slot: Int) -> String
extern fn ang_secgan_present(slot: Int) -> String
extern fn ang_secgan_past(slot: Int) -> String
extern fn ang_seon_present(slot: Int) -> String
extern fn ang_seon_past(slot: Int) -> String
extern fn ang_don_present(slot: Int) -> String
extern fn ang_don_past(slot: Int) -> String
extern fn ang_willan_present(slot: Int) -> String
extern fn ang_willan_past(slot: Int) -> String
extern fn ang_magan_present(slot: Int) -> String
extern fn ang_magan_past(slot: Int) -> String
extern fn ang_witan_present(slot: Int) -> String
extern fn ang_witan_past(slot: Int) -> String
extern fn ang_weak_present_ending(slot: Int) -> String
extern fn ang_weak_past_stem(stem: String) -> String
extern fn ang_weak_past(stem: String, slot: Int) -> String
extern fn ang_weak_stem(verb: String) -> String
extern fn ang_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn ang_declension(noun: String, gender: String) -> String
extern fn ang_decline_strong_masc(noun: String, gram_case: String, number: String) -> String
extern fn ang_decline_strong_neut(noun: String, gram_case: String, number: String) -> String
extern fn ang_decline_weak(noun: String, gram_case: String, number: String) -> String
extern fn ang_decline(noun: String, gram_case: String, number: String, gender: String) -> String
extern fn ang_article_masculine(gram_case: String, number: String) -> String
extern fn ang_article_feminine(gram_case: String, number: String) -> String
extern fn ang_article_neuter(gram_case: String, number: String) -> String
extern fn ang_article(gender: String, gram_case: String, number: String) -> String
extern fn ang_infer_gender(noun: String) -> String
extern fn ang_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
Generated Vendored
+908
View File
@@ -0,0 +1,908 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t ar_str_ends(el_val_t s, el_val_t suf);
el_val_t ar_str_len(el_val_t s);
el_val_t ar_str_drop_last(el_val_t s, el_val_t n);
el_val_t ar_str_last_char(el_val_t s);
el_val_t ar_slot(el_val_t person, el_val_t gender, el_val_t number);
el_val_t ar_perfect_suffix(el_val_t slot);
el_val_t ar_imperfect_prefix(el_val_t slot);
el_val_t ar_imperfect_suffix(el_val_t slot);
el_val_t ar_conjugate_form1(el_val_t past_base, el_val_t present_stem, el_val_t tense, el_val_t slot);
el_val_t ar_irregular_kaana(el_val_t slot, el_val_t tense);
el_val_t ar_irregular_qaala(el_val_t slot, el_val_t tense);
el_val_t ar_irregular_jaa(el_val_t slot, el_val_t tense);
el_val_t ar_irregular_raaa(el_val_t slot, el_val_t tense);
el_val_t ar_irregular_araada(el_val_t slot, el_val_t tense);
el_val_t ar_irregular_istata(el_val_t slot, el_val_t tense);
el_val_t ar_irregular(el_val_t verb, el_val_t tense, el_val_t slot);
el_val_t ar_present_stem(el_val_t verb);
el_val_t ar_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t gender, el_val_t number);
el_val_t ar_is_sun_letter(el_val_t c);
el_val_t ar_definite_article(el_val_t noun);
el_val_t ar_case_ending(el_val_t kase, el_val_t definite);
el_val_t ar_gender(el_val_t noun);
el_val_t ar_masc_pl_ending(el_val_t kase);
el_val_t ar_sound_plural(el_val_t noun, el_val_t gender);
el_val_t ar_noun_form(el_val_t noun, el_val_t gender, el_val_t kase, el_val_t number, el_val_t definite);
el_val_t ar_verb_form(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t ar_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t ar_str_len(el_val_t s) {
return str_len(s);
return 0;
}
el_val_t ar_str_drop_last(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t ar_str_last_char(el_val_t s) {
el_val_t n = str_len(s);
if (n == 0) {
return EL_STR("");
}
return str_slice(s, (n - 1), n);
return 0;
}
el_val_t ar_slot(el_val_t person, el_val_t gender, el_val_t number) {
if (str_eq(person, EL_STR("third"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gender, EL_STR("f"))) {
return 1;
}
return 0;
}
if (str_eq(gender, EL_STR("f"))) {
return 6;
}
return 5;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gender, EL_STR("f"))) {
return 3;
}
return 2;
}
if (str_eq(gender, EL_STR("f"))) {
return 8;
}
return 7;
}
if (str_eq(number, EL_STR("plural"))) {
return 9;
}
return 4;
return 0;
}
el_val_t ar_perfect_suffix(el_val_t slot) {
if (slot == 0) {
return EL_STR("");
}
if (slot == 1) {
return EL_STR("\xd8\xaa");
}
if (slot == 2) {
return EL_STR("\xd8\xaa\xd9\x8e");
}
if (slot == 3) {
return EL_STR("\xd8\xaa\xd9\x90");
}
if (slot == 4) {
return EL_STR("\xd8\xaa\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd9\x88\xd8\xa7");
}
if (slot == 6) {
return EL_STR("\xd9\x86\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd8\xaa\xd9\x8f\xd9\x85\xd9\x92");
}
if (slot == 8) {
return EL_STR("\xd8\xaa\xd9\x8f\xd9\x86\xd9\x8e\xd9\x91");
}
return EL_STR("\xd9\x86\xd9\x8e\xd8\xa7");
return 0;
}
el_val_t ar_imperfect_prefix(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xd9\x8a\xd9\x8e");
}
if (slot == 1) {
return EL_STR("\xd8\xaa\xd9\x8e");
}
if (slot == 2) {
return EL_STR("\xd8\xaa\xd9\x8e");
}
if (slot == 3) {
return EL_STR("\xd8\xaa\xd9\x8e");
}
if (slot == 4) {
return EL_STR("\xd8\xa3\xd9\x8e");
}
if (slot == 5) {
return EL_STR("\xd9\x8a\xd9\x8e");
}
if (slot == 6) {
return EL_STR("\xd9\x8a\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd8\xaa\xd9\x8e");
}
if (slot == 8) {
return EL_STR("\xd8\xaa\xd9\x8e");
}
return EL_STR("\xd9\x86\xd9\x8e");
return 0;
}
el_val_t ar_imperfect_suffix(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xd9\x8f");
}
if (slot == 1) {
return EL_STR("\xd9\x8f");
}
if (slot == 2) {
return EL_STR("\xd9\x8f");
}
if (slot == 3) {
return EL_STR("\xd9\x90\xd9\x8a\xd9\x86\xd9\x8e");
}
if (slot == 4) {
return EL_STR("\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd9\x8f\xd9\x88\xd9\x86\xd9\x8e");
}
if (slot == 6) {
return EL_STR("\xd9\x86\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd9\x8f\xd9\x88\xd9\x86\xd9\x8e");
}
if (slot == 8) {
return EL_STR("\xd9\x86\xd9\x8e");
}
return EL_STR("\xd9\x8f");
return 0;
}
el_val_t ar_conjugate_form1(el_val_t past_base, el_val_t present_stem, el_val_t tense, el_val_t slot) {
if (str_eq(tense, EL_STR("past"))) {
if (slot == 0) {
return past_base;
}
el_val_t suf = ar_perfect_suffix(slot);
el_val_t stem = ar_str_drop_last(past_base, 1);
return el_str_concat(stem, suf);
}
if (str_eq(tense, EL_STR("present"))) {
el_val_t pre = ar_imperfect_prefix(slot);
el_val_t suf = ar_imperfect_suffix(slot);
el_val_t mid = ar_str_drop_last(present_stem, 1);
return el_str_concat(el_str_concat(pre, mid), suf);
}
if (str_eq(tense, EL_STR("future"))) {
el_val_t pres_3ms = ar_conjugate_form1(past_base, present_stem, EL_STR("present"), 0);
return el_str_concat(EL_STR("\xd8\xb3\xd9\x8e"), pres_3ms);
}
return past_base;
return 0;
}
el_val_t ar_irregular_kaana(el_val_t slot, el_val_t tense) {
if (str_eq(tense, EL_STR("past"))) {
if (slot == 0) {
return EL_STR("\xd9\x83\xd9\x8e\xd8\xa7\xd9\x86\xd9\x8e");
}
if (slot == 1) {
return EL_STR("\xd9\x83\xd9\x8e\xd8\xa7\xd9\x86\xd9\x8e\xd8\xaa\xd9\x92");
}
if (slot == 2) {
return EL_STR("\xd9\x83\xd9\x8f\xd9\x86\xd9\x92\xd8\xaa\xd9\x8e");
}
if (slot == 3) {
return EL_STR("\xd9\x83\xd9\x8f\xd9\x86\xd9\x92\xd8\xaa\xd9\x90");
}
if (slot == 4) {
return EL_STR("\xd9\x83\xd9\x8f\xd9\x86\xd9\x92\xd8\xaa\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd9\x83\xd9\x8e\xd8\xa7\xd9\x86\xd9\x8f\xd9\x88\xd8\xa7");
}
if (slot == 6) {
return EL_STR("\xd9\x83\xd9\x8f\xd9\x86\xd9\x8e\xd9\x91");
}
if (slot == 7) {
return EL_STR("\xd9\x83\xd9\x8f\xd9\x86\xd9\x92\xd8\xaa\xd9\x8f\xd9\x85\xd9\x92");
}
if (slot == 8) {
return EL_STR("\xd9\x83\xd9\x8f\xd9\x86\xd9\x92\xd8\xaa\xd9\x8f\xd9\x86\xd9\x8e\xd9\x91");
}
return EL_STR("\xd9\x83\xd9\x8f\xd9\x86\xd9\x8e\xd9\x91\xd8\xa7");
}
if (str_eq(tense, EL_STR("present"))) {
if (slot == 0) {
return EL_STR("\xd9\x8a\xd9\x8e\xd9\x83\xd9\x8f\xd9\x88\xd9\x86\xd9\x8f");
}
if (slot == 1) {
return EL_STR("\xd8\xaa\xd9\x8e\xd9\x83\xd9\x8f\xd9\x88\xd9\x86\xd9\x8f");
}
if (slot == 2) {
return EL_STR("\xd8\xaa\xd9\x8e\xd9\x83\xd9\x8f\xd9\x88\xd9\x86\xd9\x8f");
}
if (slot == 3) {
return EL_STR("\xd8\xaa\xd9\x8e\xd9\x83\xd9\x8f\xd9\x88\xd9\x86\xd9\x90\xd9\x8a\xd9\x86\xd9\x8e");
}
if (slot == 4) {
return EL_STR("\xd8\xa3\xd9\x8e\xd9\x83\xd9\x8f\xd9\x88\xd9\x86\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd9\x8a\xd9\x8e\xd9\x83\xd9\x8f\xd9\x88\xd9\x86\xd9\x8f\xd9\x88\xd9\x86\xd9\x8e");
}
if (slot == 6) {
return EL_STR("\xd9\x8a\xd9\x8e\xd9\x83\xd9\x8f\xd9\x86\xd9\x8e\xd9\x91");
}
if (slot == 7) {
return EL_STR("\xd8\xaa\xd9\x8e\xd9\x83\xd9\x8f\xd9\x88\xd9\x86\xd9\x8f\xd9\x88\xd9\x86\xd9\x8e");
}
if (slot == 8) {
return EL_STR("\xd8\xaa\xd9\x8e\xd9\x83\xd9\x8f\xd9\x86\xd9\x8e\xd9\x91");
}
return EL_STR("\xd9\x86\xd9\x8e\xd9\x83\xd9\x8f\xd9\x88\xd9\x86\xd9\x8f");
}
if (str_eq(tense, EL_STR("future"))) {
el_val_t pres = ar_irregular_kaana(slot, EL_STR("present"));
return el_str_concat(EL_STR("\xd8\xb3\xd9\x8e"), pres);
}
return EL_STR("\xd9\x83\xd9\x8e\xd8\xa7\xd9\x86\xd9\x8e");
return 0;
}
el_val_t ar_irregular_qaala(el_val_t slot, el_val_t tense) {
if (str_eq(tense, EL_STR("past"))) {
if (slot == 0) {
return EL_STR("\xd9\x82\xd9\x8e\xd8\xa7\xd9\x84\xd9\x8e");
}
if (slot == 1) {
return EL_STR("\xd9\x82\xd9\x8e\xd8\xa7\xd9\x84\xd9\x8e\xd8\xaa\xd9\x92");
}
if (slot == 2) {
return EL_STR("\xd9\x82\xd9\x8f\xd9\x84\xd9\x92\xd8\xaa\xd9\x8e");
}
if (slot == 3) {
return EL_STR("\xd9\x82\xd9\x8f\xd9\x84\xd9\x92\xd8\xaa\xd9\x90");
}
if (slot == 4) {
return EL_STR("\xd9\x82\xd9\x8f\xd9\x84\xd9\x92\xd8\xaa\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd9\x82\xd9\x8e\xd8\xa7\xd9\x84\xd9\x8f\xd9\x88\xd8\xa7");
}
if (slot == 6) {
return EL_STR("\xd9\x82\xd9\x8f\xd9\x84\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd9\x82\xd9\x8f\xd9\x84\xd9\x92\xd8\xaa\xd9\x8f\xd9\x85\xd9\x92");
}
if (slot == 8) {
return EL_STR("\xd9\x82\xd9\x8f\xd9\x84\xd9\x92\xd8\xaa\xd9\x8f\xd9\x86\xd9\x8e\xd9\x91");
}
return EL_STR("\xd9\x82\xd9\x8f\xd9\x84\xd9\x92\xd9\x86\xd9\x8e\xd8\xa7");
}
if (str_eq(tense, EL_STR("present"))) {
if (slot == 0) {
return EL_STR("\xd9\x8a\xd9\x8e\xd9\x82\xd9\x8f\xd9\x88\xd9\x84\xd9\x8f");
}
if (slot == 1) {
return EL_STR("\xd8\xaa\xd9\x8e\xd9\x82\xd9\x8f\xd9\x88\xd9\x84\xd9\x8f");
}
if (slot == 2) {
return EL_STR("\xd8\xaa\xd9\x8e\xd9\x82\xd9\x8f\xd9\x88\xd9\x84\xd9\x8f");
}
if (slot == 3) {
return EL_STR("\xd8\xaa\xd9\x8e\xd9\x82\xd9\x8f\xd9\x88\xd9\x84\xd9\x90\xd9\x8a\xd9\x86\xd9\x8e");
}
if (slot == 4) {
return EL_STR("\xd8\xa3\xd9\x8e\xd9\x82\xd9\x8f\xd9\x88\xd9\x84\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd9\x8a\xd9\x8e\xd9\x82\xd9\x8f\xd9\x88\xd9\x84\xd9\x8f\xd9\x88\xd9\x86\xd9\x8e");
}
if (slot == 6) {
return EL_STR("\xd9\x8a\xd9\x8e\xd9\x82\xd9\x8f\xd9\x84\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd8\xaa\xd9\x8e\xd9\x82\xd9\x8f\xd9\x88\xd9\x84\xd9\x8f\xd9\x88\xd9\x86\xd9\x8e");
}
if (slot == 8) {
return EL_STR("\xd8\xaa\xd9\x8e\xd9\x82\xd9\x8f\xd9\x84\xd9\x92\xd9\x86\xd9\x8e");
}
return EL_STR("\xd9\x86\xd9\x8e\xd9\x82\xd9\x8f\xd9\x88\xd9\x84\xd9\x8f");
}
if (str_eq(tense, EL_STR("future"))) {
el_val_t pres = ar_irregular_qaala(slot, EL_STR("present"));
return el_str_concat(EL_STR("\xd8\xb3\xd9\x8e"), pres);
}
return EL_STR("\xd9\x82\xd9\x8e\xd8\xa7\xd9\x84\xd9\x8e");
return 0;
}
el_val_t ar_irregular_jaa(el_val_t slot, el_val_t tense) {
if (str_eq(tense, EL_STR("past"))) {
if (slot == 0) {
return EL_STR("\xd8\xac\xd9\x8e\xd8\xa7\xd8\xa1\xd9\x8e");
}
if (slot == 1) {
return EL_STR("\xd8\xac\xd9\x8e\xd8\xa7\xd8\xa1\xd9\x8e\xd8\xaa\xd9\x92");
}
if (slot == 2) {
return EL_STR("\xd8\xac\xd9\x90\xd8\xa6\xd9\x92\xd8\xaa\xd9\x8e");
}
if (slot == 3) {
return EL_STR("\xd8\xac\xd9\x90\xd8\xa6\xd9\x92\xd8\xaa\xd9\x90");
}
if (slot == 4) {
return EL_STR("\xd8\xac\xd9\x90\xd8\xa6\xd9\x92\xd8\xaa\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd8\xac\xd9\x8e\xd8\xa7\xd8\xa1\xd9\x8f\xd9\x88\xd8\xa7");
}
if (slot == 6) {
return EL_STR("\xd8\xac\xd9\x90\xd8\xa6\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd8\xac\xd9\x90\xd8\xa6\xd9\x92\xd8\xaa\xd9\x8f\xd9\x85\xd9\x92");
}
if (slot == 8) {
return EL_STR("\xd8\xac\xd9\x90\xd8\xa6\xd9\x92\xd8\xaa\xd9\x8f\xd9\x86\xd9\x8e\xd9\x91");
}
return EL_STR("\xd8\xac\xd9\x90\xd8\xa6\xd9\x92\xd9\x86\xd9\x8e\xd8\xa7");
}
if (str_eq(tense, EL_STR("present"))) {
if (slot == 0) {
return EL_STR("\xd9\x8a\xd9\x8e\xd8\xac\xd9\x90\xd9\x8a\xd8\xa1\xd9\x8f");
}
if (slot == 1) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xac\xd9\x90\xd9\x8a\xd8\xa1\xd9\x8f");
}
if (slot == 2) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xac\xd9\x90\xd9\x8a\xd8\xa1\xd9\x8f");
}
if (slot == 3) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xac\xd9\x90\xd9\x8a\xd8\xa6\xd9\x90\xd9\x8a\xd9\x86\xd9\x8e");
}
if (slot == 4) {
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xac\xd9\x90\xd9\x8a\xd8\xa1\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd9\x8a\xd9\x8e\xd8\xac\xd9\x90\xd9\x8a\xd8\xa6\xd9\x8f\xd9\x88\xd9\x86\xd9\x8e");
}
if (slot == 6) {
return EL_STR("\xd9\x8a\xd9\x8e\xd8\xac\xd9\x90\xd8\xa6\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xac\xd9\x90\xd9\x8a\xd8\xa6\xd9\x8f\xd9\x88\xd9\x86\xd9\x8e");
}
if (slot == 8) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xac\xd9\x90\xd8\xa6\xd9\x92\xd9\x86\xd9\x8e");
}
return EL_STR("\xd9\x86\xd9\x8e\xd8\xac\xd9\x90\xd9\x8a\xd8\xa1\xd9\x8f");
}
if (str_eq(tense, EL_STR("future"))) {
el_val_t pres = ar_irregular_jaa(slot, EL_STR("present"));
return el_str_concat(EL_STR("\xd8\xb3\xd9\x8e"), pres);
}
return EL_STR("\xd8\xac\xd9\x8e\xd8\xa7\xd8\xa1\xd9\x8e");
return 0;
}
el_val_t ar_irregular_raaa(el_val_t slot, el_val_t tense) {
if (str_eq(tense, EL_STR("past"))) {
if (slot == 0) {
return EL_STR("\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e\xd9\x89");
}
if (slot == 1) {
return EL_STR("\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e\xd8\xaa\xd9\x92");
}
if (slot == 2) {
return EL_STR("\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e\xd9\x8a\xd9\x92\xd8\xaa\xd9\x8e");
}
if (slot == 3) {
return EL_STR("\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e\xd9\x8a\xd9\x92\xd8\xaa\xd9\x90");
}
if (slot == 4) {
return EL_STR("\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e\xd9\x8a\xd9\x92\xd8\xaa\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e\xd9\x88\xd9\x92\xd8\xa7");
}
if (slot == 6) {
return EL_STR("\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e\xd9\x8a\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e\xd9\x8a\xd9\x92\xd8\xaa\xd9\x8f\xd9\x85\xd9\x92");
}
if (slot == 8) {
return EL_STR("\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e\xd9\x8a\xd9\x92\xd8\xaa\xd9\x8f\xd9\x86\xd9\x8e\xd9\x91");
}
return EL_STR("\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e\xd9\x8a\xd9\x92\xd9\x86\xd9\x8e\xd8\xa7");
}
if (str_eq(tense, EL_STR("present"))) {
if (slot == 0) {
return EL_STR("\xd9\x8a\xd9\x8e\xd8\xb1\xd9\x8e\xd9\x89");
}
if (slot == 1) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xb1\xd9\x8e\xd9\x89");
}
if (slot == 2) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xb1\xd9\x8e\xd9\x89");
}
if (slot == 3) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xb1\xd9\x8e\xd9\x8a\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 4) {
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd9\x89");
}
if (slot == 5) {
return EL_STR("\xd9\x8a\xd9\x8e\xd8\xb1\xd9\x8e\xd9\x88\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 6) {
return EL_STR("\xd9\x8a\xd9\x8e\xd8\xb1\xd9\x8e\xd9\x8a\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xb1\xd9\x8e\xd9\x88\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 8) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xb1\xd9\x8e\xd9\x8a\xd9\x92\xd9\x86\xd9\x8e");
}
return EL_STR("\xd9\x86\xd9\x8e\xd8\xb1\xd9\x8e\xd9\x89");
}
if (str_eq(tense, EL_STR("future"))) {
el_val_t pres = ar_irregular_raaa(slot, EL_STR("present"));
return el_str_concat(EL_STR("\xd8\xb3\xd9\x8e"), pres);
}
return EL_STR("\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e\xd9\x89");
return 0;
}
el_val_t ar_irregular_araada(el_val_t slot, el_val_t tense) {
if (str_eq(tense, EL_STR("past"))) {
if (slot == 0) {
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xa7\xd8\xaf\xd9\x8e");
}
if (slot == 1) {
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xa7\xd8\xaf\xd9\x8e\xd8\xaa\xd9\x92");
}
if (slot == 2) {
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xaf\xd9\x92\xd8\xaa\xd9\x8e");
}
if (slot == 3) {
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xaf\xd9\x92\xd8\xaa\xd9\x90");
}
if (slot == 4) {
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xaf\xd9\x92\xd8\xaa\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xa7\xd8\xaf\xd9\x8f\xd9\x88\xd8\xa7");
}
if (slot == 6) {
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xaf\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xaf\xd9\x92\xd8\xaa\xd9\x8f\xd9\x85\xd9\x92");
}
if (slot == 8) {
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xaf\xd9\x92\xd8\xaa\xd9\x8f\xd9\x86\xd9\x8e\xd9\x91");
}
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xaf\xd9\x92\xd9\x86\xd9\x8e\xd8\xa7");
}
if (str_eq(tense, EL_STR("present"))) {
if (slot == 0) {
return EL_STR("\xd9\x8a\xd9\x8f\xd8\xb1\xd9\x90\xd9\x8a\xd8\xaf\xd9\x8f");
}
if (slot == 1) {
return EL_STR("\xd8\xaa\xd9\x8f\xd8\xb1\xd9\x90\xd9\x8a\xd8\xaf\xd9\x8f");
}
if (slot == 2) {
return EL_STR("\xd8\xaa\xd9\x8f\xd8\xb1\xd9\x90\xd9\x8a\xd8\xaf\xd9\x8f");
}
if (slot == 3) {
return EL_STR("\xd8\xaa\xd9\x8f\xd8\xb1\xd9\x90\xd9\x8a\xd8\xaf\xd9\x90\xd9\x8a\xd9\x86\xd9\x8e");
}
if (slot == 4) {
return EL_STR("\xd8\xa3\xd9\x8f\xd8\xb1\xd9\x90\xd9\x8a\xd8\xaf\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd9\x8a\xd9\x8f\xd8\xb1\xd9\x90\xd9\x8a\xd8\xaf\xd9\x8f\xd9\x88\xd9\x86\xd9\x8e");
}
if (slot == 6) {
return EL_STR("\xd9\x8a\xd9\x8f\xd8\xb1\xd9\x90\xd8\xaf\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd8\xaa\xd9\x8f\xd8\xb1\xd9\x90\xd9\x8a\xd8\xaf\xd9\x8f\xd9\x88\xd9\x86\xd9\x8e");
}
if (slot == 8) {
return EL_STR("\xd8\xaa\xd9\x8f\xd8\xb1\xd9\x90\xd8\xaf\xd9\x92\xd9\x86\xd9\x8e");
}
return EL_STR("\xd9\x86\xd9\x8f\xd8\xb1\xd9\x90\xd9\x8a\xd8\xaf\xd9\x8f");
}
if (str_eq(tense, EL_STR("future"))) {
el_val_t pres = ar_irregular_araada(slot, EL_STR("present"));
return el_str_concat(EL_STR("\xd8\xb3\xd9\x8e"), pres);
}
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xa7\xd8\xaf\xd9\x8e");
return 0;
}
el_val_t ar_irregular_istata(el_val_t slot, el_val_t tense) {
if (str_eq(tense, EL_STR("past"))) {
if (slot == 0) {
return EL_STR("\xd8\xa7\xd9\x90\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x8e\xd8\xa7\xd8\xb9\xd9\x8e");
}
if (slot == 1) {
return EL_STR("\xd8\xa7\xd9\x90\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x8e\xd8\xa7\xd8\xb9\xd9\x8e\xd8\xaa\xd9\x92");
}
if (slot == 2) {
return EL_STR("\xd8\xa7\xd9\x90\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x8e\xd8\xb9\xd9\x92\xd8\xaa\xd9\x8e");
}
if (slot == 3) {
return EL_STR("\xd8\xa7\xd9\x90\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x8e\xd8\xb9\xd9\x92\xd8\xaa\xd9\x90");
}
if (slot == 4) {
return EL_STR("\xd8\xa7\xd9\x90\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x8e\xd8\xb9\xd9\x92\xd8\xaa\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd8\xa7\xd9\x90\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x8e\xd8\xa7\xd8\xb9\xd9\x8f\xd9\x88\xd8\xa7");
}
if (slot == 6) {
return EL_STR("\xd8\xa7\xd9\x90\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x8e\xd8\xb9\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd8\xa7\xd9\x90\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x8e\xd8\xb9\xd9\x92\xd8\xaa\xd9\x8f\xd9\x85\xd9\x92");
}
if (slot == 8) {
return EL_STR("\xd8\xa7\xd9\x90\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x8e\xd8\xb9\xd9\x92\xd8\xaa\xd9\x8f\xd9\x86\xd9\x8e\xd9\x91");
}
return EL_STR("\xd8\xa7\xd9\x90\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x8e\xd8\xb9\xd9\x92\xd9\x86\xd9\x8e\xd8\xa7");
}
if (str_eq(tense, EL_STR("present"))) {
if (slot == 0) {
return EL_STR("\xd9\x8a\xd9\x8e\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x90\xd9\x8a\xd8\xb9\xd9\x8f");
}
if (slot == 1) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x90\xd9\x8a\xd8\xb9\xd9\x8f");
}
if (slot == 2) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x90\xd9\x8a\xd8\xb9\xd9\x8f");
}
if (slot == 3) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x90\xd9\x8a\xd8\xb9\xd9\x90\xd9\x8a\xd9\x86\xd9\x8e");
}
if (slot == 4) {
return EL_STR("\xd8\xa3\xd9\x8e\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x90\xd9\x8a\xd8\xb9\xd9\x8f");
}
if (slot == 5) {
return EL_STR("\xd9\x8a\xd9\x8e\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x90\xd9\x8a\xd8\xb9\xd9\x8f\xd9\x88\xd9\x86\xd9\x8e");
}
if (slot == 6) {
return EL_STR("\xd9\x8a\xd9\x8e\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x90\xd8\xb9\xd9\x92\xd9\x86\xd9\x8e");
}
if (slot == 7) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x90\xd9\x8a\xd8\xb9\xd9\x8f\xd9\x88\xd9\x86\xd9\x8e");
}
if (slot == 8) {
return EL_STR("\xd8\xaa\xd9\x8e\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x90\xd8\xb9\xd9\x92\xd9\x86\xd9\x8e");
}
return EL_STR("\xd9\x86\xd9\x8e\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x90\xd9\x8a\xd8\xb9\xd9\x8f");
}
if (str_eq(tense, EL_STR("future"))) {
el_val_t pres = ar_irregular_istata(slot, EL_STR("present"));
return el_str_concat(EL_STR("\xd8\xb3\xd9\x8e"), pres);
}
return EL_STR("\xd8\xa7\xd9\x90\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x8e\xd8\xa7\xd8\xb9\xd9\x8e");
return 0;
}
el_val_t ar_irregular(el_val_t verb, el_val_t tense, el_val_t slot) {
if (str_eq(verb, EL_STR("\xd9\x83\xd9\x8e\xd8\xa7\xd9\x86\xd9\x8e"))) {
return ar_irregular_kaana(slot, tense);
}
if (str_eq(verb, EL_STR("\xd9\x82\xd9\x8e\xd8\xa7\xd9\x84\xd9\x8e"))) {
return ar_irregular_qaala(slot, tense);
}
if (str_eq(verb, EL_STR("\xd8\xac\xd9\x8e\xd8\xa7\xd8\xa1\xd9\x8e"))) {
return ar_irregular_jaa(slot, tense);
}
if (str_eq(verb, EL_STR("\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e\xd9\x89"))) {
return ar_irregular_raaa(slot, tense);
}
if (str_eq(verb, EL_STR("\xd8\xa3\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xa7\xd8\xaf\xd9\x8e"))) {
return ar_irregular_araada(slot, tense);
}
if (str_eq(verb, EL_STR("\xd8\xa7\xd9\x90\xd8\xb3\xd9\x92\xd8\xaa\xd9\x8e\xd8\xb7\xd9\x8e\xd8\xa7\xd8\xb9\xd9\x8e"))) {
return ar_irregular_istata(slot, tense);
}
return EL_STR("");
return 0;
}
el_val_t ar_present_stem(el_val_t verb) {
if (str_eq(verb, EL_STR("\xd9\x83\xd9\x8e\xd8\xaa\xd9\x8e\xd8\xa8\xd9\x8e"))) {
return EL_STR("\xd9\x83\xd9\x92\xd8\xaa\xd9\x8f\xd8\xa8\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xb0\xd9\x8e\xd9\x87\xd9\x8e\xd8\xa8\xd9\x8e"))) {
return EL_STR("\xd8\xb0\xd9\x92\xd9\x87\xd9\x8e\xd8\xa8\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xa3\xd9\x8e\xd9\x83\xd9\x8e\xd9\x84\xd9\x8e"))) {
return EL_STR("\xd8\xa3\xd9\x92\xd9\x83\xd9\x8f\xd9\x84\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xb4\xd9\x8e\xd8\xb1\xd9\x90\xd8\xa8\xd9\x8e"))) {
return EL_STR("\xd8\xb4\xd9\x92\xd8\xb1\xd9\x8e\xd8\xa8\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xb9\xd9\x8e\xd8\xb1\xd9\x8e\xd9\x81\xd9\x8e"))) {
return EL_STR("\xd8\xb9\xd9\x92\xd8\xb1\xd9\x90\xd9\x81\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd9\x81\xd9\x8e\xd8\xb9\xd9\x8e\xd9\x84\xd9\x8e"))) {
return EL_STR("\xd9\x81\xd9\x92\xd8\xb9\xd9\x8e\xd9\x84\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xa3\xd9\x8e\xd8\xae\xd9\x8e\xd8\xb0\xd9\x8e"))) {
return EL_STR("\xd8\xa3\xd9\x92\xd8\xae\xd9\x8f\xd8\xb0\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xb9\xd9\x8e\xd9\x85\xd9\x90\xd9\x84\xd9\x8e"))) {
return EL_STR("\xd8\xb9\xd9\x92\xd9\x85\xd9\x8e\xd9\x84\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xaf\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xb3\xd9\x8e"))) {
return EL_STR("\xd8\xaf\xd9\x92\xd8\xb1\xd9\x8f\xd8\xb3\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd9\x81\xd9\x8e\xd9\x87\xd9\x90\xd9\x85\xd9\x8e"))) {
return EL_STR("\xd9\x81\xd9\x92\xd9\x87\xd9\x8e\xd9\x85\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xb3\xd9\x8e\xd9\x85\xd9\x90\xd8\xb9\xd9\x8e"))) {
return EL_STR("\xd8\xb3\xd9\x92\xd9\x85\xd9\x8e\xd8\xb9\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xac\xd9\x8e\xd9\x84\xd9\x8e\xd8\xb3\xd9\x8e"))) {
return EL_STR("\xd8\xac\xd9\x92\xd9\x84\xd9\x90\xd8\xb3\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd9\x81\xd9\x8e\xd8\xaa\xd9\x8e\xd8\xad\xd9\x8e"))) {
return EL_STR("\xd9\x81\xd9\x92\xd8\xaa\xd9\x8e\xd8\xad\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xae\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xac\xd9\x8e"))) {
return EL_STR("\xd8\xae\xd9\x92\xd8\xb1\xd9\x8f\xd8\xac\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xaf\xd9\x8e\xd8\xae\xd9\x8e\xd9\x84\xd9\x8e"))) {
return EL_STR("\xd8\xaf\xd9\x92\xd8\xae\xd9\x8f\xd9\x84\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd9\x88\xd9\x8e\xd8\xac\xd9\x8e\xd8\xaf\xd9\x8e"))) {
return EL_STR("\xd8\xac\xd9\x90\xd8\xaf\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xb5\xd9\x8e\xd9\x86\xd9\x8e\xd8\xb9\xd9\x8e"))) {
return EL_STR("\xd8\xb5\xd9\x92\xd9\x86\xd9\x8e\xd8\xb9\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd8\xb1\xd9\x8e\xd8\xac\xd9\x8e\xd8\xb9\xd9\x8e"))) {
return EL_STR("\xd8\xb1\xd9\x92\xd8\xac\xd9\x90\xd8\xb9\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd9\x88\xd9\x8e\xd9\x82\xd9\x8e\xd9\x81\xd9\x8e"))) {
return EL_STR("\xd9\x82\xd9\x90\xd9\x81\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd9\x82\xd9\x8e\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8e"))) {
return EL_STR("\xd9\x82\xd9\x92\xd8\xb1\xd9\x8e\xd8\xa3\xd9\x8f");
}
if (str_eq(verb, EL_STR("\xd9\x83\xd9\x8e\xd8\xb0\xd9\x8e\xd8\xa8\xd9\x8e"))) {
return EL_STR("\xd9\x83\xd9\x92\xd8\xb0\xd9\x90\xd8\xa8\xd9\x8f");
}
return EL_STR("");
return 0;
}
el_val_t ar_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t gender, el_val_t number) {
el_val_t slot = ar_slot(person, gender, number);
el_val_t irreg = ar_irregular(verb, tense, slot);
if (!str_eq(irreg, EL_STR(""))) {
return irreg;
}
el_val_t present_stem = ar_present_stem(verb);
if (!str_eq(present_stem, EL_STR(""))) {
return ar_conjugate_form1(verb, present_stem, tense, slot);
}
return verb;
return 0;
}
el_val_t ar_is_sun_letter(el_val_t c) {
if (str_eq(c, EL_STR("\xd8\xaa"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd8\xab"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd8\xaf"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd8\xb0"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd8\xb1"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd8\xb2"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd8\xb3"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd8\xb4"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd8\xb5"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd8\xb6"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd8\xb7"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd8\xb8"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd9\x84"))) {
return 1;
}
if (str_eq(c, EL_STR("\xd9\x86"))) {
return 1;
}
return 0;
return 0;
}
el_val_t ar_definite_article(el_val_t noun) {
el_val_t n = ar_str_len(noun);
if (n == 0) {
return noun;
}
el_val_t first = str_slice(noun, 0, 1);
if (ar_is_sun_letter(first)) {
el_val_t shadda = EL_STR("\xd9\x91");
el_val_t rest = str_slice(noun, 1, n);
return el_str_concat(el_str_concat(el_str_concat(EL_STR("\xd8\xa7\xd9\x84"), first), shadda), rest);
}
return el_str_concat(EL_STR("\xd8\xa7\xd9\x84"), noun);
return 0;
}
el_val_t ar_case_ending(el_val_t kase, el_val_t definite) {
el_val_t is_def = str_eq(definite, EL_STR("true"));
if (str_eq(kase, EL_STR("nom"))) {
if (is_def) {
return EL_STR("\xd9\x8f");
}
return EL_STR("\xd9\x8c");
}
if (str_eq(kase, EL_STR("acc"))) {
if (is_def) {
return EL_STR("\xd9\x8e");
}
return EL_STR("\xd9\x8b");
}
if (str_eq(kase, EL_STR("gen"))) {
if (is_def) {
return EL_STR("\xd9\x90");
}
return EL_STR("\xd9\x8d");
}
return EL_STR("");
return 0;
}
el_val_t ar_gender(el_val_t noun) {
if (ar_str_ends(noun, EL_STR("\xd8\xa9"))) {
return EL_STR("f");
}
if (ar_str_ends(noun, EL_STR("\xd9\x80\xd8\xa9"))) {
return EL_STR("f");
}
return EL_STR("m");
return 0;
}
el_val_t ar_masc_pl_ending(el_val_t kase) {
if (str_eq(kase, EL_STR("nom"))) {
return EL_STR("\xd9\x88\xd9\x86\xd9\x8e");
}
return EL_STR("\xd9\x8a\xd9\x86\xd9\x8e");
return 0;
}
el_val_t ar_sound_plural(el_val_t noun, el_val_t gender) {
if (str_eq(gender, EL_STR("f"))) {
if (ar_str_ends(noun, EL_STR("\xd8\xa9"))) {
el_val_t base = ar_str_drop_last(noun, 1);
return el_str_concat(base, EL_STR("\xd8\xa7\xd8\xaa"));
}
return el_str_concat(noun, EL_STR("\xd8\xa7\xd8\xaa"));
}
return el_str_concat(noun, EL_STR("\xd9\x88\xd9\x86"));
return 0;
}
el_val_t ar_noun_form(el_val_t noun, el_val_t gender, el_val_t kase, el_val_t number, el_val_t definite) {
el_val_t g = gender;
if (str_eq(g, EL_STR(""))) {
g = ar_gender(noun);
}
el_val_t stem = noun;
if (str_eq(number, EL_STR("plural"))) {
if (str_eq(g, EL_STR("m"))) {
el_val_t pl_suf = ar_masc_pl_ending(kase);
if (str_eq(definite, EL_STR("true"))) {
el_val_t def_stem = ar_definite_article(noun);
return el_str_concat(def_stem, pl_suf);
}
return el_str_concat(noun, pl_suf);
}
el_val_t fem_pl = ar_sound_plural(noun, EL_STR("f"));
el_val_t case_end = ar_case_ending(kase, definite);
if (str_eq(definite, EL_STR("true"))) {
return el_str_concat(ar_definite_article(fem_pl), case_end);
}
return el_str_concat(fem_pl, case_end);
}
el_val_t case_end = ar_case_ending(kase, definite);
if (str_eq(definite, EL_STR("true"))) {
el_val_t def_stem = ar_definite_article(noun);
return el_str_concat(def_stem, case_end);
}
return el_str_concat(noun, case_end);
return 0;
}
el_val_t ar_verb_form(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
return ar_conjugate(verb, tense, person, EL_STR("m"), number);
return 0;
}
Generated Vendored
+27
View File
@@ -0,0 +1,27 @@
// auto-generated by elc --emit-header — do not edit
extern fn ar_str_ends(s: String, suf: String) -> Bool
extern fn ar_str_len(s: String) -> Int
extern fn ar_str_drop_last(s: String, n: Int) -> String
extern fn ar_str_last_char(s: String) -> String
extern fn ar_slot(person: String, gender: String, number: String) -> Int
extern fn ar_perfect_suffix(slot: Int) -> String
extern fn ar_imperfect_prefix(slot: Int) -> String
extern fn ar_imperfect_suffix(slot: Int) -> String
extern fn ar_conjugate_form1(past_base: String, present_stem: String, tense: String, slot: Int) -> String
extern fn ar_irregular_kaana(slot: Int, tense: String) -> String
extern fn ar_irregular_qaala(slot: Int, tense: String) -> String
extern fn ar_irregular_jaa(slot: Int, tense: String) -> String
extern fn ar_irregular_raaa(slot: Int, tense: String) -> String
extern fn ar_irregular_araada(slot: Int, tense: String) -> String
extern fn ar_irregular_istata(slot: Int, tense: String) -> String
extern fn ar_irregular(verb: String, tense: String, slot: Int) -> String
extern fn ar_present_stem(verb: String) -> String
extern fn ar_conjugate(verb: String, tense: String, person: String, gender: String, number: String) -> String
extern fn ar_is_sun_letter(c: String) -> Bool
extern fn ar_definite_article(noun: String) -> String
extern fn ar_case_ending(kase: String, definite: String) -> String
extern fn ar_gender(noun: String) -> String
extern fn ar_masc_pl_ending(kase: String) -> String
extern fn ar_sound_plural(noun: String, gender: String) -> String
extern fn ar_noun_form(noun: String, gender: String, kase: String, number: String, definite: String) -> String
extern fn ar_verb_form(verb: String, tense: String, person: String, number: String) -> String
Generated Vendored
+556
View File
@@ -0,0 +1,556 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t cop_str_ends(el_val_t s, el_val_t suf);
el_val_t cop_str_len(el_val_t s);
el_val_t cop_drop(el_val_t s, el_val_t n);
el_val_t cop_last_char(el_val_t s);
el_val_t cop_slot(el_val_t person, el_val_t number);
el_val_t cop_subject_prefix(el_val_t person, el_val_t number);
el_val_t cop_subject_prefix_gendered(el_val_t person, el_val_t gender, el_val_t number);
el_val_t cop_copula_particle(el_val_t gender, el_val_t number);
el_val_t cop_shwpe_present(el_val_t prefix);
el_val_t cop_shwpe_perfect(el_val_t prefix);
el_val_t cop_shwpe_future(el_val_t prefix);
el_val_t cop_bwk_present(el_val_t prefix);
el_val_t cop_bwk_perfect(el_val_t prefix);
el_val_t cop_bwk_future(el_val_t prefix);
el_val_t cop_nau_present(el_val_t prefix);
el_val_t cop_nau_perfect(el_val_t prefix);
el_val_t cop_nau_future(el_val_t prefix);
el_val_t cop_jw_present(el_val_t prefix);
el_val_t cop_jw_perfect(el_val_t prefix);
el_val_t cop_jw_future(el_val_t prefix);
el_val_t cop_di_present(el_val_t prefix);
el_val_t cop_di_perfect(el_val_t prefix);
el_val_t cop_di_future(el_val_t prefix);
el_val_t cop_is_copula(el_val_t verb);
el_val_t cop_known_verb_prefixed(el_val_t verb, el_val_t tense, el_val_t prefix);
el_val_t cop_regular_present(el_val_t prefix, el_val_t stem);
el_val_t cop_regular_perfect(el_val_t prefix, el_val_t stem);
el_val_t cop_regular_future(el_val_t prefix, el_val_t stem);
el_val_t cop_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t cop_article(el_val_t gender, el_val_t number, el_val_t definite);
el_val_t cop_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t cop_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t cop_noun_phrase_gendered(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite, el_val_t gender);
el_val_t cop_map_canonical(el_val_t verb);
el_val_t cop_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t cop_str_len(el_val_t s) {
return str_len(s);
return 0;
}
el_val_t cop_drop(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t cop_last_char(el_val_t s) {
el_val_t n = str_len(s);
if (n == 0) {
return EL_STR("");
}
return str_slice(s, (n - 1), n);
return 0;
}
el_val_t cop_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t cop_subject_prefix(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return EL_STR("\xe2\xb2\x81");
}
return EL_STR("\xe2\xb2\x9b");
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return EL_STR("\xe2\xb2\x95");
}
return EL_STR("\xe2\xb2\xa7\xe2\xb2\x89\xe2\xb2\xa7\xe2\xb2\x89\xe2\xb2\x9b");
}
if (str_eq(number, EL_STR("singular"))) {
return EL_STR("\xcf\xa5");
}
return EL_STR("\xe2\xb2\xa5\xe2\xb2\x89");
return 0;
}
el_val_t cop_subject_prefix_gendered(el_val_t person, el_val_t gender, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return EL_STR("\xe2\xb2\x81");
}
return EL_STR("\xe2\xb2\x9b");
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gender, EL_STR("f"))) {
return EL_STR("\xe2\xb2\xa7\xe2\xb2\x89");
}
return EL_STR("\xe2\xb2\x95");
}
return EL_STR("\xe2\xb2\xa7\xe2\xb2\x89\xe2\xb2\xa7\xe2\xb2\x89\xe2\xb2\x9b");
}
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gender, EL_STR("f"))) {
return EL_STR("\xe2\xb2\xa5");
}
return EL_STR("\xcf\xa5");
}
return EL_STR("\xe2\xb2\xa5\xe2\xb2\x89");
return 0;
}
el_val_t cop_copula_particle(el_val_t gender, el_val_t number) {
if (str_eq(number, EL_STR("plural"))) {
return EL_STR("\xe2\xb2\x9b\xe2\xb2\x89");
}
if (str_eq(gender, EL_STR("f"))) {
return EL_STR("\xe2\xb2\xa7\xe2\xb2\x89");
}
return EL_STR("\xe2\xb2\xa1\xe2\xb2\x89");
return 0;
}
el_val_t cop_shwpe_present(el_val_t prefix) {
return el_str_concat(prefix, EL_STR("\xcf\xa3\xe2\xb2\x9f\xe2\xb2\x9f\xe2\xb2\xa1"));
return 0;
}
el_val_t cop_shwpe_perfect(el_val_t prefix) {
return el_str_concat(el_str_concat(EL_STR("\xe2\xb2\x81"), prefix), EL_STR("\xcf\xa3\xe2\xb2\xb1\xe2\xb2\xa1\xe2\xb2\x89"));
return 0;
}
el_val_t cop_shwpe_future(el_val_t prefix) {
return el_str_concat(prefix, EL_STR("\xe2\xb2\x9b\xe2\xb2\x81\xcf\xa3\xe2\xb2\xb1\xe2\xb2\xa1\xe2\xb2\x89"));
return 0;
}
el_val_t cop_bwk_present(el_val_t prefix) {
return el_str_concat(prefix, EL_STR("\xe2\xb2\x83\xe2\xb2\xb1\xe2\xb2\x95"));
return 0;
}
el_val_t cop_bwk_perfect(el_val_t prefix) {
return el_str_concat(el_str_concat(EL_STR("\xe2\xb2\x81"), prefix), EL_STR("\xe2\xb2\x83\xe2\xb2\xb1\xe2\xb2\x95"));
return 0;
}
el_val_t cop_bwk_future(el_val_t prefix) {
return el_str_concat(prefix, EL_STR("\xe2\xb2\x9b\xe2\xb2\x81\xe2\xb2\x83\xe2\xb2\xb1\xe2\xb2\x95"));
return 0;
}
el_val_t cop_nau_present(el_val_t prefix) {
return el_str_concat(prefix, EL_STR("\xe2\xb2\x9b\xe2\xb2\x81\xe2\xb2\xa9"));
return 0;
}
el_val_t cop_nau_perfect(el_val_t prefix) {
return el_str_concat(el_str_concat(EL_STR("\xe2\xb2\x81"), prefix), EL_STR("\xe2\xb2\x9b\xe2\xb2\x81\xe2\xb2\xa9"));
return 0;
}
el_val_t cop_nau_future(el_val_t prefix) {
return el_str_concat(prefix, EL_STR("\xe2\xb2\x9b\xe2\xb2\x81\xe2\xb2\x9b\xe2\xb2\x81\xe2\xb2\xa9"));
return 0;
}
el_val_t cop_jw_present(el_val_t prefix) {
return el_str_concat(prefix, EL_STR("\xcf\xab\xe2\xb2\xb1"));
return 0;
}
el_val_t cop_jw_perfect(el_val_t prefix) {
return el_str_concat(el_str_concat(EL_STR("\xe2\xb2\x81"), prefix), EL_STR("\xcf\xab\xe2\xb2\xb1"));
return 0;
}
el_val_t cop_jw_future(el_val_t prefix) {
return el_str_concat(prefix, EL_STR("\xe2\xb2\x9b\xe2\xb2\x81\xcf\xab\xe2\xb2\xb1"));
return 0;
}
el_val_t cop_di_present(el_val_t prefix) {
return el_str_concat(prefix, EL_STR("\xcf\xaf"));
return 0;
}
el_val_t cop_di_perfect(el_val_t prefix) {
return el_str_concat(el_str_concat(EL_STR("\xe2\xb2\x81"), prefix), EL_STR("\xcf\xaf"));
return 0;
}
el_val_t cop_di_future(el_val_t prefix) {
return el_str_concat(prefix, EL_STR("\xe2\xb2\x9b\xe2\xb2\x81\xcf\xaf"));
return 0;
}
el_val_t cop_is_copula(el_val_t verb) {
if (str_eq(verb, EL_STR("\xcf\xa3\xcf\x89\xcf\x80\xce\xb5"))) {
return 1;
}
if (str_eq(verb, EL_STR("shwpe"))) {
return 1;
}
if (str_eq(verb, EL_STR("be"))) {
return 1;
}
return 0;
return 0;
}
el_val_t cop_known_verb_prefixed(el_val_t verb, el_val_t tense, el_val_t prefix) {
if (str_eq(verb, EL_STR("\xcf\xa3\xcf\x89\xcf\x80\xce\xb5"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_shwpe_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_shwpe_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_shwpe_future(prefix);
}
return cop_shwpe_present(prefix);
}
if (str_eq(verb, EL_STR("shwpe"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_shwpe_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_shwpe_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_shwpe_future(prefix);
}
return cop_shwpe_present(prefix);
}
if (str_eq(verb, EL_STR("bwk"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_bwk_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_bwk_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_bwk_future(prefix);
}
return cop_bwk_present(prefix);
}
if (str_eq(verb, EL_STR("\xe2\xb2\x83\xe2\xb2\xb1\xe2\xb2\x95"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_bwk_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_bwk_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_bwk_future(prefix);
}
return cop_bwk_present(prefix);
}
if (str_eq(verb, EL_STR("go"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_bwk_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_bwk_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_bwk_future(prefix);
}
return cop_bwk_present(prefix);
}
if (str_eq(verb, EL_STR("nau"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_nau_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_nau_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_nau_future(prefix);
}
return cop_nau_present(prefix);
}
if (str_eq(verb, EL_STR("\xe2\xb2\x9b\xe2\xb2\x81\xe2\xb2\xa9"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_nau_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_nau_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_nau_future(prefix);
}
return cop_nau_present(prefix);
}
if (str_eq(verb, EL_STR("see"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_nau_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_nau_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_nau_future(prefix);
}
return cop_nau_present(prefix);
}
if (str_eq(verb, EL_STR("jw"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_jw_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_jw_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_jw_future(prefix);
}
return cop_jw_present(prefix);
}
if (str_eq(verb, EL_STR("\xcf\xab\xe2\xb2\xb1"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_jw_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_jw_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_jw_future(prefix);
}
return cop_jw_present(prefix);
}
if (str_eq(verb, EL_STR("say"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_jw_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_jw_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_jw_future(prefix);
}
return cop_jw_present(prefix);
}
if (str_eq(verb, EL_STR("di"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_di_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_di_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_di_future(prefix);
}
return cop_di_present(prefix);
}
if (str_eq(verb, EL_STR("\xcf\xaf"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_di_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_di_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_di_future(prefix);
}
return cop_di_present(prefix);
}
if (str_eq(verb, EL_STR("give"))) {
if (str_eq(tense, EL_STR("present"))) {
return cop_di_present(prefix);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_di_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_di_future(prefix);
}
return cop_di_present(prefix);
}
return EL_STR("");
return 0;
}
el_val_t cop_regular_present(el_val_t prefix, el_val_t stem) {
return el_str_concat(prefix, stem);
return 0;
}
el_val_t cop_regular_perfect(el_val_t prefix, el_val_t stem) {
return el_str_concat(el_str_concat(EL_STR("\xe2\xb2\x81"), prefix), stem);
return 0;
}
el_val_t cop_regular_future(el_val_t prefix, el_val_t stem) {
return el_str_concat(el_str_concat(prefix, EL_STR("\xe2\xb2\x9b\xe2\xb2\x81")), stem);
return 0;
}
el_val_t cop_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t prefix = cop_subject_prefix(person, number);
if (str_eq(verb, EL_STR("be"))) {
if (str_eq(tense, EL_STR("present"))) {
return EL_STR("");
}
if (str_eq(tense, EL_STR("past"))) {
return cop_shwpe_perfect(prefix);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_shwpe_future(prefix);
}
return EL_STR("");
}
el_val_t known = cop_known_verb_prefixed(verb, tense, prefix);
if (!str_eq(known, EL_STR(""))) {
return known;
}
if (str_eq(tense, EL_STR("present"))) {
return cop_regular_present(prefix, verb);
}
if (str_eq(tense, EL_STR("past"))) {
return cop_regular_perfect(prefix, verb);
}
if (str_eq(tense, EL_STR("future"))) {
return cop_regular_future(prefix, verb);
}
return verb;
return 0;
}
el_val_t cop_article(el_val_t gender, el_val_t number, el_val_t definite) {
if (str_eq(definite, EL_STR("true"))) {
if (str_eq(number, EL_STR("plural"))) {
return EL_STR("\xe2\xb2\x9b");
}
if (str_eq(gender, EL_STR("f"))) {
return EL_STR("\xe2\xb2\xa7");
}
return EL_STR("\xe2\xb2\xa1");
}
if (str_eq(number, EL_STR("plural"))) {
return EL_STR("\xcf\xa9\xe2\xb2\x89\xe2\xb2\x9b");
}
return EL_STR("\xe2\xb2\x9f\xe2\xb2\xa9");
return 0;
}
el_val_t cop_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
return noun;
}
if (cop_str_ends(noun, EL_STR("\xe2\xb2\x89"))) {
el_val_t stem = cop_drop(noun, 1);
return el_str_concat(stem, EL_STR("\xe2\xb2\x9f\xe2\xb2\x9f\xe2\xb2\xa9\xe2\xb2\x89"));
}
return noun;
return 0;
}
el_val_t cop_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
el_val_t form = cop_decline(noun, gram_case, number);
el_val_t art = cop_article(EL_STR("m"), number, definite);
if (str_eq(definite, EL_STR("true"))) {
return el_str_concat(art, form);
}
if (str_eq(definite, EL_STR("false"))) {
return el_str_concat(art, form);
}
return form;
return 0;
}
el_val_t cop_noun_phrase_gendered(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite, el_val_t gender) {
el_val_t form = cop_decline(noun, gram_case, number);
el_val_t art = cop_article(gender, number, definite);
if (str_eq(definite, EL_STR("true"))) {
return el_str_concat(art, form);
}
if (str_eq(definite, EL_STR("false"))) {
return el_str_concat(art, form);
}
return form;
return 0;
}
el_val_t cop_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("be");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("bwk");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("nau");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("jw");
}
if (str_eq(verb, EL_STR("speak"))) {
return EL_STR("jw");
}
if (str_eq(verb, EL_STR("give"))) {
return EL_STR("di");
}
return verb;
return 0;
}
Generated Vendored
+35
View File
@@ -0,0 +1,35 @@
// auto-generated by elc --emit-header — do not edit
extern fn cop_str_ends(s: String, suf: String) -> Bool
extern fn cop_str_len(s: String) -> Int
extern fn cop_drop(s: String, n: Int) -> String
extern fn cop_last_char(s: String) -> String
extern fn cop_slot(person: String, number: String) -> Int
extern fn cop_subject_prefix(person: String, number: String) -> String
extern fn cop_subject_prefix_gendered(person: String, gender: String, number: String) -> String
extern fn cop_copula_particle(gender: String, number: String) -> String
extern fn cop_shwpe_present(prefix: String) -> String
extern fn cop_shwpe_perfect(prefix: String) -> String
extern fn cop_shwpe_future(prefix: String) -> String
extern fn cop_bwk_present(prefix: String) -> String
extern fn cop_bwk_perfect(prefix: String) -> String
extern fn cop_bwk_future(prefix: String) -> String
extern fn cop_nau_present(prefix: String) -> String
extern fn cop_nau_perfect(prefix: String) -> String
extern fn cop_nau_future(prefix: String) -> String
extern fn cop_jw_present(prefix: String) -> String
extern fn cop_jw_perfect(prefix: String) -> String
extern fn cop_jw_future(prefix: String) -> String
extern fn cop_di_present(prefix: String) -> String
extern fn cop_di_perfect(prefix: String) -> String
extern fn cop_di_future(prefix: String) -> String
extern fn cop_is_copula(verb: String) -> Bool
extern fn cop_known_verb_prefixed(verb: String, tense: String, prefix: String) -> String
extern fn cop_regular_present(prefix: String, stem: String) -> String
extern fn cop_regular_perfect(prefix: String, stem: String) -> String
extern fn cop_regular_future(prefix: String, stem: String) -> String
extern fn cop_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn cop_article(gender: String, number: String, definite: String) -> String
extern fn cop_decline(noun: String, gram_case: String, number: String) -> String
extern fn cop_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
extern fn cop_noun_phrase_gendered(noun: String, gram_case: String, number: String, definite: String, gender: String) -> String
extern fn cop_map_canonical(verb: String) -> String
Generated Vendored
+1172
View File
File diff suppressed because it is too large Load Diff
Generated Vendored
+13
View File
@@ -0,0 +1,13 @@
// auto-generated by elc --emit-header — do not edit
extern fn de_article_def(gender: String, gram_case: String, number: String) -> String
extern fn de_article_indef(gender: String, gram_case: String, number: String) -> String
extern fn de_article(gender: String, gram_case: String, number: String, definite: String) -> String
extern fn de_adj_ending(gender: String, gram_case: String, number: String, article_type: String) -> String
extern fn de_noun_plural(noun: String, gender: String) -> String
extern fn de_case_ending(noun: String, gender: String, gram_case: String, number: String) -> String
extern fn de_conjugate_weak(stem: String, tense: String, person: String, number: String) -> String
extern fn de_irregular_present(verb: String, person: String, number: String) -> String
extern fn de_strong_past_stem(verb: String) -> String
extern fn de_norm_number(number: String) -> String
extern fn de_norm_person(person: String) -> String
extern fn de_conjugate(verb: String, tense: String, person: String, number: String) -> String
Generated Vendored
+634
View File
@@ -0,0 +1,634 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t egy_str_ends(el_val_t s, el_val_t suf);
el_val_t egy_str_len(el_val_t s);
el_val_t egy_drop(el_val_t s, el_val_t n);
el_val_t egy_last_char(el_val_t s);
el_val_t egy_slot(el_val_t person, el_val_t number);
el_val_t egy_slot_with_gender(el_val_t person, el_val_t gender, el_val_t number);
el_val_t egy_conjugate_pronoun(el_val_t person, el_val_t number);
el_val_t egy_suffix_pronoun(el_val_t slot);
el_val_t egy_is_copula(el_val_t verb);
el_val_t egy_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t egy_rdi_present(el_val_t slot);
el_val_t egy_rdi_past(el_val_t slot);
el_val_t egy_rdi_future(el_val_t slot);
el_val_t egy_mAA_present(el_val_t slot);
el_val_t egy_mAA_past(el_val_t slot);
el_val_t egy_mAA_future(el_val_t slot);
el_val_t egy_Dd_present(el_val_t slot);
el_val_t egy_Dd_past(el_val_t slot);
el_val_t egy_Dd_future(el_val_t slot);
el_val_t egy_Sm_present(el_val_t slot);
el_val_t egy_Sm_past(el_val_t slot);
el_val_t egy_Sm_future(el_val_t slot);
el_val_t egy_iri_present(el_val_t slot);
el_val_t egy_iri_past(el_val_t slot);
el_val_t egy_iri_future(el_val_t slot);
el_val_t egy_sdm_present(el_val_t slot);
el_val_t egy_sdm_past(el_val_t slot);
el_val_t egy_sdm_future(el_val_t slot);
el_val_t egy_known_verb(el_val_t verb, el_val_t tense, el_val_t slot);
el_val_t egy_regular_present(el_val_t stem, el_val_t slot);
el_val_t egy_regular_past(el_val_t stem, el_val_t slot);
el_val_t egy_regular_future(el_val_t stem, el_val_t slot);
el_val_t egy_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t egy_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t egy_fem(el_val_t noun);
el_val_t egy_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t egy_map_canonical(el_val_t verb);
el_val_t egy_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t egy_str_len(el_val_t s) {
return str_len(s);
return 0;
}
el_val_t egy_drop(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t egy_last_char(el_val_t s) {
el_val_t n = str_len(s);
if (n == 0) {
return EL_STR("");
}
return str_slice(s, (n - 1), n);
return 0;
}
el_val_t egy_slot(el_val_t person, el_val_t number) {
if (str_eq(number, EL_STR("dual"))) {
return 8;
}
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("plural"))) {
return 5;
}
return 0;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("plural"))) {
return 6;
}
return 1;
}
if (str_eq(number, EL_STR("plural"))) {
return 7;
}
return 3;
return 0;
}
el_val_t egy_slot_with_gender(el_val_t person, el_val_t gender, el_val_t number) {
if (str_eq(number, EL_STR("dual"))) {
return 8;
}
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("plural"))) {
return 5;
}
return 0;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("plural"))) {
return 6;
}
if (str_eq(gender, EL_STR("f"))) {
return 2;
}
return 1;
}
if (str_eq(number, EL_STR("plural"))) {
return 7;
}
if (str_eq(gender, EL_STR("f"))) {
return 4;
}
return 3;
return 0;
}
el_val_t egy_conjugate_pronoun(el_val_t person, el_val_t number) {
el_val_t slot = egy_slot(person, number);
if (slot == 0) {
return EL_STR("=i");
}
if (slot == 1) {
return EL_STR("=k");
}
if (slot == 5) {
return EL_STR("=n");
}
if (slot == 6) {
return EL_STR("=Tn");
}
if (slot == 7) {
return EL_STR("=sn");
}
if (slot == 8) {
return EL_STR("=sny");
}
return EL_STR("=f");
return 0;
}
el_val_t egy_suffix_pronoun(el_val_t slot) {
if (slot == 0) {
return EL_STR("=i");
}
if (slot == 1) {
return EL_STR("=k");
}
if (slot == 2) {
return EL_STR("=T");
}
if (slot == 3) {
return EL_STR("=f");
}
if (slot == 4) {
return EL_STR("=s");
}
if (slot == 5) {
return EL_STR("=n");
}
if (slot == 6) {
return EL_STR("=Tn");
}
if (slot == 7) {
return EL_STR("=sn");
}
return EL_STR("=sny");
return 0;
}
el_val_t egy_is_copula(el_val_t verb) {
if (str_eq(verb, EL_STR("wnn"))) {
return 1;
}
if (str_eq(verb, EL_STR("be"))) {
return 1;
}
return 0;
return 0;
}
el_val_t egy_conjugate_copula(el_val_t tense, el_val_t slot) {
if (str_eq(tense, EL_STR("present"))) {
return EL_STR("");
}
if (str_eq(tense, EL_STR("past"))) {
return el_str_concat(EL_STR("wnn.n"), egy_suffix_pronoun(slot));
}
if (str_eq(tense, EL_STR("future"))) {
return el_str_concat(EL_STR("wnn.xr"), egy_suffix_pronoun(slot));
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("wnn");
}
return EL_STR("");
return 0;
}
el_val_t egy_rdi_present(el_val_t slot) {
return el_str_concat(EL_STR("di"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_rdi_past(el_val_t slot) {
return el_str_concat(EL_STR("di.n"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_rdi_future(el_val_t slot) {
return el_str_concat(EL_STR("di.xr"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_mAA_present(el_val_t slot) {
return el_str_concat(EL_STR("mAA"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_mAA_past(el_val_t slot) {
return el_str_concat(EL_STR("mAA.n"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_mAA_future(el_val_t slot) {
return el_str_concat(EL_STR("mAA.xr"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_Dd_present(el_val_t slot) {
return el_str_concat(EL_STR("Dd"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_Dd_past(el_val_t slot) {
return el_str_concat(EL_STR("Dd.n"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_Dd_future(el_val_t slot) {
return el_str_concat(EL_STR("Dd.xr"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_Sm_present(el_val_t slot) {
return el_str_concat(EL_STR("Sm"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_Sm_past(el_val_t slot) {
return el_str_concat(EL_STR("Sm.n"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_Sm_future(el_val_t slot) {
return el_str_concat(EL_STR("Sm.xr"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_iri_present(el_val_t slot) {
return el_str_concat(EL_STR("ir"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_iri_past(el_val_t slot) {
return el_str_concat(EL_STR("ir.n"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_iri_future(el_val_t slot) {
return el_str_concat(EL_STR("ir.xr"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_sdm_present(el_val_t slot) {
return el_str_concat(EL_STR("sdm"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_sdm_past(el_val_t slot) {
return el_str_concat(EL_STR("sdm.n"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_sdm_future(el_val_t slot) {
return el_str_concat(EL_STR("sdm.xr"), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_known_verb(el_val_t verb, el_val_t tense, el_val_t slot) {
if (str_eq(verb, EL_STR("rdi"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_rdi_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_rdi_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_rdi_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("rdi");
}
return egy_rdi_present(slot);
}
if (str_eq(verb, EL_STR("di"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_rdi_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_rdi_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_rdi_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("rdi");
}
return egy_rdi_present(slot);
}
if (str_eq(verb, EL_STR("give"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_rdi_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_rdi_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_rdi_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("rdi");
}
return egy_rdi_present(slot);
}
if (str_eq(verb, EL_STR("mAA"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_mAA_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_mAA_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_mAA_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("mAA");
}
return egy_mAA_present(slot);
}
if (str_eq(verb, EL_STR("see"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_mAA_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_mAA_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_mAA_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("mAA");
}
return egy_mAA_present(slot);
}
if (str_eq(verb, EL_STR("Dd"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_Dd_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_Dd_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_Dd_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("Dd");
}
return egy_Dd_present(slot);
}
if (str_eq(verb, EL_STR("say"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_Dd_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_Dd_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_Dd_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("Dd");
}
return egy_Dd_present(slot);
}
if (str_eq(verb, EL_STR("Sm"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_Sm_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_Sm_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_Sm_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("Sm");
}
return egy_Sm_present(slot);
}
if (str_eq(verb, EL_STR("go"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_Sm_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_Sm_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_Sm_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("Sm");
}
return egy_Sm_present(slot);
}
if (str_eq(verb, EL_STR("iri"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_iri_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_iri_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_iri_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("iri");
}
return egy_iri_present(slot);
}
if (str_eq(verb, EL_STR("do"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_iri_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_iri_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_iri_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("iri");
}
return egy_iri_present(slot);
}
if (str_eq(verb, EL_STR("make"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_iri_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_iri_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_iri_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("iri");
}
return egy_iri_present(slot);
}
if (str_eq(verb, EL_STR("sdm"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_sdm_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_sdm_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_sdm_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("sdm");
}
return egy_sdm_present(slot);
}
if (str_eq(verb, EL_STR("hear"))) {
if (str_eq(tense, EL_STR("present"))) {
return egy_sdm_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_sdm_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_sdm_future(slot);
}
if (str_eq(tense, EL_STR("infinitive"))) {
return EL_STR("sdm");
}
return egy_sdm_present(slot);
}
return EL_STR("");
return 0;
}
el_val_t egy_regular_present(el_val_t stem, el_val_t slot) {
return el_str_concat(stem, egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_regular_past(el_val_t stem, el_val_t slot) {
return el_str_concat(el_str_concat(stem, EL_STR(".n")), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_regular_future(el_val_t stem, el_val_t slot) {
return el_str_concat(el_str_concat(stem, EL_STR(".xr")), egy_suffix_pronoun(slot));
return 0;
}
el_val_t egy_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t slot = egy_slot(person, number);
if (egy_is_copula(verb)) {
return egy_conjugate_copula(tense, slot);
}
el_val_t known = egy_known_verb(verb, tense, slot);
if (!str_eq(known, EL_STR(""))) {
return known;
}
if (str_eq(tense, EL_STR("infinitive"))) {
return verb;
}
if (str_eq(tense, EL_STR("present"))) {
return egy_regular_present(verb, slot);
}
if (str_eq(tense, EL_STR("past"))) {
return egy_regular_past(verb, slot);
}
if (str_eq(tense, EL_STR("future"))) {
return egy_regular_future(verb, slot);
}
return verb;
return 0;
}
el_val_t egy_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
return noun;
}
if (str_eq(number, EL_STR("dual"))) {
if (egy_str_ends(noun, EL_STR("t"))) {
el_val_t stem = egy_drop(noun, 1);
return el_str_concat(stem, EL_STR("ty"));
}
return el_str_concat(noun, EL_STR("wy"));
}
if (egy_str_ends(noun, EL_STR("t"))) {
return el_str_concat(noun, EL_STR("wt"));
}
return el_str_concat(noun, EL_STR("w"));
return 0;
}
el_val_t egy_fem(el_val_t noun) {
if (egy_str_ends(noun, EL_STR("t"))) {
return noun;
}
return el_str_concat(noun, EL_STR("t"));
return 0;
}
el_val_t egy_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
return egy_decline(noun, gram_case, number);
return 0;
}
el_val_t egy_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("wnn");
}
if (str_eq(verb, EL_STR("give"))) {
return EL_STR("rdi");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("mAA");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("Dd");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("Sm");
}
if (str_eq(verb, EL_STR("do"))) {
return EL_STR("iri");
}
if (str_eq(verb, EL_STR("make"))) {
return EL_STR("iri");
}
if (str_eq(verb, EL_STR("hear"))) {
return EL_STR("sdm");
}
return verb;
return 0;
}
Generated Vendored
+38
View File
@@ -0,0 +1,38 @@
// auto-generated by elc --emit-header — do not edit
extern fn egy_str_ends(s: String, suf: String) -> Bool
extern fn egy_str_len(s: String) -> Int
extern fn egy_drop(s: String, n: Int) -> String
extern fn egy_last_char(s: String) -> String
extern fn egy_slot(person: String, number: String) -> Int
extern fn egy_slot_with_gender(person: String, gender: String, number: String) -> Int
extern fn egy_conjugate_pronoun(person: String, number: String) -> String
extern fn egy_suffix_pronoun(slot: Int) -> String
extern fn egy_is_copula(verb: String) -> Bool
extern fn egy_conjugate_copula(tense: String, slot: Int) -> String
extern fn egy_rdi_present(slot: Int) -> String
extern fn egy_rdi_past(slot: Int) -> String
extern fn egy_rdi_future(slot: Int) -> String
extern fn egy_mAA_present(slot: Int) -> String
extern fn egy_mAA_past(slot: Int) -> String
extern fn egy_mAA_future(slot: Int) -> String
extern fn egy_Dd_present(slot: Int) -> String
extern fn egy_Dd_past(slot: Int) -> String
extern fn egy_Dd_future(slot: Int) -> String
extern fn egy_Sm_present(slot: Int) -> String
extern fn egy_Sm_past(slot: Int) -> String
extern fn egy_Sm_future(slot: Int) -> String
extern fn egy_iri_present(slot: Int) -> String
extern fn egy_iri_past(slot: Int) -> String
extern fn egy_iri_future(slot: Int) -> String
extern fn egy_sdm_present(slot: Int) -> String
extern fn egy_sdm_past(slot: Int) -> String
extern fn egy_sdm_future(slot: Int) -> String
extern fn egy_known_verb(verb: String, tense: String, slot: Int) -> String
extern fn egy_regular_present(stem: String, slot: Int) -> String
extern fn egy_regular_past(stem: String, slot: Int) -> String
extern fn egy_regular_future(stem: String, slot: Int) -> String
extern fn egy_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn egy_decline(noun: String, gram_case: String, number: String) -> String
extern fn egy_fem(noun: String) -> String
extern fn egy_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
extern fn egy_map_canonical(verb: String) -> String
Generated Vendored
+633
View File
@@ -0,0 +1,633 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t enm_str_ends(el_val_t s, el_val_t suf);
el_val_t enm_drop(el_val_t s, el_val_t n);
el_val_t enm_first_char(el_val_t s);
el_val_t enm_slot(el_val_t person, el_val_t number);
el_val_t enm_been_present(el_val_t slot);
el_val_t enm_been_past(el_val_t slot);
el_val_t enm_haven_present(el_val_t slot);
el_val_t enm_haven_past(el_val_t slot);
el_val_t enm_goon_present(el_val_t slot);
el_val_t enm_goon_past(el_val_t slot);
el_val_t enm_seen_present(el_val_t slot);
el_val_t enm_seen_past(el_val_t slot);
el_val_t enm_seyen_present(el_val_t slot);
el_val_t enm_seyen_past(el_val_t slot);
el_val_t enm_comen_present(el_val_t slot);
el_val_t enm_comen_past(el_val_t slot);
el_val_t enm_maken_present(el_val_t slot);
el_val_t enm_maken_past(el_val_t slot);
el_val_t enm_map_canonical(el_val_t verb);
el_val_t enm_weak_stem(el_val_t verb);
el_val_t enm_weak_present(el_val_t stem, el_val_t slot);
el_val_t enm_weak_past(el_val_t stem, el_val_t slot);
el_val_t enm_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t enm_irregular_plural(el_val_t noun);
el_val_t enm_make_plural(el_val_t noun);
el_val_t enm_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t enm_is_vowel_initial(el_val_t s);
el_val_t enm_indef_article(el_val_t noun_phrase);
el_val_t enm_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t enm_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t enm_drop(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t enm_first_char(el_val_t s) {
if (str_len(s) == 0) {
return EL_STR("");
}
return str_slice(s, 0, 1);
return 0;
}
el_val_t enm_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t enm_been_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("am");
}
if (slot == 1) {
return EL_STR("art");
}
if (slot == 2) {
return EL_STR("is");
}
if (slot == 3) {
return EL_STR("aren");
}
if (slot == 4) {
return EL_STR("been");
}
return EL_STR("been");
return 0;
}
el_val_t enm_been_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("was");
}
if (slot == 1) {
return EL_STR("were");
}
if (slot == 2) {
return EL_STR("was");
}
if (slot == 3) {
return EL_STR("were");
}
if (slot == 4) {
return EL_STR("were");
}
return EL_STR("were");
return 0;
}
el_val_t enm_haven_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("have");
}
if (slot == 1) {
return EL_STR("hast");
}
if (slot == 2) {
return EL_STR("hath");
}
if (slot == 3) {
return EL_STR("have");
}
if (slot == 4) {
return EL_STR("have");
}
return EL_STR("have");
return 0;
}
el_val_t enm_haven_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("hadde");
}
if (slot == 1) {
return EL_STR("haddest");
}
if (slot == 2) {
return EL_STR("hadde");
}
if (slot == 3) {
return EL_STR("hadden");
}
if (slot == 4) {
return EL_STR("hadden");
}
return EL_STR("hadden");
return 0;
}
el_val_t enm_goon_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("go");
}
if (slot == 1) {
return EL_STR("goost");
}
if (slot == 2) {
return EL_STR("gooth");
}
if (slot == 3) {
return EL_STR("goon");
}
if (slot == 4) {
return EL_STR("goon");
}
return EL_STR("goon");
return 0;
}
el_val_t enm_goon_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("wente");
}
if (slot == 1) {
return EL_STR("wentest");
}
if (slot == 2) {
return EL_STR("wente");
}
if (slot == 3) {
return EL_STR("wenten");
}
if (slot == 4) {
return EL_STR("wenten");
}
return EL_STR("wenten");
return 0;
}
el_val_t enm_seen_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("see");
}
if (slot == 1) {
return EL_STR("seest");
}
if (slot == 2) {
return EL_STR("seeth");
}
if (slot == 3) {
return EL_STR("seen");
}
if (slot == 4) {
return EL_STR("seen");
}
return EL_STR("seen");
return 0;
}
el_val_t enm_seen_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("saugh");
}
if (slot == 1) {
return EL_STR("sawest");
}
if (slot == 2) {
return EL_STR("saugh");
}
if (slot == 3) {
return EL_STR("sawen");
}
if (slot == 4) {
return EL_STR("sawen");
}
return EL_STR("sawen");
return 0;
}
el_val_t enm_seyen_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("seye");
}
if (slot == 1) {
return EL_STR("seyst");
}
if (slot == 2) {
return EL_STR("seith");
}
if (slot == 3) {
return EL_STR("seyen");
}
if (slot == 4) {
return EL_STR("seyen");
}
return EL_STR("seyen");
return 0;
}
el_val_t enm_seyen_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("seide");
}
if (slot == 1) {
return EL_STR("seidest");
}
if (slot == 2) {
return EL_STR("seide");
}
if (slot == 3) {
return EL_STR("seiden");
}
if (slot == 4) {
return EL_STR("seiden");
}
return EL_STR("seiden");
return 0;
}
el_val_t enm_comen_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("come");
}
if (slot == 1) {
return EL_STR("comest");
}
if (slot == 2) {
return EL_STR("cometh");
}
if (slot == 3) {
return EL_STR("comen");
}
if (slot == 4) {
return EL_STR("comen");
}
return EL_STR("comen");
return 0;
}
el_val_t enm_comen_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("cam");
}
if (slot == 1) {
return EL_STR("come");
}
if (slot == 2) {
return EL_STR("cam");
}
if (slot == 3) {
return EL_STR("comen");
}
if (slot == 4) {
return EL_STR("comen");
}
return EL_STR("comen");
return 0;
}
el_val_t enm_maken_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("make");
}
if (slot == 1) {
return EL_STR("makest");
}
if (slot == 2) {
return EL_STR("maketh");
}
if (slot == 3) {
return EL_STR("maken");
}
if (slot == 4) {
return EL_STR("maken");
}
return EL_STR("maken");
return 0;
}
el_val_t enm_maken_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("made");
}
if (slot == 1) {
return EL_STR("madest");
}
if (slot == 2) {
return EL_STR("made");
}
if (slot == 3) {
return EL_STR("maden");
}
if (slot == 4) {
return EL_STR("maden");
}
return EL_STR("maden");
return 0;
}
el_val_t enm_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("been");
}
if (str_eq(verb, EL_STR("have"))) {
return EL_STR("haven");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("goon");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("seen");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("seyen");
}
if (str_eq(verb, EL_STR("come"))) {
return EL_STR("comen");
}
if (str_eq(verb, EL_STR("make"))) {
return EL_STR("maken");
}
return verb;
return 0;
}
el_val_t enm_weak_stem(el_val_t verb) {
if (enm_str_ends(verb, EL_STR("en"))) {
return enm_drop(verb, 2);
}
if (enm_str_ends(verb, EL_STR("e"))) {
return enm_drop(verb, 1);
}
return verb;
return 0;
}
el_val_t enm_weak_present(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("e"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("est"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("eth"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("en"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("en"));
}
return el_str_concat(stem, EL_STR("en"));
return 0;
}
el_val_t enm_weak_past(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("ede"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("edest"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("ede"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("eden"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("eden"));
}
return el_str_concat(stem, EL_STR("eden"));
return 0;
}
el_val_t enm_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t v = enm_map_canonical(verb);
el_val_t slot = enm_slot(person, number);
if (str_eq(v, EL_STR("been"))) {
if (str_eq(tense, EL_STR("present"))) {
return enm_been_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return enm_been_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("haven"))) {
if (str_eq(tense, EL_STR("present"))) {
return enm_haven_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return enm_haven_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("goon"))) {
if (str_eq(tense, EL_STR("present"))) {
return enm_goon_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return enm_goon_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("seen"))) {
if (str_eq(tense, EL_STR("present"))) {
return enm_seen_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return enm_seen_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("seyen"))) {
if (str_eq(tense, EL_STR("present"))) {
return enm_seyen_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return enm_seyen_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("comen"))) {
if (str_eq(tense, EL_STR("present"))) {
return enm_comen_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return enm_comen_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("maken"))) {
if (str_eq(tense, EL_STR("present"))) {
return enm_maken_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return enm_maken_past(slot);
}
return v;
}
el_val_t stem = enm_weak_stem(v);
if (str_eq(tense, EL_STR("present"))) {
return enm_weak_present(stem, slot);
}
if (str_eq(tense, EL_STR("past"))) {
return enm_weak_past(stem, slot);
}
return v;
return 0;
}
el_val_t enm_irregular_plural(el_val_t noun) {
if (str_eq(noun, EL_STR("man"))) {
return EL_STR("men");
}
if (str_eq(noun, EL_STR("woman"))) {
return EL_STR("wommen");
}
if (str_eq(noun, EL_STR("child"))) {
return EL_STR("children");
}
if (str_eq(noun, EL_STR("ox"))) {
return EL_STR("oxen");
}
if (str_eq(noun, EL_STR("foot"))) {
return EL_STR("feet");
}
if (str_eq(noun, EL_STR("tooth"))) {
return EL_STR("teeth");
}
if (str_eq(noun, EL_STR("goose"))) {
return EL_STR("gees");
}
if (str_eq(noun, EL_STR("mouse"))) {
return EL_STR("mees");
}
if (str_eq(noun, EL_STR("louse"))) {
return EL_STR("lees");
}
return EL_STR("");
return 0;
}
el_val_t enm_make_plural(el_val_t noun) {
el_val_t irreg = enm_irregular_plural(noun);
if (!str_eq(irreg, EL_STR(""))) {
return irreg;
}
if (enm_str_ends(noun, EL_STR("e"))) {
return el_str_concat(noun, EL_STR("s"));
}
return el_str_concat(noun, EL_STR("es"));
return 0;
}
el_val_t enm_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("plural"))) {
return enm_make_plural(noun);
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("es"));
}
return noun;
return 0;
}
el_val_t enm_is_vowel_initial(el_val_t s) {
el_val_t c = enm_first_char(s);
if (str_eq(c, EL_STR("a"))) {
return 1;
}
if (str_eq(c, EL_STR("e"))) {
return 1;
}
if (str_eq(c, EL_STR("i"))) {
return 1;
}
if (str_eq(c, EL_STR("o"))) {
return 1;
}
if (str_eq(c, EL_STR("u"))) {
return 1;
}
return 0;
return 0;
}
el_val_t enm_indef_article(el_val_t noun_phrase) {
if (enm_is_vowel_initial(noun_phrase)) {
return EL_STR("an");
}
return EL_STR("a");
return 0;
}
el_val_t enm_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
el_val_t form = enm_decline(noun, gram_case, number);
if (str_eq(definite, EL_STR("true"))) {
return el_str_concat(EL_STR("the "), form);
}
if (str_eq(number, EL_STR("plural"))) {
return form;
}
el_val_t art = enm_indef_article(form);
return el_str_concat(el_str_concat(art, EL_STR(" ")), form);
return 0;
}
Generated Vendored
+30
View File
@@ -0,0 +1,30 @@
// auto-generated by elc --emit-header — do not edit
extern fn enm_str_ends(s: String, suf: String) -> Bool
extern fn enm_drop(s: String, n: Int) -> String
extern fn enm_first_char(s: String) -> String
extern fn enm_slot(person: String, number: String) -> Int
extern fn enm_been_present(slot: Int) -> String
extern fn enm_been_past(slot: Int) -> String
extern fn enm_haven_present(slot: Int) -> String
extern fn enm_haven_past(slot: Int) -> String
extern fn enm_goon_present(slot: Int) -> String
extern fn enm_goon_past(slot: Int) -> String
extern fn enm_seen_present(slot: Int) -> String
extern fn enm_seen_past(slot: Int) -> String
extern fn enm_seyen_present(slot: Int) -> String
extern fn enm_seyen_past(slot: Int) -> String
extern fn enm_comen_present(slot: Int) -> String
extern fn enm_comen_past(slot: Int) -> String
extern fn enm_maken_present(slot: Int) -> String
extern fn enm_maken_past(slot: Int) -> String
extern fn enm_map_canonical(verb: String) -> String
extern fn enm_weak_stem(verb: String) -> String
extern fn enm_weak_present(stem: String, slot: Int) -> String
extern fn enm_weak_past(stem: String, slot: Int) -> String
extern fn enm_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn enm_irregular_plural(noun: String) -> String
extern fn enm_make_plural(noun: String) -> String
extern fn enm_decline(noun: String, gram_case: String, number: String) -> String
extern fn enm_is_vowel_initial(s: String) -> Bool
extern fn enm_indef_article(noun_phrase: String) -> String
extern fn enm_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
Generated Vendored
+1054
View File
File diff suppressed because it is too large Load Diff
Generated Vendored
+23
View File
@@ -0,0 +1,23 @@
// auto-generated by elc --emit-header — do not edit
extern fn es_str_ends(s: String, suf: String) -> Bool
extern fn es_str_drop_last(s: String, n: Int) -> String
extern fn es_str_last_char(s: String) -> String
extern fn es_str_last2(s: String) -> String
extern fn es_str_last3(s: String) -> String
extern fn es_verb_class(base: String) -> String
extern fn es_stem(base: String) -> String
extern fn es_slot(person: String, number: String) -> Int
extern fn es_irregular_present(verb: String, person: String, number: String) -> String
extern fn es_irregular_preterite(verb: String, person: String, number: String) -> String
extern fn es_irregular_imperfect(verb: String, person: String, number: String) -> String
extern fn es_regular_present(stem: String, vclass: String, slot: Int) -> String
extern fn es_regular_preterite(stem: String, vclass: String, slot: Int) -> String
extern fn es_regular_future(base: String, slot: Int) -> String
extern fn es_irregular_future_stem(verb: String) -> String
extern fn es_regular_imperfect(stem: String, vclass: String, slot: Int) -> String
extern fn es_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn es_gender(noun: String) -> String
extern fn es_invariant_plural(noun: String) -> String
extern fn es_pluralize(noun: String) -> String
extern fn es_starts_with_stressed_a(noun: String) -> Bool
extern fn es_agree_article(noun: String, definite: String, number: String) -> String
Generated Vendored
+560
View File
@@ -0,0 +1,560 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t fi_harmony(el_val_t word);
el_val_t fi_suffix(el_val_t base, el_val_t harmony);
el_val_t fi_noun_case(el_val_t stem, el_val_t gram_case, el_val_t number, el_val_t harmony);
el_val_t fi_str_last_char(el_val_t s);
el_val_t fi_apply_case(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t fi_verb_stem(el_val_t dict_form);
el_val_t fi_irregular_verb(el_val_t dict_form);
el_val_t fi_present_ending(el_val_t stem, el_val_t person, el_val_t number, el_val_t harmony);
el_val_t fi_past_stem(el_val_t stem);
el_val_t fi_past_ending(el_val_t stem, el_val_t person, el_val_t number, el_val_t harmony);
el_val_t fi_neg_aux(el_val_t person, el_val_t number);
el_val_t fi_negative(el_val_t verb, el_val_t person, el_val_t number);
el_val_t fi_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t fi_question_suffix(el_val_t harmony);
el_val_t fi_make_question(el_val_t verb_form, el_val_t harmony);
el_val_t fi_full_paradigm(el_val_t noun);
el_val_t fi_harmony(el_val_t word) {
el_val_t n = str_len(word);
el_val_t i = (n - 1);
while (i >= 0) {
el_val_t c = str_slice(word, i, (i + 1));
if (str_eq(c, EL_STR("a"))) {
return EL_STR("back");
}
if (str_eq(c, EL_STR("o"))) {
return EL_STR("back");
}
if (str_eq(c, EL_STR("u"))) {
return EL_STR("back");
}
if (str_eq(c, EL_STR("\xc3\xa4"))) {
return EL_STR("front");
}
if (str_eq(c, EL_STR("\xc3\xb6"))) {
return EL_STR("front");
}
if (str_eq(c, EL_STR("y"))) {
return EL_STR("front");
}
i = (i - 1);
}
return EL_STR("front");
return 0;
}
el_val_t fi_suffix(el_val_t base, el_val_t harmony) {
if (str_eq(harmony, EL_STR("front"))) {
if (str_eq(base, EL_STR("a"))) {
return EL_STR("\xc3\xa4");
}
if (str_eq(base, EL_STR("ssa"))) {
return EL_STR("ss\xc3\xa4");
}
if (str_eq(base, EL_STR("sta"))) {
return EL_STR("st\xc3\xa4");
}
if (str_eq(base, EL_STR("an"))) {
return EL_STR("\xc3\xa4n");
}
if (str_eq(base, EL_STR("aan"))) {
return EL_STR("\xc3\xa4\xc3\xa4n");
}
if (str_eq(base, EL_STR("lla"))) {
return EL_STR("ll\xc3\xa4");
}
if (str_eq(base, EL_STR("lta"))) {
return EL_STR("lt\xc3\xa4");
}
if (str_eq(base, EL_STR("lle"))) {
return EL_STR("lle");
}
if (str_eq(base, EL_STR("na"))) {
return EL_STR("n\xc3\xa4");
}
if (str_eq(base, EL_STR("ksi"))) {
return EL_STR("ksi");
}
if (str_eq(base, EL_STR("tta"))) {
return EL_STR("tt\xc3\xa4");
}
if (str_eq(base, EL_STR("ta"))) {
return EL_STR("t\xc3\xa4");
}
if (str_eq(base, EL_STR("ja"))) {
return EL_STR("j\xc3\xa4");
}
if (str_eq(base, EL_STR("oja"))) {
return EL_STR("\xc3\xb6j\xc3\xa4");
}
if (str_eq(base, EL_STR("issa"))) {
return EL_STR("iss\xc3\xa4");
}
if (str_eq(base, EL_STR("ista"))) {
return EL_STR("ist\xc3\xa4");
}
if (str_eq(base, EL_STR("ihin"))) {
return EL_STR("ihin");
}
if (str_eq(base, EL_STR("illa"))) {
return EL_STR("ill\xc3\xa4");
}
if (str_eq(base, EL_STR("ilta"))) {
return EL_STR("ilt\xc3\xa4");
}
if (str_eq(base, EL_STR("ille"))) {
return EL_STR("ille");
}
if (str_eq(base, EL_STR("ina"))) {
return EL_STR("in\xc3\xa4");
}
if (str_eq(base, EL_STR("itta"))) {
return EL_STR("itt\xc3\xa4");
}
if (str_eq(base, EL_STR("ko"))) {
return EL_STR("k\xc3\xb6");
}
if (str_eq(base, EL_STR("pa"))) {
return EL_STR("p\xc3\xa4");
}
if (str_eq(base, EL_STR("va"))) {
return EL_STR("v\xc3\xa4");
}
if (str_eq(base, EL_STR("ma"))) {
return EL_STR("m\xc3\xa4");
}
if (str_eq(base, EL_STR("han"))) {
return EL_STR("h\xc3\xa4n");
}
if (str_eq(base, EL_STR("lla"))) {
return EL_STR("ll\xc3\xa4");
}
return base;
}
return base;
return 0;
}
el_val_t fi_noun_case(el_val_t stem, el_val_t gram_case, el_val_t number, el_val_t harmony) {
el_val_t sg = str_eq(number, EL_STR("singular"));
if (str_eq(gram_case, EL_STR("nominative"))) {
if (sg) {
return stem;
}
return el_str_concat(stem, EL_STR("t"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
if (sg) {
return el_str_concat(stem, EL_STR("n"));
}
return el_str_concat(stem, EL_STR("jen"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
if (sg) {
return el_str_concat(stem, EL_STR("n"));
}
return el_str_concat(stem, EL_STR("t"));
}
if (str_eq(gram_case, EL_STR("partitive"))) {
if (sg) {
return el_str_concat(stem, fi_suffix(EL_STR("a"), harmony));
}
return el_str_concat(stem, fi_suffix(EL_STR("ja"), harmony));
}
if (str_eq(gram_case, EL_STR("inessive"))) {
if (sg) {
return el_str_concat(stem, fi_suffix(EL_STR("ssa"), harmony));
}
return el_str_concat(stem, fi_suffix(EL_STR("issa"), harmony));
}
if (str_eq(gram_case, EL_STR("elative"))) {
if (sg) {
return el_str_concat(stem, fi_suffix(EL_STR("sta"), harmony));
}
return el_str_concat(stem, fi_suffix(EL_STR("ista"), harmony));
}
if (str_eq(gram_case, EL_STR("illative"))) {
if (sg) {
el_val_t last = fi_str_last_char(stem);
return el_str_concat(el_str_concat(stem, last), EL_STR("n"));
}
return el_str_concat(stem, fi_suffix(EL_STR("ihin"), harmony));
}
if (str_eq(gram_case, EL_STR("adessive"))) {
if (sg) {
return el_str_concat(stem, fi_suffix(EL_STR("lla"), harmony));
}
return el_str_concat(stem, fi_suffix(EL_STR("illa"), harmony));
}
if (str_eq(gram_case, EL_STR("ablative"))) {
if (sg) {
return el_str_concat(stem, fi_suffix(EL_STR("lta"), harmony));
}
return el_str_concat(stem, fi_suffix(EL_STR("ilta"), harmony));
}
if (str_eq(gram_case, EL_STR("allative"))) {
if (sg) {
return el_str_concat(stem, EL_STR("lle"));
}
return el_str_concat(stem, EL_STR("ille"));
}
if (str_eq(gram_case, EL_STR("essive"))) {
if (sg) {
return el_str_concat(stem, fi_suffix(EL_STR("na"), harmony));
}
return el_str_concat(stem, fi_suffix(EL_STR("ina"), harmony));
}
if (str_eq(gram_case, EL_STR("translative"))) {
if (sg) {
return el_str_concat(stem, EL_STR("ksi"));
}
return el_str_concat(stem, EL_STR("iksi"));
}
if (str_eq(gram_case, EL_STR("instructive"))) {
return el_str_concat(stem, EL_STR("in"));
}
if (str_eq(gram_case, EL_STR("abessive"))) {
if (sg) {
return el_str_concat(stem, fi_suffix(EL_STR("tta"), harmony));
}
return el_str_concat(stem, fi_suffix(EL_STR("itta"), harmony));
}
if (str_eq(gram_case, EL_STR("comitative"))) {
return el_str_concat(stem, EL_STR("ineen"));
}
return stem;
return 0;
}
el_val_t fi_str_last_char(el_val_t s) {
el_val_t n = str_len(s);
if (n == 0) {
return EL_STR("");
}
return str_slice(s, (n - 1), n);
return 0;
}
el_val_t fi_apply_case(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t harmony = fi_harmony(noun);
if (str_eq(gram_case, EL_STR("nominative"))) {
if (str_eq(number, EL_STR("singular"))) {
return noun;
}
return el_str_concat(noun, EL_STR("t"));
}
return fi_noun_case(noun, gram_case, number, harmony);
return 0;
}
el_val_t fi_verb_stem(el_val_t dict_form) {
if (str_ends_with(dict_form, EL_STR("da"))) {
return str_drop_last(dict_form, 2);
}
if (str_ends_with(dict_form, EL_STR("d\xc3\xa4"))) {
return str_drop_last(dict_form, 2);
}
if (str_ends_with(dict_form, EL_STR("lla"))) {
return str_drop_last(dict_form, 2);
}
if (str_ends_with(dict_form, EL_STR("ll\xc3\xa4"))) {
return str_drop_last(dict_form, 2);
}
if (str_ends_with(dict_form, EL_STR("rra"))) {
return str_drop_last(dict_form, 2);
}
if (str_ends_with(dict_form, EL_STR("nna"))) {
return str_drop_last(dict_form, 2);
}
if (str_ends_with(dict_form, EL_STR("a"))) {
return str_drop_last(dict_form, 1);
}
if (str_ends_with(dict_form, EL_STR("\xc3\xa4"))) {
return str_drop_last(dict_form, 1);
}
return dict_form;
return 0;
}
el_val_t fi_irregular_verb(el_val_t dict_form) {
el_val_t empty = el_list_empty();
if (str_eq(dict_form, EL_STR("olla"))) {
el_val_t r = el_list_new(18, EL_STR("olla"), EL_STR("olen"), EL_STR("olet"), EL_STR("on"), EL_STR("olemme"), EL_STR("olette"), EL_STR("ovat"), EL_STR("olin"), EL_STR("olit"), EL_STR("oli"), EL_STR("olimme"), EL_STR("olitte"), EL_STR("olivat"), EL_STR("ole"), EL_STR("olis"), EL_STR("ole"), EL_STR("oleva"), EL_STR("ollut"));
return r;
}
if (str_eq(dict_form, EL_STR("voida"))) {
el_val_t r = el_list_new(18, EL_STR("voida"), EL_STR("voin"), EL_STR("voit"), EL_STR("voi"), EL_STR("voimme"), EL_STR("voitte"), EL_STR("voivat"), EL_STR("voin"), EL_STR("voit"), EL_STR("voi"), EL_STR("voimme"), EL_STR("voitte"), EL_STR("voivat"), EL_STR("voi"), EL_STR("vois"), EL_STR("voi"), EL_STR("voiva"), EL_STR("voinut"));
return r;
}
if (str_eq(dict_form, EL_STR("menn\xc3\xa4"))) {
el_val_t r = el_list_new(18, EL_STR("menn\xc3\xa4"), EL_STR("menen"), EL_STR("menet"), EL_STR("menee"), EL_STR("menemme"), EL_STR("menette"), EL_STR("menev\xc3\xa4t"), EL_STR("menin"), EL_STR("menit"), EL_STR("meni"), EL_STR("menimme"), EL_STR("menitte"), EL_STR("meniv\xc3\xa4t"), EL_STR("mene"), EL_STR("menis"), EL_STR("mene"), EL_STR("menev\xc3\xa4"), EL_STR("mennyt"));
return r;
}
if (str_eq(dict_form, EL_STR("tulla"))) {
el_val_t r = el_list_new(18, EL_STR("tulla"), EL_STR("tulen"), EL_STR("tulet"), EL_STR("tulee"), EL_STR("tulemme"), EL_STR("tulette"), EL_STR("tulevat"), EL_STR("tulin"), EL_STR("tulit"), EL_STR("tuli"), EL_STR("tulimme"), EL_STR("tulitte"), EL_STR("tulivat"), EL_STR("tule"), EL_STR("tulis"), EL_STR("tule"), EL_STR("tuleva"), EL_STR("tullut"));
return r;
}
if (str_eq(dict_form, EL_STR("tehd\xc3\xa4"))) {
el_val_t r = el_list_new(18, EL_STR("tehd\xc3\xa4"), EL_STR("teen"), EL_STR("teet"), EL_STR("tekee"), EL_STR("teemme"), EL_STR("teette"), EL_STR("tekev\xc3\xa4t"), EL_STR("tein"), EL_STR("teit"), EL_STR("teki"), EL_STR("teimme"), EL_STR("teitte"), EL_STR("tekiv\xc3\xa4t"), EL_STR("tee"), EL_STR("tekis"), EL_STR("tee"), EL_STR("tekev\xc3\xa4"), EL_STR("tehnyt"));
return r;
}
if (str_eq(dict_form, EL_STR("n\xc3\xa4hd\xc3\xa4"))) {
el_val_t r = el_list_new(18, EL_STR("n\xc3\xa4hd\xc3\xa4"), EL_STR("n\xc3\xa4""en"), EL_STR("n\xc3\xa4""et"), EL_STR("n\xc3\xa4kee"), EL_STR("n\xc3\xa4""emme"), EL_STR("n\xc3\xa4""ette"), EL_STR("n\xc3\xa4kev\xc3\xa4t"), EL_STR("n\xc3\xa4in"), EL_STR("n\xc3\xa4it"), EL_STR("n\xc3\xa4ki"), EL_STR("n\xc3\xa4imme"), EL_STR("n\xc3\xa4itte"), EL_STR("n\xc3\xa4kiv\xc3\xa4t"), EL_STR("n\xc3\xa4""e"), EL_STR("n\xc3\xa4kis"), EL_STR("n\xc3\xa4""e"), EL_STR("n\xc3\xa4kev\xc3\xa4"), EL_STR("n\xc3\xa4hnyt"));
return r;
}
if (str_eq(dict_form, EL_STR("saada"))) {
el_val_t r = el_list_new(18, EL_STR("saada"), EL_STR("saan"), EL_STR("saat"), EL_STR("saa"), EL_STR("saamme"), EL_STR("saatte"), EL_STR("saavat"), EL_STR("sain"), EL_STR("sait"), EL_STR("sai"), EL_STR("saimme"), EL_STR("saitte"), EL_STR("saivat"), EL_STR("saa"), EL_STR("sais"), EL_STR("saa"), EL_STR("saava"), EL_STR("saanut"));
return r;
}
if (str_eq(dict_form, EL_STR("pit\xc3\xa4\xc3\xa4"))) {
el_val_t r = el_list_new(18, EL_STR("pit\xc3\xa4\xc3\xa4"), EL_STR("pid\xc3\xa4n"), EL_STR("pid\xc3\xa4t"), EL_STR("pit\xc3\xa4\xc3\xa4"), EL_STR("pid\xc3\xa4mme"), EL_STR("pid\xc3\xa4tte"), EL_STR("pit\xc3\xa4v\xc3\xa4t"), EL_STR("pidin"), EL_STR("pidit"), EL_STR("piti"), EL_STR("pidimme"), EL_STR("piditte"), EL_STR("pitiv\xc3\xa4t"), EL_STR("pid\xc3\xa4"), EL_STR("pit\xc3\xa4is"), EL_STR("pid\xc3\xa4"), EL_STR("pit\xc3\xa4v\xc3\xa4"), EL_STR("pit\xc3\xa4nyt"));
return r;
}
if (str_eq(dict_form, EL_STR("tiet\xc3\xa4\xc3\xa4"))) {
el_val_t r = el_list_new(18, EL_STR("tiet\xc3\xa4\xc3\xa4"), EL_STR("tied\xc3\xa4n"), EL_STR("tied\xc3\xa4t"), EL_STR("tiet\xc3\xa4\xc3\xa4"), EL_STR("tied\xc3\xa4mme"), EL_STR("tied\xc3\xa4tte"), EL_STR("tiet\xc3\xa4v\xc3\xa4t"), EL_STR("tiesin"), EL_STR("tiesit"), EL_STR("tiesi"), EL_STR("tiesimme"), EL_STR("tiesitte"), EL_STR("tiesiv\xc3\xa4t"), EL_STR("tied\xc3\xa4"), EL_STR("tiet\xc3\xa4is"), EL_STR("tied\xc3\xa4"), EL_STR("tiet\xc3\xa4v\xc3\xa4"), EL_STR("tiennyt"));
return r;
}
return empty;
return 0;
}
el_val_t fi_present_ending(el_val_t stem, el_val_t person, el_val_t number, el_val_t harmony) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(person, EL_STR("first"))) {
return el_str_concat(stem, EL_STR("n"));
}
if (str_eq(person, EL_STR("second"))) {
return el_str_concat(stem, EL_STR("t"));
}
if (str_eq(person, EL_STR("third"))) {
el_val_t last = fi_str_last_char(stem);
return el_str_concat(stem, last);
}
}
if (str_eq(number, EL_STR("plural"))) {
if (str_eq(person, EL_STR("first"))) {
return el_str_concat(stem, EL_STR("mme"));
}
if (str_eq(person, EL_STR("second"))) {
return el_str_concat(stem, EL_STR("tte"));
}
if (str_eq(person, EL_STR("third"))) {
return el_str_concat(stem, fi_suffix(EL_STR("vat"), harmony));
}
}
return stem;
return 0;
}
el_val_t fi_past_stem(el_val_t stem) {
el_val_t last = fi_str_last_char(stem);
if (str_eq(last, EL_STR("a"))) {
return el_str_concat(str_drop_last(stem, 1), EL_STR("oi"));
}
if (str_eq(last, EL_STR("\xc3\xa4"))) {
return el_str_concat(str_drop_last(stem, 1), EL_STR("\xc3\xb6i"));
}
return el_str_concat(stem, EL_STR("i"));
return 0;
}
el_val_t fi_past_ending(el_val_t stem, el_val_t person, el_val_t number, el_val_t harmony) {
el_val_t pstem = fi_past_stem(stem);
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(person, EL_STR("first"))) {
return el_str_concat(pstem, EL_STR("n"));
}
if (str_eq(person, EL_STR("second"))) {
return el_str_concat(pstem, EL_STR("t"));
}
if (str_eq(person, EL_STR("third"))) {
return str_drop_last(pstem, 1);
}
}
if (str_eq(number, EL_STR("plural"))) {
if (str_eq(person, EL_STR("first"))) {
return el_str_concat(pstem, EL_STR("mme"));
}
if (str_eq(person, EL_STR("second"))) {
return el_str_concat(pstem, EL_STR("tte"));
}
if (str_eq(person, EL_STR("third"))) {
return el_str_concat(pstem, fi_suffix(EL_STR("vat"), harmony));
}
}
return pstem;
return 0;
}
el_val_t fi_neg_aux(el_val_t person, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(person, EL_STR("first"))) {
return EL_STR("en");
}
if (str_eq(person, EL_STR("second"))) {
return EL_STR("et");
}
if (str_eq(person, EL_STR("third"))) {
return EL_STR("ei");
}
}
if (str_eq(number, EL_STR("plural"))) {
if (str_eq(person, EL_STR("first"))) {
return EL_STR("emme");
}
if (str_eq(person, EL_STR("second"))) {
return EL_STR("ette");
}
if (str_eq(person, EL_STR("third"))) {
return EL_STR("eiv\xc3\xa4t");
}
}
return EL_STR("ei");
return 0;
}
el_val_t fi_negative(el_val_t verb, el_val_t person, el_val_t number) {
el_val_t irreg = fi_irregular_verb(verb);
el_val_t aux = fi_neg_aux(person, number);
if (native_list_len(irreg) > 0) {
el_val_t neg_stem = native_list_get(irreg, 13);
return el_str_concat(el_str_concat(aux, EL_STR(" ")), neg_stem);
}
el_val_t stem = fi_verb_stem(verb);
return el_str_concat(el_str_concat(aux, EL_STR(" ")), stem);
return 0;
}
el_val_t fi_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t harmony = fi_harmony(verb);
el_val_t irreg = fi_irregular_verb(verb);
if (native_list_len(irreg) > 0) {
if (str_eq(tense, EL_STR("present"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(person, EL_STR("first"))) {
return native_list_get(irreg, 1);
}
if (str_eq(person, EL_STR("second"))) {
return native_list_get(irreg, 2);
}
if (str_eq(person, EL_STR("third"))) {
return native_list_get(irreg, 3);
}
}
if (str_eq(number, EL_STR("plural"))) {
if (str_eq(person, EL_STR("first"))) {
return native_list_get(irreg, 4);
}
if (str_eq(person, EL_STR("second"))) {
return native_list_get(irreg, 5);
}
if (str_eq(person, EL_STR("third"))) {
return native_list_get(irreg, 6);
}
}
}
if (str_eq(tense, EL_STR("past"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(person, EL_STR("first"))) {
return native_list_get(irreg, 7);
}
if (str_eq(person, EL_STR("second"))) {
return native_list_get(irreg, 8);
}
if (str_eq(person, EL_STR("third"))) {
return native_list_get(irreg, 9);
}
}
if (str_eq(number, EL_STR("plural"))) {
if (str_eq(person, EL_STR("first"))) {
return native_list_get(irreg, 10);
}
if (str_eq(person, EL_STR("second"))) {
return native_list_get(irreg, 11);
}
if (str_eq(person, EL_STR("third"))) {
return native_list_get(irreg, 12);
}
}
}
}
el_val_t stem = fi_verb_stem(verb);
if (str_eq(tense, EL_STR("present"))) {
return fi_present_ending(stem, person, number, harmony);
}
if (str_eq(tense, EL_STR("past"))) {
return fi_past_ending(stem, person, number, harmony);
}
return stem;
return 0;
}
el_val_t fi_question_suffix(el_val_t harmony) {
if (str_eq(harmony, EL_STR("front"))) {
return EL_STR("k\xc3\xb6");
}
return EL_STR("ko");
return 0;
}
el_val_t fi_make_question(el_val_t verb_form, el_val_t harmony) {
return el_str_concat(verb_form, fi_question_suffix(harmony));
return 0;
}
el_val_t fi_full_paradigm(el_val_t noun) {
el_val_t harmony = fi_harmony(noun);
el_val_t r = el_list_empty();
el_val_t cases = el_list_new(15, EL_STR("nominative"), EL_STR("genitive"), EL_STR("accusative"), EL_STR("partitive"), EL_STR("inessive"), EL_STR("elative"), EL_STR("illative"), EL_STR("adessive"), EL_STR("ablative"), EL_STR("allative"), EL_STR("essive"), EL_STR("translative"), EL_STR("instructive"), EL_STR("abessive"), EL_STR("comitative"));
el_val_t n = native_list_len(cases);
el_val_t i = 0;
while (i < n) {
el_val_t c = native_list_get(cases, i);
r = native_list_append(r, c);
if (str_eq(c, EL_STR("instructive"))) {
r = native_list_append(r, EL_STR(""));
} else {
if (str_eq(c, EL_STR("comitative"))) {
r = native_list_append(r, EL_STR(""));
} else {
r = native_list_append(r, fi_noun_case(noun, c, EL_STR("singular"), harmony));
}
}
r = native_list_append(r, fi_noun_case(noun, c, EL_STR("plural"), harmony));
i = (i + 1);
}
return r;
return 0;
}
Generated Vendored
+17
View File
@@ -0,0 +1,17 @@
// auto-generated by elc --emit-header — do not edit
extern fn fi_harmony(word: String) -> String
extern fn fi_suffix(base: String, harmony: String) -> String
extern fn fi_noun_case(stem: String, gram_case: String, number: String, harmony: String) -> String
extern fn fi_str_last_char(s: String) -> String
extern fn fi_apply_case(noun: String, gram_case: String, number: String) -> String
extern fn fi_verb_stem(dict_form: String) -> String
extern fn fi_irregular_verb(dict_form: String) -> [String]
extern fn fi_present_ending(stem: String, person: String, number: String, harmony: String) -> String
extern fn fi_past_stem(stem: String) -> String
extern fn fi_past_ending(stem: String, person: String, number: String, harmony: String) -> String
extern fn fi_neg_aux(person: String, number: String) -> String
extern fn fi_negative(verb: String, person: String, number: String) -> String
extern fn fi_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn fi_question_suffix(harmony: String) -> String
extern fn fi_make_question(verb_form: String, harmony: String) -> String
extern fn fi_full_paradigm(noun: String) -> [String]
Generated Vendored
+975
View File
@@ -0,0 +1,975 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t fr_str_ends(el_val_t s, el_val_t suf);
el_val_t fr_str_drop_last(el_val_t s, el_val_t n);
el_val_t fr_str_last_char(el_val_t s);
el_val_t fr_str_last2(el_val_t s);
el_val_t fr_is_vowel_start(el_val_t s);
el_val_t fr_is_known_irregular(el_val_t verb);
el_val_t fr_verb_group(el_val_t base);
el_val_t fr_stem(el_val_t base);
el_val_t fr_slot(el_val_t person, el_val_t number);
el_val_t fr_irregular_present(el_val_t verb, el_val_t person, el_val_t number);
el_val_t fr_regular_present(el_val_t stem, el_val_t vgroup, el_val_t slot);
el_val_t fr_future_stem(el_val_t base, el_val_t vgroup);
el_val_t fr_regular_future(el_val_t fstem, el_val_t slot);
el_val_t fr_irregular_future_stem(el_val_t verb);
el_val_t fr_imperfect_stem(el_val_t base, el_val_t vgroup);
el_val_t fr_regular_imperfect(el_val_t istem, el_val_t slot);
el_val_t fr_uses_etre(el_val_t verb);
el_val_t fr_past_participle(el_val_t verb);
el_val_t fr_avoir_present(el_val_t slot);
el_val_t fr_etre_present(el_val_t slot);
el_val_t fr_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t fr_gender(el_val_t noun);
el_val_t fr_invariant_plural(el_val_t noun);
el_val_t fr_pluralize(el_val_t noun);
el_val_t fr_agree_article(el_val_t noun, el_val_t definite, el_val_t number);
el_val_t fr_subject_starts_vowel(el_val_t subject);
el_val_t fr_verb_ends_vowel(el_val_t verb_form);
el_val_t fr_question_inversion(el_val_t subject, el_val_t verb_form);
el_val_t fr_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t fr_str_drop_last(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t fr_str_last_char(el_val_t s) {
el_val_t n = str_len(s);
if (n == 0) {
return EL_STR("");
}
return str_slice(s, (n - 1), n);
return 0;
}
el_val_t fr_str_last2(el_val_t s) {
el_val_t n = str_len(s);
if (n < 2) {
return s;
}
return str_slice(s, (n - 2), n);
return 0;
}
el_val_t fr_is_vowel_start(el_val_t s) {
el_val_t n = str_len(s);
if (n == 0) {
return 0;
}
el_val_t c = str_slice(s, 0, 1);
if (str_eq(c, EL_STR("a"))) {
return 1;
}
if (str_eq(c, EL_STR("e"))) {
return 1;
}
if (str_eq(c, EL_STR("\xc3\xa9"))) {
return 1;
}
if (str_eq(c, EL_STR("\xc3\xa8"))) {
return 1;
}
if (str_eq(c, EL_STR("\xc3\xaa"))) {
return 1;
}
if (str_eq(c, EL_STR("i"))) {
return 1;
}
if (str_eq(c, EL_STR("\xc3\xae"))) {
return 1;
}
if (str_eq(c, EL_STR("o"))) {
return 1;
}
if (str_eq(c, EL_STR("\xc3\xb4"))) {
return 1;
}
if (str_eq(c, EL_STR("u"))) {
return 1;
}
if (str_eq(c, EL_STR("\xc3\xbb"))) {
return 1;
}
if (str_eq(c, EL_STR("h"))) {
return 1;
}
return 0;
return 0;
}
el_val_t fr_is_known_irregular(el_val_t verb) {
if (str_eq(verb, EL_STR("\xc3\xaatre"))) {
return 1;
}
if (str_eq(verb, EL_STR("avoir"))) {
return 1;
}
if (str_eq(verb, EL_STR("aller"))) {
return 1;
}
if (str_eq(verb, EL_STR("faire"))) {
return 1;
}
if (str_eq(verb, EL_STR("pouvoir"))) {
return 1;
}
if (str_eq(verb, EL_STR("vouloir"))) {
return 1;
}
if (str_eq(verb, EL_STR("venir"))) {
return 1;
}
if (str_eq(verb, EL_STR("dire"))) {
return 1;
}
if (str_eq(verb, EL_STR("voir"))) {
return 1;
}
if (str_eq(verb, EL_STR("prendre"))) {
return 1;
}
if (str_eq(verb, EL_STR("mettre"))) {
return 1;
}
if (str_eq(verb, EL_STR("savoir"))) {
return 1;
}
return 0;
return 0;
}
el_val_t fr_verb_group(el_val_t base) {
if (fr_is_known_irregular(base)) {
return EL_STR("irregular");
}
if (fr_str_ends(base, EL_STR("er"))) {
return EL_STR("er");
}
if (fr_str_ends(base, EL_STR("ir"))) {
return EL_STR("ir");
}
if (fr_str_ends(base, EL_STR("re"))) {
return EL_STR("re");
}
return EL_STR("er");
return 0;
}
el_val_t fr_stem(el_val_t base) {
return fr_str_drop_last(base, 2);
return 0;
}
el_val_t fr_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t fr_irregular_present(el_val_t verb, el_val_t person, el_val_t number) {
el_val_t slot = fr_slot(person, number);
if (str_eq(verb, EL_STR("\xc3\xaatre"))) {
if (slot == 0) {
return EL_STR("suis");
}
if (slot == 1) {
return EL_STR("es");
}
if (slot == 2) {
return EL_STR("est");
}
if (slot == 3) {
return EL_STR("sommes");
}
if (slot == 4) {
return EL_STR("etes");
}
return EL_STR("sont");
}
if (str_eq(verb, EL_STR("etre"))) {
if (slot == 0) {
return EL_STR("suis");
}
if (slot == 1) {
return EL_STR("es");
}
if (slot == 2) {
return EL_STR("est");
}
if (slot == 3) {
return EL_STR("sommes");
}
if (slot == 4) {
return EL_STR("etes");
}
return EL_STR("sont");
}
if (str_eq(verb, EL_STR("avoir"))) {
if (slot == 0) {
return EL_STR("ai");
}
if (slot == 1) {
return EL_STR("as");
}
if (slot == 2) {
return EL_STR("a");
}
if (slot == 3) {
return EL_STR("avons");
}
if (slot == 4) {
return EL_STR("avez");
}
return EL_STR("ont");
}
if (str_eq(verb, EL_STR("aller"))) {
if (slot == 0) {
return EL_STR("vais");
}
if (slot == 1) {
return EL_STR("vas");
}
if (slot == 2) {
return EL_STR("va");
}
if (slot == 3) {
return EL_STR("allons");
}
if (slot == 4) {
return EL_STR("allez");
}
return EL_STR("vont");
}
if (str_eq(verb, EL_STR("faire"))) {
if (slot == 0) {
return EL_STR("fais");
}
if (slot == 1) {
return EL_STR("fais");
}
if (slot == 2) {
return EL_STR("fait");
}
if (slot == 3) {
return EL_STR("faisons");
}
if (slot == 4) {
return EL_STR("faites");
}
return EL_STR("font");
}
if (str_eq(verb, EL_STR("pouvoir"))) {
if (slot == 0) {
return EL_STR("peux");
}
if (slot == 1) {
return EL_STR("peux");
}
if (slot == 2) {
return EL_STR("peut");
}
if (slot == 3) {
return EL_STR("pouvons");
}
if (slot == 4) {
return EL_STR("pouvez");
}
return EL_STR("peuvent");
}
if (str_eq(verb, EL_STR("vouloir"))) {
if (slot == 0) {
return EL_STR("veux");
}
if (slot == 1) {
return EL_STR("veux");
}
if (slot == 2) {
return EL_STR("veut");
}
if (slot == 3) {
return EL_STR("voulons");
}
if (slot == 4) {
return EL_STR("voulez");
}
return EL_STR("veulent");
}
if (str_eq(verb, EL_STR("venir"))) {
if (slot == 0) {
return EL_STR("viens");
}
if (slot == 1) {
return EL_STR("viens");
}
if (slot == 2) {
return EL_STR("vient");
}
if (slot == 3) {
return EL_STR("venons");
}
if (slot == 4) {
return EL_STR("venez");
}
return EL_STR("viennent");
}
if (str_eq(verb, EL_STR("dire"))) {
if (slot == 0) {
return EL_STR("dis");
}
if (slot == 1) {
return EL_STR("dis");
}
if (slot == 2) {
return EL_STR("dit");
}
if (slot == 3) {
return EL_STR("disons");
}
if (slot == 4) {
return EL_STR("dites");
}
return EL_STR("disent");
}
if (str_eq(verb, EL_STR("voir"))) {
if (slot == 0) {
return EL_STR("vois");
}
if (slot == 1) {
return EL_STR("vois");
}
if (slot == 2) {
return EL_STR("voit");
}
if (slot == 3) {
return EL_STR("voyons");
}
if (slot == 4) {
return EL_STR("voyez");
}
return EL_STR("voient");
}
if (str_eq(verb, EL_STR("prendre"))) {
if (slot == 0) {
return EL_STR("prends");
}
if (slot == 1) {
return EL_STR("prends");
}
if (slot == 2) {
return EL_STR("prend");
}
if (slot == 3) {
return EL_STR("prenons");
}
if (slot == 4) {
return EL_STR("prenez");
}
return EL_STR("prennent");
}
if (str_eq(verb, EL_STR("mettre"))) {
if (slot == 0) {
return EL_STR("mets");
}
if (slot == 1) {
return EL_STR("mets");
}
if (slot == 2) {
return EL_STR("met");
}
if (slot == 3) {
return EL_STR("mettons");
}
if (slot == 4) {
return EL_STR("mettez");
}
return EL_STR("mettent");
}
if (str_eq(verb, EL_STR("savoir"))) {
if (slot == 0) {
return EL_STR("sais");
}
if (slot == 1) {
return EL_STR("sais");
}
if (slot == 2) {
return EL_STR("sait");
}
if (slot == 3) {
return EL_STR("savons");
}
if (slot == 4) {
return EL_STR("savez");
}
return EL_STR("savent");
}
return EL_STR("");
return 0;
}
el_val_t fr_regular_present(el_val_t stem, el_val_t vgroup, el_val_t slot) {
if (str_eq(vgroup, EL_STR("er"))) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("e"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("es"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("e"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("ons"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("ez"));
}
return el_str_concat(stem, EL_STR("ent"));
}
if (str_eq(vgroup, EL_STR("ir"))) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("is"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("is"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("it"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("issons"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("issez"));
}
return el_str_concat(stem, EL_STR("issent"));
}
if (slot == 0) {
return el_str_concat(stem, EL_STR("s"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("s"));
}
if (slot == 2) {
return stem;
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("ons"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("ez"));
}
return el_str_concat(stem, EL_STR("ent"));
return 0;
}
el_val_t fr_future_stem(el_val_t base, el_val_t vgroup) {
if (str_eq(vgroup, EL_STR("re"))) {
return fr_str_drop_last(base, 1);
}
return base;
return 0;
}
el_val_t fr_regular_future(el_val_t fstem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(fstem, EL_STR("ai"));
}
if (slot == 1) {
return el_str_concat(fstem, EL_STR("as"));
}
if (slot == 2) {
return el_str_concat(fstem, EL_STR("a"));
}
if (slot == 3) {
return el_str_concat(fstem, EL_STR("ons"));
}
if (slot == 4) {
return el_str_concat(fstem, EL_STR("ez"));
}
return el_str_concat(fstem, EL_STR("ont"));
return 0;
}
el_val_t fr_irregular_future_stem(el_val_t verb) {
if (str_eq(verb, EL_STR("\xc3\xaatre"))) {
return EL_STR("ser");
}
if (str_eq(verb, EL_STR("avoir"))) {
return EL_STR("aur");
}
if (str_eq(verb, EL_STR("aller"))) {
return EL_STR("ir");
}
if (str_eq(verb, EL_STR("faire"))) {
return EL_STR("fer");
}
if (str_eq(verb, EL_STR("pouvoir"))) {
return EL_STR("pourr");
}
if (str_eq(verb, EL_STR("vouloir"))) {
return EL_STR("voudr");
}
if (str_eq(verb, EL_STR("venir"))) {
return EL_STR("viendr");
}
if (str_eq(verb, EL_STR("voir"))) {
return EL_STR("verr");
}
if (str_eq(verb, EL_STR("savoir"))) {
return EL_STR("saur");
}
return EL_STR("");
return 0;
}
el_val_t fr_imperfect_stem(el_val_t base, el_val_t vgroup) {
if (str_eq(base, EL_STR("\xc3\xaatre"))) {
return EL_STR("\xc3\xa9t");
}
return fr_stem(base);
return 0;
}
el_val_t fr_regular_imperfect(el_val_t istem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(istem, EL_STR("ais"));
}
if (slot == 1) {
return el_str_concat(istem, EL_STR("ais"));
}
if (slot == 2) {
return el_str_concat(istem, EL_STR("ait"));
}
if (slot == 3) {
return el_str_concat(istem, EL_STR("ions"));
}
if (slot == 4) {
return el_str_concat(istem, EL_STR("iez"));
}
return el_str_concat(istem, EL_STR("aient"));
return 0;
}
el_val_t fr_uses_etre(el_val_t verb) {
if (str_eq(verb, EL_STR("aller"))) {
return 1;
}
if (str_eq(verb, EL_STR("venir"))) {
return 1;
}
if (str_eq(verb, EL_STR("partir"))) {
return 1;
}
if (str_eq(verb, EL_STR("arriver"))) {
return 1;
}
if (str_eq(verb, EL_STR("entrer"))) {
return 1;
}
if (str_eq(verb, EL_STR("sortir"))) {
return 1;
}
if (str_eq(verb, EL_STR("na\xc3\xaetre"))) {
return 1;
}
if (str_eq(verb, EL_STR("mourir"))) {
return 1;
}
if (str_eq(verb, EL_STR("rester"))) {
return 1;
}
if (str_eq(verb, EL_STR("tomber"))) {
return 1;
}
if (str_eq(verb, EL_STR("monter"))) {
return 1;
}
if (str_eq(verb, EL_STR("descendre"))) {
return 1;
}
if (str_eq(verb, EL_STR("rentrer"))) {
return 1;
}
if (str_eq(verb, EL_STR("retourner"))) {
return 1;
}
if (str_eq(verb, EL_STR("passer"))) {
return 1;
}
return 0;
return 0;
}
el_val_t fr_past_participle(el_val_t verb) {
if (str_eq(verb, EL_STR("\xc3\xaatre"))) {
return EL_STR("\xc3\xa9t\xc3\xa9");
}
if (str_eq(verb, EL_STR("avoir"))) {
return EL_STR("eu");
}
if (str_eq(verb, EL_STR("aller"))) {
return EL_STR("all\xc3\xa9");
}
if (str_eq(verb, EL_STR("faire"))) {
return EL_STR("fait");
}
if (str_eq(verb, EL_STR("pouvoir"))) {
return EL_STR("pu");
}
if (str_eq(verb, EL_STR("vouloir"))) {
return EL_STR("voulu");
}
if (str_eq(verb, EL_STR("venir"))) {
return EL_STR("venu");
}
if (str_eq(verb, EL_STR("dire"))) {
return EL_STR("dit");
}
if (str_eq(verb, EL_STR("voir"))) {
return EL_STR("vu");
}
if (str_eq(verb, EL_STR("prendre"))) {
return EL_STR("pris");
}
if (str_eq(verb, EL_STR("mettre"))) {
return EL_STR("mis");
}
if (str_eq(verb, EL_STR("savoir"))) {
return EL_STR("su");
}
if (str_eq(verb, EL_STR("na\xc3\xaetre"))) {
return EL_STR("n\xc3\xa9");
}
if (str_eq(verb, EL_STR("mourir"))) {
return EL_STR("mort");
}
el_val_t vgroup = fr_verb_group(verb);
if (str_eq(vgroup, EL_STR("er"))) {
return el_str_concat(fr_str_drop_last(verb, 2), EL_STR("\xc3\xa9"));
}
if (str_eq(vgroup, EL_STR("ir"))) {
return el_str_concat(fr_str_drop_last(verb, 2), EL_STR("i"));
}
return el_str_concat(fr_str_drop_last(verb, 2), EL_STR("u"));
return 0;
}
el_val_t fr_avoir_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("ai");
}
if (slot == 1) {
return EL_STR("as");
}
if (slot == 2) {
return EL_STR("a");
}
if (slot == 3) {
return EL_STR("avons");
}
if (slot == 4) {
return EL_STR("avez");
}
return EL_STR("ont");
return 0;
}
el_val_t fr_etre_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("suis");
}
if (slot == 1) {
return EL_STR("es");
}
if (slot == 2) {
return EL_STR("est");
}
if (slot == 3) {
return EL_STR("sommes");
}
if (slot == 4) {
return EL_STR("\xc3\xaates");
}
return EL_STR("sont");
return 0;
}
el_val_t fr_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t slot = fr_slot(person, number);
if (str_eq(tense, EL_STR("present"))) {
el_val_t irreg = fr_irregular_present(verb, person, number);
if (!str_eq(irreg, EL_STR(""))) {
return irreg;
}
el_val_t vgroup = fr_verb_group(verb);
el_val_t stem = fr_stem(verb);
return fr_regular_present(stem, vgroup, slot);
}
if (str_eq(tense, EL_STR("future"))) {
el_val_t irreg_stem = fr_irregular_future_stem(verb);
if (!str_eq(irreg_stem, EL_STR(""))) {
return fr_regular_future(irreg_stem, slot);
}
el_val_t vgroup = fr_verb_group(verb);
el_val_t fstem = fr_future_stem(verb, vgroup);
return fr_regular_future(fstem, slot);
}
if (str_eq(tense, EL_STR("imperfect"))) {
el_val_t vgroup = fr_verb_group(verb);
el_val_t istem = fr_imperfect_stem(verb, vgroup);
return fr_regular_imperfect(istem, slot);
}
if (str_eq(tense, EL_STR("past"))) {
el_val_t pp = fr_past_participle(verb);
if (fr_uses_etre(verb)) {
el_val_t aux = fr_etre_present(slot);
return el_str_concat(el_str_concat(aux, EL_STR(" ")), pp);
}
el_val_t aux = fr_avoir_present(slot);
return el_str_concat(el_str_concat(aux, EL_STR(" ")), pp);
}
return verb;
return 0;
}
el_val_t fr_gender(el_val_t noun) {
if (fr_str_ends(noun, EL_STR("tion"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("sion"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("xion"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("ure"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("ette"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("ance"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("ence"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("it\xc3\xa9"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("t\xc3\xa9"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("ti\xc3\xa9"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("ude"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("ade"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("\xc3\xa9""e"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("ie"))) {
return EL_STR("f");
}
if (fr_str_ends(noun, EL_STR("ment"))) {
return EL_STR("m");
}
if (fr_str_ends(noun, EL_STR("age"))) {
return EL_STR("m");
}
if (fr_str_ends(noun, EL_STR("isme"))) {
return EL_STR("m");
}
if (fr_str_ends(noun, EL_STR("eau"))) {
return EL_STR("m");
}
if (fr_str_ends(noun, EL_STR("eur"))) {
return EL_STR("m");
}
if (fr_str_ends(noun, EL_STR("er"))) {
return EL_STR("m");
}
if (fr_str_ends(noun, EL_STR("\xc3\xa9"))) {
return EL_STR("m");
}
return EL_STR("unknown");
return 0;
}
el_val_t fr_invariant_plural(el_val_t noun) {
el_val_t last = fr_str_last_char(noun);
if (str_eq(last, EL_STR("s"))) {
return noun;
}
if (str_eq(last, EL_STR("x"))) {
return noun;
}
if (str_eq(last, EL_STR("z"))) {
return noun;
}
return EL_STR("");
return 0;
}
el_val_t fr_pluralize(el_val_t noun) {
el_val_t inv = fr_invariant_plural(noun);
if (!str_eq(inv, EL_STR(""))) {
return inv;
}
if (fr_str_ends(noun, EL_STR("eau"))) {
return el_str_concat(noun, EL_STR("x"));
}
if (fr_str_ends(noun, EL_STR("eu"))) {
return el_str_concat(noun, EL_STR("x"));
}
if (fr_str_ends(noun, EL_STR("al"))) {
return el_str_concat(fr_str_drop_last(noun, 2), EL_STR("aux"));
}
if (fr_str_ends(noun, EL_STR("ail"))) {
return el_str_concat(fr_str_drop_last(noun, 3), EL_STR("aux"));
}
return el_str_concat(noun, EL_STR("s"));
return 0;
}
el_val_t fr_agree_article(el_val_t noun, el_val_t definite, el_val_t number) {
el_val_t gender = fr_gender(noun);
el_val_t is_plural = str_eq(number, EL_STR("plural"));
el_val_t is_def = str_eq(definite, EL_STR("true"));
el_val_t vowel_start = fr_is_vowel_start(noun);
if (is_def) {
if (is_plural) {
return EL_STR("les");
}
if (vowel_start) {
return EL_STR("l'");
}
if (str_eq(gender, EL_STR("f"))) {
return EL_STR("la");
}
return EL_STR("le");
}
if (is_plural) {
return EL_STR("des");
}
if (str_eq(gender, EL_STR("f"))) {
return EL_STR("une");
}
return EL_STR("un");
return 0;
}
el_val_t fr_subject_starts_vowel(el_val_t subject) {
if (str_eq(subject, EL_STR("il"))) {
return 1;
}
if (str_eq(subject, EL_STR("elle"))) {
return 1;
}
if (str_eq(subject, EL_STR("ils"))) {
return 1;
}
if (str_eq(subject, EL_STR("elles"))) {
return 1;
}
return 0;
return 0;
}
el_val_t fr_verb_ends_vowel(el_val_t verb_form) {
el_val_t last = fr_str_last_char(verb_form);
if (str_eq(last, EL_STR("a"))) {
return 1;
}
if (str_eq(last, EL_STR("e"))) {
return 1;
}
if (str_eq(last, EL_STR("\xc3\xa9"))) {
return 1;
}
if (str_eq(last, EL_STR("i"))) {
return 1;
}
if (str_eq(last, EL_STR("o"))) {
return 1;
}
if (str_eq(last, EL_STR("u"))) {
return 1;
}
return 0;
return 0;
}
el_val_t fr_question_inversion(el_val_t subject, el_val_t verb_form) {
if (str_eq(subject, EL_STR("je"))) {
return el_str_concat(el_str_concat(EL_STR("est-ce que je "), verb_form), EL_STR(" ?"));
}
el_val_t need_t = 0;
if (fr_verb_ends_vowel(verb_form)) {
if (fr_subject_starts_vowel(subject)) {
need_t = 1;
}
}
if (need_t) {
return el_str_concat(el_str_concat(el_str_concat(verb_form, EL_STR("-t-")), subject), EL_STR(" ?"));
}
return el_str_concat(el_str_concat(el_str_concat(verb_form, EL_STR("-")), subject), EL_STR(" ?"));
return 0;
}
Generated Vendored
+29
View File
@@ -0,0 +1,29 @@
// auto-generated by elc --emit-header — do not edit
extern fn fr_str_ends(s: String, suf: String) -> Bool
extern fn fr_str_drop_last(s: String, n: Int) -> String
extern fn fr_str_last_char(s: String) -> String
extern fn fr_str_last2(s: String) -> String
extern fn fr_is_vowel_start(s: String) -> Bool
extern fn fr_is_known_irregular(verb: String) -> Bool
extern fn fr_verb_group(base: String) -> String
extern fn fr_stem(base: String) -> String
extern fn fr_slot(person: String, number: String) -> Int
extern fn fr_irregular_present(verb: String, person: String, number: String) -> String
extern fn fr_regular_present(stem: String, vgroup: String, slot: Int) -> String
extern fn fr_future_stem(base: String, vgroup: String) -> String
extern fn fr_regular_future(fstem: String, slot: Int) -> String
extern fn fr_irregular_future_stem(verb: String) -> String
extern fn fr_imperfect_stem(base: String, vgroup: String) -> String
extern fn fr_regular_imperfect(istem: String, slot: Int) -> String
extern fn fr_uses_etre(verb: String) -> Bool
extern fn fr_past_participle(verb: String) -> String
extern fn fr_avoir_present(slot: Int) -> String
extern fn fr_etre_present(slot: Int) -> String
extern fn fr_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn fr_gender(noun: String) -> String
extern fn fr_invariant_plural(noun: String) -> String
extern fn fr_pluralize(noun: String) -> String
extern fn fr_agree_article(noun: String, definite: String, number: String) -> String
extern fn fr_subject_starts_vowel(subject: String) -> Bool
extern fn fr_verb_ends_vowel(verb_form: String) -> Bool
extern fn fr_question_inversion(subject: String, verb_form: String) -> String
Generated Vendored
+811
View File
@@ -0,0 +1,811 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t fro_str_ends(el_val_t s, el_val_t suf);
el_val_t fro_drop(el_val_t s, el_val_t n);
el_val_t fro_slot(el_val_t person, el_val_t number);
el_val_t fro_map_canonical(el_val_t verb);
el_val_t fro_estre_present(el_val_t slot);
el_val_t fro_estre_past(el_val_t slot);
el_val_t fro_estre_future(el_val_t slot);
el_val_t fro_avoir_present(el_val_t slot);
el_val_t fro_avoir_past(el_val_t slot);
el_val_t fro_avoir_future(el_val_t slot);
el_val_t fro_aler_present(el_val_t slot);
el_val_t fro_aler_past(el_val_t slot);
el_val_t fro_aler_future(el_val_t slot);
el_val_t fro_venir_present(el_val_t slot);
el_val_t fro_venir_past(el_val_t slot);
el_val_t fro_venir_future(el_val_t slot);
el_val_t fro_faire_present(el_val_t slot);
el_val_t fro_faire_past(el_val_t slot);
el_val_t fro_faire_future(el_val_t slot);
el_val_t fro_verb_class(el_val_t verb);
el_val_t fro_verb_stem(el_val_t verb, el_val_t vclass);
el_val_t fro_conj1_present(el_val_t stem, el_val_t slot);
el_val_t fro_conj1_past(el_val_t stem, el_val_t slot);
el_val_t fro_conj1_future(el_val_t verb, el_val_t slot);
el_val_t fro_conj2_present(el_val_t stem, el_val_t slot);
el_val_t fro_conj2_past(el_val_t stem, el_val_t slot);
el_val_t fro_conj2_future(el_val_t verb, el_val_t slot);
el_val_t fro_conj3_present(el_val_t stem, el_val_t slot);
el_val_t fro_conj3_past(el_val_t stem, el_val_t slot);
el_val_t fro_conj3_future(el_val_t verb, el_val_t slot);
el_val_t fro_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t fro_gender(el_val_t noun);
el_val_t fro_decline_masc(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t fro_decline_fem(el_val_t noun, el_val_t number);
el_val_t fro_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t fro_article(el_val_t gender, el_val_t gram_case, el_val_t number);
el_val_t fro_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t fro_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t fro_drop(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t fro_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t fro_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("estre");
}
if (str_eq(verb, EL_STR("have"))) {
return EL_STR("avoir");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("aler");
}
if (str_eq(verb, EL_STR("come"))) {
return EL_STR("venir");
}
if (str_eq(verb, EL_STR("do"))) {
return EL_STR("faire");
}
if (str_eq(verb, EL_STR("make"))) {
return EL_STR("faire");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("dire");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("veoir");
}
if (str_eq(verb, EL_STR("want"))) {
return EL_STR("vouloir");
}
if (str_eq(verb, EL_STR("can"))) {
return EL_STR("pooir");
}
return verb;
return 0;
}
el_val_t fro_estre_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("sui");
}
if (slot == 1) {
return EL_STR("es");
}
if (slot == 2) {
return EL_STR("est");
}
if (slot == 3) {
return EL_STR("somes");
}
if (slot == 4) {
return EL_STR("estes");
}
return EL_STR("sont");
return 0;
}
el_val_t fro_estre_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("fui");
}
if (slot == 1) {
return EL_STR("fus");
}
if (slot == 2) {
return EL_STR("fu");
}
if (slot == 3) {
return EL_STR("fumes");
}
if (slot == 4) {
return EL_STR("fustes");
}
return EL_STR("furent");
return 0;
}
el_val_t fro_estre_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("esterai");
}
if (slot == 1) {
return EL_STR("esteras");
}
if (slot == 2) {
return EL_STR("estera");
}
if (slot == 3) {
return EL_STR("esterons");
}
if (slot == 4) {
return EL_STR("esterez");
}
return EL_STR("esteront");
return 0;
}
el_val_t fro_avoir_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("ai");
}
if (slot == 1) {
return EL_STR("as");
}
if (slot == 2) {
return EL_STR("a");
}
if (slot == 3) {
return EL_STR("avons");
}
if (slot == 4) {
return EL_STR("avez");
}
return EL_STR("ont");
return 0;
}
el_val_t fro_avoir_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("oi");
}
if (slot == 1) {
return EL_STR("os");
}
if (slot == 2) {
return EL_STR("ot");
}
if (slot == 3) {
return EL_STR("eumes");
}
if (slot == 4) {
return EL_STR("eustes");
}
return EL_STR("orent");
return 0;
}
el_val_t fro_avoir_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("avrai");
}
if (slot == 1) {
return EL_STR("avras");
}
if (slot == 2) {
return EL_STR("avra");
}
if (slot == 3) {
return EL_STR("avrons");
}
if (slot == 4) {
return EL_STR("avrez");
}
return EL_STR("avront");
return 0;
}
el_val_t fro_aler_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("vois");
}
if (slot == 1) {
return EL_STR("vas");
}
if (slot == 2) {
return EL_STR("va");
}
if (slot == 3) {
return EL_STR("alons");
}
if (slot == 4) {
return EL_STR("alez");
}
return EL_STR("vont");
return 0;
}
el_val_t fro_aler_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("alai");
}
if (slot == 1) {
return EL_STR("alas");
}
if (slot == 2) {
return EL_STR("ala");
}
if (slot == 3) {
return EL_STR("alames");
}
if (slot == 4) {
return EL_STR("alastes");
}
return EL_STR("alerent");
return 0;
}
el_val_t fro_aler_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("irai");
}
if (slot == 1) {
return EL_STR("iras");
}
if (slot == 2) {
return EL_STR("ira");
}
if (slot == 3) {
return EL_STR("irons");
}
if (slot == 4) {
return EL_STR("irez");
}
return EL_STR("iront");
return 0;
}
el_val_t fro_venir_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("vieng");
}
if (slot == 1) {
return EL_STR("viens");
}
if (slot == 2) {
return EL_STR("vient");
}
if (slot == 3) {
return EL_STR("venons");
}
if (slot == 4) {
return EL_STR("venez");
}
return EL_STR("vienent");
return 0;
}
el_val_t fro_venir_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("ving");
}
if (slot == 1) {
return EL_STR("vins");
}
if (slot == 2) {
return EL_STR("vint");
}
if (slot == 3) {
return EL_STR("vinsmes");
}
if (slot == 4) {
return EL_STR("vinstes");
}
return EL_STR("vindrent");
return 0;
}
el_val_t fro_venir_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("venrai");
}
if (slot == 1) {
return EL_STR("venras");
}
if (slot == 2) {
return EL_STR("venra");
}
if (slot == 3) {
return EL_STR("venrons");
}
if (slot == 4) {
return EL_STR("venrez");
}
return EL_STR("venront");
return 0;
}
el_val_t fro_faire_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("faz");
}
if (slot == 1) {
return EL_STR("fais");
}
if (slot == 2) {
return EL_STR("fait");
}
if (slot == 3) {
return EL_STR("faisons");
}
if (slot == 4) {
return EL_STR("faites");
}
return EL_STR("font");
return 0;
}
el_val_t fro_faire_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("fis");
}
if (slot == 1) {
return EL_STR("fis");
}
if (slot == 2) {
return EL_STR("fist");
}
if (slot == 3) {
return EL_STR("fimes");
}
if (slot == 4) {
return EL_STR("fistes");
}
return EL_STR("firent");
return 0;
}
el_val_t fro_faire_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("ferai");
}
if (slot == 1) {
return EL_STR("feras");
}
if (slot == 2) {
return EL_STR("fera");
}
if (slot == 3) {
return EL_STR("ferons");
}
if (slot == 4) {
return EL_STR("ferez");
}
return EL_STR("feront");
return 0;
}
el_val_t fro_verb_class(el_val_t verb) {
if (fro_str_ends(verb, EL_STR("er"))) {
return EL_STR("1");
}
if (fro_str_ends(verb, EL_STR("ir"))) {
return EL_STR("2");
}
if (fro_str_ends(verb, EL_STR("re"))) {
return EL_STR("3");
}
return EL_STR("1");
return 0;
}
el_val_t fro_verb_stem(el_val_t verb, el_val_t vclass) {
return fro_drop(verb, 2);
return 0;
}
el_val_t fro_conj1_present(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("e"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("es"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("e"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("ons"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("ez"));
}
return el_str_concat(stem, EL_STR("ent"));
return 0;
}
el_val_t fro_conj1_past(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("ai"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("as"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("a"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("ames"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("astes"));
}
return el_str_concat(stem, EL_STR("erent"));
return 0;
}
el_val_t fro_conj1_future(el_val_t verb, el_val_t slot) {
el_val_t base = fro_drop(verb, 1);
if (slot == 0) {
return el_str_concat(base, EL_STR("rai"));
}
if (slot == 1) {
return el_str_concat(base, EL_STR("ras"));
}
if (slot == 2) {
return el_str_concat(base, EL_STR("ra"));
}
if (slot == 3) {
return el_str_concat(base, EL_STR("rons"));
}
if (slot == 4) {
return el_str_concat(base, EL_STR("rez"));
}
return el_str_concat(base, EL_STR("ront"));
return 0;
}
el_val_t fro_conj2_present(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("is"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("is"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("it"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("issons"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("issiez"));
}
return el_str_concat(stem, EL_STR("issent"));
return 0;
}
el_val_t fro_conj2_past(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("is"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("is"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("it"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("imes"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("istes"));
}
return el_str_concat(stem, EL_STR("irent"));
return 0;
}
el_val_t fro_conj2_future(el_val_t verb, el_val_t slot) {
el_val_t base = fro_drop(verb, 1);
if (slot == 0) {
return el_str_concat(base, EL_STR("rai"));
}
if (slot == 1) {
return el_str_concat(base, EL_STR("ras"));
}
if (slot == 2) {
return el_str_concat(base, EL_STR("ra"));
}
if (slot == 3) {
return el_str_concat(base, EL_STR("rons"));
}
if (slot == 4) {
return el_str_concat(base, EL_STR("rez"));
}
return el_str_concat(base, EL_STR("ront"));
return 0;
}
el_val_t fro_conj3_present(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return stem;
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("s"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("t"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("ons"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("ez"));
}
return el_str_concat(stem, EL_STR("ent"));
return 0;
}
el_val_t fro_conj3_past(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("is"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("is"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("it"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("imes"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("istes"));
}
return el_str_concat(stem, EL_STR("irent"));
return 0;
}
el_val_t fro_conj3_future(el_val_t verb, el_val_t slot) {
el_val_t base = fro_drop(verb, 2);
if (slot == 0) {
return el_str_concat(base, EL_STR("rai"));
}
if (slot == 1) {
return el_str_concat(base, EL_STR("ras"));
}
if (slot == 2) {
return el_str_concat(base, EL_STR("ra"));
}
if (slot == 3) {
return el_str_concat(base, EL_STR("rons"));
}
if (slot == 4) {
return el_str_concat(base, EL_STR("rez"));
}
return el_str_concat(base, EL_STR("ront"));
return 0;
}
el_val_t fro_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t v = fro_map_canonical(verb);
el_val_t slot = fro_slot(person, number);
if (str_eq(v, EL_STR("estre"))) {
if (str_eq(tense, EL_STR("present"))) {
return fro_estre_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return fro_estre_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return fro_estre_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("avoir"))) {
if (str_eq(tense, EL_STR("present"))) {
return fro_avoir_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return fro_avoir_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return fro_avoir_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("aler"))) {
if (str_eq(tense, EL_STR("present"))) {
return fro_aler_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return fro_aler_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return fro_aler_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("venir"))) {
if (str_eq(tense, EL_STR("present"))) {
return fro_venir_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return fro_venir_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return fro_venir_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("faire"))) {
if (str_eq(tense, EL_STR("present"))) {
return fro_faire_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return fro_faire_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return fro_faire_future(slot);
}
return v;
}
el_val_t vclass = fro_verb_class(v);
el_val_t stem = fro_verb_stem(v, vclass);
if (str_eq(vclass, EL_STR("1"))) {
if (str_eq(tense, EL_STR("present"))) {
return fro_conj1_present(stem, slot);
}
if (str_eq(tense, EL_STR("past"))) {
return fro_conj1_past(stem, slot);
}
if (str_eq(tense, EL_STR("future"))) {
return fro_conj1_future(v, slot);
}
return v;
}
if (str_eq(vclass, EL_STR("2"))) {
if (str_eq(tense, EL_STR("present"))) {
return fro_conj2_present(stem, slot);
}
if (str_eq(tense, EL_STR("past"))) {
return fro_conj2_past(stem, slot);
}
if (str_eq(tense, EL_STR("future"))) {
return fro_conj2_future(v, slot);
}
return v;
}
if (str_eq(vclass, EL_STR("3"))) {
if (str_eq(tense, EL_STR("present"))) {
return fro_conj3_present(stem, slot);
}
if (str_eq(tense, EL_STR("past"))) {
return fro_conj3_past(stem, slot);
}
if (str_eq(tense, EL_STR("future"))) {
return fro_conj3_future(v, slot);
}
return v;
}
return v;
return 0;
}
el_val_t fro_gender(el_val_t noun) {
if (fro_str_ends(noun, EL_STR("e"))) {
return EL_STR("fem");
}
return EL_STR("masc");
return 0;
}
el_val_t fro_decline_masc(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(noun, EL_STR("s"));
}
return noun;
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return noun;
}
return el_str_concat(noun, EL_STR("s"));
return 0;
}
el_val_t fro_decline_fem(el_val_t noun, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
return noun;
}
return el_str_concat(noun, EL_STR("s"));
return 0;
}
el_val_t fro_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t gender = fro_gender(noun);
if (str_eq(gender, EL_STR("masc"))) {
return fro_decline_masc(noun, gram_case, number);
}
return fro_decline_fem(noun, number);
return 0;
}
el_val_t fro_article(el_val_t gender, el_val_t gram_case, el_val_t number) {
if (str_eq(gender, EL_STR("masc"))) {
if (str_eq(number, EL_STR("plural"))) {
return EL_STR("les");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("li");
}
return EL_STR("le");
}
if (str_eq(number, EL_STR("plural"))) {
return EL_STR("les");
}
return EL_STR("la");
return 0;
}
el_val_t fro_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
el_val_t gender = fro_gender(noun);
el_val_t declined = fro_decline(noun, gram_case, number);
if (str_eq(definite, EL_STR("true"))) {
el_val_t art = fro_article(gender, gram_case, number);
return el_str_concat(el_str_concat(art, EL_STR(" ")), declined);
}
return declined;
return 0;
}
Generated Vendored
+38
View File
@@ -0,0 +1,38 @@
// auto-generated by elc --emit-header — do not edit
extern fn fro_str_ends(s: String, suf: String) -> Bool
extern fn fro_drop(s: String, n: Int) -> String
extern fn fro_slot(person: String, number: String) -> Int
extern fn fro_map_canonical(verb: String) -> String
extern fn fro_estre_present(slot: Int) -> String
extern fn fro_estre_past(slot: Int) -> String
extern fn fro_estre_future(slot: Int) -> String
extern fn fro_avoir_present(slot: Int) -> String
extern fn fro_avoir_past(slot: Int) -> String
extern fn fro_avoir_future(slot: Int) -> String
extern fn fro_aler_present(slot: Int) -> String
extern fn fro_aler_past(slot: Int) -> String
extern fn fro_aler_future(slot: Int) -> String
extern fn fro_venir_present(slot: Int) -> String
extern fn fro_venir_past(slot: Int) -> String
extern fn fro_venir_future(slot: Int) -> String
extern fn fro_faire_present(slot: Int) -> String
extern fn fro_faire_past(slot: Int) -> String
extern fn fro_faire_future(slot: Int) -> String
extern fn fro_verb_class(verb: String) -> String
extern fn fro_verb_stem(verb: String, vclass: String) -> String
extern fn fro_conj1_present(stem: String, slot: Int) -> String
extern fn fro_conj1_past(stem: String, slot: Int) -> String
extern fn fro_conj1_future(verb: String, slot: Int) -> String
extern fn fro_conj2_present(stem: String, slot: Int) -> String
extern fn fro_conj2_past(stem: String, slot: Int) -> String
extern fn fro_conj2_future(verb: String, slot: Int) -> String
extern fn fro_conj3_present(stem: String, slot: Int) -> String
extern fn fro_conj3_past(stem: String, slot: Int) -> String
extern fn fro_conj3_future(verb: String, slot: Int) -> String
extern fn fro_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn fro_gender(noun: String) -> String
extern fn fro_decline_masc(noun: String, gram_case: String, number: String) -> String
extern fn fro_decline_fem(noun: String, number: String) -> String
extern fn fro_decline(noun: String, gram_case: String, number: String) -> String
extern fn fro_article(gender: String, gram_case: String, number: String) -> String
extern fn fro_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
Generated Vendored
+605
View File
@@ -0,0 +1,605 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t gez_str_ends(el_val_t s, el_val_t suf);
el_val_t gez_str_len(el_val_t s);
el_val_t gez_str_drop_last(el_val_t s, el_val_t n);
el_val_t gez_slot(el_val_t person, el_val_t number);
el_val_t gez_slot_g(el_val_t person, el_val_t gender, el_val_t number);
el_val_t gez_kwn_perfect(el_val_t slot);
el_val_t gez_kwn_imperfect(el_val_t slot);
el_val_t gez_is_copula(el_val_t verb);
el_val_t gez_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t gez_hlw_perfect(el_val_t slot);
el_val_t gez_hlw_imperfect(el_val_t slot);
el_val_t gez_hbl_perfect(el_val_t slot);
el_val_t gez_hbl_imperfect(el_val_t slot);
el_val_t gez_ray_perfect(el_val_t slot);
el_val_t gez_ray_imperfect(el_val_t slot);
el_val_t gez_qwl_perfect(el_val_t slot);
el_val_t gez_qwl_imperfect(el_val_t slot);
el_val_t gez_generic_perfect(el_val_t base3sg, el_val_t slot);
el_val_t gez_generic_imperfect(el_val_t base3sg, el_val_t slot);
el_val_t gez_known_verb(el_val_t verb, el_val_t tense, el_val_t slot);
el_val_t gez_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t gez_is_fidel(el_val_t noun);
el_val_t gez_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t gez_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t gez_map_canonical(el_val_t verb);
el_val_t gez_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t gez_str_len(el_val_t s) {
return str_len(s);
return 0;
}
el_val_t gez_str_drop_last(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t gez_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("plural"))) {
return 4;
}
return 0;
}
if (str_eq(person, EL_STR("second"))) {
return 1;
}
if (str_eq(number, EL_STR("plural"))) {
return 5;
}
return 2;
return 0;
}
el_val_t gez_slot_g(el_val_t person, el_val_t gender, el_val_t number) {
el_val_t base = gez_slot(person, number);
if (str_eq(person, EL_STR("third"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gender, EL_STR("f"))) {
return 3;
}
}
}
return base;
return 0;
}
el_val_t gez_kwn_perfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xe1\x88\x86\xe1\x8a\x95\xe1\x8a\xa9");
}
if (slot == 1) {
return EL_STR("\xe1\x88\x86\xe1\x8a\x95\xe1\x8a\xa8");
}
if (slot == 2) {
return EL_STR("\xe1\x88\x86\xe1\x8a\x90");
}
if (slot == 3) {
return EL_STR("\xe1\x88\x86\xe1\x8a\x90\xe1\x89\xb5");
}
if (slot == 4) {
return EL_STR("\xe1\x88\x86\xe1\x8a\x95\xe1\x8a\x90");
}
return EL_STR("\xe1\x88\x86\xe1\x8a\x91");
return 0;
}
el_val_t gez_kwn_imperfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xe1\x8a\xa5\xe1\x88\x86\xe1\x8a\x95");
}
if (slot == 1) {
return EL_STR("\xe1\x89\xb5\xe1\x88\x86\xe1\x8a\x95");
}
if (slot == 2) {
return EL_STR("\xe1\x8b\xad\xe1\x88\x86\xe1\x8a\x95");
}
if (slot == 3) {
return EL_STR("\xe1\x89\xb5\xe1\x88\x86\xe1\x8a\x95");
}
if (slot == 4) {
return EL_STR("\xe1\x8a\x95\xe1\x88\x86\xe1\x8a\x95");
}
return EL_STR("\xe1\x8b\xad\xe1\x88\x86\xe1\x8a\x91");
return 0;
}
el_val_t gez_is_copula(el_val_t verb) {
if (str_eq(verb, EL_STR("kwn"))) {
return 1;
}
if (str_eq(verb, EL_STR("\xe1\x88\x86\xe1\x8a\x90"))) {
return 1;
}
if (str_eq(verb, EL_STR("hona"))) {
return 1;
}
if (str_eq(verb, EL_STR("be"))) {
return 1;
}
return 0;
return 0;
}
el_val_t gez_conjugate_copula(el_val_t tense, el_val_t slot) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_kwn_imperfect(slot);
}
return gez_kwn_perfect(slot);
return 0;
}
el_val_t gez_hlw_perfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xe1\x88\x80\xe1\x88\x8e\xe1\x8a\xa9");
}
if (slot == 1) {
return EL_STR("\xe1\x88\x80\xe1\x88\x8e\xe1\x8a\xa8");
}
if (slot == 2) {
return EL_STR("\xe1\x88\x80\xe1\x88\x8e");
}
if (slot == 3) {
return EL_STR("\xe1\x88\x80\xe1\x88\x88\xe1\x8b\x88\xe1\x89\xb5");
}
if (slot == 4) {
return EL_STR("\xe1\x88\x80\xe1\x88\x8e\xe1\x8a\x90");
}
return EL_STR("\xe1\x88\x80\xe1\x88\x89");
return 0;
}
el_val_t gez_hlw_imperfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xe1\x8a\xa5\xe1\x88\x80\xe1\x88\x89");
}
if (slot == 1) {
return EL_STR("\xe1\x89\xb5\xe1\x88\x80\xe1\x88\x89");
}
if (slot == 2) {
return EL_STR("\xe1\x8b\xad\xe1\x88\x80\xe1\x88\x89");
}
if (slot == 3) {
return EL_STR("\xe1\x89\xb5\xe1\x88\x80\xe1\x88\x89");
}
if (slot == 4) {
return EL_STR("\xe1\x8a\x95\xe1\x88\x80\xe1\x88\x89");
}
return EL_STR("\xe1\x8b\xad\xe1\x88\x80\xe1\x88\x8d\xe1\x8b\x89");
return 0;
}
el_val_t gez_hbl_perfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xe1\x88\xb0\xe1\x8c\xa0\xe1\x8a\xa9");
}
if (slot == 1) {
return EL_STR("\xe1\x88\xb0\xe1\x8c\xa0\xe1\x8a\xa8");
}
if (slot == 2) {
return EL_STR("\xe1\x88\xb0\xe1\x8c\xa0");
}
if (slot == 3) {
return EL_STR("\xe1\x88\xb0\xe1\x8c\xa0\xe1\x89\xb5");
}
if (slot == 4) {
return EL_STR("\xe1\x88\xb0\xe1\x8c\xa0\xe1\x8a\x90");
}
return EL_STR("\xe1\x88\xb0\xe1\x8c\xa1");
return 0;
}
el_val_t gez_hbl_imperfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xe1\x8a\xa5\xe1\x88\xb0\xe1\x8c\xa5");
}
if (slot == 1) {
return EL_STR("\xe1\x89\xb5\xe1\x88\xb0\xe1\x8c\xa5");
}
if (slot == 2) {
return EL_STR("\xe1\x8b\xad\xe1\x88\xb0\xe1\x8c\xa5");
}
if (slot == 3) {
return EL_STR("\xe1\x89\xb5\xe1\x88\xb0\xe1\x8c\xa5");
}
if (slot == 4) {
return EL_STR("\xe1\x8a\x95\xe1\x88\xb0\xe1\x8c\xa5");
}
return EL_STR("\xe1\x8b\xad\xe1\x88\xb0\xe1\x8c\xa1");
return 0;
}
el_val_t gez_ray_perfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xe1\x8a\xa0\xe1\x8b\xa8\xe1\x8a\xa9");
}
if (slot == 1) {
return EL_STR("\xe1\x8a\xa0\xe1\x8b\xa8\xe1\x8a\xa8");
}
if (slot == 2) {
return EL_STR("\xe1\x8a\xa0\xe1\x8b\xa8");
}
if (slot == 3) {
return EL_STR("\xe1\x8a\xa0\xe1\x8b\xa8\xe1\x89\xb5");
}
if (slot == 4) {
return EL_STR("\xe1\x8a\xa0\xe1\x8b\xa8\xe1\x8a\x90");
}
return EL_STR("\xe1\x8a\xa0\xe1\x8b\xa9");
return 0;
}
el_val_t gez_ray_imperfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xe1\x8a\xa5\xe1\x8b\xab\xe1\x8b\xad");
}
if (slot == 1) {
return EL_STR("\xe1\x89\xb5\xe1\x8b\xab\xe1\x8b\xad");
}
if (slot == 2) {
return EL_STR("\xe1\x8b\xab\xe1\x8b\xad");
}
if (slot == 3) {
return EL_STR("\xe1\x89\xb5\xe1\x8b\xab\xe1\x8b\xad");
}
if (slot == 4) {
return EL_STR("\xe1\x8a\x95\xe1\x8b\xab\xe1\x8b\xad");
}
return EL_STR("\xe1\x8b\xab\xe1\x8b\xa9");
return 0;
}
el_val_t gez_qwl_perfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xe1\x89\xb0\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xad\xe1\x8a\xa9");
}
if (slot == 1) {
return EL_STR("\xe1\x89\xb0\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xad\xe1\x8a\xa8");
}
if (slot == 2) {
return EL_STR("\xe1\x89\xb0\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xa8");
}
if (slot == 3) {
return EL_STR("\xe1\x89\xb0\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xa8\xe1\x89\xb5");
}
if (slot == 4) {
return EL_STR("\xe1\x89\xb0\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xad\xe1\x8a\x90");
}
return EL_STR("\xe1\x89\xb0\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xa9");
return 0;
}
el_val_t gez_qwl_imperfect(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xe1\x8a\xa5\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xad");
}
if (slot == 1) {
return EL_STR("\xe1\x89\xb5\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xad");
}
if (slot == 2) {
return EL_STR("\xe1\x8b\xad\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xad");
}
if (slot == 3) {
return EL_STR("\xe1\x89\xb5\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xad");
}
if (slot == 4) {
return EL_STR("\xe1\x8a\x95\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xad");
}
return EL_STR("\xe1\x8b\xad\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xa9");
return 0;
}
el_val_t gez_generic_perfect(el_val_t base3sg, el_val_t slot) {
if (slot == 0) {
return el_str_concat(base3sg, EL_STR("\xe1\x8a\xa9"));
}
if (slot == 1) {
return el_str_concat(base3sg, EL_STR("\xe1\x8a\xa8"));
}
if (slot == 2) {
return base3sg;
}
if (slot == 3) {
return el_str_concat(base3sg, EL_STR("\xe1\x89\xb5"));
}
if (slot == 4) {
return el_str_concat(base3sg, EL_STR("\xe1\x8a\x90"));
}
return el_str_concat(base3sg, EL_STR("\xe1\x8a\xa1"));
return 0;
}
el_val_t gez_generic_imperfect(el_val_t base3sg, el_val_t slot) {
if (slot == 0) {
return el_str_concat(EL_STR("\xe1\x8a\xa5"), base3sg);
}
if (slot == 1) {
return el_str_concat(EL_STR("\xe1\x89\xb5"), base3sg);
}
if (slot == 2) {
return el_str_concat(EL_STR("\xe1\x8b\xad"), base3sg);
}
if (slot == 3) {
return el_str_concat(EL_STR("\xe1\x89\xb5"), base3sg);
}
if (slot == 4) {
return el_str_concat(EL_STR("\xe1\x8a\x95"), base3sg);
}
return el_str_concat(el_str_concat(EL_STR("\xe1\x8b\xad"), base3sg), EL_STR("\xe1\x8a\xa1"));
return 0;
}
el_val_t gez_known_verb(el_val_t verb, el_val_t tense, el_val_t slot) {
if (str_eq(verb, EL_STR("kwn"))) {
return gez_conjugate_copula(tense, slot);
}
if (str_eq(verb, EL_STR("\xe1\x88\x86\xe1\x8a\x90"))) {
return gez_conjugate_copula(tense, slot);
}
if (str_eq(verb, EL_STR("hona"))) {
return gez_conjugate_copula(tense, slot);
}
if (str_eq(verb, EL_STR("hlw"))) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_hlw_imperfect(slot);
}
return gez_hlw_perfect(slot);
}
if (str_eq(verb, EL_STR("\xe1\x88\x80\xe1\x88\x8e"))) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_hlw_imperfect(slot);
}
return gez_hlw_perfect(slot);
}
if (str_eq(verb, EL_STR("hallo"))) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_hlw_imperfect(slot);
}
return gez_hlw_perfect(slot);
}
if (str_eq(verb, EL_STR("hbl"))) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_hbl_imperfect(slot);
}
return gez_hbl_perfect(slot);
}
if (str_eq(verb, EL_STR("\xe1\x88\xb0\xe1\x8c\xa0"))) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_hbl_imperfect(slot);
}
return gez_hbl_perfect(slot);
}
if (str_eq(verb, EL_STR("s\xc3\xa4tta"))) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_hbl_imperfect(slot);
}
return gez_hbl_perfect(slot);
}
if (str_eq(verb, EL_STR("r\xca\xbey"))) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_ray_imperfect(slot);
}
return gez_ray_perfect(slot);
}
if (str_eq(verb, EL_STR("\xe1\x8a\xa0\xe1\x8b\xa8"))) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_ray_imperfect(slot);
}
return gez_ray_perfect(slot);
}
if (str_eq(verb, EL_STR("\xca\xbe""ayya"))) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_ray_imperfect(slot);
}
return gez_ray_perfect(slot);
}
if (str_eq(verb, EL_STR("qwl"))) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_qwl_imperfect(slot);
}
return gez_qwl_perfect(slot);
}
if (str_eq(verb, EL_STR("\xe1\x89\xb0\xe1\x8a\x93\xe1\x8c\x88\xe1\x88\xa8"))) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_qwl_imperfect(slot);
}
return gez_qwl_perfect(slot);
}
if (str_eq(verb, EL_STR("t\xc3\xa4nag\xc3\xa4r\xc3\xa4"))) {
if (str_eq(tense, EL_STR("imperfect"))) {
return gez_qwl_imperfect(slot);
}
return gez_qwl_perfect(slot);
}
return EL_STR("");
return 0;
}
el_val_t gez_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t slot = gez_slot(person, number);
if (gez_is_copula(verb)) {
return gez_conjugate_copula(tense, slot);
}
el_val_t known = gez_known_verb(verb, tense, slot);
if (!str_eq(known, EL_STR(""))) {
return known;
}
return verb;
return 0;
}
el_val_t gez_is_fidel(el_val_t noun) {
el_val_t n = gez_str_len(noun);
if (n == 0) {
return 0;
}
el_val_t first = str_slice(noun, 0, 1);
if (str_eq(first, EL_STR("\xe1\x88\x80"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x88\x81"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x88\x82"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x88\x83"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x88\x84"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x88\x85"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x88\x86"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x88\x88"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x88\x98"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x88\xb0"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x88\xb8"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x89\x80"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x89\xa0"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x89\xb0"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8a\x90"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8a\xa0"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8a\xa5"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8a\xa8"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8b\x88"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8b\x98"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8b\xa8"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8b\xb0"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8c\x88"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8c\xa0"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8d\x80"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8d\x88"))) {
return 1;
}
if (str_eq(first, EL_STR("\xe1\x8d\x90"))) {
return 1;
}
return 0;
return 0;
}
el_val_t gez_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("plural"))) {
if (gez_is_fidel(noun)) {
return el_str_concat(noun, EL_STR("\xe1\x8b\x8e\xe1\x89\xbd"));
}
return el_str_concat(noun, EL_STR("\xc4\x81t"));
}
if (str_eq(gram_case, EL_STR("acc"))) {
if (gez_is_fidel(noun)) {
return el_str_concat(noun, EL_STR("\xe1\x8a\x95"));
}
return el_str_concat(noun, EL_STR("a"));
}
return noun;
return 0;
}
el_val_t gez_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
return gez_decline(noun, gram_case, number);
return 0;
}
el_val_t gez_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("kwn");
}
if (str_eq(verb, EL_STR("exist"))) {
return EL_STR("hlw");
}
if (str_eq(verb, EL_STR("give"))) {
return EL_STR("hbl");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("r\xca\xbey");
}
if (str_eq(verb, EL_STR("speak"))) {
return EL_STR("qwl");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("qwl");
}
return verb;
return 0;
}
Generated Vendored
+26
View File
@@ -0,0 +1,26 @@
// auto-generated by elc --emit-header — do not edit
extern fn gez_str_ends(s: String, suf: String) -> Bool
extern fn gez_str_len(s: String) -> Int
extern fn gez_str_drop_last(s: String, n: Int) -> String
extern fn gez_slot(person: String, number: String) -> Int
extern fn gez_slot_g(person: String, gender: String, number: String) -> Int
extern fn gez_kwn_perfect(slot: Int) -> String
extern fn gez_kwn_imperfect(slot: Int) -> String
extern fn gez_is_copula(verb: String) -> Bool
extern fn gez_conjugate_copula(tense: String, slot: Int) -> String
extern fn gez_hlw_perfect(slot: Int) -> String
extern fn gez_hlw_imperfect(slot: Int) -> String
extern fn gez_hbl_perfect(slot: Int) -> String
extern fn gez_hbl_imperfect(slot: Int) -> String
extern fn gez_ray_perfect(slot: Int) -> String
extern fn gez_ray_imperfect(slot: Int) -> String
extern fn gez_qwl_perfect(slot: Int) -> String
extern fn gez_qwl_imperfect(slot: Int) -> String
extern fn gez_generic_perfect(base3sg: String, slot: Int) -> String
extern fn gez_generic_imperfect(base3sg: String, slot: Int) -> String
extern fn gez_known_verb(verb: String, tense: String, slot: Int) -> String
extern fn gez_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn gez_is_fidel(noun: String) -> Bool
extern fn gez_decline(noun: String, gram_case: String, number: String) -> String
extern fn gez_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
extern fn gez_map_canonical(verb: String) -> String
Generated Vendored
+721
View File
@@ -0,0 +1,721 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t goh_str_ends(el_val_t s, el_val_t suf);
el_val_t goh_drop(el_val_t s, el_val_t n);
el_val_t goh_slot(el_val_t person, el_val_t number);
el_val_t goh_map_canonical(el_val_t verb);
el_val_t goh_wesan_present(el_val_t slot);
el_val_t goh_wesan_past(el_val_t slot);
el_val_t goh_haben_present(el_val_t slot);
el_val_t goh_haben_past(el_val_t slot);
el_val_t goh_gan_present(el_val_t slot);
el_val_t goh_gan_past(el_val_t slot);
el_val_t goh_sehan_present(el_val_t slot);
el_val_t goh_sehan_past(el_val_t slot);
el_val_t goh_quethan_present(el_val_t slot);
el_val_t goh_quethan_past(el_val_t slot);
el_val_t goh_tuon_present(el_val_t slot);
el_val_t goh_tuon_past(el_val_t slot);
el_val_t goh_weak_present(el_val_t stem, el_val_t slot);
el_val_t goh_weak_past(el_val_t stem, el_val_t slot);
el_val_t goh_verb_stem(el_val_t verb);
el_val_t goh_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t goh_stem_type(el_val_t noun);
el_val_t goh_extract_stem(el_val_t noun, el_val_t stype);
el_val_t goh_decline_masc_a_sg(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline_masc_a_pl(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline_fem_o_sg(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline_fem_o_pl(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline_neut_a_sg(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline_neut_a_pl(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline_masc_n_sg(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline_masc_n_pl(el_val_t stem, el_val_t gram_case);
el_val_t goh_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t goh_demo_article(el_val_t stype, el_val_t number);
el_val_t goh_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t goh_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t goh_drop(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t goh_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t goh_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("wesan");
}
if (str_eq(verb, EL_STR("have"))) {
return EL_STR("haben");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("gan");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("sehan");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("quethan");
}
if (str_eq(verb, EL_STR("do"))) {
return EL_STR("tuon");
}
if (str_eq(verb, EL_STR("make"))) {
return EL_STR("tuon");
}
if (str_eq(verb, EL_STR("come"))) {
return EL_STR("queman");
}
if (str_eq(verb, EL_STR("give"))) {
return EL_STR("geban");
}
if (str_eq(verb, EL_STR("know"))) {
return EL_STR("wizzan");
}
if (str_eq(verb, EL_STR("want"))) {
return EL_STR("wellan");
}
return verb;
return 0;
}
el_val_t goh_wesan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("bim");
}
if (slot == 1) {
return EL_STR("bist");
}
if (slot == 2) {
return EL_STR("ist");
}
if (slot == 3) {
return EL_STR("birum");
}
if (slot == 4) {
return EL_STR("birut");
}
return EL_STR("sint");
return 0;
}
el_val_t goh_wesan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("was");
}
if (slot == 1) {
return EL_STR("wari");
}
if (slot == 2) {
return EL_STR("was");
}
if (slot == 3) {
return EL_STR("warum");
}
if (slot == 4) {
return EL_STR("warut");
}
return EL_STR("warun");
return 0;
}
el_val_t goh_haben_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("habem");
}
if (slot == 1) {
return EL_STR("habest");
}
if (slot == 2) {
return EL_STR("habet");
}
if (slot == 3) {
return EL_STR("habemes");
}
if (slot == 4) {
return EL_STR("habet");
}
return EL_STR("habent");
return 0;
}
el_val_t goh_haben_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("habeta");
}
if (slot == 1) {
return EL_STR("habetos");
}
if (slot == 2) {
return EL_STR("habeta");
}
if (slot == 3) {
return EL_STR("habetom");
}
if (slot == 4) {
return EL_STR("habetot");
}
return EL_STR("habeton");
return 0;
}
el_val_t goh_gan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("gan");
}
if (slot == 1) {
return EL_STR("gest");
}
if (slot == 2) {
return EL_STR("get");
}
if (slot == 3) {
return EL_STR("games");
}
if (slot == 4) {
return EL_STR("gat");
}
return EL_STR("gant");
return 0;
}
el_val_t goh_gan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("giang");
}
if (slot == 1) {
return EL_STR("giangi");
}
if (slot == 2) {
return EL_STR("giang");
}
if (slot == 3) {
return EL_STR("giangum");
}
if (slot == 4) {
return EL_STR("giangun");
}
return EL_STR("giangun");
return 0;
}
el_val_t goh_sehan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("sihu");
}
if (slot == 1) {
return EL_STR("sihist");
}
if (slot == 2) {
return EL_STR("sihit");
}
if (slot == 3) {
return EL_STR("sehemes");
}
if (slot == 4) {
return EL_STR("sehet");
}
return EL_STR("sehent");
return 0;
}
el_val_t goh_sehan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("sah");
}
if (slot == 1) {
return EL_STR("sahi");
}
if (slot == 2) {
return EL_STR("sah");
}
if (slot == 3) {
return EL_STR("sahum");
}
if (slot == 4) {
return EL_STR("sahut");
}
return EL_STR("sahun");
return 0;
}
el_val_t goh_quethan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("quidu");
}
if (slot == 1) {
return EL_STR("quidist");
}
if (slot == 2) {
return EL_STR("quidit");
}
if (slot == 3) {
return EL_STR("quethumes");
}
if (slot == 4) {
return EL_STR("quethet");
}
return EL_STR("quethent");
return 0;
}
el_val_t goh_quethan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("quad");
}
if (slot == 1) {
return EL_STR("quadi");
}
if (slot == 2) {
return EL_STR("quad");
}
if (slot == 3) {
return EL_STR("quadum");
}
if (slot == 4) {
return EL_STR("quadut");
}
return EL_STR("quadun");
return 0;
}
el_val_t goh_tuon_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("tuom");
}
if (slot == 1) {
return EL_STR("tuost");
}
if (slot == 2) {
return EL_STR("tuot");
}
if (slot == 3) {
return EL_STR("tuomes");
}
if (slot == 4) {
return EL_STR("tuot");
}
return EL_STR("tuont");
return 0;
}
el_val_t goh_tuon_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("teta");
}
if (slot == 1) {
return EL_STR("tetos");
}
if (slot == 2) {
return EL_STR("teta");
}
if (slot == 3) {
return EL_STR("tetom");
}
if (slot == 4) {
return EL_STR("tetot");
}
return EL_STR("teton");
return 0;
}
el_val_t goh_weak_present(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("u"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("ist"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("it"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("emes"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("et"));
}
return el_str_concat(stem, EL_STR("ent"));
return 0;
}
el_val_t goh_weak_past(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("ta"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("tos"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("ta"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("tom"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("tot"));
}
return el_str_concat(stem, EL_STR("ton"));
return 0;
}
el_val_t goh_verb_stem(el_val_t verb) {
return goh_drop(verb, 2);
return 0;
}
el_val_t goh_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t v = goh_map_canonical(verb);
el_val_t slot = goh_slot(person, number);
if (str_eq(v, EL_STR("wesan"))) {
if (str_eq(tense, EL_STR("present"))) {
return goh_wesan_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return goh_wesan_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("haben"))) {
if (str_eq(tense, EL_STR("present"))) {
return goh_haben_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return goh_haben_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("haben"))) {
if (str_eq(tense, EL_STR("present"))) {
return goh_haben_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return goh_haben_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("gan"))) {
if (str_eq(tense, EL_STR("present"))) {
return goh_gan_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return goh_gan_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("sehan"))) {
if (str_eq(tense, EL_STR("present"))) {
return goh_sehan_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return goh_sehan_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("quethan"))) {
if (str_eq(tense, EL_STR("present"))) {
return goh_quethan_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return goh_quethan_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("tuon"))) {
if (str_eq(tense, EL_STR("present"))) {
return goh_tuon_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return goh_tuon_past(slot);
}
return v;
}
el_val_t stem = goh_verb_stem(v);
if (str_eq(tense, EL_STR("present"))) {
return goh_weak_present(stem, slot);
}
if (str_eq(tense, EL_STR("past"))) {
return goh_weak_past(stem, slot);
}
return v;
return 0;
}
el_val_t goh_stem_type(el_val_t noun) {
if (goh_str_ends(noun, EL_STR("o"))) {
return EL_STR("masc_n");
}
if (goh_str_ends(noun, EL_STR("a"))) {
return EL_STR("fem_o");
}
if (goh_str_ends(noun, EL_STR("t"))) {
return EL_STR("neut_a");
}
if (goh_str_ends(noun, EL_STR("d"))) {
return EL_STR("neut_a");
}
if (goh_str_ends(noun, EL_STR("nd"))) {
return EL_STR("neut_a");
}
return EL_STR("masc_a");
return 0;
}
el_val_t goh_extract_stem(el_val_t noun, el_val_t stype) {
if (str_eq(stype, EL_STR("fem_o"))) {
return goh_drop(noun, 1);
}
if (str_eq(stype, EL_STR("masc_n"))) {
return goh_drop(noun, 1);
}
return noun;
return 0;
}
el_val_t goh_decline_masc_a_sg(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return stem;
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return stem;
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("es"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("e"));
}
return stem;
return 0;
}
el_val_t goh_decline_masc_a_pl(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("o"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("um"));
}
return el_str_concat(stem, EL_STR("a"));
return 0;
}
el_val_t goh_decline_fem_o_sg(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("u"));
}
return el_str_concat(stem, EL_STR("a"));
return 0;
}
el_val_t goh_decline_fem_o_pl(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("ono"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("om"));
}
return el_str_concat(stem, EL_STR("a"));
return 0;
}
el_val_t goh_decline_neut_a_sg(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return stem;
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return stem;
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("es"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("e"));
}
return stem;
return 0;
}
el_val_t goh_decline_neut_a_pl(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return stem;
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return stem;
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("o"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("um"));
}
return stem;
return 0;
}
el_val_t goh_decline_masc_n_sg(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("o"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("on"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("on"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("on"));
}
return el_str_concat(stem, EL_STR("o"));
return 0;
}
el_val_t goh_decline_masc_n_pl(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("on"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("on"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("ono"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("om"));
}
return el_str_concat(stem, EL_STR("on"));
return 0;
}
el_val_t goh_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t stype = goh_stem_type(noun);
el_val_t stem = goh_extract_stem(noun, stype);
if (str_eq(stype, EL_STR("masc_a"))) {
if (str_eq(number, EL_STR("singular"))) {
return goh_decline_masc_a_sg(stem, gram_case);
}
return goh_decline_masc_a_pl(stem, gram_case);
}
if (str_eq(stype, EL_STR("fem_o"))) {
if (str_eq(number, EL_STR("singular"))) {
return goh_decline_fem_o_sg(stem, gram_case);
}
return goh_decline_fem_o_pl(stem, gram_case);
}
if (str_eq(stype, EL_STR("neut_a"))) {
if (str_eq(number, EL_STR("singular"))) {
return goh_decline_neut_a_sg(stem, gram_case);
}
return goh_decline_neut_a_pl(stem, gram_case);
}
if (str_eq(stype, EL_STR("masc_n"))) {
if (str_eq(number, EL_STR("singular"))) {
return goh_decline_masc_n_sg(stem, gram_case);
}
return goh_decline_masc_n_pl(stem, gram_case);
}
return noun;
return 0;
}
el_val_t goh_demo_article(el_val_t stype, el_val_t number) {
if (str_eq(number, EL_STR("plural"))) {
return EL_STR("die");
}
if (str_eq(stype, EL_STR("fem_o"))) {
return EL_STR("diu");
}
if (str_eq(stype, EL_STR("neut_a"))) {
return EL_STR("daz");
}
return EL_STR("der");
return 0;
}
el_val_t goh_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
el_val_t stype = goh_stem_type(noun);
el_val_t declined = goh_decline(noun, gram_case, number);
if (str_eq(definite, EL_STR("true"))) {
el_val_t art = goh_demo_article(stype, number);
return el_str_concat(el_str_concat(art, EL_STR(" ")), declined);
}
return declined;
return 0;
}
Generated Vendored
+34
View File
@@ -0,0 +1,34 @@
// auto-generated by elc --emit-header — do not edit
extern fn goh_str_ends(s: String, suf: String) -> Bool
extern fn goh_drop(s: String, n: Int) -> String
extern fn goh_slot(person: String, number: String) -> Int
extern fn goh_map_canonical(verb: String) -> String
extern fn goh_wesan_present(slot: Int) -> String
extern fn goh_wesan_past(slot: Int) -> String
extern fn goh_haben_present(slot: Int) -> String
extern fn goh_haben_past(slot: Int) -> String
extern fn goh_gan_present(slot: Int) -> String
extern fn goh_gan_past(slot: Int) -> String
extern fn goh_sehan_present(slot: Int) -> String
extern fn goh_sehan_past(slot: Int) -> String
extern fn goh_quethan_present(slot: Int) -> String
extern fn goh_quethan_past(slot: Int) -> String
extern fn goh_tuon_present(slot: Int) -> String
extern fn goh_tuon_past(slot: Int) -> String
extern fn goh_weak_present(stem: String, slot: Int) -> String
extern fn goh_weak_past(stem: String, slot: Int) -> String
extern fn goh_verb_stem(verb: String) -> String
extern fn goh_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn goh_stem_type(noun: String) -> String
extern fn goh_extract_stem(noun: String, stype: String) -> String
extern fn goh_decline_masc_a_sg(stem: String, gram_case: String) -> String
extern fn goh_decline_masc_a_pl(stem: String, gram_case: String) -> String
extern fn goh_decline_fem_o_sg(stem: String, gram_case: String) -> String
extern fn goh_decline_fem_o_pl(stem: String, gram_case: String) -> String
extern fn goh_decline_neut_a_sg(stem: String, gram_case: String) -> String
extern fn goh_decline_neut_a_pl(stem: String, gram_case: String) -> String
extern fn goh_decline_masc_n_sg(stem: String, gram_case: String) -> String
extern fn goh_decline_masc_n_pl(stem: String, gram_case: String) -> String
extern fn goh_decline(noun: String, gram_case: String, number: String) -> String
extern fn goh_demo_article(stype: String, number: String) -> String
extern fn goh_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
Generated Vendored
+735
View File
@@ -0,0 +1,735 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t got_str_ends(el_val_t s, el_val_t suf);
el_val_t got_str_drop_last(el_val_t s, el_val_t n);
el_val_t got_slot(el_val_t person, el_val_t number);
el_val_t got_map_canonical(el_val_t verb);
el_val_t got_wisan_present(el_val_t slot);
el_val_t got_wisan_past(el_val_t slot);
el_val_t got_haban_present(el_val_t slot);
el_val_t got_haban_past(el_val_t slot);
el_val_t got_gaggan_present(el_val_t slot);
el_val_t got_gaggan_past(el_val_t slot);
el_val_t got_saihwan_present(el_val_t slot);
el_val_t got_saihwan_past(el_val_t slot);
el_val_t got_qithan_present(el_val_t slot);
el_val_t got_qithan_past(el_val_t slot);
el_val_t got_niman_present(el_val_t slot);
el_val_t got_niman_past(el_val_t slot);
el_val_t got_wk1_present_ending(el_val_t slot);
el_val_t got_wk1_past_ending(el_val_t slot);
el_val_t got_wk1_conjugate(el_val_t stem, el_val_t tense, el_val_t slot);
el_val_t got_wk2_present_ending(el_val_t slot);
el_val_t got_wk2_past_ending(el_val_t slot);
el_val_t got_wk2_conjugate(el_val_t stem, el_val_t tense, el_val_t slot);
el_val_t got_verb_class(el_val_t verb);
el_val_t got_verb_stem(el_val_t verb, el_val_t vclass);
el_val_t got_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t got_decline_a_stem_sg(el_val_t stem, el_val_t gram_case);
el_val_t got_decline_a_stem_pl(el_val_t stem, el_val_t gram_case);
el_val_t got_decline_o_stem_sg(el_val_t stem, el_val_t gram_case);
el_val_t got_decline_o_stem_pl(el_val_t stem, el_val_t gram_case);
el_val_t got_decline_n_stem_sg(el_val_t stem, el_val_t gram_case);
el_val_t got_decline_n_stem_pl(el_val_t stem, el_val_t gram_case);
el_val_t got_stem_type(el_val_t noun);
el_val_t got_extract_stem(el_val_t noun, el_val_t stype);
el_val_t got_demo_article(el_val_t stype);
el_val_t got_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t got_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t got_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t got_str_drop_last(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t got_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t got_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("wisan");
}
if (str_eq(verb, EL_STR("have"))) {
return EL_STR("haban");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("gaggan");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("saihwan");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("qi\xc3\xbe""an");
}
if (str_eq(verb, EL_STR("take"))) {
return EL_STR("niman");
}
if (str_eq(verb, EL_STR("come"))) {
return EL_STR("qiman");
}
if (str_eq(verb, EL_STR("give"))) {
return EL_STR("giban");
}
if (str_eq(verb, EL_STR("know"))) {
return EL_STR("kunnan");
}
if (str_eq(verb, EL_STR("want"))) {
return EL_STR("wiljan");
}
return verb;
return 0;
}
el_val_t got_wisan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("im");
}
if (slot == 1) {
return EL_STR("is");
}
if (slot == 2) {
return EL_STR("ist");
}
if (slot == 3) {
return EL_STR("sijum");
}
if (slot == 4) {
return EL_STR("siju\xc3\xbe");
}
return EL_STR("sind");
return 0;
}
el_val_t got_wisan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("was");
}
if (slot == 1) {
return EL_STR("wast");
}
if (slot == 2) {
return EL_STR("was");
}
if (slot == 3) {
return EL_STR("wesum");
}
if (slot == 4) {
return EL_STR("wesu\xc3\xbe");
}
return EL_STR("wesun");
return 0;
}
el_val_t got_haban_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("haba");
}
if (slot == 1) {
return EL_STR("habais");
}
if (slot == 2) {
return EL_STR("habai\xc3\xbe");
}
if (slot == 3) {
return EL_STR("habam");
}
if (slot == 4) {
return EL_STR("habai\xc3\xbe");
}
return EL_STR("haband");
return 0;
}
el_val_t got_haban_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("habida");
}
if (slot == 1) {
return EL_STR("habides");
}
if (slot == 2) {
return EL_STR("habida");
}
if (slot == 3) {
return EL_STR("habidum");
}
if (slot == 4) {
return EL_STR("habide\xc3\xbe");
}
return EL_STR("habidedun");
return 0;
}
el_val_t got_gaggan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("gagga");
}
if (slot == 1) {
return EL_STR("gaggis");
}
if (slot == 2) {
return EL_STR("gaggi\xc3\xbe");
}
if (slot == 3) {
return EL_STR("gagam");
}
if (slot == 4) {
return EL_STR("gagi\xc3\xbe");
}
return EL_STR("gaggand");
return 0;
}
el_val_t got_gaggan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("iddja");
}
if (slot == 1) {
return EL_STR("iddj\xc4\x93s");
}
if (slot == 2) {
return EL_STR("iddja");
}
if (slot == 3) {
return EL_STR("iddj\xc4\x93""dum");
}
if (slot == 4) {
return EL_STR("iddj\xc4\x93""du\xc3\xbe");
}
return EL_STR("iddj\xc4\x93""dun");
return 0;
}
el_val_t got_saihwan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("saihwa");
}
if (slot == 1) {
return EL_STR("saihwis");
}
if (slot == 2) {
return EL_STR("saihwi\xc3\xbe");
}
if (slot == 3) {
return EL_STR("saihwam");
}
if (slot == 4) {
return EL_STR("saihwi\xc3\xbe");
}
return EL_STR("saihwand");
return 0;
}
el_val_t got_saihwan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("sahw");
}
if (slot == 1) {
return EL_STR("sahwt");
}
if (slot == 2) {
return EL_STR("sahw");
}
if (slot == 3) {
return EL_STR("sehwum");
}
if (slot == 4) {
return EL_STR("sehwu\xc3\xbe");
}
return EL_STR("sehwun");
return 0;
}
el_val_t got_qithan_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("qi\xc3\xbe""a");
}
if (slot == 1) {
return EL_STR("qi\xc3\xbeis");
}
if (slot == 2) {
return EL_STR("qi\xc3\xbei\xc3\xbe");
}
if (slot == 3) {
return EL_STR("qi\xc3\xbe""am");
}
if (slot == 4) {
return EL_STR("qi\xc3\xbei\xc3\xbe");
}
return EL_STR("qi\xc3\xbe""and");
return 0;
}
el_val_t got_qithan_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("qa\xc3\xbe");
}
if (slot == 1) {
return EL_STR("qast");
}
if (slot == 2) {
return EL_STR("qa\xc3\xbe");
}
if (slot == 3) {
return EL_STR("q\xc4\x93\xc3\xbeum");
}
if (slot == 4) {
return EL_STR("q\xc4\x93\xc3\xbeu\xc3\xbe");
}
return EL_STR("q\xc4\x93\xc3\xbeun");
return 0;
}
el_val_t got_niman_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("nima");
}
if (slot == 1) {
return EL_STR("nimis");
}
if (slot == 2) {
return EL_STR("nimi\xc3\xbe");
}
if (slot == 3) {
return EL_STR("nimam");
}
if (slot == 4) {
return EL_STR("nimi\xc3\xbe");
}
return EL_STR("nimand");
return 0;
}
el_val_t got_niman_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("nam");
}
if (slot == 1) {
return EL_STR("namt");
}
if (slot == 2) {
return EL_STR("nam");
}
if (slot == 3) {
return EL_STR("n\xc4\x93mum");
}
if (slot == 4) {
return EL_STR("n\xc4\x93mu\xc3\xbe");
}
return EL_STR("n\xc4\x93mun");
return 0;
}
el_val_t got_wk1_present_ending(el_val_t slot) {
if (slot == 0) {
return EL_STR("a");
}
if (slot == 1) {
return EL_STR("is");
}
if (slot == 2) {
return EL_STR("i\xc3\xbe");
}
if (slot == 3) {
return EL_STR("jam");
}
if (slot == 4) {
return EL_STR("ji\xc3\xbe");
}
return EL_STR("jand");
return 0;
}
el_val_t got_wk1_past_ending(el_val_t slot) {
if (slot == 0) {
return EL_STR("ida");
}
if (slot == 1) {
return EL_STR("ides");
}
if (slot == 2) {
return EL_STR("ida");
}
if (slot == 3) {
return EL_STR("idum");
}
if (slot == 4) {
return EL_STR("ide\xc3\xbe");
}
return EL_STR("idedun");
return 0;
}
el_val_t got_wk1_conjugate(el_val_t stem, el_val_t tense, el_val_t slot) {
if (str_eq(tense, EL_STR("present"))) {
return el_str_concat(stem, got_wk1_present_ending(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return el_str_concat(stem, got_wk1_past_ending(slot));
}
return stem;
return 0;
}
el_val_t got_wk2_present_ending(el_val_t slot) {
if (slot == 0) {
return EL_STR("o");
}
if (slot == 1) {
return EL_STR("os");
}
if (slot == 2) {
return EL_STR("o\xc3\xbe");
}
if (slot == 3) {
return EL_STR("om");
}
if (slot == 4) {
return EL_STR("o\xc3\xbe");
}
return EL_STR("ond");
return 0;
}
el_val_t got_wk2_past_ending(el_val_t slot) {
if (slot == 0) {
return EL_STR("oda");
}
if (slot == 1) {
return EL_STR("odes");
}
if (slot == 2) {
return EL_STR("oda");
}
if (slot == 3) {
return EL_STR("odum");
}
if (slot == 4) {
return EL_STR("ode\xc3\xbe");
}
return EL_STR("odedun");
return 0;
}
el_val_t got_wk2_conjugate(el_val_t stem, el_val_t tense, el_val_t slot) {
if (str_eq(tense, EL_STR("present"))) {
return el_str_concat(stem, got_wk2_present_ending(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return el_str_concat(stem, got_wk2_past_ending(slot));
}
return stem;
return 0;
}
el_val_t got_verb_class(el_val_t verb) {
if (got_str_ends(verb, EL_STR("jan"))) {
return EL_STR("wk1");
}
if (got_str_ends(verb, EL_STR("on"))) {
return EL_STR("wk2");
}
return EL_STR("wk1");
return 0;
}
el_val_t got_verb_stem(el_val_t verb, el_val_t vclass) {
if (str_eq(vclass, EL_STR("wk1"))) {
return got_str_drop_last(verb, 3);
}
if (str_eq(vclass, EL_STR("wk2"))) {
return got_str_drop_last(verb, 2);
}
return got_str_drop_last(verb, 2);
return 0;
}
el_val_t got_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t v = got_map_canonical(verb);
el_val_t slot = got_slot(person, number);
if (str_eq(v, EL_STR("wisan"))) {
if (str_eq(tense, EL_STR("present"))) {
return got_wisan_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return got_wisan_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("haban"))) {
if (str_eq(tense, EL_STR("present"))) {
return got_haban_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return got_haban_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("gaggan"))) {
if (str_eq(tense, EL_STR("present"))) {
return got_gaggan_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return got_gaggan_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("saihwan"))) {
if (str_eq(tense, EL_STR("present"))) {
return got_saihwan_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return got_saihwan_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("qi\xc3\xbe""an"))) {
if (str_eq(tense, EL_STR("present"))) {
return got_qithan_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return got_qithan_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("niman"))) {
if (str_eq(tense, EL_STR("present"))) {
return got_niman_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return got_niman_past(slot);
}
return v;
}
el_val_t vclass = got_verb_class(v);
el_val_t stem = got_verb_stem(v, vclass);
if (str_eq(vclass, EL_STR("wk1"))) {
return got_wk1_conjugate(stem, tense, slot);
}
if (str_eq(vclass, EL_STR("wk2"))) {
return got_wk2_conjugate(stem, tense, slot);
}
return v;
return 0;
}
el_val_t got_decline_a_stem_sg(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("s"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return stem;
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("is"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("a"));
}
return el_str_concat(stem, EL_STR("s"));
return 0;
}
el_val_t got_decline_a_stem_pl(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("os"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("ans"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("e"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("am"));
}
return el_str_concat(stem, EL_STR("os"));
return 0;
}
el_val_t got_decline_o_stem_sg(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("o"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("os"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("ai"));
}
return el_str_concat(stem, EL_STR("o"));
return 0;
}
el_val_t got_decline_o_stem_pl(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("os"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("os"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("o"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("om"));
}
return el_str_concat(stem, EL_STR("os"));
return 0;
}
el_val_t got_decline_n_stem_sg(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("an"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("ins"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("in"));
}
return el_str_concat(stem, EL_STR("a"));
return 0;
}
el_val_t got_decline_n_stem_pl(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("ans"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("ans"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("ane"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("am"));
}
return el_str_concat(stem, EL_STR("ans"));
return 0;
}
el_val_t got_stem_type(el_val_t noun) {
if (got_str_ends(noun, EL_STR("o"))) {
return EL_STR("o");
}
if (got_str_ends(noun, EL_STR("a"))) {
return EL_STR("n");
}
if (got_str_ends(noun, EL_STR("s"))) {
return EL_STR("a");
}
return EL_STR("a");
return 0;
}
el_val_t got_extract_stem(el_val_t noun, el_val_t stype) {
el_val_t n = str_len(noun);
return str_slice(noun, 0, (n - 1));
return 0;
}
el_val_t got_demo_article(el_val_t stype) {
if (str_eq(stype, EL_STR("o"))) {
return EL_STR("\xc3\xbeo");
}
return EL_STR("sa");
return 0;
}
el_val_t got_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t stype = got_stem_type(noun);
el_val_t stem = got_extract_stem(noun, stype);
if (str_eq(stype, EL_STR("a"))) {
if (str_eq(number, EL_STR("singular"))) {
return got_decline_a_stem_sg(stem, gram_case);
}
return got_decline_a_stem_pl(stem, gram_case);
}
if (str_eq(stype, EL_STR("o"))) {
if (str_eq(number, EL_STR("singular"))) {
return got_decline_o_stem_sg(stem, gram_case);
}
return got_decline_o_stem_pl(stem, gram_case);
}
if (str_eq(stype, EL_STR("n"))) {
if (str_eq(number, EL_STR("singular"))) {
return got_decline_n_stem_sg(stem, gram_case);
}
return got_decline_n_stem_pl(stem, gram_case);
}
return noun;
return 0;
}
el_val_t got_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
el_val_t declined = got_decline(noun, gram_case, number);
if (str_eq(definite, EL_STR("true"))) {
el_val_t stype = got_stem_type(noun);
el_val_t article = got_demo_article(stype);
return el_str_concat(el_str_concat(article, EL_STR(" ")), declined);
}
return declined;
return 0;
}
Generated Vendored
+37
View File
@@ -0,0 +1,37 @@
// auto-generated by elc --emit-header — do not edit
extern fn got_str_ends(s: String, suf: String) -> Bool
extern fn got_str_drop_last(s: String, n: Int) -> String
extern fn got_slot(person: String, number: String) -> Int
extern fn got_map_canonical(verb: String) -> String
extern fn got_wisan_present(slot: Int) -> String
extern fn got_wisan_past(slot: Int) -> String
extern fn got_haban_present(slot: Int) -> String
extern fn got_haban_past(slot: Int) -> String
extern fn got_gaggan_present(slot: Int) -> String
extern fn got_gaggan_past(slot: Int) -> String
extern fn got_saihwan_present(slot: Int) -> String
extern fn got_saihwan_past(slot: Int) -> String
extern fn got_qithan_present(slot: Int) -> String
extern fn got_qithan_past(slot: Int) -> String
extern fn got_niman_present(slot: Int) -> String
extern fn got_niman_past(slot: Int) -> String
extern fn got_wk1_present_ending(slot: Int) -> String
extern fn got_wk1_past_ending(slot: Int) -> String
extern fn got_wk1_conjugate(stem: String, tense: String, slot: Int) -> String
extern fn got_wk2_present_ending(slot: Int) -> String
extern fn got_wk2_past_ending(slot: Int) -> String
extern fn got_wk2_conjugate(stem: String, tense: String, slot: Int) -> String
extern fn got_verb_class(verb: String) -> String
extern fn got_verb_stem(verb: String, vclass: String) -> String
extern fn got_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn got_decline_a_stem_sg(stem: String, gram_case: String) -> String
extern fn got_decline_a_stem_pl(stem: String, gram_case: String) -> String
extern fn got_decline_o_stem_sg(stem: String, gram_case: String) -> String
extern fn got_decline_o_stem_pl(stem: String, gram_case: String) -> String
extern fn got_decline_n_stem_sg(stem: String, gram_case: String) -> String
extern fn got_decline_n_stem_pl(stem: String, gram_case: String) -> String
extern fn got_stem_type(noun: String) -> String
extern fn got_extract_stem(noun: String, stype: String) -> String
extern fn got_demo_article(stype: String) -> String
extern fn got_decline(noun: String, gram_case: String, number: String) -> String
extern fn got_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
Generated Vendored
+1093
View File
File diff suppressed because it is too large Load Diff
Generated Vendored
+45
View File
@@ -0,0 +1,45 @@
// auto-generated by elc --emit-header — do not edit
extern fn grc_str_ends(s: String, suf: String) -> Bool
extern fn grc_str_drop_last(s: String, n: Int) -> String
extern fn grc_str_last_char(s: String) -> String
extern fn grc_str_last2(s: String) -> String
extern fn grc_str_last3(s: String) -> String
extern fn grc_slot(person: String, number: String) -> Int
extern fn grc_map_canonical(verb: String) -> String
extern fn grc_einai_present(slot: Int) -> String
extern fn grc_einai_imperfect(slot: Int) -> String
extern fn grc_einai_future(slot: Int) -> String
extern fn grc_echein_present(slot: Int) -> String
extern fn grc_echein_imperfect(slot: Int) -> String
extern fn grc_echein_aorist(slot: Int) -> String
extern fn grc_echein_future(slot: Int) -> String
extern fn grc_legein_present(slot: Int) -> String
extern fn grc_legein_imperfect(slot: Int) -> String
extern fn grc_legein_aorist(slot: Int) -> String
extern fn grc_legein_future(slot: Int) -> String
extern fn grc_horao_present(slot: Int) -> String
extern fn grc_horao_imperfect(slot: Int) -> String
extern fn grc_horao_aorist(slot: Int) -> String
extern fn grc_horao_future(slot: Int) -> String
extern fn grc_erchesthai_present(slot: Int) -> String
extern fn grc_erchesthai_imperfect(slot: Int) -> String
extern fn grc_erchesthai_aorist(slot: Int) -> String
extern fn grc_erchesthai_future(slot: Int) -> String
extern fn grc_thematic_present_ending(slot: Int) -> String
extern fn grc_thematic_imperfect_ending(slot: Int) -> String
extern fn grc_thematic_future_ending(slot: Int) -> String
extern fn grc_weak_aorist_ending(slot: Int) -> String
extern fn grc_present_stem(verb: String) -> String
extern fn grc_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn grc_declension(noun: String) -> String
extern fn grc_decline_2m(stem: String, gram_case: String, number: String) -> String
extern fn grc_decline_2n(stem: String, gram_case: String, number: String) -> String
extern fn grc_decline_1a(stem: String, gram_case: String, number: String) -> String
extern fn grc_decline_1e(stem: String, gram_case: String, number: String) -> String
extern fn grc_decline(noun: String, gram_case: String, number: String) -> String
extern fn grc_article_masculine(gram_case: String, number: String) -> String
extern fn grc_article_feminine(gram_case: String, number: String) -> String
extern fn grc_article_neuter(gram_case: String, number: String) -> String
extern fn grc_article(gender: String, gram_case: String, number: String) -> String
extern fn grc_infer_gender(noun: String) -> String
extern fn grc_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
Generated Vendored
+819
View File
@@ -0,0 +1,819 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t he_str_ends(el_val_t s, el_val_t suf);
el_val_t he_str_len(el_val_t s);
el_val_t he_str_drop_last(el_val_t s, el_val_t n);
el_val_t he_str_last_char(el_val_t s);
el_val_t he_slot(el_val_t person, el_val_t gender, el_val_t number);
el_val_t he_present_form_code(el_val_t slot);
el_val_t he_copula_past(el_val_t slot);
el_val_t he_copula_future(el_val_t slot);
el_val_t he_is_copula(el_val_t verb);
el_val_t he_conjugate_copula(el_val_t tense, el_val_t slot);
el_val_t he_present_lir_ot(el_val_t form);
el_val_t he_present_le_exol(el_val_t form);
el_val_t he_present_ledaber(el_val_t form);
el_val_t he_present_lalechet(el_val_t form);
el_val_t he_past_lir_ot(el_val_t slot);
el_val_t he_past_le_exol(el_val_t slot);
el_val_t he_past_ledaber(el_val_t slot);
el_val_t he_past_lalechet(el_val_t slot);
el_val_t he_future_lir_ot(el_val_t slot);
el_val_t he_future_le_exol(el_val_t slot);
el_val_t he_future_ledaber(el_val_t slot);
el_val_t he_future_lalechet(el_val_t slot);
el_val_t he_known_verb(el_val_t verb, el_val_t tense, el_val_t slot);
el_val_t he_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t gender, el_val_t number);
el_val_t he_pluralize(el_val_t noun, el_val_t gender);
el_val_t he_is_hebrew_script(el_val_t noun);
el_val_t he_definite_prefix(el_val_t noun);
el_val_t he_noun_phrase(el_val_t noun, el_val_t number, el_val_t gender, el_val_t definite);
el_val_t he_map_canonical(el_val_t verb);
el_val_t he_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t he_str_len(el_val_t s) {
return str_len(s);
return 0;
}
el_val_t he_str_drop_last(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t he_str_last_char(el_val_t s) {
el_val_t n = str_len(s);
if (n == 0) {
return EL_STR("");
}
return str_slice(s, (n - 1), n);
return 0;
}
el_val_t he_slot(el_val_t person, el_val_t gender, el_val_t number) {
if (str_eq(person, EL_STR("third"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gender, EL_STR("f"))) {
return 1;
}
return 0;
}
if (str_eq(gender, EL_STR("f"))) {
return 6;
}
return 5;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gender, EL_STR("f"))) {
return 3;
}
return 2;
}
if (str_eq(gender, EL_STR("f"))) {
return 8;
}
return 7;
}
if (str_eq(number, EL_STR("plural"))) {
return 9;
}
return 4;
return 0;
}
el_val_t he_present_form_code(el_val_t slot) {
if (slot == 0) {
return 0;
}
if (slot == 1) {
return 1;
}
if (slot == 2) {
return 0;
}
if (slot == 3) {
return 1;
}
if (slot == 4) {
return 0;
}
if (slot == 5) {
return 2;
}
if (slot == 6) {
return 3;
}
if (slot == 7) {
return 2;
}
if (slot == 8) {
return 3;
}
return 2;
return 0;
}
el_val_t he_copula_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xd7\x94\xd7\x99\xd7\x94");
}
if (slot == 1) {
return EL_STR("\xd7\x94\xd7\x99\xd7\x99\xd7\xaa\xd7\x94");
}
if (slot == 2) {
return EL_STR("\xd7\x94\xd7\x99\xd7\x99\xd7\xaa");
}
if (slot == 3) {
return EL_STR("\xd7\x94\xd7\x99\xd7\x99\xd7\xaa\xd7\x94");
}
if (slot == 4) {
return EL_STR("\xd7\x94\xd7\x99\xd7\x99\xd7\xaa\xd7\x99");
}
if (slot == 5) {
return EL_STR("\xd7\x94\xd7\x99\xd7\x95");
}
if (slot == 6) {
return EL_STR("\xd7\x94\xd7\x99\xd7\x95");
}
if (slot == 7) {
return EL_STR("\xd7\x94\xd7\x99\xd7\x99\xd7\xaa\xd7\x9d");
}
if (slot == 8) {
return EL_STR("\xd7\x94\xd7\x99\xd7\x99\xd7\xaa\xd7\x9f");
}
return EL_STR("\xd7\x94\xd7\x99\xd7\x99\xd7\xa0\xd7\x95");
return 0;
}
el_val_t he_copula_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xd7\x99\xd7\x94\xd7\x99\xd7\x94");
}
if (slot == 1) {
return EL_STR("\xd7\xaa\xd7\x94\xd7\x99\xd7\x94");
}
if (slot == 2) {
return EL_STR("\xd7\xaa\xd7\x94\xd7\x99\xd7\x94");
}
if (slot == 3) {
return EL_STR("\xd7\xaa\xd7\x94\xd7\x99\xd7\x99");
}
if (slot == 4) {
return EL_STR("\xd7\x90\xd7\x94\xd7\x99\xd7\x94");
}
if (slot == 5) {
return EL_STR("\xd7\x99\xd7\x94\xd7\x99\xd7\x95");
}
if (slot == 6) {
return EL_STR("\xd7\x99\xd7\x94\xd7\x99\xd7\x95");
}
if (slot == 7) {
return EL_STR("\xd7\xaa\xd7\x94\xd7\x99\xd7\x95");
}
if (slot == 8) {
return EL_STR("\xd7\xaa\xd7\x94\xd7\x99\xd7\x95");
}
return EL_STR("\xd7\xa0\xd7\x94\xd7\x99\xd7\x94");
return 0;
}
el_val_t he_is_copula(el_val_t verb) {
if (str_eq(verb, EL_STR("lihyot"))) {
return 1;
}
if (str_eq(verb, EL_STR("haya"))) {
return 1;
}
if (str_eq(verb, EL_STR("be"))) {
return 1;
}
if (str_eq(verb, EL_STR("\xd7\x94\xd7\x99\xd7\x94"))) {
return 1;
}
if (str_eq(verb, EL_STR("\xd7\x9c\xd6\xb4\xd7\x94\xd6\xb0\xd7\x99\xd7\x95\xd6\xb9\xd7\xaa"))) {
return 1;
}
return 0;
return 0;
}
el_val_t he_conjugate_copula(el_val_t tense, el_val_t slot) {
if (str_eq(tense, EL_STR("present"))) {
return EL_STR("");
}
if (str_eq(tense, EL_STR("past"))) {
return he_copula_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return he_copula_future(slot);
}
return EL_STR("");
return 0;
}
el_val_t he_present_lir_ot(el_val_t form) {
if (form == 0) {
return EL_STR("\xd7\xa8\xd7\x95\xd6\xb9\xd7\x90\xd6\xb6\xd7\x94");
}
if (form == 1) {
return EL_STR("\xd7\xa8\xd7\x95\xd6\xb9\xd7\x90\xd6\xb8\xd7\x94");
}
if (form == 2) {
return EL_STR("\xd7\xa8\xd7\x95\xd6\xb9\xd7\x90\xd6\xb4\xd7\x99\xd7\x9d");
}
return EL_STR("\xd7\xa8\xd7\x95\xd6\xb9\xd7\x90\xd7\x95\xd6\xb9\xd7\xaa");
return 0;
}
el_val_t he_present_le_exol(el_val_t form) {
if (form == 0) {
return EL_STR("\xd7\x90\xd7\x95\xd6\xb9\xd7\x9b\xd6\xb5\xd7\x9c");
}
if (form == 1) {
return EL_STR("\xd7\x90\xd7\x95\xd6\xb9\xd7\x9b\xd6\xb6\xd7\x9c\xd6\xb6\xd7\xaa");
}
if (form == 2) {
return EL_STR("\xd7\x90\xd7\x95\xd6\xb9\xd7\x9b\xd6\xb0\xd7\x9c\xd6\xb4\xd7\x99\xd7\x9d");
}
return EL_STR("\xd7\x90\xd7\x95\xd6\xb9\xd7\x9b\xd6\xb0\xd7\x9c\xd7\x95\xd6\xb9\xd7\xaa");
return 0;
}
el_val_t he_present_ledaber(el_val_t form) {
if (form == 0) {
return EL_STR("\xd7\x9e\xd6\xb0\xd7\x93\xd6\xb7\xd7\x91\xd6\xb5\xd6\xbc\xd7\xa8");
}
if (form == 1) {
return EL_STR("\xd7\x9e\xd6\xb0\xd7\x93\xd6\xb7\xd7\x91\xd6\xb6\xd6\xbc\xd7\xa8\xd6\xb6\xd7\xaa");
}
if (form == 2) {
return EL_STR("\xd7\x9e\xd6\xb0\xd7\x93\xd6\xb7\xd7\x91\xd6\xb0\xd6\xbc\xd7\xa8\xd6\xb4\xd7\x99\xd7\x9d");
}
return EL_STR("\xd7\x9e\xd6\xb0\xd7\x93\xd6\xb7\xd7\x91\xd6\xb0\xd6\xbc\xd7\xa8\xd7\x95\xd6\xb9\xd7\xaa");
return 0;
}
el_val_t he_present_lalechet(el_val_t form) {
if (form == 0) {
return EL_STR("\xd7\x94\xd7\x95\xd6\xb9\xd7\x9c\xd6\xb5\xd7\x9a\xd6\xb0");
}
if (form == 1) {
return EL_STR("\xd7\x94\xd7\x95\xd6\xb9\xd7\x9c\xd6\xb6\xd7\x9b\xd6\xb6\xd7\xaa");
}
if (form == 2) {
return EL_STR("\xd7\x94\xd7\x95\xd6\xb9\xd7\x9c\xd6\xb0\xd7\x9b\xd6\xb4\xd7\x99\xd7\x9d");
}
return EL_STR("\xd7\x94\xd7\x95\xd6\xb9\xd7\x9c\xd6\xb0\xd7\x9b\xd7\x95\xd6\xb9\xd7\xaa");
return 0;
}
el_val_t he_past_lir_ot(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xd7\xa8\xd6\xb8\xd7\x90\xd6\xb8\xd7\x94");
}
if (slot == 1) {
return EL_STR("\xd7\xa8\xd6\xb8\xd7\x90\xd6\xb2\xd7\xaa\xd6\xb8\xd7\x94");
}
if (slot == 2) {
return EL_STR("\xd7\xa8\xd6\xb8\xd7\x90\xd6\xb4\xd7\x99\xd7\xaa\xd6\xb8");
}
if (slot == 3) {
return EL_STR("\xd7\xa8\xd6\xb8\xd7\x90\xd6\xb4\xd7\x99\xd7\xaa");
}
if (slot == 4) {
return EL_STR("\xd7\xa8\xd6\xb8\xd7\x90\xd6\xb4\xd7\x99\xd7\xaa\xd6\xb4\xd7\x99");
}
if (slot == 5) {
return EL_STR("\xd7\xa8\xd6\xb8\xd7\x90\xd7\x95\xd6\xbc");
}
if (slot == 6) {
return EL_STR("\xd7\xa8\xd6\xb8\xd7\x90\xd7\x95\xd6\xbc");
}
if (slot == 7) {
return EL_STR("\xd7\xa8\xd6\xb0\xd7\x90\xd6\xb4\xd7\x99\xd7\xaa\xd6\xb6\xd7\x9d");
}
if (slot == 8) {
return EL_STR("\xd7\xa8\xd6\xb0\xd7\x90\xd6\xb4\xd7\x99\xd7\xaa\xd6\xb6\xd7\x9f");
}
return EL_STR("\xd7\xa8\xd6\xb8\xd7\x90\xd6\xb4\xd7\x99\xd7\xa0\xd7\x95\xd6\xbc");
return 0;
}
el_val_t he_past_le_exol(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xd7\x90\xd6\xb8\xd7\x9b\xd6\xb7\xd7\x9c");
}
if (slot == 1) {
return EL_STR("\xd7\x90\xd6\xb8\xd7\x9b\xd6\xb0\xd7\x9c\xd6\xb8\xd7\x94");
}
if (slot == 2) {
return EL_STR("\xd7\x90\xd6\xb8\xd7\x9b\xd6\xb7\xd7\x9c\xd6\xb0\xd7\xaa\xd6\xb8\xd6\xbc");
}
if (slot == 3) {
return EL_STR("\xd7\x90\xd6\xb8\xd7\x9b\xd6\xb7\xd7\x9c\xd6\xb0\xd7\xaa\xd6\xb0\xd6\xbc");
}
if (slot == 4) {
return EL_STR("\xd7\x90\xd6\xb8\xd7\x9b\xd6\xb7\xd7\x9c\xd6\xb0\xd7\xaa\xd6\xb4\xd6\xbc\xd7\x99");
}
if (slot == 5) {
return EL_STR("\xd7\x90\xd6\xb8\xd7\x9b\xd6\xb0\xd7\x9c\xd7\x95\xd6\xbc");
}
if (slot == 6) {
return EL_STR("\xd7\x90\xd6\xb8\xd7\x9b\xd6\xb0\xd7\x9c\xd7\x95\xd6\xbc");
}
if (slot == 7) {
return EL_STR("\xd7\x90\xd6\xb2\xd7\x9b\xd6\xb7\xd7\x9c\xd6\xb0\xd7\xaa\xd6\xb6\xd6\xbc\xd7\x9d");
}
if (slot == 8) {
return EL_STR("\xd7\x90\xd6\xb2\xd7\x9b\xd6\xb7\xd7\x9c\xd6\xb0\xd7\xaa\xd6\xb6\xd6\xbc\xd7\x9f");
}
return EL_STR("\xd7\x90\xd6\xb8\xd7\x9b\xd6\xb7\xd7\x9c\xd6\xb0\xd7\xa0\xd7\x95\xd6\xbc");
return 0;
}
el_val_t he_past_ledaber(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xd7\x93\xd6\xb4\xd6\xbc\xd7\x91\xd6\xb5\xd6\xbc\xd7\xa8");
}
if (slot == 1) {
return EL_STR("\xd7\x93\xd6\xb4\xd6\xbc\xd7\x91\xd6\xb0\xd6\xbc\xd7\xa8\xd6\xb8\xd7\x94");
}
if (slot == 2) {
return EL_STR("\xd7\x93\xd6\xb4\xd6\xbc\xd7\x91\xd6\xb7\xd6\xbc\xd7\xa8\xd6\xb0\xd7\xaa\xd6\xb8\xd6\xbc");
}
if (slot == 3) {
return EL_STR("\xd7\x93\xd6\xb4\xd6\xbc\xd7\x91\xd6\xb7\xd6\xbc\xd7\xa8\xd6\xb0\xd7\xaa\xd6\xb0\xd6\xbc");
}
if (slot == 4) {
return EL_STR("\xd7\x93\xd6\xb4\xd6\xbc\xd7\x91\xd6\xb7\xd6\xbc\xd7\xa8\xd6\xb0\xd7\xaa\xd6\xb4\xd6\xbc\xd7\x99");
}
if (slot == 5) {
return EL_STR("\xd7\x93\xd6\xb4\xd6\xbc\xd7\x91\xd6\xb0\xd6\xbc\xd7\xa8\xd7\x95\xd6\xbc");
}
if (slot == 6) {
return EL_STR("\xd7\x93\xd6\xb4\xd6\xbc\xd7\x91\xd6\xb0\xd6\xbc\xd7\xa8\xd7\x95\xd6\xbc");
}
if (slot == 7) {
return EL_STR("\xd7\x93\xd6\xb4\xd6\xbc\xd7\x91\xd6\xb7\xd6\xbc\xd7\xa8\xd6\xb0\xd7\xaa\xd6\xb6\xd6\xbc\xd7\x9d");
}
if (slot == 8) {
return EL_STR("\xd7\x93\xd6\xb4\xd6\xbc\xd7\x91\xd6\xb7\xd6\xbc\xd7\xa8\xd6\xb0\xd7\xaa\xd6\xb6\xd6\xbc\xd7\x9f");
}
return EL_STR("\xd7\x93\xd6\xb4\xd6\xbc\xd7\x91\xd6\xb7\xd6\xbc\xd7\xa8\xd6\xb0\xd7\xa0\xd7\x95\xd6\xbc");
return 0;
}
el_val_t he_past_lalechet(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xd7\x94\xd6\xb8\xd7\x9c\xd6\xb7\xd7\x9a\xd6\xb0");
}
if (slot == 1) {
return EL_STR("\xd7\x94\xd6\xb8\xd7\x9c\xd6\xb0\xd7\x9b\xd6\xb8\xd7\x94");
}
if (slot == 2) {
return EL_STR("\xd7\x94\xd6\xb8\xd7\x9c\xd6\xb7\xd7\x9b\xd6\xb0\xd7\xaa\xd6\xb8\xd6\xbc");
}
if (slot == 3) {
return EL_STR("\xd7\x94\xd6\xb8\xd7\x9c\xd6\xb7\xd7\x9b\xd6\xb0\xd7\xaa\xd6\xb0\xd6\xbc");
}
if (slot == 4) {
return EL_STR("\xd7\x94\xd6\xb8\xd7\x9c\xd6\xb7\xd7\x9b\xd6\xb0\xd7\xaa\xd6\xb4\xd6\xbc\xd7\x99");
}
if (slot == 5) {
return EL_STR("\xd7\x94\xd6\xb8\xd7\x9c\xd6\xb0\xd7\x9b\xd7\x95\xd6\xbc");
}
if (slot == 6) {
return EL_STR("\xd7\x94\xd6\xb8\xd7\x9c\xd6\xb0\xd7\x9b\xd7\x95\xd6\xbc");
}
if (slot == 7) {
return EL_STR("\xd7\x94\xd6\xb2\xd7\x9c\xd6\xb7\xd7\x9b\xd6\xb0\xd7\xaa\xd6\xb6\xd6\xbc\xd7\x9d");
}
if (slot == 8) {
return EL_STR("\xd7\x94\xd6\xb2\xd7\x9c\xd6\xb7\xd7\x9b\xd6\xb0\xd7\xaa\xd6\xb6\xd6\xbc\xd7\x9f");
}
return EL_STR("\xd7\x94\xd6\xb8\xd7\x9c\xd6\xb7\xd7\x9b\xd6\xb0\xd7\xa0\xd7\x95\xd6\xbc");
return 0;
}
el_val_t he_future_lir_ot(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xd7\x99\xd6\xb4\xd7\xa8\xd6\xb0\xd7\x90\xd6\xb6\xd7\x94");
}
if (slot == 1) {
return EL_STR("\xd7\xaa\xd6\xb4\xd6\xbc\xd7\xa8\xd6\xb0\xd7\x90\xd6\xb6\xd7\x94");
}
if (slot == 2) {
return EL_STR("\xd7\xaa\xd6\xb4\xd6\xbc\xd7\xa8\xd6\xb0\xd7\x90\xd6\xb6\xd7\x94");
}
if (slot == 3) {
return EL_STR("\xd7\xaa\xd6\xb4\xd6\xbc\xd7\xa8\xd6\xb0\xd7\x90\xd6\xb4\xd7\x99");
}
if (slot == 4) {
return EL_STR("\xd7\x90\xd6\xb6\xd7\xa8\xd6\xb0\xd7\x90\xd6\xb6\xd7\x94");
}
if (slot == 5) {
return EL_STR("\xd7\x99\xd6\xb4\xd7\xa8\xd6\xb0\xd7\x90\xd7\x95\xd6\xbc");
}
if (slot == 6) {
return EL_STR("\xd7\xaa\xd6\xb4\xd6\xbc\xd7\xa8\xd6\xb0\xd7\x90\xd6\xb6\xd7\x99\xd7\xa0\xd6\xb8\xd7\x94");
}
if (slot == 7) {
return EL_STR("\xd7\xaa\xd6\xb4\xd6\xbc\xd7\xa8\xd6\xb0\xd7\x90\xd7\x95\xd6\xbc");
}
if (slot == 8) {
return EL_STR("\xd7\xaa\xd6\xb4\xd6\xbc\xd7\xa8\xd6\xb0\xd7\x90\xd6\xb6\xd7\x99\xd7\xa0\xd6\xb8\xd7\x94");
}
return EL_STR("\xd7\xa0\xd6\xb4\xd7\xa8\xd6\xb0\xd7\x90\xd6\xb6\xd7\x94");
return 0;
}
el_val_t he_future_le_exol(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xd7\x99\xd6\xb9\xd7\x90\xd7\x9b\xd6\xb7\xd7\x9c");
}
if (slot == 1) {
return EL_STR("\xd7\xaa\xd6\xb9\xd6\xbc\xd7\x90\xd7\x9b\xd6\xb7\xd7\x9c");
}
if (slot == 2) {
return EL_STR("\xd7\xaa\xd6\xb9\xd6\xbc\xd7\x90\xd7\x9b\xd6\xb7\xd7\x9c");
}
if (slot == 3) {
return EL_STR("\xd7\xaa\xd6\xb9\xd6\xbc\xd7\x90\xd7\x9b\xd6\xb0\xd7\x9c\xd6\xb4\xd7\x99");
}
if (slot == 4) {
return EL_STR("\xd7\x90\xd6\xb9\xd7\x9b\xd6\xb7\xd7\x9c");
}
if (slot == 5) {
return EL_STR("\xd7\x99\xd6\xb9\xd7\x90\xd7\x9b\xd6\xb0\xd7\x9c\xd7\x95\xd6\xbc");
}
if (slot == 6) {
return EL_STR("\xd7\xaa\xd6\xb9\xd6\xbc\xd7\x90\xd7\x9b\xd6\xb7\xd7\x9c\xd6\xb0\xd7\xa0\xd6\xb8\xd7\x94");
}
if (slot == 7) {
return EL_STR("\xd7\xaa\xd6\xb9\xd6\xbc\xd7\x90\xd7\x9b\xd6\xb0\xd7\x9c\xd7\x95\xd6\xbc");
}
if (slot == 8) {
return EL_STR("\xd7\xaa\xd6\xb9\xd6\xbc\xd7\x90\xd7\x9b\xd6\xb7\xd7\x9c\xd6\xb0\xd7\xa0\xd6\xb8\xd7\x94");
}
return EL_STR("\xd7\xa0\xd6\xb9\xd7\x90\xd7\x9b\xd6\xb7\xd7\x9c");
return 0;
}
el_val_t he_future_ledaber(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xd7\x99\xd6\xb0\xd7\x93\xd6\xb7\xd7\x91\xd6\xb5\xd6\xbc\xd7\xa8");
}
if (slot == 1) {
return EL_STR("\xd7\xaa\xd6\xb0\xd6\xbc\xd7\x93\xd6\xb7\xd7\x91\xd6\xb5\xd6\xbc\xd7\xa8");
}
if (slot == 2) {
return EL_STR("\xd7\xaa\xd6\xb0\xd6\xbc\xd7\x93\xd6\xb7\xd7\x91\xd6\xb5\xd6\xbc\xd7\xa8");
}
if (slot == 3) {
return EL_STR("\xd7\xaa\xd6\xb0\xd6\xbc\xd7\x93\xd6\xb7\xd7\x91\xd6\xb0\xd6\xbc\xd7\xa8\xd6\xb4\xd7\x99");
}
if (slot == 4) {
return EL_STR("\xd7\x90\xd6\xb2\xd7\x93\xd6\xb7\xd7\x91\xd6\xb5\xd6\xbc\xd7\xa8");
}
if (slot == 5) {
return EL_STR("\xd7\x99\xd6\xb0\xd7\x93\xd6\xb7\xd7\x91\xd6\xb0\xd6\xbc\xd7\xa8\xd7\x95\xd6\xbc");
}
if (slot == 6) {
return EL_STR("\xd7\xaa\xd6\xb0\xd6\xbc\xd7\x93\xd6\xb7\xd7\x91\xd6\xb5\xd6\xbc\xd7\xa8\xd6\xb0\xd7\xa0\xd6\xb8\xd7\x94");
}
if (slot == 7) {
return EL_STR("\xd7\xaa\xd6\xb0\xd6\xbc\xd7\x93\xd6\xb7\xd7\x91\xd6\xb0\xd6\xbc\xd7\xa8\xd7\x95\xd6\xbc");
}
if (slot == 8) {
return EL_STR("\xd7\xaa\xd6\xb0\xd6\xbc\xd7\x93\xd6\xb7\xd7\x91\xd6\xb5\xd6\xbc\xd7\xa8\xd6\xb0\xd7\xa0\xd6\xb8\xd7\x94");
}
return EL_STR("\xd7\xa0\xd6\xb0\xd7\x93\xd6\xb7\xd7\x91\xd6\xb5\xd6\xbc\xd7\xa8");
return 0;
}
el_val_t he_future_lalechet(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xd7\x99\xd6\xb5\xd7\x9c\xd6\xb5\xd7\x9a\xd6\xb0");
}
if (slot == 1) {
return EL_STR("\xd7\xaa\xd6\xb5\xd6\xbc\xd7\x9c\xd6\xb5\xd7\x9a\xd6\xb0");
}
if (slot == 2) {
return EL_STR("\xd7\xaa\xd6\xb5\xd6\xbc\xd7\x9c\xd6\xb5\xd7\x9a\xd6\xb0");
}
if (slot == 3) {
return EL_STR("\xd7\xaa\xd6\xb5\xd6\xbc\xd7\x9c\xd6\xb0\xd7\x9b\xd6\xb4\xd7\x99");
}
if (slot == 4) {
return EL_STR("\xd7\x90\xd6\xb5\xd7\x9c\xd6\xb5\xd7\x9a\xd6\xb0");
}
if (slot == 5) {
return EL_STR("\xd7\x99\xd6\xb5\xd7\x9c\xd6\xb0\xd7\x9b\xd7\x95\xd6\xbc");
}
if (slot == 6) {
return EL_STR("\xd7\xaa\xd6\xb5\xd6\xbc\xd7\x9c\xd6\xb7\xd7\x9b\xd6\xb0\xd7\xa0\xd6\xb8\xd7\x94");
}
if (slot == 7) {
return EL_STR("\xd7\xaa\xd6\xb5\xd6\xbc\xd7\x9c\xd6\xb0\xd7\x9b\xd7\x95\xd6\xbc");
}
if (slot == 8) {
return EL_STR("\xd7\xaa\xd6\xb5\xd6\xbc\xd7\x9c\xd6\xb7\xd7\x9b\xd6\xb0\xd7\xa0\xd6\xb8\xd7\x94");
}
return EL_STR("\xd7\xa0\xd6\xb5\xd7\x9c\xd6\xb5\xd7\x9a\xd6\xb0");
return 0;
}
el_val_t he_known_verb(el_val_t verb, el_val_t tense, el_val_t slot) {
if (str_eq(verb, EL_STR("lir'ot"))) {
if (str_eq(tense, EL_STR("present"))) {
return he_present_lir_ot(he_present_form_code(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return he_past_lir_ot(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return he_future_lir_ot(slot);
}
return he_present_lir_ot(he_present_form_code(slot));
}
if (str_eq(verb, EL_STR("\xd7\x9c\xd6\xb4\xd7\xa8\xd6\xb0\xd7\x90\xd7\x95\xd6\xb9\xd7\xaa"))) {
if (str_eq(tense, EL_STR("present"))) {
return he_present_lir_ot(he_present_form_code(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return he_past_lir_ot(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return he_future_lir_ot(slot);
}
return he_present_lir_ot(he_present_form_code(slot));
}
if (str_eq(verb, EL_STR("le'exol"))) {
if (str_eq(tense, EL_STR("present"))) {
return he_present_le_exol(he_present_form_code(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return he_past_le_exol(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return he_future_le_exol(slot);
}
return he_present_le_exol(he_present_form_code(slot));
}
if (str_eq(verb, EL_STR("\xd7\x9c\xd6\xb6\xd7\x90\xd6\xb1\xd7\x9b\xd7\x95\xd6\xb9\xd7\x9c"))) {
if (str_eq(tense, EL_STR("present"))) {
return he_present_le_exol(he_present_form_code(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return he_past_le_exol(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return he_future_le_exol(slot);
}
return he_present_le_exol(he_present_form_code(slot));
}
if (str_eq(verb, EL_STR("ledaber"))) {
if (str_eq(tense, EL_STR("present"))) {
return he_present_ledaber(he_present_form_code(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return he_past_ledaber(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return he_future_ledaber(slot);
}
return he_present_ledaber(he_present_form_code(slot));
}
if (str_eq(verb, EL_STR("\xd7\x9c\xd6\xb0\xd7\x93\xd6\xb7\xd7\x91\xd6\xb5\xd6\xbc\xd7\xa8"))) {
if (str_eq(tense, EL_STR("present"))) {
return he_present_ledaber(he_present_form_code(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return he_past_ledaber(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return he_future_ledaber(slot);
}
return he_present_ledaber(he_present_form_code(slot));
}
if (str_eq(verb, EL_STR("lalechet"))) {
if (str_eq(tense, EL_STR("present"))) {
return he_present_lalechet(he_present_form_code(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return he_past_lalechet(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return he_future_lalechet(slot);
}
return he_present_lalechet(he_present_form_code(slot));
}
if (str_eq(verb, EL_STR("\xd7\x9c\xd6\xb8\xd7\x9c\xd6\xb6\xd7\x9b\xd6\xb6\xd7\xaa"))) {
if (str_eq(tense, EL_STR("present"))) {
return he_present_lalechet(he_present_form_code(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return he_past_lalechet(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return he_future_lalechet(slot);
}
return he_present_lalechet(he_present_form_code(slot));
}
return EL_STR("");
return 0;
}
el_val_t he_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t gender, el_val_t number) {
el_val_t slot = he_slot(person, gender, number);
if (he_is_copula(verb)) {
return he_conjugate_copula(tense, slot);
}
el_val_t known = he_known_verb(verb, tense, slot);
if (!str_eq(known, EL_STR(""))) {
return known;
}
return verb;
return 0;
}
el_val_t he_pluralize(el_val_t noun, el_val_t gender) {
if (str_eq(gender, EL_STR("m"))) {
return el_str_concat(noun, EL_STR("\xd7\x99\xd7\x9d"));
}
if (he_str_ends(noun, EL_STR("\xd7\x94"))) {
el_val_t stem = he_str_drop_last(noun, 1);
return el_str_concat(stem, EL_STR("\xd7\x95\xd7\xaa"));
}
if (he_str_ends(noun, EL_STR("\xd7\xaa"))) {
el_val_t stem = he_str_drop_last(noun, 1);
return el_str_concat(stem, EL_STR("\xd7\x95\xd7\xaa"));
}
if (he_str_ends(noun, EL_STR("a"))) {
el_val_t stem = he_str_drop_last(noun, 1);
return el_str_concat(stem, EL_STR("ot"));
}
if (he_str_ends(noun, EL_STR("et"))) {
el_val_t stem = he_str_drop_last(noun, 2);
return el_str_concat(stem, EL_STR("ot"));
}
return el_str_concat(noun, EL_STR("\xd7\x95\xd7\xaa"));
return 0;
}
el_val_t he_is_hebrew_script(el_val_t noun) {
el_val_t n = str_len(noun);
if (n == 0) {
return 0;
}
el_val_t first = str_slice(noun, 0, 1);
if (str_eq(first, EL_STR("\xd7\x90"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\x91"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\x92"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\x93"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\x94"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\x95"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\x96"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\x97"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\x98"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\x99"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\x9b"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\x9c"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\x9e"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\xa0"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\xa1"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\xa2"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\xa4"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\xa6"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\xa7"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\xa8"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\xa9"))) {
return 1;
}
if (str_eq(first, EL_STR("\xd7\xaa"))) {
return 1;
}
return 0;
return 0;
}
el_val_t he_definite_prefix(el_val_t noun) {
if (he_is_hebrew_script(noun)) {
return el_str_concat(EL_STR("\xd7\x94"), noun);
}
return el_str_concat(EL_STR("ha"), noun);
return 0;
}
el_val_t he_noun_phrase(el_val_t noun, el_val_t number, el_val_t gender, el_val_t definite) {
el_val_t stem = noun;
if (str_eq(number, EL_STR("plural"))) {
stem = he_pluralize(noun, gender);
}
if (str_eq(definite, EL_STR("true"))) {
return he_definite_prefix(stem);
}
return stem;
return 0;
}
el_val_t he_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("lihyot");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("lir'ot");
}
if (str_eq(verb, EL_STR("eat"))) {
return EL_STR("le'exol");
}
if (str_eq(verb, EL_STR("speak"))) {
return EL_STR("ledaber");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("ledaber");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("lalechet");
}
return verb;
return 0;
}
Generated Vendored
+30
View File
@@ -0,0 +1,30 @@
// auto-generated by elc --emit-header — do not edit
extern fn he_str_ends(s: String, suf: String) -> Bool
extern fn he_str_len(s: String) -> Int
extern fn he_str_drop_last(s: String, n: Int) -> String
extern fn he_str_last_char(s: String) -> String
extern fn he_slot(person: String, gender: String, number: String) -> Int
extern fn he_present_form_code(slot: Int) -> Int
extern fn he_copula_past(slot: Int) -> String
extern fn he_copula_future(slot: Int) -> String
extern fn he_is_copula(verb: String) -> Bool
extern fn he_conjugate_copula(tense: String, slot: Int) -> String
extern fn he_present_lir_ot(form: Int) -> String
extern fn he_present_le_exol(form: Int) -> String
extern fn he_present_ledaber(form: Int) -> String
extern fn he_present_lalechet(form: Int) -> String
extern fn he_past_lir_ot(slot: Int) -> String
extern fn he_past_le_exol(slot: Int) -> String
extern fn he_past_ledaber(slot: Int) -> String
extern fn he_past_lalechet(slot: Int) -> String
extern fn he_future_lir_ot(slot: Int) -> String
extern fn he_future_le_exol(slot: Int) -> String
extern fn he_future_ledaber(slot: Int) -> String
extern fn he_future_lalechet(slot: Int) -> String
extern fn he_known_verb(verb: String, tense: String, slot: Int) -> String
extern fn he_conjugate(verb: String, tense: String, person: String, gender: String, number: String) -> String
extern fn he_pluralize(noun: String, gender: String) -> String
extern fn he_is_hebrew_script(noun: String) -> Bool
extern fn he_definite_prefix(noun: String) -> String
extern fn he_noun_phrase(noun: String, number: String, gender: String, definite: String) -> String
extern fn he_map_canonical(verb: String) -> String
Generated Vendored
+748
View File
@@ -0,0 +1,748 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t hi_str_ends(el_val_t s, el_val_t suf);
el_val_t hi_str_drop_last(el_val_t s, el_val_t n);
el_val_t hi_str_last_char(el_val_t s);
el_val_t hi_gender(el_val_t noun);
el_val_t hi_masc_aa_stem(el_val_t noun);
el_val_t hi_noun_direct_m(el_val_t noun, el_val_t number);
el_val_t hi_noun_oblique_m(el_val_t noun, el_val_t number);
el_val_t hi_noun_direct_f(el_val_t noun, el_val_t number);
el_val_t hi_noun_oblique_f(el_val_t noun, el_val_t number);
el_val_t hi_noun_direct(el_val_t noun, el_val_t gender, el_val_t number);
el_val_t hi_noun_oblique(el_val_t noun, el_val_t gender, el_val_t number);
el_val_t hi_postposition(el_val_t gram_case);
el_val_t hi_agree_genitive(el_val_t possessed_gender, el_val_t possessed_number);
el_val_t hi_verb_stem(el_val_t infinitive);
el_val_t hi_verb_stem_clean(el_val_t infinitive);
el_val_t hi_present_aspect(el_val_t gender, el_val_t number);
el_val_t hi_aux_present(el_val_t person, el_val_t number);
el_val_t hi_past_suffix(el_val_t gender, el_val_t number);
el_val_t hi_past_irregular(el_val_t stem, el_val_t gender, el_val_t number);
el_val_t hi_future_suffix(el_val_t person, el_val_t number, el_val_t gender);
el_val_t hi_tense_suffix(el_val_t tense, el_val_t gender, el_val_t number);
el_val_t hi_hona_present(el_val_t person, el_val_t number);
el_val_t hi_hona_past(el_val_t gender, el_val_t number);
el_val_t hi_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t gender, el_val_t number);
el_val_t hi_noun_with_post(el_val_t noun, el_val_t gender, el_val_t number, el_val_t gram_case);
el_val_t hi_genitive_phrase(el_val_t possessor, el_val_t possessor_gender, el_val_t possessor_number, el_val_t possessed, el_val_t possessed_gender, el_val_t possessed_number);
el_val_t hi_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t hi_str_drop_last(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t hi_str_last_char(el_val_t s) {
el_val_t n = str_len(s);
if (n == 0) {
return EL_STR("");
}
return str_slice(s, (n - 1), n);
return 0;
}
el_val_t hi_gender(el_val_t noun) {
if (hi_str_ends(noun, EL_STR("\xe0\xa5\x80"))) {
return EL_STR("f");
}
if (hi_str_ends(noun, EL_STR("\xe0\xa4\xbe"))) {
return EL_STR("m");
}
if (hi_str_ends(noun, EL_STR("\xe0\xa4\xa8"))) {
return EL_STR("f");
}
if (hi_str_ends(noun, EL_STR("\xe0\xa4\xa4"))) {
return EL_STR("f");
}
if (hi_str_ends(noun, EL_STR("\xe0\xa4\x9f"))) {
return EL_STR("f");
}
if (hi_str_ends(noun, EL_STR("\xe0\xa4\xb6"))) {
return EL_STR("m");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xb2\xe0\xa4\xa1\xe0\xa4\xbc\xe0\xa4\x95\xe0\xa4\xbe"))) {
return EL_STR("m");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xb2\xe0\xa4\xa1\xe0\xa4\xbc\xe0\xa4\x95\xe0\xa5\x80"))) {
return EL_STR("f");
}
if (str_eq(noun, EL_STR("\xe0\xa4\x86\xe0\xa4\xa6\xe0\xa4\xae\xe0\xa5\x80"))) {
return EL_STR("m");
}
if (str_eq(noun, EL_STR("\xe0\xa4\x94\xe0\xa4\xb0\xe0\xa4\xa4"))) {
return EL_STR("f");
}
if (str_eq(noun, EL_STR("\xe0\xa4\x98\xe0\xa4\xb0"))) {
return EL_STR("m");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xae\xe0\xa5\x87\xe0\xa4\x9c\xe0\xa4\xbc"))) {
return EL_STR("f");
}
if (str_eq(noun, EL_STR("\xe0\xa4\x95\xe0\xa4\xbf\xe0\xa4\xa4\xe0\xa4\xbe\xe0\xa4\xac"))) {
return EL_STR("f");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xaa\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa5\x80"))) {
return EL_STR("m");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xa6\xe0\xa5\x82\xe0\xa4\xa7"))) {
return EL_STR("m");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xb9\xe0\xa4\xbe\xe0\xa4\xa5"))) {
return EL_STR("m");
}
if (str_eq(noun, EL_STR("\xe0\xa4\x86\xe0\xa4\x81\xe0\xa4\x96"))) {
return EL_STR("f");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xac\xe0\xa4\x9a\xe0\xa5\x8d\xe0\xa4\x9a\xe0\xa4\xbe"))) {
return EL_STR("m");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xac\xe0\xa4\x9a\xe0\xa5\x8d\xe0\xa4\x9a\xe0\xa5\x80"))) {
return EL_STR("f");
}
if (str_eq(noun, EL_STR("\xe0\xa4\x95\xe0\xa4\xbe\xe0\xa4\xae"))) {
return EL_STR("m");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xac\xe0\xa4\xbe\xe0\xa4\xa4"))) {
return EL_STR("f");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xa6\xe0\xa4\xbf\xe0\xa4\xa8"))) {
return EL_STR("m");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xb0\xe0\xa4\xbe\xe0\xa4\xa4"))) {
return EL_STR("f");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xa6\xe0\xa5\x87\xe0\xa4\xb6"))) {
return EL_STR("m");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xad\xe0\xa4\xbe\xe0\xa4\xb7\xe0\xa4\xbe"))) {
return EL_STR("f");
}
if (str_eq(noun, EL_STR("\xe0\xa4\x9c\xe0\xa4\x97\xe0\xa4\xb9"))) {
return EL_STR("f");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xb8\xe0\xa4\xae\xe0\xa4\xaf"))) {
return EL_STR("m");
}
if (str_eq(noun, EL_STR("\xe0\xa4\xb8\xe0\xa4\xbe\xe0\xa4\xb2"))) {
return EL_STR("m");
}
return EL_STR("m");
return 0;
}
el_val_t hi_masc_aa_stem(el_val_t noun) {
return hi_str_drop_last(noun, 1);
return 0;
}
el_val_t hi_noun_direct_m(el_val_t noun, el_val_t number) {
if (hi_str_ends(noun, EL_STR("\xe0\xa4\xbe"))) {
if (str_eq(number, EL_STR("sg"))) {
return noun;
}
return el_str_concat(hi_masc_aa_stem(noun), EL_STR("\xe0\xa5\x87"));
}
return noun;
return 0;
}
el_val_t hi_noun_oblique_m(el_val_t noun, el_val_t number) {
if (hi_str_ends(noun, EL_STR("\xe0\xa4\xbe"))) {
el_val_t stem = hi_masc_aa_stem(noun);
if (str_eq(number, EL_STR("sg"))) {
return el_str_concat(stem, EL_STR("\xe0\xa5\x87"));
}
return el_str_concat(stem, EL_STR("\xe0\xa5\x8b\xe0\xa4\x82"));
}
if (hi_str_ends(noun, EL_STR("\xe0\xa5\x80"))) {
if (str_eq(number, EL_STR("sg"))) {
return noun;
}
el_val_t stem = hi_str_drop_last(noun, 1);
return el_str_concat(stem, EL_STR("\xe0\xa4\xbf\xe0\xa4\xaf\xe0\xa5\x8b\xe0\xa4\x82"));
}
if (str_eq(number, EL_STR("sg"))) {
return noun;
}
return el_str_concat(noun, EL_STR("\xe0\xa5\x8b\xe0\xa4\x82"));
return 0;
}
el_val_t hi_noun_direct_f(el_val_t noun, el_val_t number) {
if (hi_str_ends(noun, EL_STR("\xe0\xa5\x80"))) {
if (str_eq(number, EL_STR("sg"))) {
return noun;
}
el_val_t stem = hi_str_drop_last(noun, 1);
return el_str_concat(stem, EL_STR("\xe0\xa4\xbf\xe0\xa4\xaf\xe0\xa4\xbe\xe0\xa4\x81"));
}
if (str_eq(number, EL_STR("sg"))) {
return noun;
}
return el_str_concat(noun, EL_STR("\xe0\xa5\x87\xe0\xa4\x82"));
return 0;
}
el_val_t hi_noun_oblique_f(el_val_t noun, el_val_t number) {
if (hi_str_ends(noun, EL_STR("\xe0\xa5\x80"))) {
if (str_eq(number, EL_STR("sg"))) {
return noun;
}
el_val_t stem = hi_str_drop_last(noun, 1);
return el_str_concat(stem, EL_STR("\xe0\xa4\xbf\xe0\xa4\xaf\xe0\xa5\x8b\xe0\xa4\x82"));
}
if (str_eq(number, EL_STR("sg"))) {
return noun;
}
return el_str_concat(noun, EL_STR("\xe0\xa5\x8b\xe0\xa4\x82"));
return 0;
}
el_val_t hi_noun_direct(el_val_t noun, el_val_t gender, el_val_t number) {
if (str_eq(gender, EL_STR("m"))) {
return hi_noun_direct_m(noun, number);
}
if (str_eq(gender, EL_STR("f"))) {
return hi_noun_direct_f(noun, number);
}
return noun;
return 0;
}
el_val_t hi_noun_oblique(el_val_t noun, el_val_t gender, el_val_t number) {
if (str_eq(gender, EL_STR("m"))) {
return hi_noun_oblique_m(noun, number);
}
if (str_eq(gender, EL_STR("f"))) {
return hi_noun_oblique_f(noun, number);
}
return noun;
return 0;
}
el_val_t hi_postposition(el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("");
}
if (str_eq(gram_case, EL_STR("accusative_animate"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa5\x8b");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa5\x8b");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa4\xbe");
}
if (str_eq(gram_case, EL_STR("locative_in"))) {
return EL_STR("\xe0\xa4\xae\xe0\xa5\x87\xe0\xa4\x82");
}
if (str_eq(gram_case, EL_STR("locative_on"))) {
return EL_STR("\xe0\xa4\xaa\xe0\xa4\xb0");
}
if (str_eq(gram_case, EL_STR("instrumental"))) {
return EL_STR("\xe0\xa4\xb8\xe0\xa5\x87");
}
if (str_eq(gram_case, EL_STR("ablative"))) {
return EL_STR("\xe0\xa4\xb8\xe0\xa5\x87");
}
if (str_eq(gram_case, EL_STR("comitative"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa5\x87 \xe0\xa4\xb8\xe0\xa4\xbe\xe0\xa4\xa5");
}
if (str_eq(gram_case, EL_STR("benefactive"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa5\x87 \xe0\xa4\xb2\xe0\xa4\xbf\xe0\xa4\x8f");
}
return EL_STR("");
return 0;
}
el_val_t hi_agree_genitive(el_val_t possessed_gender, el_val_t possessed_number) {
if (str_eq(possessed_gender, EL_STR("f"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa5\x80");
}
if (str_eq(possessed_number, EL_STR("pl"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa5\x87");
}
return EL_STR("\xe0\xa4\x95\xe0\xa4\xbe");
return 0;
}
el_val_t hi_verb_stem(el_val_t infinitive) {
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb9\xe0\xa5\x8b\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb9\xe0\xa5\x8b");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x95\xe0\xa4\xb0\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa4\xb0");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x9c\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x9c\xe0\xa4\xbe");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x86\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x86");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xa6\xe0\xa5\x87\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xa6\xe0\xa5\x87");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb2\xe0\xa5\x87\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb2\xe0\xa5\x87");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xa6\xe0\xa5\x87\xe0\xa4\x96\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xa6\xe0\xa5\x87\xe0\xa4\x96");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x95\xe0\xa4\xb9\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa4\xb9");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x9c\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x9c\xe0\xa4\xbe\xe0\xa4\xa8");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x9a\xe0\xa4\xbe\xe0\xa4\xb9\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x9a\xe0\xa4\xbe\xe0\xa4\xb9");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x96\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x96\xe0\xa4\xbe");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xaa\xe0\xa5\x80\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xaa\xe0\xa5\x80");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb8\xe0\xa5\x8b\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb8\xe0\xa5\x8b");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb2\xe0\xa4\xbf\xe0\xa4\x96\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb2\xe0\xa4\xbf\xe0\xa4\x96");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xaa\xe0\xa4\xa2\xe0\xa4\xbc\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xaa\xe0\xa4\xa2\xe0\xa4\xbc");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xac\xe0\xa5\x8b\xe0\xa4\xb2\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xac\xe0\xa5\x8b\xe0\xa4\xb2");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x9a\xe0\xa4\xb2\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x9a\xe0\xa4\xb2");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xac\xe0\xa5\x88\xe0\xa4\xa0\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xac\xe0\xa5\x88\xe0\xa4\xa0");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x89\xe0\xa4\xa0\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x89\xe0\xa4\xa0");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xae\xe0\xa4\xbf\xe0\xa4\xb2\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xae\xe0\xa4\xbf\xe0\xa4\xb2");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb0\xe0\xa4\xb9\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb0\xe0\xa4\xb9");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb8\xe0\xa5\x81\xe0\xa4\xa8\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb8\xe0\xa5\x81\xe0\xa4\xa8");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb8\xe0\xa4\xae\xe0\xa4\x9d\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb8\xe0\xa4\xae\xe0\xa4\x9d");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xae\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xae\xe0\xa4\xbe\xe0\xa4\xa8");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xac\xe0\xa4\xa8\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xac\xe0\xa4\xa8\xe0\xa4\xbe");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb2\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb2\xe0\xa4\xbe");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xad\xe0\xa5\x87\xe0\xa4\x9c\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xad\xe0\xa5\x87\xe0\xa4\x9c");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x96\xe0\xa5\x8b\xe0\xa4\xb2\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x96\xe0\xa5\x8b\xe0\xa4\xb2");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xac\xe0\xa4\x82\xe0\xa4\xa6 \xe0\xa4\x95\xe0\xa4\xb0\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xac\xe0\xa4\x82\xe0\xa4\xa6 \xe0\xa4\x95\xe0\xa4\xb0");
}
if (hi_str_ends(infinitive, EL_STR("\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return hi_str_drop_last(infinitive, 1);
}
return infinitive;
return 0;
}
el_val_t hi_verb_stem_clean(el_val_t infinitive) {
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb9\xe0\xa5\x8b\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb9\xe0\xa5\x8b");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x95\xe0\xa4\xb0\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa4\xb0");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x9c\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x9c\xe0\xa4\xbe");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x86\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x86");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xa6\xe0\xa5\x87\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xa6\xe0\xa5\x87");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb2\xe0\xa5\x87\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb2\xe0\xa5\x87");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xa6\xe0\xa5\x87\xe0\xa4\x96\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xa6\xe0\xa5\x87\xe0\xa4\x96");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x95\xe0\xa4\xb9\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa4\xb9");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x9c\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x9c\xe0\xa4\xbe\xe0\xa4\xa8");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x9a\xe0\xa4\xbe\xe0\xa4\xb9\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x9a\xe0\xa4\xbe\xe0\xa4\xb9");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x96\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x96\xe0\xa4\xbe");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xaa\xe0\xa5\x80\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xaa\xe0\xa5\x80");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb8\xe0\xa5\x8b\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb8\xe0\xa5\x8b");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb2\xe0\xa4\xbf\xe0\xa4\x96\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb2\xe0\xa4\xbf\xe0\xa4\x96");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xaa\xe0\xa4\xa2\xe0\xa4\xbc\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xaa\xe0\xa4\xa2\xe0\xa4\xbc");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xac\xe0\xa5\x8b\xe0\xa4\xb2\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xac\xe0\xa5\x8b\xe0\xa4\xb2");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x9a\xe0\xa4\xb2\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x9a\xe0\xa4\xb2");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xac\xe0\xa5\x88\xe0\xa4\xa0\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xac\xe0\xa5\x88\xe0\xa4\xa0");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x89\xe0\xa4\xa0\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x89\xe0\xa4\xa0");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xae\xe0\xa4\xbf\xe0\xa4\xb2\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xae\xe0\xa4\xbf\xe0\xa4\xb2");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb0\xe0\xa4\xb9\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb0\xe0\xa4\xb9");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb8\xe0\xa5\x81\xe0\xa4\xa8\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb8\xe0\xa5\x81\xe0\xa4\xa8");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb8\xe0\xa4\xae\xe0\xa4\x9d\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb8\xe0\xa4\xae\xe0\xa4\x9d");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xae\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xae\xe0\xa4\xbe\xe0\xa4\xa8");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xac\xe0\xa4\xa8\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xac\xe0\xa4\xa8\xe0\xa4\xbe");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xb2\xe0\xa4\xbe\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xb2\xe0\xa4\xbe");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\xad\xe0\xa5\x87\xe0\xa4\x9c\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\xad\xe0\xa5\x87\xe0\xa4\x9c");
}
if (str_eq(infinitive, EL_STR("\xe0\xa4\x96\xe0\xa5\x8b\xe0\xa4\xb2\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return EL_STR("\xe0\xa4\x96\xe0\xa5\x8b\xe0\xa4\xb2");
}
if (hi_str_ends(infinitive, EL_STR("\xe0\xa4\xa8\xe0\xa4\xbe"))) {
return hi_str_drop_last(infinitive, 2);
}
return infinitive;
return 0;
}
el_val_t hi_present_aspect(el_val_t gender, el_val_t number) {
if (str_eq(gender, EL_STR("f"))) {
return EL_STR("\xe0\xa4\xa4\xe0\xa5\x80");
}
if (str_eq(number, EL_STR("pl"))) {
return EL_STR("\xe0\xa4\xa4\xe0\xa5\x87");
}
return EL_STR("\xe0\xa4\xa4\xe0\xa4\xbe");
return 0;
}
el_val_t hi_aux_present(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("1"))) {
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xb9\xe0\xa5\x82\xe0\xa4\x81");
}
return EL_STR("\xe0\xa4\xb9\xe0\xa5\x88\xe0\xa4\x82");
}
if (str_eq(person, EL_STR("2"))) {
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xb9\xe0\xa5\x8b");
}
return EL_STR("\xe0\xa4\xb9\xe0\xa5\x8b");
}
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xb9\xe0\xa5\x88");
}
return EL_STR("\xe0\xa4\xb9\xe0\xa5\x88\xe0\xa4\x82");
return 0;
}
el_val_t hi_past_suffix(el_val_t gender, el_val_t number) {
if (str_eq(gender, EL_STR("m"))) {
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\x86");
}
return EL_STR("\xe0\xa4\x8f");
}
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\x88");
}
return EL_STR("\xe0\xa4\x88\xe0\xa4\x82");
return 0;
}
el_val_t hi_past_irregular(el_val_t stem, el_val_t gender, el_val_t number) {
if (str_eq(stem, EL_STR("\xe0\xa4\xb9\xe0\xa5\x8b"))) {
if (str_eq(gender, EL_STR("m"))) {
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xa5\xe0\xa4\xbe");
}
return EL_STR("\xe0\xa4\xa5\xe0\xa5\x87");
}
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xa5\xe0\xa5\x80");
}
return EL_STR("\xe0\xa4\xa5\xe0\xa5\x80\xe0\xa4\x82");
}
if (str_eq(stem, EL_STR("\xe0\xa4\x9c\xe0\xa4\xbe"))) {
if (str_eq(gender, EL_STR("m"))) {
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\x97\xe0\xa4\xaf\xe0\xa4\xbe");
}
return EL_STR("\xe0\xa4\x97\xe0\xa4\x8f");
}
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\x97\xe0\xa4\x88");
}
return EL_STR("\xe0\xa4\x97\xe0\xa4\x88\xe0\xa4\x82");
}
if (str_eq(stem, EL_STR("\xe0\xa4\x95\xe0\xa4\xb0"))) {
if (str_eq(gender, EL_STR("m"))) {
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa4\xbf\xe0\xa4\xaf\xe0\xa4\xbe");
}
return EL_STR("\xe0\xa4\x95\xe0\xa4\xbf\xe0\xa4\x8f");
}
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\x95\xe0\xa5\x80");
}
return EL_STR("\xe0\xa4\x95\xe0\xa5\x80\xe0\xa4\x82");
}
if (str_eq(stem, EL_STR("\xe0\xa4\xa6\xe0\xa5\x87"))) {
if (str_eq(gender, EL_STR("m"))) {
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xa6\xe0\xa4\xbf\xe0\xa4\xaf\xe0\xa4\xbe");
}
return EL_STR("\xe0\xa4\xa6\xe0\xa4\xbf\xe0\xa4\x8f");
}
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xa6\xe0\xa5\x80");
}
return EL_STR("\xe0\xa4\xa6\xe0\xa5\x80\xe0\xa4\x82");
}
if (str_eq(stem, EL_STR("\xe0\xa4\xb2\xe0\xa5\x87"))) {
if (str_eq(gender, EL_STR("m"))) {
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xb2\xe0\xa4\xbf\xe0\xa4\xaf\xe0\xa4\xbe");
}
return EL_STR("\xe0\xa4\xb2\xe0\xa4\xbf\xe0\xa4\x8f");
}
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xb2\xe0\xa5\x80");
}
return EL_STR("\xe0\xa4\xb2\xe0\xa5\x80\xe0\xa4\x82");
}
if (str_eq(stem, EL_STR("\xe0\xa4\x86"))) {
if (str_eq(gender, EL_STR("m"))) {
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\x86\xe0\xa4\xaf\xe0\xa4\xbe");
}
return EL_STR("\xe0\xa4\x86\xe0\xa4\x8f");
}
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\x86\xe0\xa4\x88");
}
return EL_STR("\xe0\xa4\x86\xe0\xa4\x88\xe0\xa4\x82");
}
if (str_eq(stem, EL_STR("\xe0\xa4\x96\xe0\xa4\xbe"))) {
if (str_eq(gender, EL_STR("m"))) {
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\x96\xe0\xa4\xbe\xe0\xa4\xaf\xe0\xa4\xbe");
}
return EL_STR("\xe0\xa4\x96\xe0\xa4\xbe\xe0\xa4\x8f");
}
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\x96\xe0\xa4\xbe\xe0\xa4\x88");
}
return EL_STR("\xe0\xa4\x96\xe0\xa4\xbe\xe0\xa4\x88\xe0\xa4\x82");
}
if (str_eq(stem, EL_STR("\xe0\xa4\xaa\xe0\xa5\x80"))) {
if (str_eq(gender, EL_STR("m"))) {
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xaa\xe0\xa4\xbf\xe0\xa4\xaf\xe0\xa4\xbe");
}
return EL_STR("\xe0\xa4\xaa\xe0\xa4\xbf\xe0\xa4\x8f");
}
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xaa\xe0\xa5\x80");
}
return EL_STR("\xe0\xa4\xaa\xe0\xa5\x80\xe0\xa4\x82");
}
return EL_STR("");
return 0;
}
el_val_t hi_future_suffix(el_val_t person, el_val_t number, el_val_t gender) {
if (str_eq(person, EL_STR("1"))) {
if (str_eq(number, EL_STR("sg"))) {
if (str_eq(gender, EL_STR("f"))) {
return EL_STR("\xe0\xa4\x8a\xe0\xa4\x81\xe0\xa4\x97\xe0\xa5\x80");
}
return EL_STR("\xe0\xa4\x8a\xe0\xa4\x81\xe0\xa4\x97\xe0\xa4\xbe");
}
if (str_eq(gender, EL_STR("f"))) {
return EL_STR("\xe0\xa4\x8f\xe0\xa4\x82\xe0\xa4\x97\xe0\xa5\x80");
}
return EL_STR("\xe0\xa4\x8f\xe0\xa4\x82\xe0\xa4\x97\xe0\xa5\x87");
}
if (str_eq(person, EL_STR("2"))) {
if (str_eq(gender, EL_STR("f"))) {
return EL_STR("\xe0\xa4\x93\xe0\xa4\x97\xe0\xa5\x80");
}
return EL_STR("\xe0\xa4\x93\xe0\xa4\x97\xe0\xa5\x87");
}
if (str_eq(number, EL_STR("sg"))) {
if (str_eq(gender, EL_STR("f"))) {
return EL_STR("\xe0\xa4\x8f\xe0\xa4\x97\xe0\xa5\x80");
}
return EL_STR("\xe0\xa4\x8f\xe0\xa4\x97\xe0\xa4\xbe");
}
if (str_eq(gender, EL_STR("f"))) {
return EL_STR("\xe0\xa4\x8f\xe0\xa4\x82\xe0\xa4\x97\xe0\xa5\x80");
}
return EL_STR("\xe0\xa4\x8f\xe0\xa4\x82\xe0\xa4\x97\xe0\xa5\x87");
return 0;
}
el_val_t hi_tense_suffix(el_val_t tense, el_val_t gender, el_val_t number) {
if (str_eq(tense, EL_STR("present"))) {
return hi_present_aspect(gender, number);
}
if (str_eq(tense, EL_STR("past"))) {
return hi_past_suffix(gender, number);
}
return EL_STR("");
return 0;
}
el_val_t hi_hona_present(el_val_t person, el_val_t number) {
return hi_aux_present(person, number);
return 0;
}
el_val_t hi_hona_past(el_val_t gender, el_val_t number) {
if (str_eq(gender, EL_STR("m"))) {
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xa5\xe0\xa4\xbe");
}
return EL_STR("\xe0\xa4\xa5\xe0\xa5\x87");
}
if (str_eq(number, EL_STR("sg"))) {
return EL_STR("\xe0\xa4\xa5\xe0\xa5\x80");
}
return EL_STR("\xe0\xa4\xa5\xe0\xa5\x80\xe0\xa4\x82");
return 0;
}
el_val_t hi_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t gender, el_val_t number) {
el_val_t stem = hi_verb_stem_clean(verb);
if (str_eq(verb, EL_STR("\xe0\xa4\xb9\xe0\xa5\x8b\xe0\xa4\xa8\xe0\xa4\xbe"))) {
if (str_eq(tense, EL_STR("present"))) {
return hi_hona_present(person, number);
}
if (str_eq(tense, EL_STR("past"))) {
return hi_hona_past(gender, number);
}
return el_str_concat(EL_STR("\xe0\xa4\xb9\xe0\xa5\x8b"), hi_future_suffix(person, number, gender));
}
if (str_eq(tense, EL_STR("present"))) {
el_val_t aspect = hi_present_aspect(gender, number);
el_val_t aux = hi_aux_present(person, number);
return el_str_concat(el_str_concat(el_str_concat(stem, aspect), EL_STR(" ")), aux);
}
if (str_eq(tense, EL_STR("past"))) {
el_val_t irreg = hi_past_irregular(stem, gender, number);
if (!str_eq(irreg, EL_STR(""))) {
return irreg;
}
return el_str_concat(stem, hi_past_suffix(gender, number));
}
if (str_eq(tense, EL_STR("future"))) {
return el_str_concat(stem, hi_future_suffix(person, number, gender));
}
return verb;
return 0;
}
el_val_t hi_noun_with_post(el_val_t noun, el_val_t gender, el_val_t number, el_val_t gram_case) {
el_val_t post = hi_postposition(gram_case);
if (str_eq(post, EL_STR(""))) {
return hi_noun_direct(noun, gender, number);
}
el_val_t oblique = hi_noun_oblique(noun, gender, number);
return el_str_concat(el_str_concat(oblique, EL_STR(" ")), post);
return 0;
}
el_val_t hi_genitive_phrase(el_val_t possessor, el_val_t possessor_gender, el_val_t possessor_number, el_val_t possessed, el_val_t possessed_gender, el_val_t possessed_number) {
el_val_t obl = hi_noun_oblique(possessor, possessor_gender, possessor_number);
el_val_t gen = hi_agree_genitive(possessed_gender, possessed_number);
el_val_t poss = hi_noun_direct(possessed, possessed_gender, possessed_number);
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(obl, EL_STR(" ")), gen), EL_STR(" ")), poss);
return 0;
}
Generated Vendored
+27
View File
@@ -0,0 +1,27 @@
// auto-generated by elc --emit-header — do not edit
extern fn hi_str_ends(s: String, suf: String) -> Bool
extern fn hi_str_drop_last(s: String, n: Int) -> String
extern fn hi_str_last_char(s: String) -> String
extern fn hi_gender(noun: String) -> String
extern fn hi_masc_aa_stem(noun: String) -> String
extern fn hi_noun_direct_m(noun: String, number: String) -> String
extern fn hi_noun_oblique_m(noun: String, number: String) -> String
extern fn hi_noun_direct_f(noun: String, number: String) -> String
extern fn hi_noun_oblique_f(noun: String, number: String) -> String
extern fn hi_noun_direct(noun: String, gender: String, number: String) -> String
extern fn hi_noun_oblique(noun: String, gender: String, number: String) -> String
extern fn hi_postposition(gram_case: String) -> String
extern fn hi_agree_genitive(possessed_gender: String, possessed_number: String) -> String
extern fn hi_verb_stem(infinitive: String) -> String
extern fn hi_verb_stem_clean(infinitive: String) -> String
extern fn hi_present_aspect(gender: String, number: String) -> String
extern fn hi_aux_present(person: String, number: String) -> String
extern fn hi_past_suffix(gender: String, number: String) -> String
extern fn hi_past_irregular(stem: String, gender: String, number: String) -> String
extern fn hi_future_suffix(person: String, number: String, gender: String) -> String
extern fn hi_tense_suffix(tense: String, gender: String, number: String) -> String
extern fn hi_hona_present(person: String, number: String) -> String
extern fn hi_hona_past(gender: String, number: String) -> String
extern fn hi_conjugate(verb: String, tense: String, person: String, gender: String, number: String) -> String
extern fn hi_noun_with_post(noun: String, gender: String, number: String, gram_case: String) -> String
extern fn hi_genitive_phrase(possessor: String, possessor_gender: String, possessor_number: String, possessed: String, possessed_gender: String, possessed_number: String) -> String
Generated Vendored
+746
View File
@@ -0,0 +1,746 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t ja_verb_group(el_val_t dict_form);
el_val_t ja_ichidan_stem(el_val_t dict_form);
el_val_t ja_godan_stem_change(el_val_t dict_form, el_val_t row);
el_val_t ja_conjugate(el_val_t dict_form, el_val_t form);
el_val_t ja_particle(el_val_t gram_case);
el_val_t ja_noun_phrase(el_val_t noun, el_val_t gram_case);
el_val_t ja_question_particle(void);
el_val_t ja_make_question(el_val_t sentence);
el_val_t ja_verb_group(el_val_t dict_form) {
if (str_eq(dict_form, EL_STR("\xe3\x81\x99\xe3\x82\x8b"))) {
return EL_STR("irregular");
}
if (str_eq(dict_form, EL_STR("\xe3\x81\x8f\xe3\x82\x8b"))) {
return EL_STR("irregular");
}
if (str_eq(dict_form, EL_STR("\xe3\x81\x8f\xe3\x82\x8b"))) {
return EL_STR("irregular");
}
if (str_eq(dict_form, EL_STR("\xe3\x81\x84\xe3\x82\x8b"))) {
return EL_STR("irregular");
}
if (str_eq(dict_form, EL_STR("\xe3\x81\x82\xe3\x82\x8b"))) {
return EL_STR("irregular");
}
if (str_eq(dict_form, EL_STR("\xe3\x81\xa0"))) {
return EL_STR("irregular");
}
if (str_eq(dict_form, EL_STR("suru"))) {
return EL_STR("irregular");
}
if (str_eq(dict_form, EL_STR("kuru"))) {
return EL_STR("irregular");
}
if (str_eq(dict_form, EL_STR("iru"))) {
return EL_STR("irregular");
}
if (str_eq(dict_form, EL_STR("aru"))) {
return EL_STR("irregular");
}
if (str_eq(dict_form, EL_STR("da"))) {
return EL_STR("irregular");
}
if (str_ends_with(dict_form, EL_STR("\xe3\x82\x8b"))) {
return EL_STR("ichidan");
}
if (str_ends_with(dict_form, EL_STR("eru"))) {
return EL_STR("ichidan");
}
if (str_ends_with(dict_form, EL_STR("iru"))) {
return EL_STR("ichidan");
}
return EL_STR("godan");
return 0;
}
el_val_t ja_ichidan_stem(el_val_t dict_form) {
if (str_ends_with(dict_form, EL_STR("\xe3\x82\x8b"))) {
el_val_t n = str_len(dict_form);
return str_drop_last(dict_form, 1);
}
if (str_ends_with(dict_form, EL_STR("ru"))) {
el_val_t n = str_len(dict_form);
return str_slice(dict_form, 0, (n - 2));
}
return dict_form;
return 0;
}
el_val_t ja_godan_stem_change(el_val_t dict_form, el_val_t row) {
el_val_t n = str_len(dict_form);
if (n == 0) {
return dict_form;
}
if (str_eq(row, EL_STR("i"))) {
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x8f"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\x8d"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x90"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\x8e"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x99"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\x97"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xa4"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\xa1"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xac"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\xab"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xb6"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\xb3"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x82\x80"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\xbf"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x82\x8b"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x82\x8a"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x86"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\x84"));
}
if (str_ends_with(dict_form, EL_STR("ku"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("ki"));
}
if (str_ends_with(dict_form, EL_STR("gu"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("gi"));
}
if (str_ends_with(dict_form, EL_STR("su"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("shi"));
}
if (str_ends_with(dict_form, EL_STR("tsu"))) {
return el_str_concat(str_drop_last(dict_form, 3), EL_STR("chi"));
}
if (str_ends_with(dict_form, EL_STR("nu"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("ni"));
}
if (str_ends_with(dict_form, EL_STR("bu"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("bi"));
}
if (str_ends_with(dict_form, EL_STR("mu"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("mi"));
}
if (str_ends_with(dict_form, EL_STR("ru"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("ri"));
}
if (str_ends_with(dict_form, EL_STR("u"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("i"));
}
return dict_form;
}
if (str_eq(row, EL_STR("a"))) {
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x8f"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\x8b"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x90"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\x8c"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x99"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\x95"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xa4"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\x9f"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xac"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\xaa"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xb6"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\xb0"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x82\x80"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\xbe"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x82\x8b"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x82\x89"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x86"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x82\x8f"));
}
if (str_ends_with(dict_form, EL_STR("ku"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("ka"));
}
if (str_ends_with(dict_form, EL_STR("gu"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("ga"));
}
if (str_ends_with(dict_form, EL_STR("su"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("sa"));
}
if (str_ends_with(dict_form, EL_STR("tsu"))) {
return el_str_concat(str_drop_last(dict_form, 3), EL_STR("ta"));
}
if (str_ends_with(dict_form, EL_STR("nu"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("na"));
}
if (str_ends_with(dict_form, EL_STR("bu"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("ba"));
}
if (str_ends_with(dict_form, EL_STR("mu"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("ma"));
}
if (str_ends_with(dict_form, EL_STR("ru"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("ra"));
}
if (str_ends_with(dict_form, EL_STR("u"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("wa"));
}
return dict_form;
}
if (str_eq(row, EL_STR("te"))) {
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x8f"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\x84"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x90"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\x84"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x99"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\x97"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xa4"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\xa3"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xac"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x82\x93"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xb6"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x82\x93"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x82\x80"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x82\x93"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x82\x8b"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\xa3"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x86"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\xa3"));
}
if (str_ends_with(dict_form, EL_STR("ku"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("i"));
}
if (str_ends_with(dict_form, EL_STR("gu"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("i"));
}
if (str_ends_with(dict_form, EL_STR("su"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("shi"));
}
if (str_ends_with(dict_form, EL_STR("tsu"))) {
return el_str_concat(str_drop_last(dict_form, 3), EL_STR("tt"));
}
if (str_ends_with(dict_form, EL_STR("nu"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("n"));
}
if (str_ends_with(dict_form, EL_STR("bu"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("n"));
}
if (str_ends_with(dict_form, EL_STR("mu"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("n"));
}
if (str_ends_with(dict_form, EL_STR("ru"))) {
return el_str_concat(str_drop_last(dict_form, 2), EL_STR("tt"));
}
if (str_ends_with(dict_form, EL_STR("u"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("tt"));
}
return dict_form;
}
return dict_form;
return 0;
}
el_val_t ja_conjugate(el_val_t dict_form, el_val_t form) {
el_val_t group = ja_verb_group(dict_form);
if (str_eq(group, EL_STR("irregular"))) {
if (str_eq(dict_form, EL_STR("\xe3\x81\x99\xe3\x82\x8b"))) {
if (str_eq(form, EL_STR("present"))) {
return EL_STR("\xe3\x81\x99\xe3\x82\x8b");
}
if (str_eq(form, EL_STR("past"))) {
return EL_STR("\xe3\x81\x97\xe3\x81\x9f");
}
if (str_eq(form, EL_STR("negative"))) {
return EL_STR("\xe3\x81\x97\xe3\x81\xaa\xe3\x81\x84");
}
if (str_eq(form, EL_STR("volitional"))) {
return EL_STR("\xe3\x81\x97\xe3\x82\x88\xe3\x81\x86");
}
if (str_eq(form, EL_STR("polite"))) {
return EL_STR("\xe3\x81\x97\xe3\x81\xbe\xe3\x81\x99");
}
if (str_eq(form, EL_STR("polite-past"))) {
return EL_STR("\xe3\x81\x97\xe3\x81\xbe\xe3\x81\x97\xe3\x81\x9f");
}
if (str_eq(form, EL_STR("polite-neg"))) {
return EL_STR("\xe3\x81\x97\xe3\x81\xbe\xe3\x81\x9b\xe3\x82\x93");
}
if (str_eq(form, EL_STR("te"))) {
return EL_STR("\xe3\x81\x97\xe3\x81\xa6");
}
return dict_form;
}
if (str_eq(dict_form, EL_STR("suru"))) {
if (str_eq(form, EL_STR("present"))) {
return EL_STR("suru");
}
if (str_eq(form, EL_STR("past"))) {
return EL_STR("shita");
}
if (str_eq(form, EL_STR("negative"))) {
return EL_STR("shinai");
}
if (str_eq(form, EL_STR("volitional"))) {
return EL_STR("shiyou");
}
if (str_eq(form, EL_STR("polite"))) {
return EL_STR("shimasu");
}
if (str_eq(form, EL_STR("polite-past"))) {
return EL_STR("shimashita");
}
if (str_eq(form, EL_STR("polite-neg"))) {
return EL_STR("shimasen");
}
if (str_eq(form, EL_STR("te"))) {
return EL_STR("shite");
}
return dict_form;
}
if (str_eq(dict_form, EL_STR("\xe3\x81\x8f\xe3\x82\x8b"))) {
if (str_eq(form, EL_STR("present"))) {
return EL_STR("\xe3\x81\x8f\xe3\x82\x8b");
}
if (str_eq(form, EL_STR("past"))) {
return EL_STR("\xe3\x81\x8d\xe3\x81\x9f");
}
if (str_eq(form, EL_STR("negative"))) {
return EL_STR("\xe3\x81\x93\xe3\x81\xaa\xe3\x81\x84");
}
if (str_eq(form, EL_STR("volitional"))) {
return EL_STR("\xe3\x81\x93\xe3\x82\x88\xe3\x81\x86");
}
if (str_eq(form, EL_STR("polite"))) {
return EL_STR("\xe3\x81\x8d\xe3\x81\xbe\xe3\x81\x99");
}
if (str_eq(form, EL_STR("polite-past"))) {
return EL_STR("\xe3\x81\x8d\xe3\x81\xbe\xe3\x81\x97\xe3\x81\x9f");
}
if (str_eq(form, EL_STR("polite-neg"))) {
return EL_STR("\xe3\x81\x8d\xe3\x81\xbe\xe3\x81\x9b\xe3\x82\x93");
}
if (str_eq(form, EL_STR("te"))) {
return EL_STR("\xe3\x81\x8d\xe3\x81\xa6");
}
return dict_form;
}
if (str_eq(dict_form, EL_STR("kuru"))) {
if (str_eq(form, EL_STR("present"))) {
return EL_STR("kuru");
}
if (str_eq(form, EL_STR("past"))) {
return EL_STR("kita");
}
if (str_eq(form, EL_STR("negative"))) {
return EL_STR("konai");
}
if (str_eq(form, EL_STR("volitional"))) {
return EL_STR("koyou");
}
if (str_eq(form, EL_STR("polite"))) {
return EL_STR("kimasu");
}
if (str_eq(form, EL_STR("polite-past"))) {
return EL_STR("kimashita");
}
if (str_eq(form, EL_STR("polite-neg"))) {
return EL_STR("kimasen");
}
if (str_eq(form, EL_STR("te"))) {
return EL_STR("kite");
}
return dict_form;
}
if (str_eq(dict_form, EL_STR("\xe3\x81\x84\xe3\x82\x8b"))) {
if (str_eq(form, EL_STR("present"))) {
return EL_STR("\xe3\x81\x84\xe3\x82\x8b");
}
if (str_eq(form, EL_STR("past"))) {
return EL_STR("\xe3\x81\x84\xe3\x81\x9f");
}
if (str_eq(form, EL_STR("negative"))) {
return EL_STR("\xe3\x81\x84\xe3\x81\xaa\xe3\x81\x84");
}
if (str_eq(form, EL_STR("volitional"))) {
return EL_STR("\xe3\x81\x84\xe3\x82\x88\xe3\x81\x86");
}
if (str_eq(form, EL_STR("polite"))) {
return EL_STR("\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x99");
}
if (str_eq(form, EL_STR("polite-past"))) {
return EL_STR("\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x97\xe3\x81\x9f");
}
if (str_eq(form, EL_STR("polite-neg"))) {
return EL_STR("\xe3\x81\x84\xe3\x81\xbe\xe3\x81\x9b\xe3\x82\x93");
}
if (str_eq(form, EL_STR("te"))) {
return EL_STR("\xe3\x81\x84\xe3\x81\xa6");
}
return dict_form;
}
if (str_eq(dict_form, EL_STR("iru"))) {
if (str_eq(form, EL_STR("present"))) {
return EL_STR("iru");
}
if (str_eq(form, EL_STR("past"))) {
return EL_STR("ita");
}
if (str_eq(form, EL_STR("negative"))) {
return EL_STR("inai");
}
if (str_eq(form, EL_STR("volitional"))) {
return EL_STR("iyou");
}
if (str_eq(form, EL_STR("polite"))) {
return EL_STR("imasu");
}
if (str_eq(form, EL_STR("polite-past"))) {
return EL_STR("imashita");
}
if (str_eq(form, EL_STR("polite-neg"))) {
return EL_STR("imasen");
}
if (str_eq(form, EL_STR("te"))) {
return EL_STR("ite");
}
return dict_form;
}
if (str_eq(dict_form, EL_STR("\xe3\x81\x82\xe3\x82\x8b"))) {
if (str_eq(form, EL_STR("present"))) {
return EL_STR("\xe3\x81\x82\xe3\x82\x8b");
}
if (str_eq(form, EL_STR("past"))) {
return EL_STR("\xe3\x81\x82\xe3\x81\xa3\xe3\x81\x9f");
}
if (str_eq(form, EL_STR("negative"))) {
return EL_STR("\xe3\x81\xaa\xe3\x81\x84");
}
if (str_eq(form, EL_STR("volitional"))) {
return EL_STR("\xe3\x81\x82\xe3\x82\x8d\xe3\x81\x86");
}
if (str_eq(form, EL_STR("polite"))) {
return EL_STR("\xe3\x81\x82\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x99");
}
if (str_eq(form, EL_STR("polite-past"))) {
return EL_STR("\xe3\x81\x82\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x97\xe3\x81\x9f");
}
if (str_eq(form, EL_STR("polite-neg"))) {
return EL_STR("\xe3\x81\x82\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x9b\xe3\x82\x93");
}
if (str_eq(form, EL_STR("te"))) {
return EL_STR("\xe3\x81\x82\xe3\x81\xa3\xe3\x81\xa6");
}
return dict_form;
}
if (str_eq(dict_form, EL_STR("aru"))) {
if (str_eq(form, EL_STR("present"))) {
return EL_STR("aru");
}
if (str_eq(form, EL_STR("past"))) {
return EL_STR("atta");
}
if (str_eq(form, EL_STR("negative"))) {
return EL_STR("nai");
}
if (str_eq(form, EL_STR("volitional"))) {
return EL_STR("arou");
}
if (str_eq(form, EL_STR("polite"))) {
return EL_STR("arimasu");
}
if (str_eq(form, EL_STR("polite-past"))) {
return EL_STR("arimashita");
}
if (str_eq(form, EL_STR("polite-neg"))) {
return EL_STR("arimasen");
}
if (str_eq(form, EL_STR("te"))) {
return EL_STR("atte");
}
return dict_form;
}
if (str_eq(dict_form, EL_STR("\xe3\x81\xa0"))) {
if (str_eq(form, EL_STR("present"))) {
return EL_STR("\xe3\x81\xa0");
}
if (str_eq(form, EL_STR("past"))) {
return EL_STR("\xe3\x81\xa0\xe3\x81\xa3\xe3\x81\x9f");
}
if (str_eq(form, EL_STR("negative"))) {
return EL_STR("\xe3\x81\xa7\xe3\x81\xaf\xe3\x81\xaa\xe3\x81\x84");
}
if (str_eq(form, EL_STR("volitional"))) {
return EL_STR("\xe3\x81\xa0\xe3\x82\x8d\xe3\x81\x86");
}
if (str_eq(form, EL_STR("polite"))) {
return EL_STR("\xe3\x81\xa7\xe3\x81\x99");
}
if (str_eq(form, EL_STR("polite-past"))) {
return EL_STR("\xe3\x81\xa7\xe3\x81\x97\xe3\x81\x9f");
}
if (str_eq(form, EL_STR("polite-neg"))) {
return EL_STR("\xe3\x81\xa7\xe3\x81\xaf\xe3\x81\x82\xe3\x82\x8a\xe3\x81\xbe\xe3\x81\x9b\xe3\x82\x93");
}
if (str_eq(form, EL_STR("te"))) {
return EL_STR("\xe3\x81\xa7");
}
return dict_form;
}
if (str_eq(dict_form, EL_STR("da"))) {
if (str_eq(form, EL_STR("present"))) {
return EL_STR("da");
}
if (str_eq(form, EL_STR("past"))) {
return EL_STR("datta");
}
if (str_eq(form, EL_STR("negative"))) {
return EL_STR("dewanai");
}
if (str_eq(form, EL_STR("volitional"))) {
return EL_STR("darou");
}
if (str_eq(form, EL_STR("polite"))) {
return EL_STR("desu");
}
if (str_eq(form, EL_STR("polite-past"))) {
return EL_STR("deshita");
}
if (str_eq(form, EL_STR("polite-neg"))) {
return EL_STR("dewaarimarsen");
}
if (str_eq(form, EL_STR("te"))) {
return EL_STR("de");
}
return dict_form;
}
return dict_form;
}
if (str_eq(group, EL_STR("ichidan"))) {
el_val_t stem = ja_ichidan_stem(dict_form);
if (str_eq(form, EL_STR("present"))) {
return dict_form;
}
if (str_eq(form, EL_STR("past"))) {
return el_str_concat(stem, EL_STR("\xe3\x81\x9f"));
}
if (str_eq(form, EL_STR("negative"))) {
return el_str_concat(stem, EL_STR("\xe3\x81\xaa\xe3\x81\x84"));
}
if (str_eq(form, EL_STR("volitional"))) {
return el_str_concat(stem, EL_STR("\xe3\x82\x88\xe3\x81\x86"));
}
if (str_eq(form, EL_STR("polite"))) {
return el_str_concat(stem, EL_STR("\xe3\x81\xbe\xe3\x81\x99"));
}
if (str_eq(form, EL_STR("polite-past"))) {
return el_str_concat(stem, EL_STR("\xe3\x81\xbe\xe3\x81\x97\xe3\x81\x9f"));
}
if (str_eq(form, EL_STR("polite-neg"))) {
return el_str_concat(stem, EL_STR("\xe3\x81\xbe\xe3\x81\x9b\xe3\x82\x93"));
}
if (str_eq(form, EL_STR("te"))) {
return el_str_concat(stem, EL_STR("\xe3\x81\xa6"));
}
return dict_form;
}
if (str_eq(form, EL_STR("present"))) {
return dict_form;
}
if (str_eq(form, EL_STR("polite"))) {
el_val_t istem = ja_godan_stem_change(dict_form, EL_STR("i"));
return el_str_concat(istem, EL_STR("\xe3\x81\xbe\xe3\x81\x99"));
}
if (str_eq(form, EL_STR("polite-past"))) {
el_val_t istem = ja_godan_stem_change(dict_form, EL_STR("i"));
return el_str_concat(istem, EL_STR("\xe3\x81\xbe\xe3\x81\x97\xe3\x81\x9f"));
}
if (str_eq(form, EL_STR("polite-neg"))) {
el_val_t istem = ja_godan_stem_change(dict_form, EL_STR("i"));
return el_str_concat(istem, EL_STR("\xe3\x81\xbe\xe3\x81\x9b\xe3\x82\x93"));
}
if (str_eq(form, EL_STR("negative"))) {
el_val_t astem = ja_godan_stem_change(dict_form, EL_STR("a"));
return el_str_concat(astem, EL_STR("\xe3\x81\xaa\xe3\x81\x84"));
}
if (str_eq(form, EL_STR("volitional"))) {
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x86"))) {
return el_str_concat(str_drop_last(dict_form, 1), EL_STR("\xe3\x81\x8a\xe3\x81\x86"));
}
el_val_t istem = ja_godan_stem_change(dict_form, EL_STR("i"));
return el_str_concat(istem, EL_STR("\xe3\x82\x8d\xe3\x81\x86"));
}
if (str_eq(form, EL_STR("te"))) {
el_val_t tstem = ja_godan_stem_change(dict_form, EL_STR("te"));
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x90"))) {
return el_str_concat(tstem, EL_STR("\xe3\x81\x84\xe3\x81\xa7"));
}
if (str_ends_with(dict_form, EL_STR("gu"))) {
return el_str_concat(tstem, EL_STR("ide"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xac"))) {
return el_str_concat(tstem, EL_STR("\xe3\x82\x93\xe3\x81\xa7"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xb6"))) {
return el_str_concat(tstem, EL_STR("\xe3\x82\x93\xe3\x81\xa7"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x82\x80"))) {
return el_str_concat(tstem, EL_STR("\xe3\x82\x93\xe3\x81\xa7"));
}
if (str_ends_with(dict_form, EL_STR("nu"))) {
return el_str_concat(tstem, EL_STR("nde"));
}
if (str_ends_with(dict_form, EL_STR("bu"))) {
return el_str_concat(tstem, EL_STR("nde"));
}
if (str_ends_with(dict_form, EL_STR("mu"))) {
return el_str_concat(tstem, EL_STR("nde"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x99"))) {
return el_str_concat(tstem, EL_STR("\xe3\x81\x97\xe3\x81\xa6"));
}
if (str_ends_with(dict_form, EL_STR("su"))) {
return el_str_concat(tstem, EL_STR("shite"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x8f"))) {
return el_str_concat(tstem, EL_STR("\xe3\x81\xa6"));
}
if (str_ends_with(dict_form, EL_STR("ku"))) {
return el_str_concat(tstem, EL_STR("te"));
}
return el_str_concat(tstem, EL_STR("\xe3\x81\xa6"));
}
if (str_eq(form, EL_STR("past"))) {
el_val_t tstem = ja_godan_stem_change(dict_form, EL_STR("te"));
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x90"))) {
return el_str_concat(tstem, EL_STR("\xe3\x81\x84\xe3\x81\xa0"));
}
if (str_ends_with(dict_form, EL_STR("gu"))) {
return el_str_concat(tstem, EL_STR("ida"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xac"))) {
return el_str_concat(tstem, EL_STR("\xe3\x82\x93\xe3\x81\xa0"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\xb6"))) {
return el_str_concat(tstem, EL_STR("\xe3\x82\x93\xe3\x81\xa0"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x82\x80"))) {
return el_str_concat(tstem, EL_STR("\xe3\x82\x93\xe3\x81\xa0"));
}
if (str_ends_with(dict_form, EL_STR("nu"))) {
return el_str_concat(tstem, EL_STR("nda"));
}
if (str_ends_with(dict_form, EL_STR("bu"))) {
return el_str_concat(tstem, EL_STR("nda"));
}
if (str_ends_with(dict_form, EL_STR("mu"))) {
return el_str_concat(tstem, EL_STR("nda"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x99"))) {
return el_str_concat(tstem, EL_STR("\xe3\x81\x97\xe3\x81\x9f"));
}
if (str_ends_with(dict_form, EL_STR("su"))) {
return el_str_concat(tstem, EL_STR("shita"));
}
if (str_ends_with(dict_form, EL_STR("\xe3\x81\x8f"))) {
return el_str_concat(tstem, EL_STR("\xe3\x81\x9f"));
}
if (str_ends_with(dict_form, EL_STR("ku"))) {
return el_str_concat(tstem, EL_STR("ta"));
}
return el_str_concat(tstem, EL_STR("\xe3\x81\x9f"));
}
return dict_form;
return 0;
}
el_val_t ja_particle(el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("\xe3\x81\x8c");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("\xe3\x82\x92");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("\xe3\x81\xab");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("\xe3\x81\xae");
}
if (str_eq(gram_case, EL_STR("topic"))) {
return EL_STR("\xe3\x81\xaf");
}
if (str_eq(gram_case, EL_STR("instrumental"))) {
return EL_STR("\xe3\x81\xa7");
}
if (str_eq(gram_case, EL_STR("locative"))) {
return EL_STR("\xe3\x81\xab");
}
if (str_eq(gram_case, EL_STR("ablative"))) {
return EL_STR("\xe3\x81\x8b\xe3\x82\x89");
}
if (str_eq(gram_case, EL_STR("direction"))) {
return EL_STR("\xe3\x81\xb8");
}
if (str_eq(gram_case, EL_STR("comitative"))) {
return EL_STR("\xe3\x81\xa8");
}
return EL_STR("");
return 0;
}
el_val_t ja_noun_phrase(el_val_t noun, el_val_t gram_case) {
el_val_t p = ja_particle(gram_case);
if (str_eq(p, EL_STR(""))) {
return noun;
}
return el_str_concat(noun, p);
return 0;
}
el_val_t ja_question_particle(void) {
return EL_STR("\xe3\x81\x8b");
return 0;
}
el_val_t ja_make_question(el_val_t sentence) {
return el_str_concat(sentence, ja_question_particle());
return 0;
}
Generated Vendored
+9
View File
@@ -0,0 +1,9 @@
// auto-generated by elc --emit-header — do not edit
extern fn ja_verb_group(dict_form: String) -> String
extern fn ja_ichidan_stem(dict_form: String) -> String
extern fn ja_godan_stem_change(dict_form: String, row: String) -> String
extern fn ja_conjugate(dict_form: String, form: String) -> String
extern fn ja_particle(gram_case: String) -> String
extern fn ja_noun_phrase(noun: String, gram_case: String) -> String
extern fn ja_question_particle() -> String
extern fn ja_make_question(sentence: String) -> String
Generated Vendored
+1150
View File
File diff suppressed because it is too large Load Diff
Generated Vendored
+41
View File
@@ -0,0 +1,41 @@
// auto-generated by elc --emit-header — do not edit
extern fn la_str_ends(s: String, suf: String) -> Bool
extern fn la_str_drop_last(s: String, n: Int) -> String
extern fn la_str_last_char(s: String) -> String
extern fn la_str_last2(s: String) -> String
extern fn la_str_last3(s: String) -> String
extern fn la_slot(person: String, number: String) -> Int
extern fn la_verb_class(verb: String) -> String
extern fn la_stem(verb: String, vclass: String) -> String
extern fn la_perfect_stem(verb: String, vclass: String) -> String
extern fn la_perfect_ending(slot: Int) -> String
extern fn la_present_ending(vclass: String, slot: Int) -> String
extern fn la_present_form(stem: String, vclass: String, slot: Int) -> String
extern fn la_future_ending_12(slot: Int) -> String
extern fn la_future_ending_34(slot: Int) -> String
extern fn la_future_form(stem: String, vclass: String, slot: Int) -> String
extern fn la_esse_present(slot: Int) -> String
extern fn la_esse_past(slot: Int) -> String
extern fn la_esse_future(slot: Int) -> String
extern fn la_ire_present(slot: Int) -> String
extern fn la_ire_past(slot: Int) -> String
extern fn la_ire_future(slot: Int) -> String
extern fn la_velle_present(slot: Int) -> String
extern fn la_velle_past(slot: Int) -> String
extern fn la_velle_future(slot: Int) -> String
extern fn la_posse_present(slot: Int) -> String
extern fn la_posse_past(slot: Int) -> String
extern fn la_posse_future(slot: Int) -> String
extern fn la_irregular_perfect_stem(verb: String) -> String
extern fn la_map_canonical(verb: String) -> String
extern fn la_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn la_declension(noun: String) -> String
extern fn la_decline_1(stem: String, gram_case: String, number: String) -> String
extern fn la_decline_2m(stem: String, gram_case: String, number: String) -> String
extern fn la_decline_2n(stem: String, gram_case: String, number: String) -> String
extern fn la_decline_3(noun: String, gram_case: String, number: String) -> String
extern fn la_decline_4(stem: String, gram_case: String, number: String) -> String
extern fn la_decline_5(stem: String, gram_case: String, number: String) -> String
extern fn la_decline_2er(noun: String, gram_case: String, number: String) -> String
extern fn la_decline(noun: String, gram_case: String, number: String) -> String
extern fn la_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
Generated Vendored
+808
View File
@@ -0,0 +1,808 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t non_str_ends(el_val_t s, el_val_t suf);
el_val_t non_drop(el_val_t s, el_val_t n);
el_val_t non_last(el_val_t s);
el_val_t non_slot(el_val_t person, el_val_t number);
el_val_t non_vera_present(el_val_t slot);
el_val_t non_vera_past(el_val_t slot);
el_val_t non_hafa_present(el_val_t slot);
el_val_t non_hafa_past(el_val_t slot);
el_val_t non_ganga_present(el_val_t slot);
el_val_t non_ganga_past(el_val_t slot);
el_val_t non_sja_present(el_val_t slot);
el_val_t non_sja_past(el_val_t slot);
el_val_t non_segja_present(el_val_t slot);
el_val_t non_segja_past(el_val_t slot);
el_val_t non_koma_present(el_val_t slot);
el_val_t non_koma_past(el_val_t slot);
el_val_t non_map_canonical(el_val_t verb);
el_val_t non_weak_present(el_val_t stem, el_val_t slot);
el_val_t non_weak_past(el_val_t stem, el_val_t slot);
el_val_t non_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t non_decline_masc(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t non_decline_fem(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t non_decline_neut(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t non_detect_gender(el_val_t noun);
el_val_t non_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t non_def_suffix_masc(el_val_t gram_case, el_val_t number);
el_val_t non_def_suffix_neut(el_val_t gram_case, el_val_t number);
el_val_t non_def_suffix_fem(el_val_t gram_case, el_val_t number);
el_val_t non_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t non_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t non_drop(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t non_last(el_val_t s) {
el_val_t n = str_len(s);
if (n == 0) {
return EL_STR("");
}
return str_slice(s, (n - 1), n);
return 0;
}
el_val_t non_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t non_vera_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("em");
}
if (slot == 1) {
return EL_STR("ert");
}
if (slot == 2) {
return EL_STR("er");
}
if (slot == 3) {
return EL_STR("erum");
}
if (slot == 4) {
return EL_STR("eru\xc3\xb0");
}
return EL_STR("eru");
return 0;
}
el_val_t non_vera_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("var");
}
if (slot == 1) {
return EL_STR("vart");
}
if (slot == 2) {
return EL_STR("var");
}
if (slot == 3) {
return EL_STR("v\xc3\xb3rum");
}
if (slot == 4) {
return EL_STR("v\xc3\xb3ru\xc3\xb0");
}
return EL_STR("v\xc3\xb3ru");
return 0;
}
el_val_t non_hafa_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("hefi");
}
if (slot == 1) {
return EL_STR("hefr");
}
if (slot == 2) {
return EL_STR("hefr");
}
if (slot == 3) {
return EL_STR("h\xc3\xb6""fum");
}
if (slot == 4) {
return EL_STR("hafi\xc3\xb0");
}
return EL_STR("hafa");
return 0;
}
el_val_t non_hafa_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("haf\xc3\xb0""a");
}
if (slot == 1) {
return EL_STR("haf\xc3\xb0ir");
}
if (slot == 2) {
return EL_STR("haf\xc3\xb0i");
}
if (slot == 3) {
return EL_STR("h\xc3\xb6""f\xc3\xb0um");
}
if (slot == 4) {
return EL_STR("h\xc3\xb6""f\xc3\xb0u\xc3\xb0");
}
return EL_STR("h\xc3\xb6""f\xc3\xb0u");
return 0;
}
el_val_t non_ganga_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("geng");
}
if (slot == 1) {
return EL_STR("gengr");
}
if (slot == 2) {
return EL_STR("gengr");
}
if (slot == 3) {
return EL_STR("g\xc3\xb6ngum");
}
if (slot == 4) {
return EL_STR("gangi\xc3\xb0");
}
return EL_STR("ganga");
return 0;
}
el_val_t non_ganga_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("gekk");
}
if (slot == 1) {
return EL_STR("gekkt");
}
if (slot == 2) {
return EL_STR("gekk");
}
if (slot == 3) {
return EL_STR("gengum");
}
if (slot == 4) {
return EL_STR("gengu\xc3\xb0");
}
return EL_STR("gengu");
return 0;
}
el_val_t non_sja_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("s\xc3\xa9");
}
if (slot == 1) {
return EL_STR("s\xc3\xa9r");
}
if (slot == 2) {
return EL_STR("s\xc3\xa9r");
}
if (slot == 3) {
return EL_STR("s\xc3\xa9um");
}
if (slot == 4) {
return EL_STR("s\xc3\xa9i\xc3\xb0");
}
return EL_STR("sj\xc3\xa1");
return 0;
}
el_val_t non_sja_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("s\xc3\xa1");
}
if (slot == 1) {
return EL_STR("s\xc3\xa1st");
}
if (slot == 2) {
return EL_STR("s\xc3\xa1");
}
if (slot == 3) {
return EL_STR("s\xc3\xa1m");
}
if (slot == 4) {
return EL_STR("s\xc3\xa1\xc3\xb0");
}
return EL_STR("s\xc3\xa1u");
return 0;
}
el_val_t non_segja_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("segi");
}
if (slot == 1) {
return EL_STR("segir");
}
if (slot == 2) {
return EL_STR("segir");
}
if (slot == 3) {
return EL_STR("segjum");
}
if (slot == 4) {
return EL_STR("segi\xc3\xb0");
}
return EL_STR("segja");
return 0;
}
el_val_t non_segja_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("sag\xc3\xb0i");
}
if (slot == 1) {
return EL_STR("sag\xc3\xb0ir");
}
if (slot == 2) {
return EL_STR("sag\xc3\xb0i");
}
if (slot == 3) {
return EL_STR("s\xc3\xb6g\xc3\xb0um");
}
if (slot == 4) {
return EL_STR("s\xc3\xb6g\xc3\xb0u\xc3\xb0");
}
return EL_STR("s\xc3\xb6g\xc3\xb0u");
return 0;
}
el_val_t non_koma_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("kem");
}
if (slot == 1) {
return EL_STR("kemr");
}
if (slot == 2) {
return EL_STR("kemr");
}
if (slot == 3) {
return EL_STR("komum");
}
if (slot == 4) {
return EL_STR("komi\xc3\xb0");
}
return EL_STR("koma");
return 0;
}
el_val_t non_koma_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("kom");
}
if (slot == 1) {
return EL_STR("komt");
}
if (slot == 2) {
return EL_STR("kom");
}
if (slot == 3) {
return EL_STR("komum");
}
if (slot == 4) {
return EL_STR("komu\xc3\xb0");
}
return EL_STR("komu");
return 0;
}
el_val_t non_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("vera");
}
if (str_eq(verb, EL_STR("have"))) {
return EL_STR("hafa");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("ganga");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("sj\xc3\xa1");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("segja");
}
if (str_eq(verb, EL_STR("come"))) {
return EL_STR("koma");
}
return verb;
return 0;
}
el_val_t non_weak_present(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("a"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("ar"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("ar"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("um"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("i\xc3\xb0"));
}
return el_str_concat(stem, EL_STR("a"));
return 0;
}
el_val_t non_weak_past(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("a\xc3\xb0i"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("a\xc3\xb0ir"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("a\xc3\xb0i"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("u\xc3\xb0um"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("u\xc3\xb0u\xc3\xb0"));
}
return el_str_concat(stem, EL_STR("u\xc3\xb0u"));
return 0;
}
el_val_t non_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t v = non_map_canonical(verb);
el_val_t slot = non_slot(person, number);
if (str_eq(v, EL_STR("vera"))) {
if (str_eq(tense, EL_STR("present"))) {
return non_vera_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return non_vera_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("hafa"))) {
if (str_eq(tense, EL_STR("present"))) {
return non_hafa_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return non_hafa_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("ganga"))) {
if (str_eq(tense, EL_STR("present"))) {
return non_ganga_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return non_ganga_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("sj\xc3\xa1"))) {
if (str_eq(tense, EL_STR("present"))) {
return non_sja_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return non_sja_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("segja"))) {
if (str_eq(tense, EL_STR("present"))) {
return non_segja_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return non_segja_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("koma"))) {
if (str_eq(tense, EL_STR("present"))) {
return non_koma_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return non_koma_past(slot);
}
return v;
}
if (non_str_ends(v, EL_STR("a"))) {
el_val_t stem = non_drop(v, 1);
if (str_eq(tense, EL_STR("present"))) {
return non_weak_present(stem, slot);
}
if (str_eq(tense, EL_STR("past"))) {
return non_weak_past(stem, slot);
}
return v;
}
return v;
return 0;
}
el_val_t non_decline_masc(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t stem = noun;
if (non_str_ends(noun, EL_STR("r"))) {
stem = non_drop(noun, 1);
}
if (str_eq(noun, EL_STR("armr"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("armr");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("arm");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("arms");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("armi");
}
return EL_STR("armr");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("armar");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("arma");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("arma");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("\xc3\xb6rmum");
}
return EL_STR("armar");
}
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("r"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return stem;
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("s"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("i"));
}
return el_str_concat(stem, EL_STR("r"));
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("ar"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("um"));
}
return el_str_concat(stem, EL_STR("ar"));
return 0;
}
el_val_t non_decline_fem(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(noun, EL_STR("g\xc3\xb6r"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("g\xc3\xb6r");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("g\xc3\xb6rvar");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("g\xc3\xb6rvar");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("g\xc3\xb6rvi");
}
return EL_STR("g\xc3\xb6r");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("g\xc3\xb6rvar");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("g\xc3\xb6rvar");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("g\xc3\xb6rva");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("g\xc3\xb6rvum");
}
return EL_STR("g\xc3\xb6rvar");
}
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(noun, EL_STR("var"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("var"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("vi"));
}
return noun;
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(noun, EL_STR("var"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(noun, EL_STR("var"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("va"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("vum"));
}
return el_str_concat(noun, EL_STR("var"));
return 0;
}
el_val_t non_decline_neut(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(noun, EL_STR("land"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("land");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("land");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("lands");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("landi");
}
return EL_STR("land");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("l\xc3\xb6nd");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("l\xc3\xb6nd");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("landa");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("l\xc3\xb6ndum");
}
return EL_STR("l\xc3\xb6nd");
}
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("s"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("i"));
}
return noun;
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("um"));
}
return noun;
return 0;
}
el_val_t non_detect_gender(el_val_t noun) {
if (str_eq(noun, EL_STR("land"))) {
return EL_STR("neuter");
}
if (str_eq(noun, EL_STR("g\xc3\xb6r"))) {
return EL_STR("feminine");
}
return EL_STR("masculine");
return 0;
}
el_val_t non_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t gender = non_detect_gender(noun);
if (str_eq(gender, EL_STR("masculine"))) {
return non_decline_masc(noun, gram_case, number);
}
if (str_eq(gender, EL_STR("feminine"))) {
return non_decline_fem(noun, gram_case, number);
}
if (str_eq(gender, EL_STR("neuter"))) {
return non_decline_neut(noun, gram_case, number);
}
return noun;
return 0;
}
el_val_t non_def_suffix_masc(el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("inn");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("ins");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("inum");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("inn");
}
return EL_STR("inn");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("inir");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("ina");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("anna");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("unum");
}
return EL_STR("inir");
return 0;
}
el_val_t non_def_suffix_neut(el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("it");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("ins");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("inu");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("it");
}
return EL_STR("it");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("in");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("in");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("anna");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("unum");
}
return EL_STR("in");
return 0;
}
el_val_t non_def_suffix_fem(el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("in");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("innar");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("inni");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("ina");
}
return EL_STR("in");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("inar");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("inar");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("anna");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("innar");
}
return EL_STR("inar");
return 0;
}
el_val_t non_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
el_val_t base = non_decline(noun, gram_case, number);
if (!str_eq(definite, EL_STR("true"))) {
return base;
}
el_val_t gender = non_detect_gender(noun);
if (str_eq(gender, EL_STR("masculine"))) {
return el_str_concat(base, non_def_suffix_masc(gram_case, number));
}
if (str_eq(gender, EL_STR("neuter"))) {
return el_str_concat(base, non_def_suffix_neut(gram_case, number));
}
if (str_eq(gender, EL_STR("feminine"))) {
return el_str_concat(base, non_def_suffix_fem(gram_case, number));
}
return el_str_concat(base, EL_STR("inn"));
return 0;
}
Generated Vendored
+30
View File
@@ -0,0 +1,30 @@
// auto-generated by elc --emit-header — do not edit
extern fn non_str_ends(s: String, suf: String) -> Bool
extern fn non_drop(s: String, n: Int) -> String
extern fn non_last(s: String) -> String
extern fn non_slot(person: String, number: String) -> Int
extern fn non_vera_present(slot: Int) -> String
extern fn non_vera_past(slot: Int) -> String
extern fn non_hafa_present(slot: Int) -> String
extern fn non_hafa_past(slot: Int) -> String
extern fn non_ganga_present(slot: Int) -> String
extern fn non_ganga_past(slot: Int) -> String
extern fn non_sja_present(slot: Int) -> String
extern fn non_sja_past(slot: Int) -> String
extern fn non_segja_present(slot: Int) -> String
extern fn non_segja_past(slot: Int) -> String
extern fn non_koma_present(slot: Int) -> String
extern fn non_koma_past(slot: Int) -> String
extern fn non_map_canonical(verb: String) -> String
extern fn non_weak_present(stem: String, slot: Int) -> String
extern fn non_weak_past(stem: String, slot: Int) -> String
extern fn non_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn non_decline_masc(noun: String, gram_case: String, number: String) -> String
extern fn non_decline_fem(noun: String, gram_case: String, number: String) -> String
extern fn non_decline_neut(noun: String, gram_case: String, number: String) -> String
extern fn non_detect_gender(noun: String) -> String
extern fn non_decline(noun: String, gram_case: String, number: String) -> String
extern fn non_def_suffix_masc(gram_case: String, number: String) -> String
extern fn non_def_suffix_neut(gram_case: String, number: String) -> String
extern fn non_def_suffix_fem(gram_case: String, number: String) -> String
extern fn non_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
Generated Vendored
+427
View File
@@ -0,0 +1,427 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t peo_drop(el_val_t s, el_val_t n);
el_val_t peo_ends(el_val_t s, el_val_t suf);
el_val_t peo_slot(el_val_t person, el_val_t number);
el_val_t peo_present_suffix(el_val_t slot);
el_val_t peo_past_suffix(el_val_t slot);
el_val_t peo_ah_present(el_val_t slot);
el_val_t peo_ah_past(el_val_t slot);
el_val_t peo_kar_present(el_val_t slot);
el_val_t peo_kar_past(el_val_t slot);
el_val_t peo_xsaya_present(el_val_t slot);
el_val_t peo_tar_present(el_val_t slot);
el_val_t peo_da_present(el_val_t slot);
el_val_t peo_da_past(el_val_t slot);
el_val_t peo_map_canonical(el_val_t verb);
el_val_t peo_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t peo_decline_astem(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t peo_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t peo_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t peo_drop(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t peo_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t peo_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t peo_present_suffix(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xc4\x81miy");
}
if (slot == 1) {
return EL_STR("ahiy");
}
if (slot == 2) {
return EL_STR("atiy");
}
if (slot == 3) {
return EL_STR("\xc4\x81mahy");
}
if (slot == 4) {
return EL_STR("\xc4\x81t\xc4\x81");
}
return EL_STR("antiy");
return 0;
}
el_val_t peo_past_suffix(el_val_t slot) {
if (slot == 0) {
return EL_STR("am");
}
if (slot == 1) {
return EL_STR("\xc4\x81");
}
if (slot == 2) {
return EL_STR("a");
}
if (slot == 3) {
return EL_STR("\xc4\x81m\xc4\x81");
}
if (slot == 4) {
return EL_STR("\xc4\x81t\xc4\x81");
}
return EL_STR("\xc4\x81");
return 0;
}
el_val_t peo_ah_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("amiy");
}
if (slot == 1) {
return EL_STR("ahiy");
}
if (slot == 2) {
return EL_STR("astiy");
}
if (slot == 3) {
return EL_STR("amahy");
}
if (slot == 4) {
return EL_STR("ast\xc4\x81");
}
return EL_STR("hatiy");
return 0;
}
el_val_t peo_ah_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xc4\x81ham");
}
if (slot == 1) {
return EL_STR("\xc4\x81ha");
}
if (slot == 2) {
return EL_STR("\xc4\x81ha");
}
if (slot == 3) {
return EL_STR("\xc4\x81hama");
}
if (slot == 4) {
return EL_STR("\xc4\x81hata");
}
return EL_STR("\xc4\x81han");
return 0;
}
el_val_t peo_kar_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("kun\xc4\x81miy");
}
if (slot == 1) {
return EL_STR("kun\xc4\x81hiy");
}
if (slot == 2) {
return EL_STR("kunautiy");
}
if (slot == 3) {
return EL_STR("kun\xc4\x81mahy");
}
if (slot == 4) {
return EL_STR("kun\xc4\x81t\xc4\x81");
}
return EL_STR("kunavantiy");
return 0;
}
el_val_t peo_kar_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("akunavam");
}
if (slot == 1) {
return EL_STR("akunav\xc4\x81");
}
if (slot == 2) {
return EL_STR("akunava");
}
if (slot == 3) {
return EL_STR("akunav\xc4\x81m\xc4\x81");
}
if (slot == 4) {
return EL_STR("akunav\xc4\x81t\xc4\x81");
}
return EL_STR("akunavan");
return 0;
}
el_val_t peo_xsaya_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("x\xc5\xa1\xc4\x81y\xc4\x81miy");
}
if (slot == 1) {
return EL_STR("x\xc5\xa1\xc4\x81y\xc4\x81hiy");
}
if (slot == 2) {
return EL_STR("x\xc5\xa1\xc4\x81yatiy");
}
if (slot == 3) {
return EL_STR("x\xc5\xa1\xc4\x81y\xc4\x81mahy");
}
if (slot == 4) {
return EL_STR("x\xc5\xa1\xc4\x81y\xc4\x81t\xc4\x81");
}
return EL_STR("x\xc5\xa1\xc4\x81yantiy");
return 0;
}
el_val_t peo_tar_present(el_val_t slot) {
if (slot == 2) {
return EL_STR("taratiy");
}
if (slot == 5) {
return EL_STR("tarantiy");
}
return el_str_concat(EL_STR("tar"), peo_present_suffix(slot));
return 0;
}
el_val_t peo_da_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("d\xc4\x81miy");
}
if (slot == 1) {
return EL_STR("d\xc4\x81hiy");
}
if (slot == 2) {
return EL_STR("d\xc4\x81tiy");
}
if (slot == 3) {
return EL_STR("d\xc4\x81mahy");
}
if (slot == 4) {
return EL_STR("d\xc4\x81t\xc4\x81");
}
return EL_STR("dantiy");
return 0;
}
el_val_t peo_da_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("ad\xc4\x81m");
}
if (slot == 1) {
return EL_STR("ad\xc4\x81\xc4\x81");
}
if (slot == 2) {
return EL_STR("ad\xc4\x81");
}
if (slot == 3) {
return EL_STR("ad\xc4\x81m\xc4\x81");
}
if (slot == 4) {
return EL_STR("ad\xc4\x81t\xc4\x81");
}
return EL_STR("ad\xc4\x81n");
return 0;
}
el_val_t peo_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("ah");
}
if (str_eq(verb, EL_STR("do"))) {
return EL_STR("kar");
}
if (str_eq(verb, EL_STR("make"))) {
return EL_STR("kar");
}
if (str_eq(verb, EL_STR("rule"))) {
return EL_STR("x\xc5\xa1\xc4\x81ya");
}
if (str_eq(verb, EL_STR("cross"))) {
return EL_STR("tar");
}
if (str_eq(verb, EL_STR("give"))) {
return EL_STR("d\xc4\x81");
}
return verb;
return 0;
}
el_val_t peo_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t v = peo_map_canonical(verb);
el_val_t slot = peo_slot(person, number);
if (str_eq(v, EL_STR("ah"))) {
if (str_eq(tense, EL_STR("present"))) {
return peo_ah_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return peo_ah_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("kar"))) {
if (str_eq(tense, EL_STR("present"))) {
return peo_kar_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return peo_kar_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("x\xc5\xa1\xc4\x81ya"))) {
if (str_eq(tense, EL_STR("present"))) {
return peo_xsaya_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return el_str_concat(EL_STR("x\xc5\xa1\xc4\x81ya"), peo_past_suffix(slot));
}
return v;
}
if (str_eq(v, EL_STR("tar"))) {
if (str_eq(tense, EL_STR("present"))) {
return peo_tar_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return el_str_concat(EL_STR("tar"), peo_past_suffix(slot));
}
return v;
}
if (str_eq(v, EL_STR("d\xc4\x81"))) {
if (str_eq(tense, EL_STR("present"))) {
return peo_da_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return peo_da_past(slot);
}
return v;
}
if (str_eq(tense, EL_STR("present"))) {
return el_str_concat(v, peo_present_suffix(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return el_str_concat(v, peo_past_suffix(slot));
}
return v;
return 0;
}
el_val_t peo_decline_astem(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(noun, EL_STR("dahyu"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("dahy\xc4\x81u\xc5\xa1");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("dahyum");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("dahy\xc4\x81u\xc5\xa1");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("dahyav\xc4\x81");
}
return EL_STR("dahy\xc4\x81u\xc5\xa1");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("dahy\xc4\x81va");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("dahy\xc5\xabn");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("dahy\xc5\xabn\xc4\x81m");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("dahyubiy\xc4\x81");
}
return EL_STR("dahy\xc4\x81va");
}
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(noun, EL_STR("\xc4\x81u\xc5\xa1"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(noun, EL_STR("am"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("\xc4\x81u\xc5\xa1"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("av\xc4\x81"));
}
return el_str_concat(noun, EL_STR("\xc4\x81u\xc5\xa1"));
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(noun, EL_STR("\xc4\x81va"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(noun, EL_STR("\xc5\xabn"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("\xc5\xabn\xc4\x81m"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("ubiy\xc4\x81"));
}
return el_str_concat(noun, EL_STR("\xc4\x81va"));
return 0;
}
el_val_t peo_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
return peo_decline_astem(noun, gram_case, number);
return 0;
}
el_val_t peo_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
return peo_decline(noun, gram_case, number);
return 0;
}
Generated Vendored
+19
View File
@@ -0,0 +1,19 @@
// auto-generated by elc --emit-header — do not edit
extern fn peo_drop(s: String, n: Int) -> String
extern fn peo_ends(s: String, suf: String) -> Bool
extern fn peo_slot(person: String, number: String) -> Int
extern fn peo_present_suffix(slot: Int) -> String
extern fn peo_past_suffix(slot: Int) -> String
extern fn peo_ah_present(slot: Int) -> String
extern fn peo_ah_past(slot: Int) -> String
extern fn peo_kar_present(slot: Int) -> String
extern fn peo_kar_past(slot: Int) -> String
extern fn peo_xsaya_present(slot: Int) -> String
extern fn peo_tar_present(slot: Int) -> String
extern fn peo_da_present(slot: Int) -> String
extern fn peo_da_past(slot: Int) -> String
extern fn peo_map_canonical(verb: String) -> String
extern fn peo_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn peo_decline_astem(noun: String, gram_case: String, number: String) -> String
extern fn peo_decline(noun: String, gram_case: String, number: String) -> String
extern fn peo_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
Generated Vendored
+774
View File
@@ -0,0 +1,774 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t pi_str_ends(el_val_t s, el_val_t suf);
el_val_t pi_drop(el_val_t s, el_val_t n);
el_val_t pi_last_char(el_val_t s);
el_val_t pi_slot(el_val_t person, el_val_t number);
el_val_t pi_present_ending(el_val_t slot);
el_val_t pi_aorist_ending(el_val_t slot);
el_val_t pi_future_ending(el_val_t slot);
el_val_t pi_hoti_present(el_val_t slot);
el_val_t pi_atthi_present(el_val_t slot);
el_val_t pi_hoti_aorist(el_val_t slot);
el_val_t pi_hoti_future(el_val_t slot);
el_val_t pi_gacchati_present(el_val_t slot);
el_val_t pi_gacchati_aorist(el_val_t slot);
el_val_t pi_gacchati_future(el_val_t slot);
el_val_t pi_passati_present(el_val_t slot);
el_val_t pi_passati_aorist(el_val_t slot);
el_val_t pi_passati_future(el_val_t slot);
el_val_t pi_vadati_present(el_val_t slot);
el_val_t pi_vadati_aorist(el_val_t slot);
el_val_t pi_vadati_future(el_val_t slot);
el_val_t pi_karoti_present(el_val_t slot);
el_val_t pi_karoti_aorist(el_val_t slot);
el_val_t pi_karoti_future(el_val_t slot);
el_val_t pi_map_canonical(el_val_t verb);
el_val_t pi_regular_root(el_val_t verb);
el_val_t pi_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t pi_decline_a_masc_sg(el_val_t stem, el_val_t gram_case);
el_val_t pi_decline_a_masc_pl(el_val_t stem, el_val_t gram_case);
el_val_t pi_decline_a_fem_sg(el_val_t stem, el_val_t gram_case);
el_val_t pi_decline_a_fem_pl(el_val_t stem, el_val_t gram_case);
el_val_t pi_detect_class(el_val_t noun);
el_val_t pi_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t pi_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t pi_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t pi_drop(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t pi_last_char(el_val_t s) {
el_val_t n = str_len(s);
if (n == 0) {
return EL_STR("");
}
return str_slice(s, (n - 1), n);
return 0;
}
el_val_t pi_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t pi_present_ending(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("asi");
}
if (slot == 2) {
return EL_STR("ati");
}
if (slot == 3) {
return EL_STR("\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("atha");
}
return EL_STR("anti");
return 0;
}
el_val_t pi_aorist_ending(el_val_t slot) {
if (slot == 0) {
return EL_STR("i\xe1\xb9\x83");
}
if (slot == 1) {
return EL_STR("i");
}
if (slot == 2) {
return EL_STR("i");
}
if (slot == 3) {
return EL_STR("imh\xc4\x81");
}
if (slot == 4) {
return EL_STR("ittha");
}
return EL_STR("i\xe1\xb9\x83su");
return 0;
}
el_val_t pi_future_ending(el_val_t slot) {
if (slot == 0) {
return EL_STR("iss\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("issasi");
}
if (slot == 2) {
return EL_STR("issati");
}
if (slot == 3) {
return EL_STR("iss\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("issatha");
}
return EL_STR("issanti");
return 0;
}
el_val_t pi_hoti_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("homi");
}
if (slot == 1) {
return EL_STR("hosi");
}
if (slot == 2) {
return EL_STR("hoti");
}
if (slot == 3) {
return EL_STR("homa");
}
if (slot == 4) {
return EL_STR("hotha");
}
return EL_STR("honti");
return 0;
}
el_val_t pi_atthi_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("amhi");
}
if (slot == 1) {
return EL_STR("asi");
}
if (slot == 2) {
return EL_STR("atthi");
}
if (slot == 3) {
return EL_STR("amha");
}
if (slot == 4) {
return EL_STR("attha");
}
return EL_STR("santi");
return 0;
}
el_val_t pi_hoti_aorist(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xc4\x81si\xe1\xb9\x83");
}
if (slot == 1) {
return EL_STR("\xc4\x81si");
}
if (slot == 2) {
return EL_STR("\xc4\x81si");
}
if (slot == 3) {
return EL_STR("\xc4\x81simh\xc4\x81");
}
if (slot == 4) {
return EL_STR("\xc4\x81sittha");
}
return EL_STR("\xc4\x81si\xe1\xb9\x83su");
return 0;
}
el_val_t pi_hoti_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("hoss\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("hossasi");
}
if (slot == 2) {
return EL_STR("hossati");
}
if (slot == 3) {
return EL_STR("hoss\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("hossatha");
}
return EL_STR("hossanti");
return 0;
}
el_val_t pi_gacchati_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("gacch\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("gacchasi");
}
if (slot == 2) {
return EL_STR("gacchati");
}
if (slot == 3) {
return EL_STR("gacch\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("gacchatha");
}
return EL_STR("gacchanti");
return 0;
}
el_val_t pi_gacchati_aorist(el_val_t slot) {
if (slot == 0) {
return EL_STR("agam\xc4\x81si\xe1\xb9\x83");
}
if (slot == 1) {
return EL_STR("agam\xc4\x81si");
}
if (slot == 2) {
return EL_STR("agam\xc4\x81si");
}
if (slot == 3) {
return EL_STR("agam\xc4\x81simh\xc4\x81");
}
if (slot == 4) {
return EL_STR("agam\xc4\x81sittha");
}
return EL_STR("agama\xe1\xb9\x83su");
return 0;
}
el_val_t pi_gacchati_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("gamiss\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("gamissasi");
}
if (slot == 2) {
return EL_STR("gamissati");
}
if (slot == 3) {
return EL_STR("gamiss\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("gamissatha");
}
return EL_STR("gamissanti");
return 0;
}
el_val_t pi_passati_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("pass\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("passasi");
}
if (slot == 2) {
return EL_STR("passati");
}
if (slot == 3) {
return EL_STR("pass\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("passatha");
}
return EL_STR("passanti");
return 0;
}
el_val_t pi_passati_aorist(el_val_t slot) {
if (slot == 0) {
return EL_STR("addas\xc4\x81si\xe1\xb9\x83");
}
if (slot == 1) {
return EL_STR("addas\xc4\x81si");
}
if (slot == 2) {
return EL_STR("addas\xc4\x81si");
}
if (slot == 3) {
return EL_STR("addas\xc4\x81simh\xc4\x81");
}
if (slot == 4) {
return EL_STR("addas\xc4\x81sittha");
}
return EL_STR("addas\xc4\x81si\xe1\xb9\x83su");
return 0;
}
el_val_t pi_passati_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("dakkhiss\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("dakkhissasi");
}
if (slot == 2) {
return EL_STR("dakkhissati");
}
if (slot == 3) {
return EL_STR("dakkhiss\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("dakkhissatha");
}
return EL_STR("dakkhissanti");
return 0;
}
el_val_t pi_vadati_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("vad\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("vadasi");
}
if (slot == 2) {
return EL_STR("vadati");
}
if (slot == 3) {
return EL_STR("vad\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("vadatha");
}
return EL_STR("vadanti");
return 0;
}
el_val_t pi_vadati_aorist(el_val_t slot) {
if (slot == 0) {
return EL_STR("avad\xc4\x81si\xe1\xb9\x83");
}
if (slot == 1) {
return EL_STR("avad\xc4\x81si");
}
if (slot == 2) {
return EL_STR("avad\xc4\x81si");
}
if (slot == 3) {
return EL_STR("avad\xc4\x81simh\xc4\x81");
}
if (slot == 4) {
return EL_STR("avad\xc4\x81sittha");
}
return EL_STR("avad\xc4\x81si\xe1\xb9\x83su");
return 0;
}
el_val_t pi_vadati_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("vadiss\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("vadissasi");
}
if (slot == 2) {
return EL_STR("vadissati");
}
if (slot == 3) {
return EL_STR("vadiss\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("vadissatha");
}
return EL_STR("vadissanti");
return 0;
}
el_val_t pi_karoti_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("karomi");
}
if (slot == 1) {
return EL_STR("karosi");
}
if (slot == 2) {
return EL_STR("karoti");
}
if (slot == 3) {
return EL_STR("karoma");
}
if (slot == 4) {
return EL_STR("karotha");
}
return EL_STR("karonti");
return 0;
}
el_val_t pi_karoti_aorist(el_val_t slot) {
if (slot == 0) {
return EL_STR("ak\xc4\x81si\xe1\xb9\x83");
}
if (slot == 1) {
return EL_STR("ak\xc4\x81si");
}
if (slot == 2) {
return EL_STR("ak\xc4\x81si");
}
if (slot == 3) {
return EL_STR("ak\xc4\x81simh\xc4\x81");
}
if (slot == 4) {
return EL_STR("ak\xc4\x81sittha");
}
return EL_STR("ak\xc4\x81si\xe1\xb9\x83su");
return 0;
}
el_val_t pi_karoti_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("kariss\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("karissasi");
}
if (slot == 2) {
return EL_STR("karissati");
}
if (slot == 3) {
return EL_STR("kariss\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("karissatha");
}
return EL_STR("karissanti");
return 0;
}
el_val_t pi_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("hoti");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("gacchati");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("passati");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("vadati");
}
if (str_eq(verb, EL_STR("do"))) {
return EL_STR("karoti");
}
if (str_eq(verb, EL_STR("make"))) {
return EL_STR("karoti");
}
return verb;
return 0;
}
el_val_t pi_regular_root(el_val_t verb) {
if (pi_str_ends(verb, EL_STR("ati"))) {
return pi_drop(verb, 3);
}
if (pi_str_ends(verb, EL_STR("eti"))) {
return pi_drop(verb, 3);
}
return verb;
return 0;
}
el_val_t pi_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t v = pi_map_canonical(verb);
el_val_t slot = pi_slot(person, number);
if (str_eq(v, EL_STR("hoti"))) {
if (str_eq(tense, EL_STR("present"))) {
return pi_hoti_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return pi_hoti_aorist(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return pi_hoti_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("atthi"))) {
if (str_eq(tense, EL_STR("present"))) {
return pi_atthi_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return pi_hoti_aorist(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return pi_hoti_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("gacchati"))) {
if (str_eq(tense, EL_STR("present"))) {
return pi_gacchati_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return pi_gacchati_aorist(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return pi_gacchati_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("passati"))) {
if (str_eq(tense, EL_STR("present"))) {
return pi_passati_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return pi_passati_aorist(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return pi_passati_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("vadati"))) {
if (str_eq(tense, EL_STR("present"))) {
return pi_vadati_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return pi_vadati_aorist(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return pi_vadati_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("karoti"))) {
if (str_eq(tense, EL_STR("present"))) {
return pi_karoti_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return pi_karoti_aorist(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return pi_karoti_future(slot);
}
return v;
}
el_val_t root = pi_regular_root(v);
if (str_eq(tense, EL_STR("present"))) {
return el_str_concat(root, pi_present_ending(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return el_str_concat(root, pi_aorist_ending(slot));
}
if (str_eq(tense, EL_STR("future"))) {
return el_str_concat(root, pi_future_ending(slot));
}
return v;
return 0;
}
el_val_t pi_decline_a_masc_sg(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("o"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("\xe1\xb9\x83"));
}
if (str_eq(gram_case, EL_STR("instrumental"))) {
return el_str_concat(stem, EL_STR("ena"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81ya"));
}
if (str_eq(gram_case, EL_STR("ablative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("ssa"));
}
if (str_eq(gram_case, EL_STR("locative"))) {
return el_str_concat(stem, EL_STR("smi\xe1\xb9\x83"));
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return stem;
}
return el_str_concat(stem, EL_STR("o"));
return 0;
}
el_val_t pi_decline_a_masc_pl(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("e"));
}
if (str_eq(gram_case, EL_STR("instrumental"))) {
return el_str_concat(stem, EL_STR("ehi"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81na\xe1\xb9\x83"));
}
if (str_eq(gram_case, EL_STR("ablative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81na\xe1\xb9\x83"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("\xc4\x81na\xe1\xb9\x83"));
}
if (str_eq(gram_case, EL_STR("locative"))) {
return el_str_concat(stem, EL_STR("esu"));
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81"));
}
return el_str_concat(stem, EL_STR("\xc4\x81"));
return 0;
}
el_val_t pi_decline_a_fem_sg(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("a\xe1\xb9\x83"));
}
if (str_eq(gram_case, EL_STR("instrumental"))) {
return el_str_concat(stem, EL_STR("\xc4\x81ya"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81ya"));
}
if (str_eq(gram_case, EL_STR("ablative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81ya"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("\xc4\x81ya"));
}
if (str_eq(gram_case, EL_STR("locative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81ya\xe1\xb9\x83"));
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return el_str_concat(stem, EL_STR("e"));
}
return el_str_concat(stem, EL_STR("\xc4\x81"));
return 0;
}
el_val_t pi_decline_a_fem_pl(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81"));
}
if (str_eq(gram_case, EL_STR("instrumental"))) {
return el_str_concat(stem, EL_STR("\xc4\x81hi"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81na\xe1\xb9\x83"));
}
if (str_eq(gram_case, EL_STR("ablative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81na\xe1\xb9\x83"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("\xc4\x81na\xe1\xb9\x83"));
}
if (str_eq(gram_case, EL_STR("locative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81su"));
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81"));
}
return el_str_concat(stem, EL_STR("\xc4\x81"));
return 0;
}
el_val_t pi_detect_class(el_val_t noun) {
if (pi_str_ends(noun, EL_STR("o"))) {
return EL_STR("a_masc");
}
if (pi_str_ends(noun, EL_STR("\xc4\x81"))) {
return EL_STR("a_fem");
}
if (pi_str_ends(noun, EL_STR("a"))) {
return EL_STR("a_masc");
}
return EL_STR("a_masc");
return 0;
}
el_val_t pi_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t nclass = pi_detect_class(noun);
if (str_eq(nclass, EL_STR("a_masc"))) {
el_val_t stem = noun;
if (pi_str_ends(noun, EL_STR("o"))) {
stem = pi_drop(noun, 1);
}
if (pi_str_ends(noun, EL_STR("a"))) {
stem = pi_drop(noun, 1);
}
if (str_eq(number, EL_STR("singular"))) {
return pi_decline_a_masc_sg(stem, gram_case);
}
return pi_decline_a_masc_pl(stem, gram_case);
}
if (str_eq(nclass, EL_STR("a_fem"))) {
el_val_t stem = noun;
if (pi_str_ends(noun, EL_STR("\xc4\x81"))) {
stem = pi_drop(noun, 1);
}
if (str_eq(number, EL_STR("singular"))) {
return pi_decline_a_fem_sg(stem, gram_case);
}
return pi_decline_a_fem_pl(stem, gram_case);
}
return noun;
return 0;
}
el_val_t pi_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
return pi_decline(noun, gram_case, number);
return 0;
}
Generated Vendored
+34
View File
@@ -0,0 +1,34 @@
// auto-generated by elc --emit-header — do not edit
extern fn pi_str_ends(s: String, suf: String) -> Bool
extern fn pi_drop(s: String, n: Int) -> String
extern fn pi_last_char(s: String) -> String
extern fn pi_slot(person: String, number: String) -> Int
extern fn pi_present_ending(slot: Int) -> String
extern fn pi_aorist_ending(slot: Int) -> String
extern fn pi_future_ending(slot: Int) -> String
extern fn pi_hoti_present(slot: Int) -> String
extern fn pi_atthi_present(slot: Int) -> String
extern fn pi_hoti_aorist(slot: Int) -> String
extern fn pi_hoti_future(slot: Int) -> String
extern fn pi_gacchati_present(slot: Int) -> String
extern fn pi_gacchati_aorist(slot: Int) -> String
extern fn pi_gacchati_future(slot: Int) -> String
extern fn pi_passati_present(slot: Int) -> String
extern fn pi_passati_aorist(slot: Int) -> String
extern fn pi_passati_future(slot: Int) -> String
extern fn pi_vadati_present(slot: Int) -> String
extern fn pi_vadati_aorist(slot: Int) -> String
extern fn pi_vadati_future(slot: Int) -> String
extern fn pi_karoti_present(slot: Int) -> String
extern fn pi_karoti_aorist(slot: Int) -> String
extern fn pi_karoti_future(slot: Int) -> String
extern fn pi_map_canonical(verb: String) -> String
extern fn pi_regular_root(verb: String) -> String
extern fn pi_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn pi_decline_a_masc_sg(stem: String, gram_case: String) -> String
extern fn pi_decline_a_masc_pl(stem: String, gram_case: String) -> String
extern fn pi_decline_a_fem_sg(stem: String, gram_case: String) -> String
extern fn pi_decline_a_fem_pl(stem: String, gram_case: String) -> String
extern fn pi_detect_class(noun: String) -> String
extern fn pi_decline(noun: String, gram_case: String, number: String) -> String
extern fn pi_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
Generated Vendored
+1245
View File
File diff suppressed because it is too large Load Diff
Generated Vendored
+14
View File
@@ -0,0 +1,14 @@
// auto-generated by elc --emit-header — do not edit
extern fn ru_gender(noun: String) -> String
extern fn ru_stem_type(noun: String, gender: String) -> String
extern fn ru_noun_case(noun: String, gender: String, gram_case: String, number: String) -> String
extern fn ru_decline_regular(noun: String, gender: String, stype: String, gram_case: String, number: String) -> String
extern fn ru_decline_masc(noun: String, stype: String, gram_case: String, number: String) -> String
extern fn ru_decline_fem(noun: String, stype: String, gram_case: String, number: String) -> String
extern fn ru_decline_neut(noun: String, stype: String, gram_case: String, number: String) -> String
extern fn ru_past_agree(verb_stem: String, gender: String, number: String) -> String
extern fn ru_conjugate_1st(stem: String, tense: String, person: String, number: String) -> String
extern fn ru_conjugate_2nd(stem: String, tense: String, person: String, number: String) -> String
extern fn ru_irregular(verb: String, tense: String, person: String, number: String) -> String
extern fn ru_past_stem(verb: String) -> String
extern fn ru_conjugate(verb: String, tense: String, person: String, number: String, gender: String) -> String
Generated Vendored
+815
View File
@@ -0,0 +1,815 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t sa_str_ends(el_val_t s, el_val_t suf);
el_val_t sa_str_drop_last(el_val_t s, el_val_t n);
el_val_t sa_slot(el_val_t person, el_val_t number);
el_val_t sa_map_canonical(el_val_t verb);
el_val_t sa_as_present(el_val_t slot);
el_val_t sa_as_past(el_val_t slot);
el_val_t sa_as_future(el_val_t slot);
el_val_t sa_bhu_present(el_val_t slot);
el_val_t sa_bhu_past(el_val_t slot);
el_val_t sa_bhu_future(el_val_t slot);
el_val_t sa_gam_present(el_val_t slot);
el_val_t sa_gam_past(el_val_t slot);
el_val_t sa_gam_future(el_val_t slot);
el_val_t sa_drs_present(el_val_t slot);
el_val_t sa_drs_past(el_val_t slot);
el_val_t sa_drs_future(el_val_t slot);
el_val_t sa_vad_present(el_val_t slot);
el_val_t sa_vad_past(el_val_t slot);
el_val_t sa_vad_future(el_val_t slot);
el_val_t sa_kr_present(el_val_t slot);
el_val_t sa_kr_past(el_val_t slot);
el_val_t sa_kr_future(el_val_t slot);
el_val_t sa_class1_present_ending(el_val_t slot);
el_val_t sa_class1_past_ending(el_val_t slot);
el_val_t sa_class1_future_ending(el_val_t slot);
el_val_t sa_class1_conjugate(el_val_t stem, el_val_t tense, el_val_t slot);
el_val_t sa_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t sa_decline_a_stem_sg(el_val_t stem, el_val_t gram_case);
el_val_t sa_decline_a_stem_pl(el_val_t stem, el_val_t gram_case);
el_val_t sa_decline_aa_stem_sg(el_val_t stem, el_val_t gram_case);
el_val_t sa_decline_aa_stem_pl(el_val_t stem, el_val_t gram_case);
el_val_t sa_stem_type(el_val_t noun);
el_val_t sa_extract_stem(el_val_t noun, el_val_t stype);
el_val_t sa_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t sa_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t sa_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t sa_str_drop_last(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t sa_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t sa_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("as");
}
if (str_eq(verb, EL_STR("become"))) {
return EL_STR("bhu");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("gam");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("drs");
}
if (str_eq(verb, EL_STR("speak"))) {
return EL_STR("vad");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("vad");
}
if (str_eq(verb, EL_STR("do"))) {
return EL_STR("kr");
}
if (str_eq(verb, EL_STR("make"))) {
return EL_STR("kr");
}
return verb;
return 0;
}
el_val_t sa_as_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("asmi");
}
if (slot == 1) {
return EL_STR("asi");
}
if (slot == 2) {
return EL_STR("asti");
}
if (slot == 3) {
return EL_STR("sma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("stha");
}
return EL_STR("santi");
return 0;
}
el_val_t sa_as_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xc4\x81sam");
}
if (slot == 1) {
return EL_STR("\xc4\x81s\xc4\xab\xe1\xb8\xa5");
}
if (slot == 2) {
return EL_STR("\xc4\x81s\xc4\xabt");
}
if (slot == 3) {
return EL_STR("\xc4\x81sma");
}
if (slot == 4) {
return EL_STR("\xc4\x81sta");
}
return EL_STR("\xc4\x81san");
return 0;
}
el_val_t sa_as_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("bhavi\xe1\xb9\xa3y\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("bhavi\xe1\xb9\xa3yasi");
}
if (slot == 2) {
return EL_STR("bhavi\xe1\xb9\xa3yati");
}
if (slot == 3) {
return EL_STR("bhavi\xe1\xb9\xa3y\xc4\x81ma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("bhavi\xe1\xb9\xa3yatha");
}
return EL_STR("bhavi\xe1\xb9\xa3yanti");
return 0;
}
el_val_t sa_bhu_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("bhav\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("bhavasi");
}
if (slot == 2) {
return EL_STR("bhavati");
}
if (slot == 3) {
return EL_STR("bhav\xc4\x81ma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("bhavatha");
}
return EL_STR("bhavanti");
return 0;
}
el_val_t sa_bhu_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("abhavam");
}
if (slot == 1) {
return EL_STR("abhava\xe1\xb8\xa5");
}
if (slot == 2) {
return EL_STR("abhavat");
}
if (slot == 3) {
return EL_STR("abhav\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("abhavata");
}
return EL_STR("abhavan");
return 0;
}
el_val_t sa_bhu_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("bhavi\xe1\xb9\xa3y\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("bhavi\xe1\xb9\xa3yasi");
}
if (slot == 2) {
return EL_STR("bhavi\xe1\xb9\xa3yati");
}
if (slot == 3) {
return EL_STR("bhavi\xe1\xb9\xa3y\xc4\x81ma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("bhavi\xe1\xb9\xa3yatha");
}
return EL_STR("bhavi\xe1\xb9\xa3yanti");
return 0;
}
el_val_t sa_gam_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("gacch\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("gacchasi");
}
if (slot == 2) {
return EL_STR("gacchati");
}
if (slot == 3) {
return EL_STR("gacch\xc4\x81ma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("gacchatha");
}
return EL_STR("gacchanti");
return 0;
}
el_val_t sa_gam_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("agaccham");
}
if (slot == 1) {
return EL_STR("agaccha\xe1\xb8\xa5");
}
if (slot == 2) {
return EL_STR("agacchat");
}
if (slot == 3) {
return EL_STR("agacch\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("agacchata");
}
return EL_STR("agacchan");
return 0;
}
el_val_t sa_gam_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("gami\xe1\xb9\xa3y\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("gami\xe1\xb9\xa3yasi");
}
if (slot == 2) {
return EL_STR("gami\xe1\xb9\xa3yati");
}
if (slot == 3) {
return EL_STR("gami\xe1\xb9\xa3y\xc4\x81ma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("gami\xe1\xb9\xa3yatha");
}
return EL_STR("gami\xe1\xb9\xa3yanti");
return 0;
}
el_val_t sa_drs_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("pa\xc5\x9by\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("pa\xc5\x9byasi");
}
if (slot == 2) {
return EL_STR("pa\xc5\x9byati");
}
if (slot == 3) {
return EL_STR("pa\xc5\x9by\xc4\x81ma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("pa\xc5\x9byatha");
}
return EL_STR("pa\xc5\x9byanti");
return 0;
}
el_val_t sa_drs_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("apa\xc5\x9byam");
}
if (slot == 1) {
return EL_STR("apa\xc5\x9bya\xe1\xb8\xa5");
}
if (slot == 2) {
return EL_STR("apa\xc5\x9byat");
}
if (slot == 3) {
return EL_STR("apa\xc5\x9by\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("apa\xc5\x9byata");
}
return EL_STR("apa\xc5\x9byan");
return 0;
}
el_val_t sa_drs_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("drak\xe1\xb9\xa3y\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("drak\xe1\xb9\xa3yasi");
}
if (slot == 2) {
return EL_STR("drak\xe1\xb9\xa3yati");
}
if (slot == 3) {
return EL_STR("drak\xe1\xb9\xa3y\xc4\x81ma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("drak\xe1\xb9\xa3yatha");
}
return EL_STR("drak\xe1\xb9\xa3yanti");
return 0;
}
el_val_t sa_vad_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("vad\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("vadasi");
}
if (slot == 2) {
return EL_STR("vadati");
}
if (slot == 3) {
return EL_STR("vad\xc4\x81ma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("vadatha");
}
return EL_STR("vadanti");
return 0;
}
el_val_t sa_vad_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("avadam");
}
if (slot == 1) {
return EL_STR("avada\xe1\xb8\xa5");
}
if (slot == 2) {
return EL_STR("avadat");
}
if (slot == 3) {
return EL_STR("avad\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("avadata");
}
return EL_STR("avadan");
return 0;
}
el_val_t sa_vad_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("vadi\xe1\xb9\xa3y\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("vadi\xe1\xb9\xa3yasi");
}
if (slot == 2) {
return EL_STR("vadi\xe1\xb9\xa3yati");
}
if (slot == 3) {
return EL_STR("vadi\xe1\xb9\xa3y\xc4\x81ma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("vadi\xe1\xb9\xa3yatha");
}
return EL_STR("vadi\xe1\xb9\xa3yanti");
return 0;
}
el_val_t sa_kr_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("karomi");
}
if (slot == 1) {
return EL_STR("karo\xe1\xb9\xa3i");
}
if (slot == 2) {
return EL_STR("karoti");
}
if (slot == 3) {
return EL_STR("kurma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("kurutha");
}
return EL_STR("kurvanti");
return 0;
}
el_val_t sa_kr_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("akaravam");
}
if (slot == 1) {
return EL_STR("akaroda\xe1\xb8\xa5");
}
if (slot == 2) {
return EL_STR("akarot");
}
if (slot == 3) {
return EL_STR("akurma");
}
if (slot == 4) {
return EL_STR("akuruta");
}
return EL_STR("akurvan");
return 0;
}
el_val_t sa_kr_future(el_val_t slot) {
if (slot == 0) {
return EL_STR("kari\xe1\xb9\xa3y\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("kari\xe1\xb9\xa3yasi");
}
if (slot == 2) {
return EL_STR("kari\xe1\xb9\xa3yati");
}
if (slot == 3) {
return EL_STR("kari\xe1\xb9\xa3y\xc4\x81ma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("kari\xe1\xb9\xa3yatha");
}
return EL_STR("kari\xe1\xb9\xa3yanti");
return 0;
}
el_val_t sa_class1_present_ending(el_val_t slot) {
if (slot == 0) {
return EL_STR("\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("asi");
}
if (slot == 2) {
return EL_STR("ati");
}
if (slot == 3) {
return EL_STR("\xc4\x81ma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("atha");
}
return EL_STR("anti");
return 0;
}
el_val_t sa_class1_past_ending(el_val_t slot) {
if (slot == 0) {
return EL_STR("am");
}
if (slot == 1) {
return EL_STR("a\xe1\xb8\xa5");
}
if (slot == 2) {
return EL_STR("at");
}
if (slot == 3) {
return EL_STR("\xc4\x81ma");
}
if (slot == 4) {
return EL_STR("ata");
}
return EL_STR("an");
return 0;
}
el_val_t sa_class1_future_ending(el_val_t slot) {
if (slot == 0) {
return EL_STR("i\xe1\xb9\xa3y\xc4\x81mi");
}
if (slot == 1) {
return EL_STR("i\xe1\xb9\xa3yasi");
}
if (slot == 2) {
return EL_STR("i\xe1\xb9\xa3yati");
}
if (slot == 3) {
return EL_STR("i\xe1\xb9\xa3y\xc4\x81ma\xe1\xb8\xa5");
}
if (slot == 4) {
return EL_STR("i\xe1\xb9\xa3yatha");
}
return EL_STR("i\xe1\xb9\xa3yanti");
return 0;
}
el_val_t sa_class1_conjugate(el_val_t stem, el_val_t tense, el_val_t slot) {
if (str_eq(tense, EL_STR("present"))) {
return el_str_concat(stem, sa_class1_present_ending(slot));
}
if (str_eq(tense, EL_STR("past"))) {
return el_str_concat(el_str_concat(EL_STR("a"), stem), sa_class1_past_ending(slot));
}
if (str_eq(tense, EL_STR("future"))) {
return el_str_concat(stem, sa_class1_future_ending(slot));
}
return stem;
return 0;
}
el_val_t sa_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t v = sa_map_canonical(verb);
el_val_t slot = sa_slot(person, number);
if (str_eq(v, EL_STR("as"))) {
if (str_eq(tense, EL_STR("present"))) {
return sa_as_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sa_as_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return sa_as_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("bhu"))) {
if (str_eq(tense, EL_STR("present"))) {
return sa_bhu_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sa_bhu_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return sa_bhu_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("gam"))) {
if (str_eq(tense, EL_STR("present"))) {
return sa_gam_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sa_gam_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return sa_gam_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("drs"))) {
if (str_eq(tense, EL_STR("present"))) {
return sa_drs_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sa_drs_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return sa_drs_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("vad"))) {
if (str_eq(tense, EL_STR("present"))) {
return sa_vad_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sa_vad_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return sa_vad_future(slot);
}
return v;
}
if (str_eq(v, EL_STR("kr"))) {
if (str_eq(tense, EL_STR("present"))) {
return sa_kr_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sa_kr_past(slot);
}
if (str_eq(tense, EL_STR("future"))) {
return sa_kr_future(slot);
}
return v;
}
return sa_class1_conjugate(v, tense, slot);
return 0;
}
el_val_t sa_decline_a_stem_sg(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("\xe1\xb8\xa5"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("m"));
}
if (str_eq(gram_case, EL_STR("instrumental"))) {
return el_str_concat(stem, EL_STR("ena"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81ya"));
}
if (str_eq(gram_case, EL_STR("ablative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81t"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("sya"));
}
if (str_eq(gram_case, EL_STR("locative"))) {
return el_str_concat(stem, EL_STR("e"));
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return stem;
}
return stem;
return 0;
}
el_val_t sa_decline_a_stem_pl(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81\xe1\xb8\xa5"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81n"));
}
if (str_eq(gram_case, EL_STR("instrumental"))) {
return el_str_concat(stem, EL_STR("ai\xe1\xb8\xa5"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("ebhya\xe1\xb8\xa5"));
}
if (str_eq(gram_case, EL_STR("ablative"))) {
return el_str_concat(stem, EL_STR("ebhya\xe1\xb8\xa5"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("\xc4\x81n\xc4\x81m"));
}
if (str_eq(gram_case, EL_STR("locative"))) {
return el_str_concat(stem, EL_STR("e\xe1\xb9\xa3u"));
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return el_str_concat(stem, EL_STR("\xc4\x81\xe1\xb8\xa5"));
}
return el_str_concat(stem, EL_STR("\xc4\x81\xe1\xb8\xa5"));
return 0;
}
el_val_t sa_decline_aa_stem_sg(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("\xc4\xab"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("\xc4\xabm"));
}
if (str_eq(gram_case, EL_STR("instrumental"))) {
return el_str_concat(stem, EL_STR("y\xc4\x81"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("yai"));
}
if (str_eq(gram_case, EL_STR("ablative"))) {
return el_str_concat(stem, EL_STR("y\xc4\x81\xe1\xb8\xa5"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("y\xc4\x81\xe1\xb8\xa5"));
}
if (str_eq(gram_case, EL_STR("locative"))) {
return el_str_concat(stem, EL_STR("y\xc4\x81m"));
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return el_str_concat(stem, EL_STR("i"));
}
return el_str_concat(stem, EL_STR("\xc4\xab"));
return 0;
}
el_val_t sa_decline_aa_stem_pl(el_val_t stem, el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(stem, EL_STR("ya\xe1\xb8\xa5"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(stem, EL_STR("\xc4\xab\xe1\xb8\xa5"));
}
if (str_eq(gram_case, EL_STR("instrumental"))) {
return el_str_concat(stem, EL_STR("\xc4\xab""bhi\xe1\xb8\xa5"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(stem, EL_STR("\xc4\xab""bhya\xe1\xb8\xa5"));
}
if (str_eq(gram_case, EL_STR("ablative"))) {
return el_str_concat(stem, EL_STR("\xc4\xab""bhya\xe1\xb8\xa5"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(stem, EL_STR("\xc4\xab\xe1\xb9\x87\xc4\x81m"));
}
if (str_eq(gram_case, EL_STR("locative"))) {
return el_str_concat(stem, EL_STR("\xc4\xab\xe1\xb9\xa3u"));
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return el_str_concat(stem, EL_STR("ya\xe1\xb8\xa5"));
}
return el_str_concat(stem, EL_STR("ya\xe1\xb8\xa5"));
return 0;
}
el_val_t sa_stem_type(el_val_t noun) {
if (sa_str_ends(noun, EL_STR("\xc4\x81"))) {
return EL_STR("aa");
}
if (sa_str_ends(noun, EL_STR("\xc4\xab"))) {
return EL_STR("aa");
}
if (sa_str_ends(noun, EL_STR("a\xe1\xb8\xa5"))) {
return EL_STR("a");
}
if (sa_str_ends(noun, EL_STR("a"))) {
return EL_STR("a");
}
return EL_STR("unknown");
return 0;
}
el_val_t sa_extract_stem(el_val_t noun, el_val_t stype) {
el_val_t n = str_len(noun);
if (str_eq(stype, EL_STR("a"))) {
if (sa_str_ends(noun, EL_STR("a\xe1\xb8\xa5"))) {
return str_slice(noun, 0, (n - 4));
}
return str_slice(noun, 0, (n - 1));
}
if (str_eq(stype, EL_STR("aa"))) {
return str_slice(noun, 0, (n - 2));
}
return noun;
return 0;
}
el_val_t sa_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t stype = sa_stem_type(noun);
if (str_eq(stype, EL_STR("a"))) {
el_val_t stem = sa_extract_stem(noun, EL_STR("a"));
if (str_eq(number, EL_STR("singular"))) {
return sa_decline_a_stem_sg(stem, gram_case);
}
return sa_decline_a_stem_pl(stem, gram_case);
}
if (str_eq(stype, EL_STR("aa"))) {
el_val_t stem = sa_extract_stem(noun, EL_STR("aa"));
if (str_eq(number, EL_STR("singular"))) {
return sa_decline_aa_stem_sg(stem, gram_case);
}
return sa_decline_aa_stem_pl(stem, gram_case);
}
return noun;
return 0;
}
el_val_t sa_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
return sa_decline(noun, gram_case, number);
return 0;
}
Generated Vendored
+36
View File
@@ -0,0 +1,36 @@
// auto-generated by elc --emit-header — do not edit
extern fn sa_str_ends(s: String, suf: String) -> Bool
extern fn sa_str_drop_last(s: String, n: Int) -> String
extern fn sa_slot(person: String, number: String) -> Int
extern fn sa_map_canonical(verb: String) -> String
extern fn sa_as_present(slot: Int) -> String
extern fn sa_as_past(slot: Int) -> String
extern fn sa_as_future(slot: Int) -> String
extern fn sa_bhu_present(slot: Int) -> String
extern fn sa_bhu_past(slot: Int) -> String
extern fn sa_bhu_future(slot: Int) -> String
extern fn sa_gam_present(slot: Int) -> String
extern fn sa_gam_past(slot: Int) -> String
extern fn sa_gam_future(slot: Int) -> String
extern fn sa_drs_present(slot: Int) -> String
extern fn sa_drs_past(slot: Int) -> String
extern fn sa_drs_future(slot: Int) -> String
extern fn sa_vad_present(slot: Int) -> String
extern fn sa_vad_past(slot: Int) -> String
extern fn sa_vad_future(slot: Int) -> String
extern fn sa_kr_present(slot: Int) -> String
extern fn sa_kr_past(slot: Int) -> String
extern fn sa_kr_future(slot: Int) -> String
extern fn sa_class1_present_ending(slot: Int) -> String
extern fn sa_class1_past_ending(slot: Int) -> String
extern fn sa_class1_future_ending(slot: Int) -> String
extern fn sa_class1_conjugate(stem: String, tense: String, slot: Int) -> String
extern fn sa_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn sa_decline_a_stem_sg(stem: String, gram_case: String) -> String
extern fn sa_decline_a_stem_pl(stem: String, gram_case: String) -> String
extern fn sa_decline_aa_stem_sg(stem: String, gram_case: String) -> String
extern fn sa_decline_aa_stem_pl(stem: String, gram_case: String) -> String
extern fn sa_stem_type(noun: String) -> String
extern fn sa_extract_stem(noun: String, stype: String) -> String
extern fn sa_decline(noun: String, gram_case: String, number: String) -> String
extern fn sa_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
Generated Vendored
+571
View File
@@ -0,0 +1,571 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t sga_drop(el_val_t s, el_val_t n);
el_val_t sga_first(el_val_t s);
el_val_t sga_rest(el_val_t s);
el_val_t sga_slot(el_val_t person, el_val_t number);
el_val_t sga_lenite(el_val_t word);
el_val_t sga_copula_present(el_val_t slot);
el_val_t sga_bith_present(el_val_t slot);
el_val_t sga_bith_past(el_val_t slot);
el_val_t sga_teit_present(el_val_t slot);
el_val_t sga_teit_past(el_val_t slot);
el_val_t sga_gaibid_present(el_val_t slot);
el_val_t sga_adci_present(el_val_t slot);
el_val_t sga_asbeir_present(el_val_t slot);
el_val_t sga_map_canonical(el_val_t verb);
el_val_t sga_ai_present(el_val_t stem, el_val_t slot);
el_val_t sga_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t sga_decline_ostem(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t sga_decline_astem(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t sga_detect_gender(el_val_t noun);
el_val_t sga_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t sga_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t sga_drop(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t sga_first(el_val_t s) {
if (str_len(s) == 0) {
return EL_STR("");
}
return str_slice(s, 0, 1);
return 0;
}
el_val_t sga_rest(el_val_t s) {
el_val_t n = str_len(s);
if (n <= 1) {
return EL_STR("");
}
return str_slice(s, 1, n);
return 0;
}
el_val_t sga_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t sga_lenite(el_val_t word) {
el_val_t init = sga_first(word);
el_val_t tail = sga_rest(word);
if (str_eq(init, EL_STR("b"))) {
return el_str_concat(EL_STR("bh"), tail);
}
if (str_eq(init, EL_STR("c"))) {
return el_str_concat(EL_STR("ch"), tail);
}
if (str_eq(init, EL_STR("d"))) {
return el_str_concat(EL_STR("dh"), tail);
}
if (str_eq(init, EL_STR("f"))) {
return el_str_concat(EL_STR("fh"), tail);
}
if (str_eq(init, EL_STR("g"))) {
return el_str_concat(EL_STR("gh"), tail);
}
if (str_eq(init, EL_STR("m"))) {
return el_str_concat(EL_STR("mh"), tail);
}
if (str_eq(init, EL_STR("p"))) {
return el_str_concat(EL_STR("ph"), tail);
}
if (str_eq(init, EL_STR("s"))) {
return el_str_concat(EL_STR("sh"), tail);
}
if (str_eq(init, EL_STR("t"))) {
return el_str_concat(EL_STR("th"), tail);
}
return word;
return 0;
}
el_val_t sga_copula_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("am");
}
if (slot == 1) {
return EL_STR("at");
}
if (slot == 2) {
return EL_STR("is");
}
if (slot == 3) {
return EL_STR("am");
}
if (slot == 4) {
return EL_STR("adib");
}
return EL_STR("it");
return 0;
}
el_val_t sga_bith_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("am");
}
if (slot == 1) {
return EL_STR("at");
}
if (slot == 2) {
return EL_STR("is");
}
if (slot == 3) {
return EL_STR("am");
}
if (slot == 4) {
return EL_STR("adib");
}
return EL_STR("at");
return 0;
}
el_val_t sga_bith_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("ba");
}
if (slot == 1) {
return EL_STR("ba");
}
if (slot == 2) {
return EL_STR("ba");
}
if (slot == 3) {
return EL_STR("b\xc3\xa1mmar");
}
if (slot == 4) {
return EL_STR("b\xc3\xa1""daid");
}
return EL_STR("batar");
return 0;
}
el_val_t sga_teit_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("t\xc3\xad""agu");
}
if (slot == 1) {
return EL_STR("t\xc3\xa9it");
}
if (slot == 2) {
return EL_STR("t\xc3\xa9it");
}
if (slot == 3) {
return EL_STR("t\xc3\xad""agmai");
}
if (slot == 4) {
return EL_STR("t\xc3\xad""agid");
}
return EL_STR("t\xc3\xad""agat");
return 0;
}
el_val_t sga_teit_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("lod");
}
if (slot == 1) {
return EL_STR("lod");
}
if (slot == 2) {
return EL_STR("luid");
}
if (slot == 3) {
return EL_STR("lodmar");
}
if (slot == 4) {
return EL_STR("lodaid");
}
return EL_STR("lotar");
return 0;
}
el_val_t sga_gaibid_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("gaibim");
}
if (slot == 1) {
return EL_STR("gaibi");
}
if (slot == 2) {
return EL_STR("gaibid");
}
if (slot == 3) {
return EL_STR("gaibmi");
}
if (slot == 4) {
return EL_STR("gaibthe");
}
return EL_STR("gaibid");
return 0;
}
el_val_t sga_adci_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("ad\xc2\xb7""ciu");
}
if (slot == 1) {
return EL_STR("ad\xc2\xb7""c\xc3\xad");
}
if (slot == 2) {
return EL_STR("ad\xc2\xb7""c\xc3\xad");
}
if (slot == 3) {
return EL_STR("ad\xc2\xb7""c\xc3\xadmi");
}
if (slot == 4) {
return EL_STR("ad\xc2\xb7""c\xc3\xadthe");
}
return EL_STR("ad\xc2\xb7""ciat");
return 0;
}
el_val_t sga_asbeir_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("as\xc2\xb7""biur");
}
if (slot == 1) {
return EL_STR("as\xc2\xb7""beir");
}
if (slot == 2) {
return EL_STR("as\xc2\xb7""beir");
}
if (slot == 3) {
return EL_STR("as\xc2\xb7""beram");
}
if (slot == 4) {
return EL_STR("as\xc2\xb7""berid");
}
return EL_STR("as\xc2\xb7""berat");
return 0;
}
el_val_t sga_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("is");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("t\xc3\xa9it");
}
if (str_eq(verb, EL_STR("take"))) {
return EL_STR("gaibid");
}
if (str_eq(verb, EL_STR("hold"))) {
return EL_STR("gaibid");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("ad\xc2\xb7""c\xc3\xad");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("as\xc2\xb7""beir");
}
return verb;
return 0;
}
el_val_t sga_ai_present(el_val_t stem, el_val_t slot) {
if (slot == 0) {
return el_str_concat(stem, EL_STR("aim"));
}
if (slot == 1) {
return el_str_concat(stem, EL_STR("ai"));
}
if (slot == 2) {
return el_str_concat(stem, EL_STR("aid"));
}
if (slot == 3) {
return el_str_concat(stem, EL_STR("am"));
}
if (slot == 4) {
return el_str_concat(stem, EL_STR("aid"));
}
return el_str_concat(stem, EL_STR("at"));
return 0;
}
el_val_t sga_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t v = sga_map_canonical(verb);
el_val_t slot = sga_slot(person, number);
if (str_eq(v, EL_STR("is"))) {
if (str_eq(tense, EL_STR("present"))) {
return sga_copula_present(slot);
}
return EL_STR("ba");
}
if (str_eq(v, EL_STR("bith"))) {
if (str_eq(tense, EL_STR("present"))) {
return sga_bith_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sga_bith_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("t\xc3\xa9it"))) {
if (str_eq(tense, EL_STR("present"))) {
return sga_teit_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sga_teit_past(slot);
}
return v;
}
if (str_eq(v, EL_STR("gaibid"))) {
if (str_eq(tense, EL_STR("present"))) {
return sga_gaibid_present(slot);
}
return EL_STR("gab");
}
if (str_eq(v, EL_STR("ad\xc2\xb7""c\xc3\xad"))) {
if (str_eq(tense, EL_STR("present"))) {
return sga_adci_present(slot);
}
return v;
}
if (str_eq(v, EL_STR("as\xc2\xb7""beir"))) {
if (str_eq(tense, EL_STR("present"))) {
return sga_asbeir_present(slot);
}
return v;
}
if (str_ends_with(v, EL_STR("id"))) {
el_val_t stem = sga_drop(v, 2);
if (str_eq(tense, EL_STR("present"))) {
return sga_ai_present(stem, slot);
}
return v;
}
return v;
return 0;
}
el_val_t sga_decline_ostem(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(noun, EL_STR("fer"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("fer");
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return EL_STR("fhir");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("fer");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("fir");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("fiur");
}
return EL_STR("fer");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("fir");
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return EL_STR("firu");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("firu");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("fer");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("feraib");
}
return EL_STR("fir");
}
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return sga_lenite(noun);
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("u"));
}
return noun;
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(noun, EL_STR("i"));
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return el_str_concat(noun, EL_STR("u"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(noun, EL_STR("u"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("aib"));
}
return el_str_concat(noun, EL_STR("i"));
return 0;
}
el_val_t sga_decline_astem(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(noun, EL_STR("ben"))) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("ben");
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return EL_STR("ben");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("bein");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("mn\xc3\xa1");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("mn\xc3\xa1ib");
}
return EL_STR("ben");
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return EL_STR("mn\xc3\xa1");
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return EL_STR("mn\xc3\xa1");
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return EL_STR("mn\xc3\xa1");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("ban");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("mn\xc3\xa1ib");
}
return EL_STR("mn\xc3\xa1");
}
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(noun, EL_STR("i"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("e"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("aib"));
}
return noun;
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(noun, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("vocative"))) {
return el_str_concat(noun, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(noun, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return noun;
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("aib"));
}
return el_str_concat(noun, EL_STR("a"));
return 0;
}
el_val_t sga_detect_gender(el_val_t noun) {
if (str_eq(noun, EL_STR("ben"))) {
return EL_STR("feminine");
}
if (str_eq(noun, EL_STR("mn\xc3\xa1"))) {
return EL_STR("feminine");
}
return EL_STR("masculine");
return 0;
}
el_val_t sga_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t gender = sga_detect_gender(noun);
if (str_eq(gender, EL_STR("masculine"))) {
return sga_decline_ostem(noun, gram_case, number);
}
if (str_eq(gender, EL_STR("feminine"))) {
return sga_decline_astem(noun, gram_case, number);
}
return noun;
return 0;
}
el_val_t sga_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
el_val_t base = sga_decline(noun, gram_case, number);
if (!str_eq(definite, EL_STR("true"))) {
return base;
}
return el_str_concat(EL_STR("in "), base);
return 0;
}
Generated Vendored
+22
View File
@@ -0,0 +1,22 @@
// auto-generated by elc --emit-header — do not edit
extern fn sga_drop(s: String, n: Int) -> String
extern fn sga_first(s: String) -> String
extern fn sga_rest(s: String) -> String
extern fn sga_slot(person: String, number: String) -> Int
extern fn sga_lenite(word: String) -> String
extern fn sga_copula_present(slot: Int) -> String
extern fn sga_bith_present(slot: Int) -> String
extern fn sga_bith_past(slot: Int) -> String
extern fn sga_teit_present(slot: Int) -> String
extern fn sga_teit_past(slot: Int) -> String
extern fn sga_gaibid_present(slot: Int) -> String
extern fn sga_adci_present(slot: Int) -> String
extern fn sga_asbeir_present(slot: Int) -> String
extern fn sga_map_canonical(verb: String) -> String
extern fn sga_ai_present(stem: String, slot: Int) -> String
extern fn sga_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn sga_decline_ostem(noun: String, gram_case: String, number: String) -> String
extern fn sga_decline_astem(noun: String, gram_case: String, number: String) -> String
extern fn sga_detect_gender(noun: String) -> String
extern fn sga_decline(noun: String, gram_case: String, number: String) -> String
extern fn sga_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
Generated Vendored
+591
View File
@@ -0,0 +1,591 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t sux_str_ends(el_val_t s, el_val_t suf);
el_val_t sux_str_drop_last(el_val_t s, el_val_t n);
el_val_t sux_str_last_char(el_val_t s);
el_val_t sux_str_last2(el_val_t s);
el_val_t sux_slot(el_val_t person, el_val_t number);
el_val_t sux_ergative_suffix(el_val_t person, el_val_t number);
el_val_t sux_absolutive_suffix(el_val_t person, el_val_t number);
el_val_t sux_map_canonical(el_val_t verb);
el_val_t sux_personal_suffix(el_val_t slot);
el_val_t sux_me_present(el_val_t slot);
el_val_t sux_me_past(el_val_t slot);
el_val_t sux_dug4_present(el_val_t slot);
el_val_t sux_dug4_past(el_val_t slot);
el_val_t sux_du_present(el_val_t slot);
el_val_t sux_du_past(el_val_t slot);
el_val_t sux_igibar_present(el_val_t slot);
el_val_t sux_igibar_past(el_val_t slot);
el_val_t sux_ak_present(el_val_t slot);
el_val_t sux_ak_past(el_val_t slot);
el_val_t sux_tum2_present(el_val_t slot);
el_val_t sux_tum2_past(el_val_t slot);
el_val_t sux_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t sux_is_animate(el_val_t noun);
el_val_t sux_case_suffix(el_val_t gram_case);
el_val_t sux_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t sux_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t sux_verb_chain(el_val_t agent, el_val_t verb, el_val_t patient, el_val_t tense);
el_val_t sux_realize_sentence(el_val_t intent, el_val_t agent, el_val_t predicate, el_val_t patient, el_val_t tense);
el_val_t sux_str_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t sux_str_drop_last(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t sux_str_last_char(el_val_t s) {
el_val_t n = str_len(s);
if (n == 0) {
return EL_STR("");
}
return str_slice(s, (n - 1), n);
return 0;
}
el_val_t sux_str_last2(el_val_t s) {
el_val_t n = str_len(s);
if (n < 2) {
return s;
}
return str_slice(s, (n - 2), n);
return 0;
}
el_val_t sux_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t sux_ergative_suffix(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return EL_STR("-en");
}
return EL_STR("-enden");
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return EL_STR("-en");
}
return EL_STR("-enzen");
}
if (str_eq(number, EL_STR("singular"))) {
return EL_STR("-e");
}
return EL_STR("-e\xc5\xa1");
return 0;
}
el_val_t sux_absolutive_suffix(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return EL_STR("-en");
}
return EL_STR("-enden");
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return EL_STR("-en");
}
return EL_STR("-enzen");
}
return EL_STR("");
return 0;
}
el_val_t sux_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("me");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("dug4");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("du");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("igi-bar");
}
if (str_eq(verb, EL_STR("do"))) {
return EL_STR("ak");
}
if (str_eq(verb, EL_STR("make"))) {
return EL_STR("ak");
}
if (str_eq(verb, EL_STR("bring"))) {
return EL_STR("tum2");
}
if (str_eq(verb, EL_STR("build"))) {
return EL_STR("d\xc3\xb9");
}
if (str_eq(verb, EL_STR("give"))) {
return EL_STR("\xc5\xa1um2");
}
if (str_eq(verb, EL_STR("know"))) {
return EL_STR("zu");
}
if (str_eq(verb, EL_STR("hear"))) {
return EL_STR("\xc4\x9d""e\xc5\xa1tug2 \xc4\x9d""ar");
}
if (str_eq(verb, EL_STR("love"))) {
return EL_STR("ki-a\xc4\x9d""2");
}
if (str_eq(verb, EL_STR("sit"))) {
return EL_STR("tu\xc5\xa1");
}
if (str_eq(verb, EL_STR("stand"))) {
return EL_STR("gub");
}
if (str_eq(verb, EL_STR("come"))) {
return EL_STR("\xc4\x9d""en");
}
if (str_eq(verb, EL_STR("eat"))) {
return EL_STR("gu7");
}
if (str_eq(verb, EL_STR("drink"))) {
return EL_STR("na\xc4\x9d");
}
if (str_eq(verb, EL_STR("write"))) {
return EL_STR("sar");
}
return verb;
return 0;
}
el_val_t sux_personal_suffix(el_val_t slot) {
if (slot == 0) {
return EL_STR("en");
}
if (slot == 1) {
return EL_STR("en");
}
if (slot == 2) {
return EL_STR("");
}
if (slot == 3) {
return EL_STR("enden");
}
if (slot == 4) {
return EL_STR("enzen");
}
return EL_STR("e\xc5\xa1");
return 0;
}
el_val_t sux_me_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("me-en");
}
if (slot == 1) {
return EL_STR("me-en");
}
if (slot == 2) {
return EL_STR("");
}
if (slot == 3) {
return EL_STR("me-en-d\xc3\xa8");
}
if (slot == 4) {
return EL_STR("me-en-z\xc3\xa8-en");
}
return EL_STR("me-e\xc5\xa1");
return 0;
}
el_val_t sux_me_past(el_val_t slot) {
if (slot == 0) {
return EL_STR("ba-me-en");
}
if (slot == 1) {
return EL_STR("ba-me-en");
}
if (slot == 2) {
return EL_STR("ba-me");
}
if (slot == 3) {
return EL_STR("ba-me-en-d\xc3\xa8");
}
if (slot == 4) {
return EL_STR("ba-me-en-z\xc3\xa8-en");
}
return EL_STR("ba-me-e\xc5\xa1");
return 0;
}
el_val_t sux_dug4_present(el_val_t slot) {
el_val_t suf = sux_personal_suffix(slot);
if (str_eq(suf, EL_STR(""))) {
return EL_STR("e");
}
return el_str_concat(EL_STR("e-"), suf);
return 0;
}
el_val_t sux_dug4_past(el_val_t slot) {
el_val_t suf = sux_personal_suffix(slot);
if (str_eq(suf, EL_STR(""))) {
return EL_STR("mu-un-dug4");
}
return el_str_concat(EL_STR("mu-un-dug4-"), suf);
return 0;
}
el_val_t sux_du_present(el_val_t slot) {
el_val_t suf = sux_personal_suffix(slot);
if (str_eq(suf, EL_STR(""))) {
return EL_STR("i-du");
}
return el_str_concat(EL_STR("i-du-"), suf);
return 0;
}
el_val_t sux_du_past(el_val_t slot) {
el_val_t suf = sux_personal_suffix(slot);
if (str_eq(suf, EL_STR(""))) {
return EL_STR("mu-un-du");
}
return el_str_concat(EL_STR("mu-un-du-"), suf);
return 0;
}
el_val_t sux_igibar_present(el_val_t slot) {
el_val_t suf = sux_personal_suffix(slot);
if (str_eq(suf, EL_STR(""))) {
return EL_STR("igi i-bar");
}
return el_str_concat(EL_STR("igi i-bar-"), suf);
return 0;
}
el_val_t sux_igibar_past(el_val_t slot) {
el_val_t suf = sux_personal_suffix(slot);
if (str_eq(suf, EL_STR(""))) {
return EL_STR("igi mu-un-bar");
}
return el_str_concat(EL_STR("igi mu-un-bar-"), suf);
return 0;
}
el_val_t sux_ak_present(el_val_t slot) {
el_val_t suf = sux_personal_suffix(slot);
if (str_eq(suf, EL_STR(""))) {
return EL_STR("i-ak");
}
return el_str_concat(EL_STR("i-ak-"), suf);
return 0;
}
el_val_t sux_ak_past(el_val_t slot) {
el_val_t suf = sux_personal_suffix(slot);
if (str_eq(suf, EL_STR(""))) {
return EL_STR("mu-un-ak");
}
return el_str_concat(EL_STR("mu-un-ak-"), suf);
return 0;
}
el_val_t sux_tum2_present(el_val_t slot) {
el_val_t suf = sux_personal_suffix(slot);
if (str_eq(suf, EL_STR(""))) {
return EL_STR("i-tum2");
}
return el_str_concat(EL_STR("i-tum2-"), suf);
return 0;
}
el_val_t sux_tum2_past(el_val_t slot) {
el_val_t suf = sux_personal_suffix(slot);
if (str_eq(suf, EL_STR(""))) {
return EL_STR("mu-un-tum2");
}
return el_str_concat(EL_STR("mu-un-tum2-"), suf);
return 0;
}
el_val_t sux_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t v = sux_map_canonical(verb);
el_val_t slot = sux_slot(person, number);
if (str_eq(v, EL_STR("me"))) {
if (str_eq(tense, EL_STR("present"))) {
return sux_me_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sux_me_past(slot);
}
return sux_me_present(slot);
}
if (str_eq(v, EL_STR("dug4"))) {
if (str_eq(tense, EL_STR("present"))) {
return sux_dug4_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sux_dug4_past(slot);
}
return sux_dug4_past(slot);
}
if (str_eq(v, EL_STR("du"))) {
if (str_eq(tense, EL_STR("present"))) {
return sux_du_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sux_du_past(slot);
}
return sux_du_past(slot);
}
if (str_eq(v, EL_STR("igi-bar"))) {
if (str_eq(tense, EL_STR("present"))) {
return sux_igibar_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sux_igibar_past(slot);
}
return sux_igibar_past(slot);
}
if (str_eq(v, EL_STR("ak"))) {
if (str_eq(tense, EL_STR("present"))) {
return sux_ak_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sux_ak_past(slot);
}
return sux_ak_past(slot);
}
if (str_eq(v, EL_STR("tum2"))) {
if (str_eq(tense, EL_STR("present"))) {
return sux_tum2_present(slot);
}
if (str_eq(tense, EL_STR("past"))) {
return sux_tum2_past(slot);
}
return sux_tum2_past(slot);
}
el_val_t suf = sux_personal_suffix(slot);
if (str_eq(tense, EL_STR("present"))) {
if (str_eq(suf, EL_STR(""))) {
return el_str_concat(EL_STR("i-"), v);
}
return el_str_concat(el_str_concat(el_str_concat(EL_STR("i-"), v), EL_STR("-")), suf);
}
if (str_eq(suf, EL_STR(""))) {
return el_str_concat(EL_STR("mu-"), v);
}
return el_str_concat(el_str_concat(el_str_concat(EL_STR("mu-"), v), EL_STR("-")), suf);
return 0;
}
el_val_t sux_is_animate(el_val_t noun) {
if (sux_str_ends(noun, EL_STR("di\xc4\x9dir"))) {
return 1;
}
if (sux_str_ends(noun, EL_STR("dingir"))) {
return 1;
}
if (str_eq(noun, EL_STR("lugal"))) {
return 1;
}
if (str_eq(noun, EL_STR("nin"))) {
return 1;
}
if (str_eq(noun, EL_STR("en"))) {
return 1;
}
if (str_eq(noun, EL_STR("ensi2"))) {
return 1;
}
if (str_eq(noun, EL_STR("dumu"))) {
return 1;
}
if (str_eq(noun, EL_STR("dam"))) {
return 1;
}
if (str_eq(noun, EL_STR("ama"))) {
return 1;
}
if (str_eq(noun, EL_STR("ad"))) {
return 1;
}
if (str_eq(noun, EL_STR("a2-dam"))) {
return 1;
}
if (str_eq(noun, EL_STR("lu2"))) {
return 1;
}
if (str_eq(noun, EL_STR("munus"))) {
return 1;
}
if (str_eq(noun, EL_STR("ur"))) {
return 1;
}
if (str_eq(noun, EL_STR("sa\xc4\x9d"))) {
return 1;
}
if (str_eq(noun, EL_STR("gudu4"))) {
return 1;
}
if (str_eq(noun, EL_STR("sanga"))) {
return 1;
}
if (str_eq(noun, EL_STR("ugula"))) {
return 1;
}
if (str_eq(noun, EL_STR("dub-sar"))) {
return 1;
}
if (str_eq(noun, EL_STR("nar"))) {
return 1;
}
if (str_eq(noun, EL_STR("sukkal"))) {
return 1;
}
if (sux_str_ends(noun, EL_STR("d-"))) {
return 1;
}
return 0;
return 0;
}
el_val_t sux_case_suffix(el_val_t gram_case) {
if (str_eq(gram_case, EL_STR("absolutive"))) {
return EL_STR("");
}
if (str_eq(gram_case, EL_STR("ergative"))) {
return EL_STR("-e");
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return EL_STR("-ak");
}
if (str_eq(gram_case, EL_STR("dative"))) {
return EL_STR("-ra");
}
if (str_eq(gram_case, EL_STR("locative"))) {
return EL_STR("-a");
}
if (str_eq(gram_case, EL_STR("ablative"))) {
return EL_STR("-ta");
}
if (str_eq(gram_case, EL_STR("comitative"))) {
return EL_STR("-da");
}
if (str_eq(gram_case, EL_STR("equative"))) {
return EL_STR("-gin");
}
if (str_eq(gram_case, EL_STR("terminative"))) {
return EL_STR("-\xc5\xa1""e");
}
return EL_STR("");
return 0;
}
el_val_t sux_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t csuf = sux_case_suffix(gram_case);
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("absolutive"))) {
return noun;
}
el_val_t suf_len = str_len(csuf);
el_val_t bare_suf = str_slice(csuf, 1, suf_len);
return el_str_concat(noun, bare_suf);
}
el_val_t animate = sux_is_animate(noun);
el_val_t plural_stem = EL_STR("");
if (animate) {
plural_stem = el_str_concat(noun, EL_STR("ene"));
}
if (!animate) {
plural_stem = el_str_concat(noun, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("absolutive"))) {
return plural_stem;
}
el_val_t suf_len2 = str_len(csuf);
el_val_t bare_suf2 = str_slice(csuf, 1, suf_len2);
return el_str_concat(plural_stem, bare_suf2);
return 0;
}
el_val_t sux_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
return sux_decline(noun, gram_case, number);
return 0;
}
el_val_t sux_verb_chain(el_val_t agent, el_val_t verb, el_val_t patient, el_val_t tense) {
el_val_t conjugated = sux_conjugate(verb, tense, EL_STR("third"), EL_STR("singular"));
if (str_eq(patient, EL_STR(""))) {
return el_str_concat(el_str_concat(agent, EL_STR(" ")), conjugated);
}
el_val_t agent_erg = el_str_concat(agent, EL_STR("e"));
return el_str_concat(el_str_concat(el_str_concat(el_str_concat(agent_erg, EL_STR(" ")), patient), EL_STR(" ")), conjugated);
return 0;
}
el_val_t sux_realize_sentence(el_val_t intent, el_val_t agent, el_val_t predicate, el_val_t patient, el_val_t tense) {
if (str_eq(intent, EL_STR("assert"))) {
return sux_verb_chain(agent, predicate, patient, tense);
}
if (str_eq(intent, EL_STR("question"))) {
el_val_t assertion = sux_verb_chain(agent, predicate, patient, tense);
return el_str_concat(assertion, EL_STR("-a"));
}
if (str_eq(intent, EL_STR("describe"))) {
if (str_eq(patient, EL_STR(""))) {
return el_str_concat(el_str_concat(el_str_concat(agent, EL_STR(" ")), predicate), EL_STR("-am3"));
}
return el_str_concat(el_str_concat(el_str_concat(agent, EL_STR(" ")), patient), EL_STR("-am3"));
}
return sux_verb_chain(agent, predicate, patient, tense);
return 0;
}
Generated Vendored
+29
View File
@@ -0,0 +1,29 @@
// auto-generated by elc --emit-header — do not edit
extern fn sux_str_ends(s: String, suf: String) -> Bool
extern fn sux_str_drop_last(s: String, n: Int) -> String
extern fn sux_str_last_char(s: String) -> String
extern fn sux_str_last2(s: String) -> String
extern fn sux_slot(person: String, number: String) -> Int
extern fn sux_ergative_suffix(person: String, number: String) -> String
extern fn sux_absolutive_suffix(person: String, number: String) -> String
extern fn sux_map_canonical(verb: String) -> String
extern fn sux_personal_suffix(slot: Int) -> String
extern fn sux_me_present(slot: Int) -> String
extern fn sux_me_past(slot: Int) -> String
extern fn sux_dug4_present(slot: Int) -> String
extern fn sux_dug4_past(slot: Int) -> String
extern fn sux_du_present(slot: Int) -> String
extern fn sux_du_past(slot: Int) -> String
extern fn sux_igibar_present(slot: Int) -> String
extern fn sux_igibar_past(slot: Int) -> String
extern fn sux_ak_present(slot: Int) -> String
extern fn sux_ak_past(slot: Int) -> String
extern fn sux_tum2_present(slot: Int) -> String
extern fn sux_tum2_past(slot: Int) -> String
extern fn sux_conjugate(verb: String, tense: String, person: String, number: String) -> String
extern fn sux_is_animate(noun: String) -> Bool
extern fn sux_case_suffix(gram_case: String) -> String
extern fn sux_decline(noun: String, gram_case: String, number: String) -> String
extern fn sux_noun_phrase(noun: String, gram_case: String, number: String, definite: String) -> String
extern fn sux_verb_chain(agent: String, verb: String, patient: String, tense: String) -> String
extern fn sux_realize_sentence(intent: String, agent: String, predicate: String, patient: String, tense: String) -> String
Generated Vendored
+1243
View File
File diff suppressed because it is too large Load Diff
Generated Vendored
+23
View File
@@ -0,0 +1,23 @@
// auto-generated by elc --emit-header — do not edit
extern fn sw_str_ends(s: String, suf: String) -> Bool
extern fn sw_str_drop_last(s: String, n: Int) -> String
extern fn sw_str_first_char(s: String) -> String
extern fn sw_str_first2(s: String) -> String
extern fn sw_str_first3(s: String) -> String
extern fn sw_str_last_char(s: String) -> String
extern fn sw_is_class1_noun(noun: String) -> Bool
extern fn sw_noun_class(noun: String) -> String
extern fn sw_subj_prefix(person: String, number: String, noun_class: String) -> String
extern fn sw_obj_prefix(person: String, number: String, noun_class: String) -> String
extern fn sw_tense_marker(tense: String) -> String
extern fn sw_verb_final(tense: String, negative: Bool) -> String
extern fn sw_neg_subj_prefix(person: String, number: String, noun_class: String) -> String
extern fn sw_verb_stem(infinitive: String) -> String
extern fn sw_conjugate(verb_stem: String, person: String, number: String, noun_class: String, tense: String) -> String
extern fn sw_negative(verb_stem: String, person: String, number: String, noun_class: String, tense: String) -> String
extern fn sw_noun_plural(noun: String) -> String
extern fn sw_adj_prefix(noun_class: String, number: String) -> String
extern fn sw_agree_adj(adj_stem: String, noun_class: String, number: String) -> String
extern fn sw_demonstrative(noun_class: String, number: String, proximity: String) -> String
extern fn sw_copula_present(person: String, number: String, use_case: String) -> String
extern fn sw_copula_neg_present(person: String, number: String) -> String
Generated Vendored
+335
View File
@@ -0,0 +1,335 @@
#include <stdint.h>
#include <stdlib.h>
#include "el_runtime.h"
el_val_t str_ends(el_val_t s, el_val_t suf);
el_val_t str_last_char(el_val_t s);
el_val_t str_last2(el_val_t s);
el_val_t str_last3(el_val_t s);
el_val_t str_drop_last(el_val_t s, el_val_t n);
el_val_t is_vowel(el_val_t c);
el_val_t morph_apply_suffix(el_val_t base, el_val_t suffix);
el_val_t en_irregular_plural(el_val_t word);
el_val_t en_irregular_singular(el_val_t word);
el_val_t en_irregular_verb(el_val_t base);
el_val_t en_verb_3sg(el_val_t base);
el_val_t en_should_double_final(el_val_t base);
el_val_t en_verb_past(el_val_t base);
el_val_t en_verb_gerund(el_val_t base);
el_val_t en_pluralize_regular(el_val_t singular);
el_val_t en_verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t agree_determiner(el_val_t det, el_val_t noun);
el_val_t morph_pluralize(el_val_t noun, el_val_t profile);
el_val_t morph_map_canonical(el_val_t verb, el_val_t code);
el_val_t morph_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number, el_val_t profile);
el_val_t morph_inflect(el_val_t word, el_val_t features, el_val_t profile);
el_val_t pluralize(el_val_t singular);
el_val_t singularize(el_val_t plural);
el_val_t verb_form(el_val_t base, el_val_t tense, el_val_t person, el_val_t number);
el_val_t irregular_plural(el_val_t word);
el_val_t irregular_singular(el_val_t word);
el_val_t txb_drop(el_val_t s, el_val_t n);
el_val_t txb_ends(el_val_t s, el_val_t suf);
el_val_t txb_slot(el_val_t person, el_val_t number);
el_val_t txb_pres1_suffix(el_val_t slot);
el_val_t txb_kam_present(el_val_t slot);
el_val_t txb_ya_present(el_val_t slot);
el_val_t txb_wes_present(el_val_t slot);
el_val_t txb_lyut_present(el_val_t slot);
el_val_t txb_wak_present(el_val_t slot);
el_val_t txb_map_canonical(el_val_t verb);
el_val_t txb_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number);
el_val_t txb_decline_masc(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t txb_decline_fem(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t txb_detect_gender(el_val_t noun);
el_val_t txb_decline(el_val_t noun, el_val_t gram_case, el_val_t number);
el_val_t txb_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite);
el_val_t txb_drop(el_val_t s, el_val_t n) {
el_val_t len = str_len(s);
if (n >= len) {
return EL_STR("");
}
return str_slice(s, 0, (len - n));
return 0;
}
el_val_t txb_ends(el_val_t s, el_val_t suf) {
return str_ends_with(s, suf);
return 0;
}
el_val_t txb_slot(el_val_t person, el_val_t number) {
if (str_eq(person, EL_STR("first"))) {
if (str_eq(number, EL_STR("singular"))) {
return 0;
}
return 3;
}
if (str_eq(person, EL_STR("second"))) {
if (str_eq(number, EL_STR("singular"))) {
return 1;
}
return 4;
}
if (str_eq(number, EL_STR("singular"))) {
return 2;
}
return 5;
return 0;
}
el_val_t txb_pres1_suffix(el_val_t slot) {
if (slot == 0) {
return EL_STR("au");
}
if (slot == 1) {
return EL_STR("\xc3\xa4t");
}
if (slot == 2) {
return EL_STR("em");
}
if (slot == 3) {
return EL_STR("emane");
}
if (slot == 4) {
return EL_STR("em");
}
return EL_STR("em");
return 0;
}
el_val_t txb_kam_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("kam");
}
if (slot == 1) {
return EL_STR("k\xc3\xa4m");
}
if (slot == 2) {
return EL_STR("k\xc3\xa4m");
}
if (slot == 3) {
return EL_STR("kamn\xc3\xa4\xe1\xb9\x83");
}
if (slot == 4) {
return EL_STR("kamn\xc3\xa4\xe1\xb9\x83");
}
return EL_STR("kamn\xc3\xa4\xe1\xb9\x83");
return 0;
}
el_val_t txb_ya_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("yau");
}
if (slot == 1) {
return EL_STR("y\xc3\xa4t");
}
if (slot == 2) {
return EL_STR("y\xc3\xa4m");
}
if (slot == 3) {
return EL_STR("ym\xc3\xa4\xe1\xb9\x83");
}
if (slot == 4) {
return EL_STR("ym\xc3\xa4\xe1\xb9\x83");
}
return EL_STR("y\xc3\xa4nm\xc3\xa4\xe1\xb9\x83");
return 0;
}
el_val_t txb_wes_present(el_val_t slot) {
if (slot == 2) {
return EL_STR("ste");
}
return EL_STR("wes");
return 0;
}
el_val_t txb_lyut_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("lyutau");
}
if (slot == 1) {
return EL_STR("lyut\xc3\xa4t");
}
if (slot == 2) {
return EL_STR("lyutem");
}
if (slot == 3) {
return EL_STR("lyutemane");
}
if (slot == 4) {
return EL_STR("lyutem");
}
return EL_STR("lyutem");
return 0;
}
el_val_t txb_wak_present(el_val_t slot) {
if (slot == 0) {
return EL_STR("wakau");
}
if (slot == 1) {
return EL_STR("wak\xc3\xa4t");
}
if (slot == 2) {
return EL_STR("wakem");
}
if (slot == 3) {
return EL_STR("wakemane");
}
if (slot == 4) {
return EL_STR("wakem");
}
return EL_STR("wakem");
return 0;
}
el_val_t txb_map_canonical(el_val_t verb) {
if (str_eq(verb, EL_STR("be"))) {
return EL_STR("wes");
}
if (str_eq(verb, EL_STR("come"))) {
return EL_STR("k\xc3\xa4m");
}
if (str_eq(verb, EL_STR("go"))) {
return EL_STR("y\xc3\xa4");
}
if (str_eq(verb, EL_STR("see"))) {
return EL_STR("lyut");
}
if (str_eq(verb, EL_STR("speak"))) {
return EL_STR("wak");
}
if (str_eq(verb, EL_STR("say"))) {
return EL_STR("wak");
}
return verb;
return 0;
}
el_val_t txb_conjugate(el_val_t verb, el_val_t tense, el_val_t person, el_val_t number) {
el_val_t v = txb_map_canonical(verb);
el_val_t slot = txb_slot(person, number);
if (str_eq(v, EL_STR("wes"))) {
if (str_eq(tense, EL_STR("present"))) {
return txb_wes_present(slot);
}
return v;
}
if (str_eq(v, EL_STR("k\xc3\xa4m"))) {
if (str_eq(tense, EL_STR("present"))) {
return txb_kam_present(slot);
}
return v;
}
if (str_eq(v, EL_STR("y\xc3\xa4"))) {
if (str_eq(tense, EL_STR("present"))) {
return txb_ya_present(slot);
}
return v;
}
if (str_eq(v, EL_STR("lyut"))) {
if (str_eq(tense, EL_STR("present"))) {
return txb_lyut_present(slot);
}
return v;
}
if (str_eq(v, EL_STR("wak"))) {
if (str_eq(tense, EL_STR("present"))) {
return txb_wak_present(slot);
}
return v;
}
if (str_eq(tense, EL_STR("present"))) {
return el_str_concat(v, txb_pres1_suffix(slot));
}
return v;
return 0;
}
el_val_t txb_decline_masc(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(noun, EL_STR("e"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(noun, EL_STR("e"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("entse"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("ene"));
}
return el_str_concat(noun, EL_STR("e"));
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(noun, EL_STR("i"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(noun, EL_STR("i"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("entwetse"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("ene"));
}
return el_str_concat(noun, EL_STR("i"));
return 0;
}
el_val_t txb_decline_fem(el_val_t noun, el_val_t gram_case, el_val_t number) {
if (str_eq(number, EL_STR("singular"))) {
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(noun, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(noun, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("antse"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("ane"));
}
return el_str_concat(noun, EL_STR("a"));
}
if (str_eq(gram_case, EL_STR("nominative"))) {
return el_str_concat(noun, EL_STR("\xc3\xa4"));
}
if (str_eq(gram_case, EL_STR("accusative"))) {
return el_str_concat(noun, EL_STR("\xc3\xa4"));
}
if (str_eq(gram_case, EL_STR("genitive"))) {
return el_str_concat(noun, EL_STR("antse"));
}
if (str_eq(gram_case, EL_STR("dative"))) {
return el_str_concat(noun, EL_STR("ane"));
}
return el_str_concat(noun, EL_STR("\xc3\xa4"));
return 0;
}
el_val_t txb_detect_gender(el_val_t noun) {
return EL_STR("masculine");
return 0;
}
el_val_t txb_decline(el_val_t noun, el_val_t gram_case, el_val_t number) {
el_val_t gender = txb_detect_gender(noun);
if (str_eq(gender, EL_STR("feminine"))) {
return txb_decline_fem(noun, gram_case, number);
}
return txb_decline_masc(noun, gram_case, number);
return 0;
}
el_val_t txb_noun_phrase(el_val_t noun, el_val_t gram_case, el_val_t number, el_val_t definite) {
return txb_decline(noun, gram_case, number);
return 0;
}

Some files were not shown because too many files have changed in this diff Show More