1pub struct KeywordInfo {
12 pub word: &'static str,
13 pub meaning: &'static str,
14}
15
16pub const KEYWORDS: &[KeywordInfo] = &[
18 k("Bool", "The boolean base type."),
19 k(
20 "Bytes",
21 "The binary base type — an immutable octet sequence, erased to `Uint8Array` (`Bytes.fromUtf8(s)`).",
22 ),
23 k(
24 "Duration",
25 "The time-span base type, in milliseconds (`5.minutes`).",
26 ),
27 k("Effect", "The effectful-computation type, `Effect[T]`."),
28 k("Err", "The error variant of `Result`."),
29 k("Float", "The floating-point base type."),
30 k(
31 "Instant",
32 "The absolute-time base type, in epoch milliseconds (`Clock.now()`).",
33 ),
34 k("Int", "The integer base type."),
35 k(
36 "JsonError",
37 "The JSON-decode error type, `Result[T, JsonError]` from `Json.decode`.",
38 ),
39 k("None", "The empty variant of `Option`."),
40 k("Ok", "The success variant of `Result`."),
41 k("Option", "The optional-value type, `Option[T]`."),
42 k("Result", "The success-or-error type, `Result[T, E]`."),
43 k("Some", "The present variant of `Option`."),
44 k("String", "The string base type."),
45 k(
46 "ValidationError",
47 "The error type returned by a refined type's `.of`.",
48 ),
49 k(
50 "actor",
51 "Declare an actor — a boundary contract a handler consumes via `by`.",
52 ),
53 k(
54 "adapter",
55 "Declare an adapter — the host boundary (capability contract + binding).",
56 ),
57 k("agent", "Declare a stateful, keyed agent inside a context."),
58 k("as", "Alias a consumed context (`consumes X as Y`)."),
59 k(
60 "binding",
61 "Name an adapter's TypeScript binding module (`binding \"<module>\"`).",
62 ),
63 k(
64 "by",
65 "Name the actor a handler consumes, after the return type — or a service-level default on the header (`… -> T by <name>: <Actor>`).",
66 ),
67 k(
68 "capability",
69 "Declare a capability (a dependency interface) in a context.",
70 ),
71 k(
72 "case",
73 "Declare a test case inside a `suite` (`case \"…\" { … }`).",
74 ),
75 k(
76 "commons",
77 "Declare a pure, stateless module of types and functions.",
78 ),
79 k(
80 "consumes",
81 "Declare a dependency on another context's services.",
82 ),
83 k(
84 "context",
85 "Declare a deployable context (services, agents, capabilities).",
86 ),
87 k(
88 "cron",
89 "The cron protocol on a service header (`from cron`).",
90 ),
91 k(
92 "do",
93 "Perform a unit effect as a statement (`do e` — the binder-free `let _ <- e`).",
94 ),
95 k("else", "The alternative branch of an `if` expression."),
96 k(
97 "ensures",
98 "Declare a function postcondition — a pure `Bool` clause over the parameters and `result` (`ensures <name>: <pred>`).",
99 ),
100 k("enum", "Declare a payloadless sum type (`enum { A, B }`)."),
101 k(
102 "event",
103 "Declare a typed fact a context may emit (`event Name = { fields }`), inside a context.",
104 ),
105 k(
106 "expect",
107 "Assert a predicate inside a test case (`expect <bool-predicate>`).",
108 ),
109 k("exports", "Declare which types a context exposes, and how."),
110 k("false", "The boolean literal `false`."),
111 k("fn", "Declare a function."),
112 k(
113 "from",
114 "Name the protocol a service conforms to (`service X from http`).",
115 ),
116 k("given", "Declare the capabilities a handler requires."),
117 k(
118 "http",
119 "The HTTP protocol on a service header (`from http`).",
120 ),
121 k("if", "A conditional expression."),
122 k(
123 "implies",
124 "Logical implication (`P implies Q` ≡ `!P || Q`), used in invariant predicates.",
125 ),
126 k(
127 "invariant",
128 "Declare an agent invariant — a predicate that must hold of every committed state.",
129 ),
130 k(
131 "is",
132 "Test a value against a variant pattern, yielding a `Bool`.",
133 ),
134 k(
135 "let",
136 "Bind a local value (`let x = …`, or `let x <- …` for an effect).",
137 ),
138 k(
139 "match",
140 "Pattern-match over a sum type, `Result`, or `Option`.",
141 ),
142 k(
143 "messages",
144 "Declare a message bundle for one locale (`messages \"<tag>\" { \"code\" => \"template\" }`), inside a commons.",
145 ),
146 k(
147 "on",
148 "Begin a handler declaration (`on call`, `on GET(…)`, `on message`, `on open`/`on close`).",
149 ),
150 k(
151 "opaque",
152 "Declare an opaque type, or export a type opaquely.",
153 ),
154 k(
155 "property",
156 "Declare a generative test inside a `suite` (`property \"…\" { for all … }`).",
157 ),
158 k(
159 "protocol",
160 "Reserved keyword (protocols are a closed, compiler-known set).",
161 ),
162 k("provides", "Provide an implementation of a capability."),
163 k(
164 "queue",
165 "The queue protocol on a service header (`from queue(\"name\")`).",
166 ),
167 k(
168 "record",
169 "Reserved keyword (records are written `type X = { … }`).",
170 ),
171 k(
172 "requires",
173 "Declare a function precondition — a pure `Bool` clause over the parameters (`requires <name>: <pred>`).",
174 ),
175 k("self", "The current agent instance, inside a handler."),
176 k(
177 "service",
178 "Declare a service (a group of handlers) in a context.",
179 ),
180 k(
181 "stub",
182 "Stub a consumed capability operation at a test seam (`stub Cap.op(…) returns <v>` / `fails`).",
183 ),
184 k(
185 "suite",
186 "Declare a test suite targeting a unit (`suite <target> { case … }`).",
187 ),
188 k(
189 "transition",
190 "Declare an agent step invariant over the `old`/`new` state pair (`transition <name>: …`).",
191 ),
192 k(
193 "transparent",
194 "Export a type with its structure visible (`exports transparent { … }`).",
195 ),
196 k("true", "The boolean literal `true`."),
197 k(
198 "type",
199 "Declare a type: alias, record, sum, opaque, or refined.",
200 ),
201 k("uses", "Bring a commons into scope."),
202 k("where", "Attach refinement predicates to a base type."),
203];
204
205pub const CONTEXTUAL_KEYWORDS: &[KeywordInfo] = &[
213 k(
214 "key",
215 "The agent's identity field — one per agent; keys the store.",
216 ),
217 k("store", "A persisted agent-state field."),
218];
219
220pub const RESERVED_CONTEXTUAL: &[&str] = &["case", "event", "messages", "on", "suite"];
233
234pub fn is_reserved_contextual(word: &str) -> bool {
240 RESERVED_CONTEXTUAL.contains(&word)
241}
242
243pub const BUILTIN_TYPE_NAMES: &[KeywordInfo] = &[
257 k(
258 "Connection",
259 "A held WebSocket connection, `Connection[F]`.",
260 ),
261 k(
262 "History",
263 "A generated call-history generator, `History[Agent]` (test-only).",
264 ),
265 k(
266 "HttpResult",
267 "The HTTP handler result type, `HttpResult[T]`.",
268 ),
269 k("List", "The immutable list type, `List[T]`."),
270 k("Map", "The immutable map type, `Map[K, V]`."),
271 k("Query", "The lazy storage-read type, `Query[T]`."),
272 k(
273 "QueueResult",
274 "The queue handler result type (non-generic).",
275 ),
276 k("Stream", "The value-over-time primitive, `Stream[T]`."),
277];
278
279pub fn is_builtin_type_name(name: &str) -> bool {
282 BUILTIN_TYPE_NAMES.iter().any(|b| b.word == name)
283}
284
285const fn k(word: &'static str, meaning: &'static str) -> KeywordInfo {
286 KeywordInfo { word, meaning }
287}
288
289pub fn render_markdown() -> String {
293 let mut out = String::new();
294 out.push_str("# Keywords\n\n");
295 out.push_str(
296 "<!-- GENERATED FILE — do not edit by hand.\n \
297 Source: bynk-syntax/src/keywords.rs (`render_markdown`).\n \
298 Regenerate with: BYNK_BLESS=1 cargo test -p bynkc --test keywords_reference -->\n\n",
299 );
300 out.push_str(
301 "Bynk reserves names in three tiers. The first two are lexer keywords; the \
302 third are compiler-known type names. Only the **hard keywords** can never \
303 be used as an identifier.\n\n",
304 );
305
306 let hard: Vec<&KeywordInfo> = KEYWORDS
308 .iter()
309 .filter(|k| !RESERVED_CONTEXTUAL.contains(&k.word))
310 .collect();
311 out.push_str("## Hard keywords\n\n");
312 out.push_str(&format!(
313 "Reserved everywhere — these **{}** words can never be used as an \
314 identifier.\n\n",
315 hard.len()
316 ));
317 out.push_str("| Keyword | Meaning |\n|---|---|\n");
318 for info in hard {
319 out.push_str(&format!("| `{}` | {} |\n", info.word, info.meaning));
320 }
321
322 let contextual: Vec<&KeywordInfo> = RESERVED_CONTEXTUAL
325 .iter()
326 .filter_map(|w| KEYWORDS.iter().find(|k| &k.word == w))
327 .collect();
328 out.push_str("\n## Contextual keywords\n\n");
329 out.push_str(
330 "Reserved only in the one position named below; elsewhere (a field, \
331 parameter, or other identifier) they are ordinary names.\n\n",
332 );
333 out.push_str("| Keyword | Meaning |\n|---|---|\n");
334 for info in contextual {
335 out.push_str(&format!("| `{}` | {} |\n", info.word, info.meaning));
336 }
337
338 out.push_str("\n## Built-in type names\n\n");
341 out.push_str(
342 "Compiler-known type constructors. They are not lexer keywords — you may \
343 use them as an identifier in value position — but they are reserved in \
344 type position: a `type` declaration may not reuse one of these names \
345 (`bynk.resolve.reserved_builtin_type`).\n\n",
346 );
347 out.push_str("| Name | Meaning |\n|---|---|\n");
348 for info in BUILTIN_TYPE_NAMES {
349 out.push_str(&format!("| `{}` | {} |\n", info.word, info.meaning));
350 }
351 out
352}