Skip to content

feat(oxabl_semantic): crate skeleton and declare pass (Phase 3)#49

Merged
evanbrobertson merged 1 commit into
masterfrom
feat/oxabl-semantic-phase3
Apr 18, 2026
Merged

feat(oxabl_semantic): crate skeleton and declare pass (Phase 3)#49
evanbrobertson merged 1 commit into
masterfrom
feat/oxabl-semantic-phase3

Conversation

@evanbrobertson
Copy link
Copy Markdown
Contributor

Summary

Ships Phase 3 of the semantic layer v1 plan (docs/plans/2026-04-16-004-feat-semantic-layer-v1-plan.md): the `oxabl_semantic` crate skeleton plus the declare pass.

  • New crate `oxabl_semantic` — no `serde_json` dep, per plan (dump crate stays separate so formatter/LSP don't transitively pull it).
  • Scope tree (`scope.rs`): arena-allocated `ScopeTree` + `Scope` + `ScopeKind` covering every parser-produced construct that opens a scope.
  • BindingMap: `Small(SmallVec)` → `Large(FxHashMap)` with a cap-8 threshold matching the plan's measurement that > 95% of ABL scopes stay in the small variant.
  • Symbol table (`symbol.rs`): `SymbolId` arena, bitflags-based `SymbolFlags`, `rebinding_scopes` side map (reserved for Phase 4a SHARED handling). Display casing sliced from source at diagnostic time rather than stored per-symbol.
  • Namespaces (`namespace.rs`): 10 variants + `NUM_NAMESPACES` constant, discriminant-indexed.
  • Types stub (`types.rs`): `ResolvedType` + `PrimitiveTy` with `DataType → ResolvedType` lowering for the declare pass's typed declarations.
  • Builtins (`builtins.rs`): seeds five entries (`THIS-OBJECT`, `SUPER`, `SELF`, `SESSION`, `ERROR-STATUS`) per plan.
  • Declare pass (`resolve.rs`, declare half): walks every declaration-emitting statement, opens the correct scope, records the symbol. Emits `SEM0001` (duplicate) and `SEM0003` (BLOB/CLOB local); `SEM0002` reserved for Phase 4a.
  • `NodeIndexVec` side table (`index_vec.rs`): dense, monotonically-keyed side table for references + types. Seeded empty now so Phase 4a/4b slot in without reworking the `Semantic` shape.
  • `VirtualSpan` newtype (`oxabl_common`): load-bearing distinction for the post-preprocessor offset regime.

Testing

  • 66 inline tests in `oxabl_semantic` (47 covering the declare pass across VARIABLE / PARAMETER / TEMP-TABLE / BUFFER / STREAM / FRAME / EVENT / PROPERTY / DATASET / DATA-SOURCE / PROCEDURE / FUNCTION / CLASS / METHOD / INTERFACE / CONSTRUCTOR / DESTRUCTOR / CATCH / DO-counter / FOR EACH / PreprocIf / ON / TRIGGER PROCEDURE / SEM0001 / SEM0003, plus 19 for supporting data structures).
  • `cargo test --workspace` green.
  • `cargo clippy --workspace --all-targets -- -D warnings` green.
  • `cargo fmt --check` green.

Post-Deploy Monitoring & Validation

No additional operational monitoring required: `oxabl_semantic` is a library crate with no runtime, network, or on-disk state. Correctness is verified by the 66 inline tests and workspace CI; there is no service to observe after merge.

Plan linkage

  • Phase 3 checkboxes marked complete in `docs/plans/2026-04-16-004-feat-semantic-layer-v1-plan.md`.
  • Sets up the NodeIndexVec side table + Semantic shape for Phase 4a/4b.

Compound Engineered 🤖 Generated with Claude Code

Introduces the oxabl_semantic crate — the first semantic analysis layer for
oxabl. v1 ships the declare pass plus the scaffolding every subsequent pass
will build on:

- Scope tree: arena-allocated ScopeTree, Scope, ScopeKind covering every
  parser-produced construct (file root, procedure, function, class, method,
  property accessors, constructor/destructor, blocks, catch/finally,
  triggers, frame, trigger procedure).
- BindingMap: Small/Large enum with linear-scan inline storage up to 8
  bindings (the majority case in ABL per the plan), spilling to a hashmap
  past the cap.
- Symbol table: SymbolId arena + bitflags SymbolFlags covering access
  modifier, static/abstract/final/override, NO_UNDO, parameter direction,
  and SHARED/NEW SHARED/NEW GLOBAL SHARED. Stores case-folded OxablAtom;
  display casing reconstructed from span at diagnostic time.
- Namespace: NamespaceId enum with 10 variants + NUM_NAMESPACES. Scopes
  carry [BindingMap; NUM_NAMESPACES] indexed by discriminant.
- Types: ResolvedType + PrimitiveTy, with DataType→ResolvedType lowering
  used by the declare pass for typed declarations.
- Builtins: five ambient names seeded into the file scope per plan.
- Declare pass (resolve.rs, declare half): walks every declaration-emitting
  statement, opens the right scope, records the symbol, tracks flags.
  Emits SEM0001 (duplicate), SEM0003 (BLOB/CLOB local). SEM0002 reserved
  for Phase 4a when SHARED-mismatch becomes visible.
- NodeIndexVec side table: dense Vec-backed side table keyed by NodeId,
  seeded (empty) for references + types so Phase 4a/4b plug into an
  existing shape without reworking Semantic.

Also lands:

- oxabl_common::VirtualSpan newtype — post-preprocessor offsets; the plan
  calls out VirtualSpan/FileSpan distinction as load-bearing and this is
  the only dependency the semantic layer needs from oxabl_common for spans.

Tests: 66 inline tests in oxabl_semantic (47 covering every declaration
form in the declare pass, 19 covering supporting data structures). Zero
serde_json dependency per plan.
@evanbrobertson evanbrobertson merged commit b5adc7e into master Apr 18, 2026
6 checks passed
@evanbrobertson evanbrobertson deleted the feat/oxabl-semantic-phase3 branch April 18, 2026 03:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant