Merge lang/machines e4265f5f: phase 27.1 - a state machine as data (@Machine(Record.field) on a registry of transitions: generated row reducers and tick, the field written only by its table, graph checks, schema machines); reseeded, syntax regenerated
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
d7adc28125
34 changed files with 131221 additions and 109416 deletions
|
|
@ -41,6 +41,7 @@
|
|||
"annot-target",
|
||||
"annot-column",
|
||||
"annot-rowverb",
|
||||
"annot-machine",
|
||||
"annot-permap",
|
||||
"annot-range",
|
||||
"annot-ref",
|
||||
|
|
|
|||
|
|
@ -269,8 +269,20 @@ function dp_fn_name(n: pointer) -> pointer {
|
|||
}
|
||||
return n
|
||||
}
|
||||
# 27.3: a row reducer's symbol says `Deer__in__Herd__deer` for `Deer in Herd.deer`
|
||||
function dp_row_name(s: pointer) -> pointer {
|
||||
# 27.3: a row reducer's symbol says `Deer__in__Herd__deer` for `Deer in Herd.deer`; one a @Machine
|
||||
# wrote ends `__machine__DeerSteps` (27.1)
|
||||
function dp_row_name(s0: pointer) -> pointer {
|
||||
var s = s0
|
||||
var tail = ""
|
||||
var k = 0
|
||||
while k + 11 <= slen(s0) {
|
||||
if s0[k .. k + 11] == "__machine__" {
|
||||
s = s0[0 .. k]
|
||||
tail = ` (machine {s0[k + 11 .. slen(s0)]})`
|
||||
break
|
||||
}
|
||||
k += 1
|
||||
}
|
||||
var out = ""
|
||||
var seen = false
|
||||
var i = 0
|
||||
|
|
@ -287,7 +299,7 @@ function dp_row_name(s: pointer) -> pointer {
|
|||
i += 1
|
||||
}
|
||||
}
|
||||
return out
|
||||
return out + tail
|
||||
}
|
||||
function dp_own(k: int) -> bool { return dp_pkg[k] == 0 }
|
||||
# an edge the numbers count: between two of the program's own modules
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ function selfhost_frags() -> []pointer {
|
|||
push(f, "selfhost/frontend/state.ludic")
|
||||
push(f, "selfhost/frontend/actions.ludic")
|
||||
push(f, "selfhost/frontend/actions_rows.ludic")
|
||||
push(f, "selfhost/frontend/machines.ludic")
|
||||
push(f, "selfhost/frontend/machines_write.ludic")
|
||||
push(f, "selfhost/frontend/migrate.ludic")
|
||||
push(f, "selfhost/frontend/registry.ludic")
|
||||
push(f, "selfhost/frontend/registry_finish.ludic")
|
||||
|
|
|
|||
|
|
@ -1252,6 +1252,17 @@ function cmd_dev_test() -> int {
|
|||
reject_case("rejected/row_reducer_writes_state", "a row reducer writes its row alone, and n is a mut Noise", "a row reducer writes no state")
|
||||
reject_case("rejected/rowverb_no_row", "@RowVerb scare: a row verb takes the row first", "a @RowVerb takes its row first")
|
||||
reject_case("rejected/row_reducer_owner", "Herd is module herd's, and this reducer is in the program", "only the state's module reduces its table's rows")
|
||||
feat_case("actions/machine", "", "0 0 1 1", "machine.ludic (27.1: @Machine - a state machine as data: the reducer on Spook, first match by guard, enter, and the tick's guard-only transitions)")
|
||||
reject_case("rejected/machine_unreachable", "Mood.Fled is never reached from the start, Mood.Calm", "every state of a machine is reached from its start")
|
||||
reject_case("rejected/machine_no_way_out", "Mood.Fled has no way out", "every state of a machine has a way out")
|
||||
reject_case("rejected/machine_on_unknown", "on: \"Spok\" names no action", "a machine's on names an action")
|
||||
reject_case("rejected/machine_on_no_target", "on: \"Shout\" names no row", "a machine's action names its row with @Target")
|
||||
reject_case("rejected/machine_self_no_guard", "a transition from Wary to itself with no guard", "a self-transition has a guard")
|
||||
reject_case("rejected/machine_ambiguous", "settles and stays both leave Wary on Spook, and settles has no guard", "one trigger, one unguarded way out")
|
||||
reject_case("rejected/machine_guard_writes", "guard deer_nervous asks and changes nothing", "a machine's guard writes nothing through its row")
|
||||
reject_case("rejected/machine_field_written", "Deer.mood is the machine DeerSteps's (@Machine(Deer.mood))", "a machine's field changes only by a transition in its table")
|
||||
reject_case("rejected/machine_not_registry", "@Machine(Deer.mood) marks the registry of a machine's transitions", "@Machine is on a registry")
|
||||
reject_case("rejected/machine_not_enum", "Deer.mood is int - a machine's state is a plain enum", "a machine's state is an enum field")
|
||||
feat_case("state/counter", "", "11 3 heard 5", "counter.ludic (0.S: a state, mut and read-only parameters, entry, listener and fn-value injection)")
|
||||
feat_case("state/port_field", "", "40", "port_field.ludic (0.S: a port member bound to a state's field)")
|
||||
spec_case("state/tested", "== 2 passed, 0 failed ==")
|
||||
|
|
@ -1373,6 +1384,7 @@ function cmd_dev_test() -> int {
|
|||
schema_case("actions/modules", "{\"action\": \"PickUp\", \"module\": null, \"at\": \"examples/actions/modules.ludic:8:21\"}", "--emit-schema: code.dispatch - every dispatch site")
|
||||
schema_case("actions/rows", "{\"record\": \"Deer\", \"table\": \"Herd.deer\", \"state\": \"Herd\", \"action\": \"Spook\", \"target\": \"who\", \"predicted\": false, \"net\": null, \"module\": null, \"at\": \"examples/actions/rows.ludic:17:32\"}", "--emit-schema: code.row_reducers - a row reducer's record, table, action and target")
|
||||
schema_case("actions/rows", "{\"name\": \"deer_move\", \"record\": \"Deer\", \"module\": null, \"at\": \"examples/actions/rows.ludic:24:21\"}", "--emit-schema: code.row_verbs - a @RowVerb and its record")
|
||||
schema_case("actions/machine", "{\"registry\": \"DeerSteps\", \"record\": \"Deer\", \"field\": \"mood\", \"enum\": \"Mood\", \"table\": \"Herd.deer\", \"start\": \"Calm\", \"states\": [\"Calm\", \"Wary\", \"Fled\"], \"actions\": [\"Spook\"], \"tick\": \"deer_steps_tick\", \"module\": null, \"at\": \"examples/actions/machine.ludic:28:32\"}", "--emit-schema: code.machines - a @Machine's registry, field, enum, table, start, actions and tick")
|
||||
schema_case("actions/rows", "{\"name\": \"Spook\", \"module\": null, \"at\": \"examples/actions/rows.ludic:14:10\", \"target\": \"who\"}", "--emit-schema: code.actions - an action's @Target field")
|
||||
schema_case("modules/ports", "{\"name\": \"Clock\", \"module\": \"clock\", \"at\": \"examples/modules/station/clock/index.ludic:4:13\", \"bound\": true, \"members\": [{\"name\": \"now\", \"type\": \"fn()->int\", \"default\": null, \"required\": true}, {\"name\": \"day\", \"type\": \"fn()->int\", \"default\": \"fn first_day\", \"required\": false}]}", "--emit-schema: code.ports - a port's members, their fn types and defaults")
|
||||
schema_case("modules/ports", "{\"port\": \"Clock\", \"member\": \"now\", \"fn\": \"game_hours\", \"value\": \"fn game_hours\", \"module\": \"app\", \"at\": \"examples/modules/station/app/index.ludic:3:14\"}", "--emit-schema: code.binds - a bind's member, the function it names and where")
|
||||
|
|
|
|||
|
|
@ -84,10 +84,10 @@ static const char* LUDIC_PHASES[] = {
|
|||
static const char* LUDIC_ATTRIBUTES[] = {
|
||||
"Ref","OneOf","Range","Unit","Asset","Color","Node","Clip","Material","Tint","Derived","Text",
|
||||
"Multiline","Key","Computed","Sync","frame","max","owns","Target","Column","AppendOnly","ByKey",
|
||||
"PerMap","Chunked","TextKey","export","Public","On","Queries","OnSpawn","OnDespawn","OnAttach",
|
||||
"OnDetach","OnEnable","OnDisable","OnStart","OnQuit","Owned","Server","Predicted","ToServer",
|
||||
"ToClients","System","EngineSystem","Namespace","deterministic","ClearColor","alloc_ok",
|
||||
"creates","releases","RowVerb","Handles","Reads","Writes", 0
|
||||
"PerMap","Chunked","Machine","TextKey","export","Public","On","Queries","OnSpawn","OnDespawn",
|
||||
"OnAttach","OnDetach","OnEnable","OnDisable","OnStart","OnQuit","Owned","Server","Predicted",
|
||||
"ToServer","ToClients","System","EngineSystem","Namespace","deterministic","ClearColor",
|
||||
"alloc_ok","creates","releases","RowVerb","Handles","Reads","Writes", 0
|
||||
};
|
||||
/* ludic-dev syntax: end */
|
||||
static const char* LUDIC_WIDGETS[] = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue