nx_synthroom.nx source
↩ module page · 153 lines · 7096 B
1// nx_synthroom.nx -- THE ROOM PROTOCOL TOOL (/compare/synthroom rung SR1): the thin main over
2// nx_synthroom_lib. All judgement lives in the lib so the gate can reach it in-process and a mutation
3// bite is not hidden behind a fork boundary.
4//
5// nx_synthroom append <log> <nonce> <verb> <actor> [a1] [a2] -> appends ONE event row, or refuses by name
6// nx_synthroom replay <log> <menu.conf> -> prints the derived intent stream
7// nx_synthroom menu <menu.conf> <amount> [item] -> prints the intent one tip maps to
8// nx_synthroom verbs -> prints the verb vocabulary
9//
10// exit 0 done | 1 refused (the reason is printed and named) | 2 usage
11// license_tier: ORIGINAL No hw writes (Rule 26).
12import "nx_syscalls.nx"
13import "nx_synthroom_lib.nx"
14
15const SRT_EXIT_OK: i64 = 0
16const SRT_EXIT_REFUSED: i64 = 1
17const SRT_EXIT_USAGE: i64 = 2
18const SRT_ARGV_VERB: i64 = 1
19const SRT_MIN_ARGC: i64 = 2
20const SRT_APPEND_MIN: i64 = 6
21const SRT_REPLAY_ARGC: i64 = 4
22const SRT_MENU_MIN: i64 = 4
23const SRT_A_LOG: i64 = 2
24const SRT_A_NONCE: i64 = 3
25const SRT_A_VERB: i64 = 4
26const SRT_A_ACTOR: i64 = 5
27const SRT_A_A1: i64 = 6
28const SRT_A_A2: i64 = 7
29const SRT_A_MENU: i64 = 3
30const SRT_M_CONF: i64 = 2
31const SRT_M_AMT: i64 = 3
32const SRT_M_ITEM: i64 = 4
33// The menu table and the replay buffer are sized from the inputs: rows <= lines + 1 of the conf, and the
34// intent stream is at most the log plus one bounded row per event -- derived, never guessed.
35const SRT_ROW_MAX: i64 = 128
36const SRT_WORD: i64 = 8
37
38func srt_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
39func srt_n(v: i64) -> i64 {
40 let b: *u8 = sys_mmap(SR_SCRATCH)
41 let p: i64 = sr_catnum(b, 0, v)
42 sys_write(1, b, p)
43 return 0
44}
45
46func srt_usage() -> i64 {
47 srt_w("usage: nx_synthroom append <log> <nonce> <verb> <actor> [a1] [a2]\n" as *u8)
48 srt_w(" nx_synthroom replay <log> <menu.conf>\n" as *u8)
49 srt_w(" nx_synthroom menu <menu.conf> <amount> [item]\n" as *u8)
50 srt_w(" nx_synthroom verbs\n" as *u8)
51 srt_w(" verbs: tip say enter leave gesture command toy. A tip carries a1=amount a2=item-or-dash.\n" as *u8)
52 srt_w(" The nonce is the caller's identity for the event: a duplicate is REFUSED, never double-applied.\n" as *u8)
53 srt_w(" exit 0 done | 1 refused by name | 2 usage\n" as *u8)
54 return 0
55}
56
57func srt_refuse(d: i64) -> i64 {
58 srt_w(" " as *u8); srt_w(sr_decision_name(d))
59 srt_w("\n " as *u8); srt_w(sr_decision_why(d)); srt_w("\n" as *u8)
60 return 0
61}
62
63// lines + 1 of a counted buffer: the derived row capacity for a menu conf.
64func srt_lines(buf: *u8, n: i64) -> i64 {
65 var l: i64 = 1
66 var i: i64 = 0
67 while i < n { if buf[i] == (SR_CH_NL as u8) { l = l + 1 } i = i + 1 }
68 return l
69}
70
71func main(argc: i64, argv: *i64) -> i64 {
72 if argc < SRT_MIN_ARGC { srt_usage(); sys_exit(SRT_EXIT_USAGE) }
73 let verb: *u8 = argv[SRT_ARGV_VERB] as *u8
74
75 if sr_streq(verb, "verbs" as *u8) == 1 {
76 var v: i64 = 0
77 while v < SR_V_N { srt_w(" " as *u8); srt_w(sr_verb_name(v)); srt_w("\n" as *u8); v = v + 1 }
78 sys_exit(SRT_EXIT_OK)
79 }
80
81 if sr_streq(verb, "append" as *u8) == 1 {
82 if argc < SRT_APPEND_MIN { srt_usage(); sys_exit(SRT_EXIT_USAGE) }
83 var a1: *u8 = SR_EMPTY
84 var a2: *u8 = SR_EMPTY
85 if argc > SRT_A_A1 { a1 = argv[SRT_A_A1] as *u8 }
86 if argc > SRT_A_A2 { a2 = argv[SRT_A_A2] as *u8 }
87 let line: *u8 = sys_mmap(SR_LINE)
88 let scratch: *u8 = sys_mmap(SR_SCRATCH)
89 let lp: *i64 = sys_mmap(SRT_WORD * 2) as *i64
90 let now: i64 = sys_now_realtime_sec()
91 let d: i64 = sr_event_append(argv[SRT_A_LOG] as *u8, argv[SRT_A_NONCE] as *u8, now, argv[SRT_A_VERB] as *u8,
92 argv[SRT_A_ACTOR] as *u8, a1, a2, line, SR_LINE, scratch, lp)
93 srt_w("=== NX-SYNTHROOM append log=" as *u8); srt_w(argv[SRT_A_LOG] as *u8)
94 srt_w(" nonce=" as *u8); srt_w(argv[SRT_A_NONCE] as *u8)
95 srt_w(" ts=" as *u8); srt_n(now); srt_w(" ===\n" as *u8)
96 srt_refuse(d)
97 if d == SR_OK { srt_w(" row=" as *u8); srt_w(line) }
98 if d != SR_OK { sys_exit(SRT_EXIT_REFUSED) }
99 sys_exit(SRT_EXIT_OK)
100 }
101
102 if sr_streq(verb, "menu" as *u8) == 1 {
103 if argc < SRT_MENU_MIN { srt_usage(); sys_exit(SRT_EXIT_USAGE) }
104 let amount: i64 = sr_atoi_strict(argv[SRT_M_AMT] as *u8)
105 if amount < 0 { srt_w("REFUSED-BAD-AMOUNT: the amount must be a non-negative integer\n" as *u8); sys_exit(SRT_EXIT_USAGE) }
106 var item: *u8 = SR_EMPTY
107 if argc > SRT_M_ITEM { item = argv[SRT_M_ITEM] as *u8 }
108 let lp: *i64 = sys_mmap(SRT_WORD * 2) as *i64
109 let why: *i64 = sys_mmap(SRT_WORD) as *i64
110 let fb: *i64 = sys_mmap(SRT_WORD) as *i64
111 let tab: *i64 = sys_mmap(SRT_ROW_MAX * SR_M_STRIDE * SR_I64_BYTES) as *i64
112 let rows: i64 = sr_menu_load(argv[SRT_M_CONF] as *u8, tab, SRT_ROW_MAX, fb, why, lp)
113 if rows < 0 { srt_refuse(why[0]); sys_exit(SRT_EXIT_REFUSED) }
114 let intent: *u8 = sr_menu_intent(tab, rows, fb[0] as *u8, amount, item)
115 srt_w(" rows=" as *u8); srt_n(rows)
116 srt_w(" amount=" as *u8); srt_n(amount)
117 srt_w(" item=" as *u8); srt_w(item)
118 srt_w(" intent=" as *u8); srt_w(intent); srt_w("\n" as *u8)
119 sys_exit(SRT_EXIT_OK)
120 }
121
122 if sr_streq(verb, "replay" as *u8) == 1 {
123 if argc < SRT_REPLAY_ARGC { srt_usage(); sys_exit(SRT_EXIT_USAGE) }
124 let lp: *i64 = sys_mmap(SRT_WORD * 2) as *i64
125 let why: *i64 = sys_mmap(SRT_WORD) as *i64
126 let fb: *i64 = sys_mmap(SRT_WORD) as *i64
127 let tab: *i64 = sys_mmap(SRT_ROW_MAX * SR_M_STRIDE * SR_I64_BYTES) as *i64
128 let rows: i64 = sr_menu_load(argv[SRT_A_MENU] as *u8, tab, SRT_ROW_MAX, fb, why, lp)
129 if rows < 0 { srt_refuse(why[0]); sys_exit(SRT_EXIT_REFUSED) }
130 let lg: *u8 = sys_read_file(argv[SRT_A_LOG] as *u8, lp)
131 if (lg as i64) == 0 { srt_refuse(SR_D_NOLOG); sys_exit(SRT_EXIT_REFUSED) }
132 let n: i64 = lp[0]
133 // one bounded intent row per event: the log length plus one SR_LINE per newline is a safe cap
134 let ocap: i64 = n + (srt_lines(lg, n) * SR_LINE) + 1
135 let out: *u8 = sys_mmap(ocap)
136 let cnt: *i64 = sys_mmap(SRT_WORD) as *i64
137 let bad: *i64 = sys_mmap(SRT_WORD) as *i64
138 let d: i64 = sr_replay(lg, n, tab, rows, fb[0] as *u8, out, ocap, cnt, bad)
139 if d != SR_OK {
140 srt_refuse(d)
141 if bad[0] >= 0 { srt_w(" row-index=" as *u8); srt_n(bad[0]); srt_w("\n" as *u8) }
142 sys_exit(SRT_EXIT_REFUSED)
143 }
144 srt_w(out)
145 srt_w(" intents=" as *u8); srt_n(cnt[0]); srt_w(" menu_rows=" as *u8); srt_n(rows); srt_w("\n" as *u8)
146 sys_exit(SRT_EXIT_OK)
147 }
148
149 srt_w("REFUSED-BAD-VERB: the verbs are append replay menu verbs\n" as *u8)
150 srt_usage()
151 sys_exit(SRT_EXIT_USAGE)
152 return 0
153}