From e3828129227984ad3216aaccd6cc2833331955a8 Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Tue, 6 Jan 2026 10:59:20 -0300 Subject: [PATCH] refactor: decompose `emit/mod.rs` into focused modules --- .../emit/{codegen_tests.rs => emit_tests.rs} | 44 +- crates/plotnik-lib/src/emit/emitter.rs | 291 ++++++ crates/plotnik-lib/src/emit/error.rs | 41 + crates/plotnik-lib/src/emit/mod.rs | 984 +----------------- ...t__emit_tests__alternations_captured.snap} | 2 +- ..._tests__alternations_captured_tagged.snap} | 2 +- ...it_tests__alternations_in_quantifier.snap} | 2 +- ...it__emit_tests__alternations_labeled.snap} | 2 +- ...s__alternations_no_internal_captures.snap} | 2 +- ...t_tests__alternations_null_injection.snap} | 2 +- ...ernations_tagged_in_field_constraint.snap} | 2 +- ...ernations_tagged_with_definition_ref.snap} | 2 +- ...__emit_tests__alternations_unlabeled.snap} | 2 +- ...emit_tests__anchors_between_siblings.snap} | 2 +- ...mit__emit_tests__anchors_first_child.snap} | 2 +- ...emit__emit_tests__anchors_last_child.snap} | 2 +- ..._emit__emit_tests__anchors_no_anchor.snap} | 2 +- ...__emit_tests__anchors_with_anonymous.snap} | 2 +- ...ib__emit__emit_tests__captures_basic.snap} | 2 +- ...__emit_tests__captures_deeply_nested.snap} | 2 +- ...__captures_enum_with_type_annotation.snap} | 2 +- ..._emit__emit_tests__captures_multiple.snap} | 2 +- ...it__emit_tests__captures_nested_flat.snap} | 2 +- ...ts__captures_optional_wrapper_struct.snap} | 2 +- ...t__emit_tests__captures_struct_scope.snap} | 2 +- ...captures_struct_with_type_annotation.snap} | 2 +- ...mit_tests__captures_with_type_custom.snap} | 2 +- ...mit_tests__captures_with_type_string.snap} | 2 +- ..._emit_tests__captures_wrapper_struct.snap} | 2 +- ...ests__comprehensive_multi_definition.snap} | 2 +- ...it__emit_tests__definitions_multiple.snap} | 2 +- ...it_tests__definitions_nested_capture.snap} | 2 +- ...t__emit_tests__definitions_reference.snap} | 2 +- ...emit__emit_tests__definitions_single.snap} | 2 +- ...emit__emit_tests__fields_alternation.snap} | 2 +- ...b__emit__emit_tests__fields_multiple.snap} | 2 +- ...ib__emit__emit_tests__fields_negated.snap} | 2 +- ...lib__emit__emit_tests__fields_single.snap} | 2 +- ...b__emit__emit_tests__nodes_anonymous.snap} | 2 +- ...k_lib__emit__emit_tests__nodes_error.snap} | 2 +- ...lib__emit__emit_tests__nodes_missing.snap} | 2 +- ...k_lib__emit__emit_tests__nodes_named.snap} | 2 +- ...emit__emit_tests__nodes_wildcard_any.snap} | 2 +- ...it__emit_tests__nodes_wildcard_named.snap} | 2 +- ...it__emit_tests__optional_first_child.snap} | 2 +- ..._emit_tests__optional_null_injection.snap} | 2 +- ...tests__quantifiers_first_child_array.snap} | 2 +- ...it__emit_tests__quantifiers_optional.snap} | 2 +- ...ests__quantifiers_optional_nongreedy.snap} | 2 +- ...__emit__emit_tests__quantifiers_plus.snap} | 2 +- ...it_tests__quantifiers_plus_nongreedy.snap} | 2 +- ...tests__quantifiers_repeat_navigation.snap} | 2 +- ...__quantifiers_sequence_in_called_def.snap} | 2 +- ...__emit__emit_tests__quantifiers_star.snap} | 2 +- ...it_tests__quantifiers_star_nongreedy.snap} | 2 +- ...emit_tests__quantifiers_struct_array.snap} | 2 +- ...__emit__emit_tests__recursion_simple.snap} | 2 +- ...ts__recursion_with_structured_result.snap} | 2 +- ...b__emit__emit_tests__sequences_basic.snap} | 2 +- ..._emit_tests__sequences_in_quantifier.snap} | 2 +- ...__emit__emit_tests__sequences_nested.snap} | 2 +- ..._emit_tests__sequences_with_captures.snap} | 2 +- crates/plotnik-lib/src/emit/string_table.rs | 129 +++ .../src/emit/string_table_tests.rs | 120 +++ crates/plotnik-lib/src/emit/type_table.rs | 539 ++++++++++ .../plotnik-lib/src/emit/type_table_tests.rs | 30 + crates/plotnik-lib/src/engine/engine_tests.rs | 36 +- docs/binary-format/07-dump-format.md | 16 +- docs/binary-format/08-trace-format.md | 1 + 69 files changed, 1250 insertions(+), 1097 deletions(-) rename crates/plotnik-lib/src/emit/{codegen_tests.rs => emit_tests.rs} (82%) create mode 100644 crates/plotnik-lib/src/emit/emitter.rs create mode 100644 crates/plotnik-lib/src/emit/error.rs rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__alternations_captured.snap => plotnik_lib__emit__emit_tests__alternations_captured.snap} (93%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__alternations_captured_tagged.snap => plotnik_lib__emit__emit_tests__alternations_captured_tagged.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__alternations_in_quantifier.snap => plotnik_lib__emit__emit_tests__alternations_in_quantifier.snap} (97%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__alternations_labeled.snap => plotnik_lib__emit__emit_tests__alternations_labeled.snap} (94%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__alternations_no_internal_captures.snap => plotnik_lib__emit__emit_tests__alternations_no_internal_captures.snap} (94%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__alternations_null_injection.snap => plotnik_lib__emit__emit_tests__alternations_null_injection.snap} (94%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__alternations_tagged_in_field_constraint.snap => plotnik_lib__emit__emit_tests__alternations_tagged_in_field_constraint.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__alternations_tagged_with_definition_ref.snap => plotnik_lib__emit__emit_tests__alternations_tagged_with_definition_ref.snap} (96%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__alternations_unlabeled.snap => plotnik_lib__emit__emit_tests__alternations_unlabeled.snap} (94%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__anchors_between_siblings.snap => plotnik_lib__emit__emit_tests__anchors_between_siblings.snap} (93%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__anchors_first_child.snap => plotnik_lib__emit__emit_tests__anchors_first_child.snap} (93%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__anchors_last_child.snap => plotnik_lib__emit__emit_tests__anchors_last_child.snap} (94%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__anchors_no_anchor.snap => plotnik_lib__emit__emit_tests__anchors_no_anchor.snap} (93%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__anchors_with_anonymous.snap => plotnik_lib__emit__emit_tests__anchors_with_anonymous.snap} (93%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__captures_basic.snap => plotnik_lib__emit__emit_tests__captures_basic.snap} (92%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__captures_deeply_nested.snap => plotnik_lib__emit__emit_tests__captures_deeply_nested.snap} (96%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__captures_enum_with_type_annotation.snap => plotnik_lib__emit__emit_tests__captures_enum_with_type_annotation.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__captures_multiple.snap => plotnik_lib__emit__emit_tests__captures_multiple.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__captures_nested_flat.snap => plotnik_lib__emit__emit_tests__captures_nested_flat.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__captures_optional_wrapper_struct.snap => plotnik_lib__emit__emit_tests__captures_optional_wrapper_struct.snap} (96%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__captures_struct_scope.snap => plotnik_lib__emit__emit_tests__captures_struct_scope.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__captures_struct_with_type_annotation.snap => plotnik_lib__emit__emit_tests__captures_struct_with_type_annotation.snap} (94%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__captures_with_type_custom.snap => plotnik_lib__emit__emit_tests__captures_with_type_custom.snap} (93%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__captures_with_type_string.snap => plotnik_lib__emit__emit_tests__captures_with_type_string.snap} (92%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__captures_wrapper_struct.snap => plotnik_lib__emit__emit_tests__captures_wrapper_struct.snap} (97%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__comprehensive_multi_definition.snap => plotnik_lib__emit__emit_tests__comprehensive_multi_definition.snap} (97%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__definitions_multiple.snap => plotnik_lib__emit__emit_tests__definitions_multiple.snap} (94%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__definitions_nested_capture.snap => plotnik_lib__emit__emit_tests__definitions_nested_capture.snap} (97%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__definitions_reference.snap => plotnik_lib__emit__emit_tests__definitions_reference.snap} (96%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__definitions_single.snap => plotnik_lib__emit__emit_tests__definitions_single.snap} (92%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__fields_alternation.snap => plotnik_lib__emit__emit_tests__fields_alternation.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__fields_multiple.snap => plotnik_lib__emit__emit_tests__fields_multiple.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__fields_negated.snap => plotnik_lib__emit__emit_tests__fields_negated.snap} (94%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__fields_single.snap => plotnik_lib__emit__emit_tests__fields_single.snap} (93%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__nodes_anonymous.snap => plotnik_lib__emit__emit_tests__nodes_anonymous.snap} (93%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__nodes_error.snap => plotnik_lib__emit__emit_tests__nodes_error.snap} (92%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__nodes_missing.snap => plotnik_lib__emit__emit_tests__nodes_missing.snap} (92%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__nodes_named.snap => plotnik_lib__emit__emit_tests__nodes_named.snap} (92%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__nodes_wildcard_any.snap => plotnik_lib__emit__emit_tests__nodes_wildcard_any.snap} (93%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__nodes_wildcard_named.snap => plotnik_lib__emit__emit_tests__nodes_wildcard_named.snap} (93%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__optional_first_child.snap => plotnik_lib__emit__emit_tests__optional_first_child.snap} (96%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__quantifiers_optional.snap => plotnik_lib__emit__emit_tests__optional_null_injection.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__quantifiers_first_child_array.snap => plotnik_lib__emit__emit_tests__quantifiers_first_child_array.snap} (97%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__optional_null_injection.snap => plotnik_lib__emit__emit_tests__quantifiers_optional.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__quantifiers_optional_nongreedy.snap => plotnik_lib__emit__emit_tests__quantifiers_optional_nongreedy.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__quantifiers_plus.snap => plotnik_lib__emit__emit_tests__quantifiers_plus.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__quantifiers_plus_nongreedy.snap => plotnik_lib__emit__emit_tests__quantifiers_plus_nongreedy.snap} (95%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__quantifiers_repeat_navigation.snap => plotnik_lib__emit__emit_tests__quantifiers_repeat_navigation.snap} (96%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__quantifiers_sequence_in_called_def.snap => plotnik_lib__emit__emit_tests__quantifiers_sequence_in_called_def.snap} (97%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__quantifiers_star.snap => plotnik_lib__emit__emit_tests__quantifiers_star.snap} (96%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__quantifiers_star_nongreedy.snap => plotnik_lib__emit__emit_tests__quantifiers_star_nongreedy.snap} (96%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__quantifiers_struct_array.snap => plotnik_lib__emit__emit_tests__quantifiers_struct_array.snap} (97%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__recursion_simple.snap => plotnik_lib__emit__emit_tests__recursion_simple.snap} (96%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__recursion_with_structured_result.snap => plotnik_lib__emit__emit_tests__recursion_with_structured_result.snap} (97%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__sequences_basic.snap => plotnik_lib__emit__emit_tests__sequences_basic.snap} (93%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__sequences_in_quantifier.snap => plotnik_lib__emit__emit_tests__sequences_in_quantifier.snap} (96%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__sequences_nested.snap => plotnik_lib__emit__emit_tests__sequences_nested.snap} (94%) rename crates/plotnik-lib/src/emit/snapshots/{plotnik_lib__emit__codegen_tests__sequences_with_captures.snap => plotnik_lib__emit__emit_tests__sequences_with_captures.snap} (94%) create mode 100644 crates/plotnik-lib/src/emit/string_table.rs create mode 100644 crates/plotnik-lib/src/emit/string_table_tests.rs create mode 100644 crates/plotnik-lib/src/emit/type_table.rs create mode 100644 crates/plotnik-lib/src/emit/type_table_tests.rs diff --git a/crates/plotnik-lib/src/emit/codegen_tests.rs b/crates/plotnik-lib/src/emit/emit_tests.rs similarity index 82% rename from crates/plotnik-lib/src/emit/codegen_tests.rs rename to crates/plotnik-lib/src/emit/emit_tests.rs index 4f654d77..2be50782 100644 --- a/crates/plotnik-lib/src/emit/codegen_tests.rs +++ b/crates/plotnik-lib/src/emit/emit_tests.rs @@ -18,9 +18,7 @@ macro_rules! snap { }}; } -// ============================================================================ -// 1. NODES -// ============================================================================ +// Nodes #[test] fn nodes_named() { @@ -64,9 +62,7 @@ fn nodes_missing() { "#}); } -// ============================================================================ -// 2. CAPTURES -// ============================================================================ +// Captures #[test] fn captures_basic() { @@ -147,9 +143,7 @@ fn captures_enum_with_type_annotation() { "#}); } -// ============================================================================ -// 3. FIELDS -// ============================================================================ +// Fields #[test] fn fields_single() { @@ -184,9 +178,7 @@ fn fields_alternation() { "#}); } -// ============================================================================ -// 4. QUANTIFIERS -// ============================================================================ +// Quantifiers #[test] fn quantifiers_optional() { @@ -262,9 +254,7 @@ fn quantifiers_sequence_in_called_def() { "#}); } -// ============================================================================ -// 5. SEQUENCES -// ============================================================================ +// Sequences #[test] fn sequences_basic() { @@ -294,9 +284,7 @@ fn sequences_in_quantifier() { "#}); } -// ============================================================================ -// 6. ALTERNATIONS -// ============================================================================ +// Alternations #[test] fn alternations_unlabeled() { @@ -368,9 +356,7 @@ fn alternations_tagged_in_field_constraint() { "#}); } -// ============================================================================ -// 7. ANCHORS -// ============================================================================ +// Anchors #[test] fn anchors_between_siblings() { @@ -407,9 +393,7 @@ fn anchors_no_anchor() { "#}); } -// ============================================================================ -// 8. NAMED EXPRESSIONS -// ============================================================================ +// Named expressions #[test] fn definitions_single() { @@ -442,9 +426,7 @@ fn definitions_nested_capture() { "#}); } -// ============================================================================ -// 9. RECURSION -// ============================================================================ +// Recursion #[test] fn recursion_simple() { @@ -468,9 +450,7 @@ fn recursion_with_structured_result() { "#}); } -// ============================================================================ -// 10. OPTIONALS -// ============================================================================ +// Optionals #[test] fn optional_first_child() { @@ -486,9 +466,7 @@ fn optional_null_injection() { "#}); } -// ============================================================================ -// 11. COMPREHENSIVE -// ============================================================================ +// Comprehensive #[test] fn comprehensive_multi_definition() { diff --git a/crates/plotnik-lib/src/emit/emitter.rs b/crates/plotnik-lib/src/emit/emitter.rs new file mode 100644 index 00000000..b1f6dd46 --- /dev/null +++ b/crates/plotnik-lib/src/emit/emitter.rs @@ -0,0 +1,291 @@ +//! Core bytecode emission logic. +//! +//! Contains the main entry points for emitting bytecode from compiled queries. + +use indexmap::IndexMap; +use plotnik_core::{Interner, NodeFieldId, NodeTypeId, Symbol}; + +use crate::analyze::symbol_table::SymbolTable; +use crate::analyze::type_check::{TypeContext, TypeId}; +use crate::bytecode::ir::Label; +use crate::bytecode::{ + Entrypoint, FieldSymbol, Header, NodeSymbol, SECTION_ALIGN, TriviaEntry, TypeMetaHeader, +}; +use crate::compile::Compiler; +use crate::query::query::LinkedQuery; + +use super::EmitError; +use super::layout::CacheAligned; +use super::string_table::StringTableBuilder; +use super::type_table::TypeTableBuilder; + +/// Emit bytecode from type context only (no node validation). +pub fn emit( + type_ctx: &TypeContext, + interner: &Interner, + symbol_table: &SymbolTable, +) -> Result, EmitError> { + emit_inner(type_ctx, interner, symbol_table, None, None) +} + +/// Emit bytecode from a LinkedQuery (includes node type/field validation info). +pub fn emit_linked(query: &LinkedQuery) -> Result, EmitError> { + emit_inner( + query.type_context(), + query.interner(), + &query.symbol_table, + Some(query.node_type_ids()), + Some(query.node_field_ids()), + ) +} + +/// Shared bytecode emission logic. +fn emit_inner( + type_ctx: &TypeContext, + interner: &Interner, + symbol_table: &SymbolTable, + node_type_ids: Option<&IndexMap>, + node_field_ids: Option<&IndexMap>, +) -> Result, EmitError> { + let is_linked = node_type_ids.is_some(); + let mut strings = StringTableBuilder::new(); + let mut types = TypeTableBuilder::new(); + types.build(type_ctx, interner, &mut strings)?; + + // Compile transitions (strings are interned here for unlinked mode) + let compile_result = Compiler::compile( + interner, + type_ctx, + symbol_table, + &mut strings, + node_type_ids, + node_field_ids, + ) + .map_err(EmitError::Compile)?; + + // Layout with cache alignment + // Preamble entry FIRST ensures it gets the lowest address (step 0) + let mut entry_labels: Vec