Lime Parser Generator 0.1.0
Runtime-extensible LALR(1) parser with SIMD tokenization and LLVM JIT
Loading...
Searching...
No Matches
snapshot.h
1/*
2** Snapshot system core data structures for the extensible SQL parser.
3**
4** A ParserSnapshot captures the complete state of a parser's tables at a
5** point in time. Snapshots use atomic reference counting so they can be
6** safely shared across threads: readers acquire a reference before use and
7** release it when done. When the last reference is released the snapshot
8** and all of its owned memory are freed.
9*/
10#ifndef SNAPSHOT_H
11#define SNAPSHOT_H
12
13#include <stdint.h>
14#include <stdbool.h>
15
16/* Magic + ABI version stamped on every ParserSnapshot constructed
17** via snapshot_build_from_tables. Bumped on any layout-breaking
18** change to the struct. */
19#define LIME_SNAPSHOT_MAGIC 0x4C494D45U /* L,I,M,E */
20#define LIME_SNAPSHOT_ABI_VERSION 2
21
22
23/* Atomic refcount type.
24**
25** In C this is just <stdatomic.h>'s atomic_uint_fast32_t. In C++
26** the same name is not necessarily available (g++ before C++23
27** does not pull in <stdatomic.h>'s typedefs), so we typedef it to
28** std::atomic<std::uint_fast32_t> which has the same memory
29** layout in practice on every supported platform. The atomic
30** operations themselves only happen in C code in src/snapshot.c
31** (compiled as C, sees the C definition); C++ consumers only need
32** the field to exist for sizeof / pointer-to-struct purposes. */
33#ifdef __cplusplus
34#include <atomic>
35#include <cstdint>
36typedef std::atomic<std::uint_fast32_t> atomic_uint_fast32_t;
37#else
38#include <stdatomic.h>
39#endif
40
41/* Forward declarations for Lemon grammar structures.
42** The actual definitions live in lemon.c; snapshot consumers only
43** need pointers to these types. */
44struct symbol;
45struct rule;
46struct state;
47
48/* ------------------------------------------------------------------ */
49/* Host-reduce hook (Letter 30) */
50/* ------------------------------------------------------------------ */
51
80typedef int (*LimeHostReduceFn)(void *user, int ruleno,
81 const void *rhs_values, const int *rhs_locs,
82 int nrhs, void *lhs_out, int *lhs_loc_out);
83
84/* ------------------------------------------------------------------ */
85/* Semantic versioning */
86/* ------------------------------------------------------------------ */
87
95typedef struct SemVer {
96 uint32_t major;
97 uint32_t minor;
98 uint32_t patch;
99 char *prerelease;
100} SemVer;
101
105typedef enum VersionOp {
106 VERSION_OP_EQ = 0, /* == exact match */
107 VERSION_OP_GTE, /* >= greater-than-or-equal */
108 VERSION_OP_LTE, /* <= less-than-or-equal */
109 VERSION_OP_GT, /* > strictly greater */
110 VERSION_OP_LT, /* < strictly less */
111 VERSION_OP_CARET, /* ^ compatible (same major) */
112 VERSION_OP_TILDE, /* ~ approximately (same major.minor) */
113} VersionOp;
114
122
123/* ------------------------------------------------------------------ */
124/* Module dependency metadata */
125/* ------------------------------------------------------------------ */
126
142
163
164/* ------------------------------------------------------------------ */
165/* Snapshot */
166/* ------------------------------------------------------------------ */
167
168/*
169** A ParserSnapshot holds a frozen copy of every table the generated parser
170** needs at runtime. Fields fall into three groups:
171**
172** 1. Bookkeeping - version, refcount, timestamps
173** 2. Grammar data - symbols, rules, states (deep copies)
174** 3. Action tables - the compact arrays that drive the parse engine
175** 4. Module data - optional module identity and content hash
176*/
177typedef struct ParserSnapshot {
178 /* ================================================================
179 ** CACHELINE 0 (bytes 0..63): hot pointer reads.
180 **
181 ** Every parse_token call reads from these. Layout-critical: do
182 ** not move fields around within this block without rerunning
183 ** bench/bench_parse_fanout (the layout was chosen so all 8
184 ** pointers occupy exactly one 64-byte cacheline on x86_64 +
185 ** aarch64). L1 data prefetcher pulls the whole line in as a
186 ** unit on the first miss.
187 ** ================================================================ */
188
195
196 uint16_t *yy_action;
197 uint16_t *yy_lookahead;
198 int32_t *yy_shift_ofst;
204 int32_t *yy_reduce_ofst;
206 uint16_t *yy_default;
210 /* ================================================================
211 ** CACHELINE 1 (bytes 64..127): hot scalars + counts.
212 **
213 ** Action-table dispatch constants the parse_engine_step hot path
214 ** consults to classify action-table entries (shift vs reduce vs
215 ** accept) and to bounds-check indices into yy_action / yy_lookahead.
216 ** ================================================================ */
217
219 uint32_t action_count;
220 uint32_t nrule;
221 uint32_t nstate;
223 uint16_t yy_max_shift;
228 uint16_t yy_no_action;
229 uint16_t yy_min_reduce;
230 uint16_t yy_ntoken;
236
237 /* Cacheline 1 has 6 bytes of padding here to land yy_fallback on
238 ** an 8-byte boundary. Compiler inserts implicitly. */
239
241 uint16_t *yy_fallback;
242 uint32_t nfallback;
243 uint32_t reserved_pad;
245 /* ================================================================
246 ** CACHELINE 2 (bytes 128..191): refcount + magic.
247 **
248 ** Refcount is the only WRITTEN field on the parse path (via
249 ** atomic_fetch_add/sub in snapshot_acquire/release). Keep it
250 ** away from the read-only hot lines above so threads doing
251 ** parse_begin do not invalidate the cachelines other threads
252 ** are reading yy_action etc from.
253 **
254 ** parse_begin_borrowed bypasses the refcount entirely (see
255 ** include/parse_context.h); for the borrowed-API path this
256 ** cacheline is never touched on the hot path.
257 ** ================================================================ */
258
262 uint32_t magic;
263 uint16_t abi_version;
264 uint16_t reserved16;
269 uint64_t version;
270
274 atomic_uint_fast32_t refcount;
275
276 uint32_t reserved_pad2;
278 /* ================================================================
279 ** COLD: setup-time + introspection fields (rarely read after
280 ** snapshot construction).
281 ** ================================================================ */
282
283 /* --- Grammar data (deep-copied, owned by this snapshot) ----------- */
284
285 struct symbol **symbols;
286 uint32_t nsymbol;
287 uint32_t nterminal;
289 struct rule *rules;
291 struct state **states;
297 uint32_t grammar_source_len;
298 uint32_t reserved_pad3;
299
300 /* --- Module identity (optional, NULL when not part of a module) --- */
301
302 uint8_t merkle_root[32];
303 ParserModule *module;
307
309 void *jit_ctx;
310
311 /* --- Host-reduce hook (Letter 30) -------------------------------
312 ** Optional callback that runs a BASE-grammar reduce action over
313 ** this snapshot when the push parser (parse_token) performs a
314 ** reduce. NULL on every snapshot built before this feature and
315 ** on any recognition-only snapshot, in which case parse_token
316 ** drives the automaton to accept/reject WITHOUT running actions
317 ** (the historical behaviour -- fully back-compatible).
318 **
319 ** `lime -n` wires this to the generated, exported
320 ** <Name>HostReduce wrapper, which adapts the engine's value
321 ** stack to the static per-rule yy_rule_reduce_fn[] dispatch in
322 ** the parser .c. The signature mirrors LimeReduceFn (extension
323 ** reduces), so base and extension reduce paths share one ABI.
324 **
325 ** COLD field: never read on the shift hot path; consulted only
326 ** inside the reduce branch, and only when non-NULL. Additive
327 ** trailing field -- old snapshot readers never touch it, so no
328 ** abi_version bump is required (snapshot_build_from_tables
329 ** zero-inits it for tables that don't supply one). */
330 LimeHostReduceFn host_reduce;
331 void *host_reduce_user;
332
333 /* --- Token-name table (name -> code lookup) ---------------------
334 ** Optional copy of the generated yyTokenName[], indexed by internal
335 ** symbol index ([0]="$", terminals then nonterminals). Lets
336 ** lime_snapshot_token_code() map a token NAME to its external code
337 ** in THIS snapshot -- needed so a scanner can emit the right code
338 ** for an extension keyword after a runtime recompile renumbers the
339 ** token set. NULL when names were not provided (the lookup then
340 ** returns -1). Deep-copied + owned by the snapshot. */
341 char **token_names;
342 uint32_t token_names_count;
344
345/*
346** Acquire a reference to an existing snapshot. The caller must eventually
347** call snapshot_release() to avoid leaking the snapshot.
348**
349** Returns the same pointer that was passed in, for convenience:
350** ParserSnapshot *my_ref = snapshot_acquire(shared_snap);
351**
352** Passing NULL is safe and returns NULL.
353*/
354ParserSnapshot *snapshot_acquire(ParserSnapshot *snap);
355
356/*
357** Release a reference previously obtained via snapshot_acquire() or
358** create_base_snapshot(). When the last reference is released the
359** snapshot and all memory it owns are freed.
360**
361** Passing NULL is safe and does nothing.
362*/
363void snapshot_release(ParserSnapshot *snap);
364
365/*
366** Create a base snapshot from *grammar_file*.
367**
368** The runtime delegates to a per-grammar <Prefix>BuildSnapshot()
369** function emitted by `lime -n grammar.y` (see snapshot_build.h
370** and the LimeParserTables struct). When no such builder is linked
371** into the host process this function returns NULL with an
372** actionable error message.
373**
374** Building a snapshot directly from a grammar file at runtime --
375** without a pre-compiled <Prefix>BuildSnapshot() symbol -- is
376** under construction. It requires exposing the lime generator's
377** LALR(1) Build()/ReportTable() phases as a library callable from
378** the runtime; the generator's algorithm is fully implemented in
379** lime.c but not yet refactored into a public function.
380**
381** Returns a snapshot with refcount == 1 on success, or NULL with
382** *error pointing to a malloc'd message on failure.
383*/
384ParserSnapshot *create_base_snapshot(const char *grammar_file, char **error);
385
386/* ------------------------------------------------------------------ */
387/* SemVer utilities */
388/* ------------------------------------------------------------------ */
389
390/*
391** Parse a semantic version string ("1.2.3" or "1.2.3-beta.1") into a
392** SemVer struct. Returns true on success. On failure *out is zeroed
393** and the function returns false.
394*/
395bool semver_parse(const char *str, SemVer *out);
396
397/*
398** Compare two semantic versions. Returns <0, 0, or >0 following the
399** same convention as strcmp. Prerelease versions sort before their
400** release counterpart (e.g. 1.0.0-alpha < 1.0.0).
401*/
402int semver_compare(const SemVer *a, const SemVer *b);
403
404/*
405** Check whether *ver* satisfies *constraint*.
406*/
407bool semver_satisfies(const SemVer *ver, const VersionConstraint *constraint);
408
409/*
410** Free resources owned by a SemVer (just the prerelease string).
411** Does not free the SemVer struct itself.
412*/
413void semver_destroy(SemVer *v);
414
415/* ------------------------------------------------------------------ */
416/* Module lifecycle helpers */
417/* ------------------------------------------------------------------ */
418
419/*
420** Deep-free a ParserModule and all memory it owns (name, version,
421** dependencies, exports, imports). Does not free the pointer itself
422** unless *mod* was heap-allocated by the caller.
423*/
424void parser_module_destroy_contents(ParserModule *mod);
425
426/*
427** Deep-free a ParserDependency's owned memory.
428*/
429void parser_dependency_destroy_contents(ParserDependency *dep);
430
431#endif /* SNAPSHOT_H */
A dependency declaration from one module to another.
Definition snapshot.h:135
bool optional
If true, unsatisfied is not an error.
Definition snapshot.h:140
char * module_name
Target module name (owned)
Definition snapshot.h:136
uint32_t nconstraints
Number of entries in constraints.
Definition snapshot.h:139
VersionConstraint * constraints
Array of version constraints.
Definition snapshot.h:138
uint8_t merkle_root[32]
Expected content hash (zero = any)
Definition snapshot.h:137
A parser module: a named, versioned unit of grammar with explicit dependency, export,...
Definition snapshot.h:150
char ** exports
Symbol names exported by this module.
Definition snapshot.h:157
char * name
Unique module name (owned)
Definition snapshot.h:151
char ** imports
Symbol names imported from other modules.
Definition snapshot.h:160
ParserDependency * dependencies
Array of dependencies (owned)
Definition snapshot.h:154
SemVer version
Module version.
Definition snapshot.h:152
uint32_t nimports
Length of imports.
Definition snapshot.h:161
uint32_t nexports
Length of exports.
Definition snapshot.h:158
uint32_t ndependencies
Length of Dependencies.
Definition snapshot.h:155
Opaque snapshot handle.
Definition snapshot.h:177
uint32_t lookahead_count
Number of entries in yy_lookahead.
Definition snapshot.h:218
uint16_t yy_no_action
Marker for unused slot.
Definition snapshot.h:228
struct symbol ** symbols
Array of pointers to symbol structs.
Definition snapshot.h:285
uint16_t yy_max_shiftreduce
Shift-reduce range maximum.
Definition snapshot.h:225
int32_t * yy_shift_ofst
Per-state offset into yy_action for shifts.
Definition snapshot.h:198
uint16_t * yy_default
Default action for each state.
Definition snapshot.h:206
uint16_t * yy_fallback
Optional fallback table (length = nfallback, may be NULL).
Definition snapshot.h:241
uint16_t yy_accept_action
Marker for parser accept.
Definition snapshot.h:227
char * grammar_source
Optional original grammar source text.
Definition snapshot.h:296
uint16_t yy_first_token
first_token directive value: subtracted from external token codes to get the internal action-table in...
Definition snapshot.h:235
void * jit_find_shift_fn
Cached pointer to the JIT'd jit_find_shift_action function, or NULL if no JIT is attached.
Definition snapshot.h:194
uint64_t version
Monotonically increasing version number.
Definition snapshot.h:269
uint32_t nfallback
Length of yy_fallback.
Definition snapshot.h:242
uint32_t reserved_pad2
Padding to 8-byte boundary.
Definition snapshot.h:276
void * jit_ctx
JIT compilation context.
Definition snapshot.h:309
atomic_uint_fast32_t refcount
Atomic reference count.
Definition snapshot.h:274
int32_t * yy_reduce_ofst
Per-state offset into yy_action for reduces.
Definition snapshot.h:204
uint16_t yy_min_shiftreduce
Shift-reduce range minimum.
Definition snapshot.h:224
uint16_t yy_max_shift
0..YY_MAX_SHIFT = shift to that state
Definition snapshot.h:223
uint32_t nterminal
Number of terminal symbols.
Definition snapshot.h:287
uint32_t nsymbol
Total number of symbols.
Definition snapshot.h:286
uint16_t yy_ntoken
Highest terminal code + 1.
Definition snapshot.h:230
int16_t * yy_rule_info_lhs
LHS symbol code per rule.
Definition snapshot.h:207
uint16_t reserved16
Padding – next field is 8-byte aligned.
Definition snapshot.h:264
int8_t * yy_rule_info_nrhs
Negative number of RHS symbols per rule.
Definition snapshot.h:208
uint32_t nrule
Total number of rules.
Definition snapshot.h:220
uint16_t yy_error_action
Marker for syntax error.
Definition snapshot.h:226
uint8_t merkle_root[32]
Content hash of grammar data.
Definition snapshot.h:302
struct state ** states
Array of pointers to state structs.
Definition snapshot.h:291
uint16_t yy_min_reduce
Reduce range minimum (max = nstate+nrule)
Definition snapshot.h:229
uint32_t reserved_pad
Padding – atomics on next line.
Definition snapshot.h:243
uint32_t action_count
Number of entries in yy_action.
Definition snapshot.h:219
uint32_t magic
Magic 'LIME' + ABI version stamped by snapshot_build_from_tables at construction time.
Definition snapshot.h:262
uint32_t nstate
Total number of parser states.
Definition snapshot.h:221
struct rule * rules
Linked list of production rules.
Definition snapshot.h:289
uint16_t * yy_lookahead
Lookahead values parallel to yy_action.
Definition snapshot.h:197
ParserModule *uint64_t create_time_ns
< Owning module metadata, or NULL
Definition snapshot.h:306
uint16_t * yy_action
Combined shift+reduce action array.
Definition snapshot.h:196
A parsed semantic version: major.minor.patch with optional prerelease label (e.g.
Definition snapshot.h:95
uint32_t major
Major version component.
Definition snapshot.h:96
uint32_t minor
Minor version component.
Definition snapshot.h:97
uint32_t patch
Patch version component.
Definition snapshot.h:98
char * prerelease
Prerelease label (malloc'd; NULL if absent)
Definition snapshot.h:99
A single version constraint on a dependency, e.g.
Definition snapshot.h:118
SemVer version
Reference version for the operator.
Definition snapshot.h:120
VersionOp op
Constraint operator.
Definition snapshot.h:119