From 2094324e6e0b47379fd2a070846cf630b5b0f41e Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Tue, 6 Jan 2026 12:58:44 -0300 Subject: [PATCH] refactor: clean up bytecode module naming and structure --- crates/plotnik-lib/src/bytecode/dump.rs | 10 +- crates/plotnik-lib/src/bytecode/entrypoint.rs | 4 +- crates/plotnik-lib/src/bytecode/format.rs | 36 ----- crates/plotnik-lib/src/bytecode/ids.rs | 2 +- crates/plotnik-lib/src/bytecode/ir.rs | 151 +----------------- crates/plotnik-lib/src/bytecode/ir_tests.rs | 139 ++++++++++++++++ crates/plotnik-lib/src/bytecode/mod.rs | 11 +- crates/plotnik-lib/src/bytecode/module.rs | 16 +- crates/plotnik-lib/src/bytecode/sections.rs | 2 +- crates/plotnik-lib/src/bytecode/type_meta.rs | 14 +- crates/plotnik-lib/src/compile/capture.rs | 2 +- crates/plotnik-lib/src/compile/compiler.rs | 4 +- crates/plotnik-lib/src/compile/error.rs | 4 +- crates/plotnik-lib/src/compile/expressions.rs | 4 +- crates/plotnik-lib/src/compile/quantifier.rs | 2 +- crates/plotnik-lib/src/compile/scope.rs | 2 +- crates/plotnik-lib/src/compile/sequences.rs | 2 +- crates/plotnik-lib/src/emit/emitter.rs | 6 +- crates/plotnik-lib/src/emit/layout.rs | 12 +- crates/plotnik-lib/src/emit/layout_tests.rs | 2 +- crates/plotnik-lib/src/emit/type_table.rs | 55 ++++--- crates/plotnik-lib/src/engine/materializer.rs | 14 +- crates/plotnik-lib/src/engine/verify.rs | 16 +- crates/plotnik-lib/src/engine/verify_tests.rs | 4 +- .../src/typegen/typescript/analysis.rs | 28 ++-- .../src/typegen/typescript/convert.rs | 18 +-- .../src/typegen/typescript/emitter.rs | 12 +- .../src/typegen/typescript/naming.rs | 12 +- .../src/typegen/typescript/render.rs | 10 +- 29 files changed, 288 insertions(+), 306 deletions(-) create mode 100644 crates/plotnik-lib/src/bytecode/ir_tests.rs diff --git a/crates/plotnik-lib/src/bytecode/dump.rs b/crates/plotnik-lib/src/bytecode/dump.rs index bccf1c37..3da907aa 100644 --- a/crates/plotnik-lib/src/bytecode/dump.rs +++ b/crates/plotnik-lib/src/bytecode/dump.rs @@ -9,7 +9,7 @@ use crate::colors::Colors; use super::NAMED_WILDCARD; use super::format::{LineBuilder, Symbol, format_effect, nav_symbol_epsilon, width_for_count}; -use super::ids::QTypeId; +use super::ids::TypeId; use super::instructions::StepId; use super::module::{Instruction, Module}; use super::type_meta::TypeKind; @@ -217,15 +217,15 @@ fn dump_types_defs(out: &mut String, module: &Module, ctx: &DumpContext) { format!("{} ; {}{}", c.dim, variants.join(" | "), c.reset) } TypeKind::Optional => { - let inner_name = format_type_name(QTypeId(def.data), module, ctx); + let inner_name = format_type_name(TypeId(def.data), module, ctx); format!("{} ; {}?{}", c.dim, inner_name, c.reset) } TypeKind::ArrayZeroOrMore => { - let inner_name = format_type_name(QTypeId(def.data), module, ctx); + let inner_name = format_type_name(TypeId(def.data), module, ctx); format!("{} ; {}*{}", c.dim, inner_name, c.reset) } TypeKind::ArrayOneOrMore => { - let inner_name = format_type_name(QTypeId(def.data), module, ctx); + let inner_name = format_type_name(TypeId(def.data), module, ctx); format!("{} ; {}+{}", c.dim, inner_name, c.reset) } TypeKind::Alias => String::new(), @@ -282,7 +282,7 @@ fn dump_types_names(out: &mut String, module: &Module, ctx: &DumpContext) { } /// Format a type ID as a human-readable name. -fn format_type_name(type_id: QTypeId, module: &Module, ctx: &DumpContext) -> String { +fn format_type_name(type_id: TypeId, module: &Module, ctx: &DumpContext) -> String { let types = module.types(); let strings = module.strings(); diff --git a/crates/plotnik-lib/src/bytecode/entrypoint.rs b/crates/plotnik-lib/src/bytecode/entrypoint.rs index 7f256855..979cba00 100644 --- a/crates/plotnik-lib/src/bytecode/entrypoint.rs +++ b/crates/plotnik-lib/src/bytecode/entrypoint.rs @@ -1,7 +1,7 @@ //! Entrypoint section types. use super::instructions::StepAddr; -use super::{QTypeId, StringId}; +use super::{StringId, TypeId}; /// Named query definition entry point (8 bytes). #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -12,7 +12,7 @@ pub struct Entrypoint { /// Starting instruction address. pub target: StepAddr, /// Result type. - pub result_type: QTypeId, + pub result_type: TypeId, pub(crate) _pad: u16, } diff --git a/crates/plotnik-lib/src/bytecode/format.rs b/crates/plotnik-lib/src/bytecode/format.rs index c1802e22..3996eb0c 100644 --- a/crates/plotnik-lib/src/bytecode/format.rs +++ b/crates/plotnik-lib/src/bytecode/format.rs @@ -10,10 +10,6 @@ use super::EffectOp; use super::effects::EffectOpcode; use super::nav::Nav; -// ============================================================================= -// Column Layout -// ============================================================================= - /// Column widths for instruction line formatting. pub mod cols { /// Leading indentation (2 spaces). @@ -26,10 +22,6 @@ pub mod cols { pub const TOTAL_WIDTH: usize = 44; } -// ============================================================================= -// Symbol Types -// ============================================================================= - /// Symbols for the 5-character symbol column. /// /// Format: `| left(2) | center(1) | right(2) |` @@ -76,10 +68,6 @@ impl Symbol { } } -// ============================================================================= -// Navigation Symbols -// ============================================================================= - /// Format navigation command as a Symbol using the doc-specified triangles. /// /// | Nav | Symbol | Notes | @@ -126,10 +114,6 @@ pub fn nav_symbol_epsilon(nav: Nav, is_epsilon: bool) -> Symbol { } } -// ============================================================================= -// Trace-Specific Symbols -// ============================================================================= - /// Trace sub-line symbols. pub mod trace { use super::Symbol; @@ -160,10 +144,6 @@ pub mod trace { pub const BACKTRACK: Symbol = Symbol::new(" ", "❮❮❮", " "); } -// ============================================================================= -// Superscript Formatting -// ============================================================================= - const SUPERSCRIPT_DIGITS: &[char] = &['⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹']; /// Convert a number to superscript digits. @@ -196,10 +176,6 @@ fn superscript_suffix(n: u8) -> &'static str { } } -// ============================================================================= -// Width Calculation -// ============================================================================= - /// Calculate minimum width needed to display numbers up to `count - 1`. pub fn width_for_count(count: usize) -> usize { if count <= 1 { @@ -209,10 +185,6 @@ pub fn width_for_count(count: usize) -> usize { } } -// ============================================================================= -// Text Truncation -// ============================================================================= - /// Truncate text to max length with ellipsis. /// /// Used for displaying node text in traces. @@ -225,10 +197,6 @@ pub fn truncate_text(s: &str, max_len: usize) -> String { } } -// ============================================================================= -// Line Building -// ============================================================================= - /// Builder for formatted output lines. /// /// Constructs lines following the column layout: @@ -306,10 +274,6 @@ fn display_width(s: &str) -> usize { width } -// ============================================================================= -// Effect Formatting -// ============================================================================= - /// Format an effect operation for display. pub fn format_effect(effect: &EffectOp) -> String { match effect.opcode { diff --git a/crates/plotnik-lib/src/bytecode/ids.rs b/crates/plotnik-lib/src/bytecode/ids.rs index 1e004293..5174b9c0 100644 --- a/crates/plotnik-lib/src/bytecode/ids.rs +++ b/crates/plotnik-lib/src/bytecode/ids.rs @@ -28,4 +28,4 @@ impl StringId { /// All types (including builtins) are stored sequentially in TypeDefs. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)] #[repr(transparent)] -pub struct QTypeId(pub u16); +pub struct TypeId(pub u16); diff --git a/crates/plotnik-lib/src/bytecode/ir.rs b/crates/plotnik-lib/src/bytecode/ir.rs index e117a7fb..a32355e9 100644 --- a/crates/plotnik-lib/src/bytecode/ir.rs +++ b/crates/plotnik-lib/src/bytecode/ir.rs @@ -213,14 +213,14 @@ impl EffectIR { /// Pre-layout instruction with symbolic references. #[derive(Clone, Debug)] -pub enum Instruction { +pub enum InstructionIR { Match(MatchIR), Call(CallIR), Return(ReturnIR), Trampoline(TrampolineIR), } -impl Instruction { +impl InstructionIR { /// Get the label where this instruction lives. #[inline] pub fn label(&self) -> Label { @@ -459,7 +459,7 @@ impl MatchIR { } } -impl From for Instruction { +impl From for InstructionIR { fn from(m: MatchIR) -> Self { Self::Match(m) } @@ -517,7 +517,7 @@ impl CallIR { } } -impl From for Instruction { +impl From for InstructionIR { fn from(c: CallIR) -> Self { Self::Call(c) } @@ -543,7 +543,7 @@ impl ReturnIR { } } -impl From for Instruction { +impl From for InstructionIR { fn from(r: ReturnIR) -> Self { Self::Return(r) } @@ -577,7 +577,7 @@ impl TrampolineIR { } } -impl From for Instruction { +impl From for InstructionIR { fn from(t: TrampolineIR) -> Self { Self::Trampoline(t) } @@ -591,142 +591,3 @@ pub struct LayoutResult { /// Total number of steps (for header). pub total_steps: u16, } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn match_ir_size_match8() { - let m = MatchIR::at(Label(0)) - .nav(Nav::Down) - .node_type(NonZeroU16::new(10)) - .next(Label(1)); - - assert_eq!(m.size(), 8); - } - - #[test] - fn match_ir_size_extended() { - let m = MatchIR::at(Label(0)) - .nav(Nav::Down) - .node_type(NonZeroU16::new(10)) - .pre_effect(EffectIR::start_obj()) - .post_effect(EffectIR::node()) - .next(Label(1)); - - // 3 slots needed (1 pre + 1 post + 1 succ), fits in Match16 (4 slots) - assert_eq!(m.size(), 16); - } - - #[test] - fn instruction_successors() { - let m: Instruction = MatchIR::at(Label(0)) - .next_many(vec![Label(1), Label(2)]) - .into(); - - assert_eq!(m.successors(), vec![Label(1), Label(2)]); - - let c: Instruction = CallIR::new(Label(3), Label(5), Label(4)) - .nav(Nav::Down) - .into(); - - assert_eq!(c.successors(), vec![Label(4)]); - - let r: Instruction = ReturnIR::new(Label(6)).into(); - - assert!(r.successors().is_empty()); - } - - #[test] - fn resolve_match_terminal() { - // Terminal match: empty successors → next = 0 in bytecode - let m = MatchIR::terminal(Label(0)); - - let mut map = BTreeMap::new(); - map.insert(Label(0), 1u16); - - let bytes = m.resolve(&map, |_, _| None, |_| None); - assert_eq!(bytes.len(), 8); - - // Verify opcode is Match8 (0x0) - assert_eq!(bytes[0] & 0xF, 0); - // Verify next is terminal (0) - assert_eq!(u16::from_le_bytes([bytes[6], bytes[7]]), 0); - } - - #[test] - fn member_ref_resolution() { - use plotnik_core::Symbol; - - // Create test symbols (these are just integer handles) - let field_name = Symbol::from_raw(100); - let field_type = TypeId(10); - let parent_type = TypeId(20); - - // Test absolute reference - let abs = MemberRef::absolute(42); - assert_eq!(abs.resolve(|_, _| None, |_| None), 42); - - // Test deferred reference with lookup (struct field) - let deferred = MemberRef::deferred(field_name, field_type); - assert_eq!( - deferred.resolve( - |name, ty| { - if name == field_name && ty == field_type { - Some(77) - } else { - None - } - }, - |_| None - ), - 77 - ); - - // Test deferred reference with no match (defaults to 0) - assert_eq!(deferred.resolve(|_, _| None, |_| None), 0); - - // Test deferred by index reference (enum variant) - let by_index = MemberRef::deferred_by_index(parent_type, 3); - assert_eq!( - by_index.resolve( - |_, _| None, - |ty| if ty == parent_type { Some(50) } else { None } - ), - 53 // base 50 + relative 3 - ); - } - - #[test] - fn effect_ir_resolution() { - use plotnik_core::Symbol; - - let field_name = Symbol::from_raw(200); - let field_type = TypeId(10); - - // Simple effect without member ref - let simple = EffectIR::simple(EffectOpcode::Node, 5); - let resolved = simple.resolve(|_, _| None, |_| None); - assert_eq!(resolved.opcode, EffectOpcode::Node); - assert_eq!(resolved.payload, 5); - - // Effect with deferred member ref - let set_effect = EffectIR::with_member( - EffectOpcode::Set, - MemberRef::deferred(field_name, field_type), - ); - let resolved = set_effect.resolve( - |name, ty| { - if name == field_name && ty == field_type { - Some(51) - } else { - None - } - }, - |_| None, - ); - assert_eq!(resolved.opcode, EffectOpcode::Set); - assert_eq!(resolved.payload, 51); - } -} diff --git a/crates/plotnik-lib/src/bytecode/ir_tests.rs b/crates/plotnik-lib/src/bytecode/ir_tests.rs new file mode 100644 index 00000000..47707ef6 --- /dev/null +++ b/crates/plotnik-lib/src/bytecode/ir_tests.rs @@ -0,0 +1,139 @@ +use std::collections::BTreeMap; +use std::num::NonZeroU16; + +use plotnik_core::Symbol; + +use super::effects::EffectOpcode; +use super::ir::{CallIR, EffectIR, InstructionIR, Label, MatchIR, MemberRef, ReturnIR}; +use super::nav::Nav; +use crate::analyze::type_check::TypeId; + +#[test] +fn match_ir_size_match8() { + let m = MatchIR::at(Label(0)) + .nav(Nav::Down) + .node_type(NonZeroU16::new(10)) + .next(Label(1)); + + assert_eq!(m.size(), 8); +} + +#[test] +fn match_ir_size_extended() { + let m = MatchIR::at(Label(0)) + .nav(Nav::Down) + .node_type(NonZeroU16::new(10)) + .pre_effect(EffectIR::start_obj()) + .post_effect(EffectIR::node()) + .next(Label(1)); + + // 3 slots needed (1 pre + 1 post + 1 succ), fits in Match16 (4 slots) + assert_eq!(m.size(), 16); +} + +#[test] +fn instruction_successors() { + let m: InstructionIR = MatchIR::at(Label(0)) + .next_many(vec![Label(1), Label(2)]) + .into(); + + assert_eq!(m.successors(), vec![Label(1), Label(2)]); + + let c: InstructionIR = CallIR::new(Label(3), Label(5), Label(4)) + .nav(Nav::Down) + .into(); + + assert_eq!(c.successors(), vec![Label(4)]); + + let r: InstructionIR = ReturnIR::new(Label(6)).into(); + + assert!(r.successors().is_empty()); +} + +#[test] +fn resolve_match_terminal() { + // Terminal match: empty successors → next = 0 in bytecode + let m = MatchIR::terminal(Label(0)); + + let mut map = BTreeMap::new(); + map.insert(Label(0), 1u16); + + let bytes = m.resolve(&map, |_, _| None, |_| None); + assert_eq!(bytes.len(), 8); + + // Verify opcode is Match8 (0x0) + assert_eq!(bytes[0] & 0xF, 0); + // Verify next is terminal (0) + assert_eq!(u16::from_le_bytes([bytes[6], bytes[7]]), 0); +} + +#[test] +fn member_ref_resolution() { + // Create test symbols (these are just integer handles) + let field_name = Symbol::from_raw(100); + let field_type = TypeId(10); + let parent_type = TypeId(20); + + // Test absolute reference + let abs = MemberRef::absolute(42); + assert_eq!(abs.resolve(|_, _| None, |_| None), 42); + + // Test deferred reference with lookup (struct field) + let deferred = MemberRef::deferred(field_name, field_type); + assert_eq!( + deferred.resolve( + |name, ty| { + if name == field_name && ty == field_type { + Some(77) + } else { + None + } + }, + |_| None + ), + 77 + ); + + // Test deferred reference with no match (defaults to 0) + assert_eq!(deferred.resolve(|_, _| None, |_| None), 0); + + // Test deferred by index reference (enum variant) + let by_index = MemberRef::deferred_by_index(parent_type, 3); + assert_eq!( + by_index.resolve( + |_, _| None, + |ty| if ty == parent_type { Some(50) } else { None } + ), + 53 // base 50 + relative 3 + ); +} + +#[test] +fn effect_ir_resolution() { + let field_name = Symbol::from_raw(200); + let field_type = TypeId(10); + + // Simple effect without member ref + let simple = EffectIR::simple(EffectOpcode::Node, 5); + let resolved = simple.resolve(|_, _| None, |_| None); + assert_eq!(resolved.opcode, EffectOpcode::Node); + assert_eq!(resolved.payload, 5); + + // Effect with deferred member ref + let set_effect = EffectIR::with_member( + EffectOpcode::Set, + MemberRef::deferred(field_name, field_type), + ); + let resolved = set_effect.resolve( + |name, ty| { + if name == field_name && ty == field_type { + Some(51) + } else { + None + } + }, + |_| None, + ); + assert_eq!(resolved.opcode, EffectOpcode::Set); + assert_eq!(resolved.payload, 51); +} diff --git a/crates/plotnik-lib/src/bytecode/mod.rs b/crates/plotnik-lib/src/bytecode/mod.rs index 483fe76b..828f8556 100644 --- a/crates/plotnik-lib/src/bytecode/mod.rs +++ b/crates/plotnik-lib/src/bytecode/mod.rs @@ -10,7 +10,7 @@ mod format; mod header; mod ids; mod instructions; -pub mod ir; +mod ir; mod module; mod nav; mod sections; @@ -20,7 +20,7 @@ pub use constants::{ MAGIC, MAX_MATCH_PAYLOAD_SLOTS, NAMED_WILDCARD, SECTION_ALIGN, STEP_SIZE, VERSION, }; -pub use ids::{QTypeId, StringId}; +pub use ids::{StringId, TypeId}; pub use header::{Header, flags}; @@ -51,7 +51,14 @@ pub use format::{ truncate_text, width_for_count, }; +pub use ir::{ + CallIR, EffectIR, InstructionIR, Label, LayoutResult, MatchIR, MemberRef, ReturnIR, + TrampolineIR, +}; + #[cfg(test)] mod instructions_tests; #[cfg(test)] +mod ir_tests; +#[cfg(test)] mod module_tests; diff --git a/crates/plotnik-lib/src/bytecode/module.rs b/crates/plotnik-lib/src/bytecode/module.rs index ac253230..d0f80883 100644 --- a/crates/plotnik-lib/src/bytecode/module.rs +++ b/crates/plotnik-lib/src/bytecode/module.rs @@ -8,7 +8,7 @@ use std::ops::Deref; use std::path::Path; use super::header::Header; -use super::ids::{QTypeId, StringId}; +use super::ids::{StringId, TypeId}; use super::instructions::{Call, Match, MatchView, Opcode, Return, Trampoline}; use super::sections::{FieldSymbol, NodeSymbol, TriviaEntry}; use super::type_meta::{TypeDef, TypeMember, TypeMetaHeader, TypeName}; @@ -443,8 +443,8 @@ impl<'a> TypesView<'a> { } } - /// Get a type definition by QTypeId. - pub fn get(&self, id: QTypeId) -> Option { + /// Get a type definition by TypeId. + pub fn get(&self, id: TypeId) -> Option { let idx = id.0 as usize; if idx < self.defs_count { Some(self.get_def(idx)) @@ -459,7 +459,7 @@ impl<'a> TypesView<'a> { let offset = idx * 4; TypeMember { name: StringId::new(read_u16_le(self.members_bytes, offset)), - type_id: QTypeId(read_u16_le(self.members_bytes, offset + 2)), + type_id: TypeId(read_u16_le(self.members_bytes, offset + 2)), } } @@ -469,7 +469,7 @@ impl<'a> TypesView<'a> { let offset = idx * 4; TypeName { name: StringId::new(read_u16_le(self.names_bytes, offset)), - type_id: QTypeId(read_u16_le(self.names_bytes, offset + 2)), + type_id: TypeId(read_u16_le(self.names_bytes, offset + 2)), } } @@ -497,14 +497,14 @@ impl<'a> TypesView<'a> { /// Unwrap Optional wrapper and return (inner_type, is_optional). /// If not Optional, returns (type_id, false). - pub fn unwrap_optional(&self, type_id: QTypeId) -> (QTypeId, bool) { + pub fn unwrap_optional(&self, type_id: TypeId) -> (TypeId, bool) { let Some(type_def) = self.get(type_id) else { return (type_id, false); }; if !type_def.is_optional() { return (type_id, false); } - (QTypeId(type_def.data), true) + (TypeId(type_def.data), true) } } @@ -522,7 +522,7 @@ impl<'a> EntrypointsView<'a> { Entrypoint { name: StringId::new(read_u16_le(self.bytes, offset)), target: read_u16_le(self.bytes, offset + 2), - result_type: QTypeId(read_u16_le(self.bytes, offset + 4)), + result_type: TypeId(read_u16_le(self.bytes, offset + 4)), _pad: 0, } } diff --git a/crates/plotnik-lib/src/bytecode/sections.rs b/crates/plotnik-lib/src/bytecode/sections.rs index 3a1beaf5..3d84ade1 100644 --- a/crates/plotnik-lib/src/bytecode/sections.rs +++ b/crates/plotnik-lib/src/bytecode/sections.rs @@ -5,7 +5,7 @@ use super::ids::StringId; /// Range into an array: [ptr..ptr+len). /// /// Dual-use depending on context: -/// - For `TypeDef` wrappers (Optional, Array*): `ptr` is inner `QTypeId`, `len` is 0. +/// - For `TypeDef` wrappers (Optional, Array*): `ptr` is inner `TypeId`, `len` is 0. /// - For `TypeDef` composites (Struct, Enum): `ptr` is index into TypeMember array, `len` is count. #[derive(Clone, Copy, Debug, Default)] #[repr(C)] diff --git a/crates/plotnik-lib/src/bytecode/type_meta.rs b/crates/plotnik-lib/src/bytecode/type_meta.rs index 43d7d89c..3a39aaf2 100644 --- a/crates/plotnik-lib/src/bytecode/type_meta.rs +++ b/crates/plotnik-lib/src/bytecode/type_meta.rs @@ -1,6 +1,6 @@ //! Type metadata definitions for bytecode format. -use super::{QTypeId, StringId}; +use super::{StringId, TypeId}; // Re-export the shared TypeKind pub use crate::type_system::TypeKind; @@ -77,10 +77,10 @@ const _: () = assert!(std::mem::size_of::() == 4); impl TypeDef { /// For wrapper types, get the inner type. #[inline] - pub fn inner_type(&self) -> Option { + pub fn inner_type(&self) -> Option { TypeKind::from_u8(self.kind) .filter(|k| k.is_wrapper()) - .map(|_| QTypeId(self.data)) + .map(|_| TypeId(self.data)) } /// Get the TypeKind for this definition. @@ -103,10 +103,10 @@ impl TypeDef { /// For alias types, get the target type. #[inline] - pub fn alias_target(&self) -> Option { + pub fn alias_target(&self) -> Option { TypeKind::from_u8(self.kind) .filter(|k| k.is_alias()) - .map(|_| QTypeId(self.data)) + .map(|_| TypeId(self.data)) } /// For Struct/Enum types, get the member index. @@ -136,7 +136,7 @@ pub struct TypeName { /// StringId of the type name. pub name: StringId, /// TypeId this name refers to. - pub type_id: QTypeId, + pub type_id: TypeId, } const _: () = assert!(std::mem::size_of::() == 4); @@ -148,7 +148,7 @@ pub struct TypeMember { /// Field/variant name. pub name: StringId, /// Type of this field/variant. - pub type_id: QTypeId, + pub type_id: TypeId, } const _: () = assert!(std::mem::size_of::() == 4); diff --git a/crates/plotnik-lib/src/compile/capture.rs b/crates/plotnik-lib/src/compile/capture.rs index 502eab83..45fd34c3 100644 --- a/crates/plotnik-lib/src/compile/capture.rs +++ b/crates/plotnik-lib/src/compile/capture.rs @@ -6,8 +6,8 @@ use std::collections::HashSet; use crate::analyze::type_check::{TypeContext, TypeId, TypeShape}; +use crate::bytecode::EffectIR; use crate::bytecode::EffectOpcode; -use crate::bytecode::ir::EffectIR; use crate::parser::ast::{self, Expr}; use super::Compiler; diff --git a/crates/plotnik-lib/src/compile/compiler.rs b/crates/plotnik-lib/src/compile/compiler.rs index 0bb64020..649d6379 100644 --- a/crates/plotnik-lib/src/compile/compiler.rs +++ b/crates/plotnik-lib/src/compile/compiler.rs @@ -6,7 +6,7 @@ use plotnik_core::{Interner, NodeFieldId, NodeTypeId, Symbol}; use crate::analyze::symbol_table::SymbolTable; use crate::analyze::type_check::{DefId, TypeContext}; use crate::bytecode::Nav; -use crate::bytecode::ir::{Instruction, Label, ReturnIR, TrampolineIR}; +use crate::bytecode::{InstructionIR, Label, ReturnIR, TrampolineIR}; use crate::emit::StringTableBuilder; use crate::parser::ast::Expr; @@ -22,7 +22,7 @@ pub struct Compiler<'a> { pub(super) strings: &'a mut StringTableBuilder, pub(super) node_type_ids: Option<&'a IndexMap>, pub(super) node_field_ids: Option<&'a IndexMap>, - pub(super) instructions: Vec, + pub(super) instructions: Vec, next_label_id: u32, pub(super) def_entries: IndexMap, /// Stack of active struct scopes for capture lookup. diff --git a/crates/plotnik-lib/src/compile/error.rs b/crates/plotnik-lib/src/compile/error.rs index 58b6dfdb..30224506 100644 --- a/crates/plotnik-lib/src/compile/error.rs +++ b/crates/plotnik-lib/src/compile/error.rs @@ -3,7 +3,7 @@ use indexmap::IndexMap; use crate::analyze::type_check::DefId; -use crate::bytecode::ir::{Instruction, Label}; +use crate::bytecode::{InstructionIR, Label}; /// Error during compilation. #[derive(Clone, Debug)] @@ -29,7 +29,7 @@ impl std::error::Error for CompileError {} #[derive(Clone, Debug)] pub struct CompileResult { /// All generated instructions. - pub instructions: Vec, + pub instructions: Vec, /// Entry labels for each definition (in definition order). pub def_entries: IndexMap, /// Entry label for the universal preamble. diff --git a/crates/plotnik-lib/src/compile/expressions.rs b/crates/plotnik-lib/src/compile/expressions.rs index abf8d08c..c4ad19a6 100644 --- a/crates/plotnik-lib/src/compile/expressions.rs +++ b/crates/plotnik-lib/src/compile/expressions.rs @@ -12,7 +12,7 @@ use std::num::NonZeroU16; use crate::analyze::type_check::TypeShape; use crate::bytecode::NAMED_WILDCARD; use crate::bytecode::Nav; -use crate::bytecode::ir::{EffectIR, Instruction, Label, MatchIR}; +use crate::bytecode::{EffectIR, InstructionIR, Label, MatchIR}; use crate::parser::ast::{self, Expr}; use super::Compiler; @@ -355,7 +355,7 @@ impl Compiler<'_> { .instructions .iter_mut() .find(|i| i.label() == value_entry) - && let Instruction::Match(m) = instr + && let InstructionIR::Match(m) = instr && m.node_field.is_none() { m.node_field = Some(field_id); diff --git a/crates/plotnik-lib/src/compile/quantifier.rs b/crates/plotnik-lib/src/compile/quantifier.rs index 50cc24d1..7d73b553 100644 --- a/crates/plotnik-lib/src/compile/quantifier.rs +++ b/crates/plotnik-lib/src/compile/quantifier.rs @@ -8,7 +8,7 @@ use crate::analyze::type_check::TypeId; use crate::bytecode::Nav; -use crate::bytecode::ir::{EffectIR, Label}; +use crate::bytecode::{EffectIR, Label}; use crate::parser::ast::{self, Expr}; use crate::parser::cst::SyntaxKind; diff --git a/crates/plotnik-lib/src/compile/scope.rs b/crates/plotnik-lib/src/compile/scope.rs index e643b325..0bf8d796 100644 --- a/crates/plotnik-lib/src/compile/scope.rs +++ b/crates/plotnik-lib/src/compile/scope.rs @@ -5,7 +5,7 @@ use std::num::NonZeroU16; use crate::analyze::type_check::TypeId; -use crate::bytecode::ir::{CallIR, EffectIR, Label, MatchIR, MemberRef}; +use crate::bytecode::{CallIR, EffectIR, Label, MatchIR, MemberRef}; use crate::bytecode::{EffectOpcode, Nav}; use crate::parser::ast::Expr; diff --git a/crates/plotnik-lib/src/compile/sequences.rs b/crates/plotnik-lib/src/compile/sequences.rs index 57ad1b99..739c7af8 100644 --- a/crates/plotnik-lib/src/compile/sequences.rs +++ b/crates/plotnik-lib/src/compile/sequences.rs @@ -9,7 +9,7 @@ use std::collections::BTreeMap; use plotnik_core::Symbol; use crate::analyze::type_check::{TypeId, TypeShape}; -use crate::bytecode::ir::{EffectIR, Label, MemberRef}; +use crate::bytecode::{EffectIR, Label, MemberRef}; use crate::bytecode::{EffectOpcode, Nav}; use crate::parser::ast::{self, Expr, SeqItem}; diff --git a/crates/plotnik-lib/src/emit/emitter.rs b/crates/plotnik-lib/src/emit/emitter.rs index b1f6dd46..04fb6646 100644 --- a/crates/plotnik-lib/src/emit/emitter.rs +++ b/crates/plotnik-lib/src/emit/emitter.rs @@ -7,7 +7,7 @@ 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::Label; use crate::bytecode::{ Entrypoint, FieldSymbol, Header, NodeSymbol, SECTION_ALIGN, TriviaEntry, TypeMetaHeader, }; @@ -211,8 +211,8 @@ fn pad_to_section(buf: &mut Vec) { /// Emit transitions section from instructions and layout. fn emit_transitions( - instructions: &[crate::bytecode::ir::Instruction], - layout: &crate::bytecode::ir::LayoutResult, + instructions: &[crate::bytecode::InstructionIR], + layout: &crate::bytecode::LayoutResult, types: &TypeTableBuilder, strings: &StringTableBuilder, ) -> Vec { diff --git a/crates/plotnik-lib/src/emit/layout.rs b/crates/plotnik-lib/src/emit/layout.rs index 0871b8ba..5aa91f3e 100644 --- a/crates/plotnik-lib/src/emit/layout.rs +++ b/crates/plotnik-lib/src/emit/layout.rs @@ -5,7 +5,7 @@ use std::collections::{BTreeMap, HashSet}; -use crate::bytecode::ir::{Instruction, Label, LayoutResult}; +use crate::bytecode::{InstructionIR, Label, LayoutResult}; const CACHE_LINE: usize = 64; const STEP_SIZE: usize = 8; @@ -19,7 +19,7 @@ struct Graph { } impl Graph { - fn build(instructions: &[Instruction]) -> Self { + fn build(instructions: &[InstructionIR]) -> Self { let mut successors: BTreeMap> = BTreeMap::new(); let mut predecessors: BTreeMap> = BTreeMap::new(); @@ -58,7 +58,7 @@ impl CacheAligned { /// Compute layout for instructions with given entry points. /// /// Returns mapping from labels to step IDs and total step count. - pub fn layout(instructions: &[Instruction], entries: &[Label]) -> LayoutResult { + pub fn layout(instructions: &[InstructionIR], entries: &[Label]) -> LayoutResult { if instructions.is_empty() { return LayoutResult { label_to_step: BTreeMap::new(), @@ -67,7 +67,7 @@ impl CacheAligned { } let graph = Graph::build(instructions); - let label_to_instr: BTreeMap = + let label_to_instr: BTreeMap = instructions.iter().map(|i| (i.label(), i)).collect(); let chains = extract_chains(&graph, instructions, entries); @@ -80,7 +80,7 @@ impl CacheAligned { /// Extract linear chains from the control flow graph. fn extract_chains( graph: &Graph, - instructions: &[Instruction], + instructions: &[InstructionIR], entries: &[Label], ) -> Vec> { let mut visited = HashSet::new(); @@ -150,7 +150,7 @@ fn order_chains(mut chains: Vec>, entries: &[Label]) -> Vec>, - label_to_instr: &BTreeMap, + label_to_instr: &BTreeMap, ) -> LayoutResult { let mut mapping = BTreeMap::new(); diff --git a/crates/plotnik-lib/src/emit/layout_tests.rs b/crates/plotnik-lib/src/emit/layout_tests.rs index 347eb6b0..61add329 100644 --- a/crates/plotnik-lib/src/emit/layout_tests.rs +++ b/crates/plotnik-lib/src/emit/layout_tests.rs @@ -2,7 +2,7 @@ use std::num::NonZeroU16; use super::layout::CacheAligned; use crate::bytecode::Nav; -use crate::bytecode::ir::{CallIR, EffectIR, Label, MatchIR, ReturnIR}; +use crate::bytecode::{CallIR, EffectIR, Label, MatchIR, ReturnIR}; #[test] fn layout_empty() { diff --git a/crates/plotnik-lib/src/emit/type_table.rs b/crates/plotnik-lib/src/emit/type_table.rs index 3dd265f1..616062d7 100644 --- a/crates/plotnik-lib/src/emit/type_table.rs +++ b/crates/plotnik-lib/src/emit/type_table.rs @@ -1,6 +1,6 @@ //! Type table builder for bytecode emission. //! -//! Converts query-level types (TypeContext) into bytecode-level types (QTypeId). +//! Converts query-level types (TypeContext) into bytecode-level types (BytecodeTypeId). use std::collections::{HashMap, HashSet}; @@ -9,16 +9,16 @@ use plotnik_core::{Interner, Symbol}; use crate::analyze::type_check::{ FieldInfo, TYPE_NODE, TYPE_STRING, TYPE_VOID, TypeContext, TypeId, TypeShape, }; -use crate::bytecode::{QTypeId, StringId, TypeDef, TypeMember, TypeName}; +use crate::bytecode::{StringId, TypeDef, TypeId as BytecodeTypeId, TypeMember, TypeName}; use crate::type_system::TypeKind; use super::{EmitError, StringTableBuilder}; -/// Builds the type metadata, remapping query TypeIds to bytecode QTypeIds. +/// Builds the type metadata, remapping query TypeIds to bytecode BytecodeTypeIds. #[derive(Debug)] pub struct TypeTableBuilder { - /// Map from query TypeId to bytecode QTypeId. - mapping: HashMap, + /// Map from query TypeId to bytecode BytecodeTypeId. + mapping: HashMap, /// Type definitions (4 bytes each). type_defs: Vec, /// Type members for structs/enums (4 bytes each). @@ -26,11 +26,11 @@ pub struct TypeTableBuilder { /// Type names for named types (4 bytes each). type_names: Vec, /// Cache for dynamically created Optional wrappers: base_type -> Optional(base_type) - optional_wrappers: HashMap, - /// Cache for deduplicated members: (StringId, QTypeId) -> member_index. + optional_wrappers: HashMap, + /// Cache for deduplicated members: (StringId, BytecodeTypeId) -> member_index. /// Same (name, type) pair → same member index globally. /// This enables call-site scoping where uncaptured refs share the caller's scope. - member_cache: HashMap<(StringId, QTypeId), u16>, + member_cache: HashMap<(StringId, BytecodeTypeId), u16>, } impl TypeTableBuilder { @@ -95,7 +95,7 @@ impl TypeTableBuilder { ]; for (i, &(builtin_id, kind)) in builtin_types.iter().enumerate() { if used_builtins[i] { - let bc_id = QTypeId(self.type_defs.len() as u16); + let bc_id = BytecodeTypeId(self.type_defs.len() as u16); self.mapping.insert(builtin_id, bc_id); self.type_defs.push(TypeDef { data: 0, @@ -105,9 +105,9 @@ impl TypeTableBuilder { } } - // Phase 2: Pre-assign QTypeIds for custom types and reserve slots + // Phase 2: Pre-assign BytecodeTypeIds for custom types and reserve slots for &type_id in &ordered_types { - let bc_id = QTypeId(self.type_defs.len() as u16); + let bc_id = BytecodeTypeId(self.type_defs.len() as u16); self.mapping.insert(type_id, bc_id); self.type_defs.push(TypeDef { data: 0, @@ -131,7 +131,11 @@ impl TypeTableBuilder { for (def_id, type_id) in type_ctx.iter_def_types() { let name_sym = type_ctx.def_name_sym(def_id); let name = strings.get_or_intern(name_sym, interner)?; - let bc_type_id = self.mapping.get(&type_id).copied().unwrap_or(QTypeId(0)); + let bc_type_id = self + .mapping + .get(&type_id) + .copied() + .unwrap_or(BytecodeTypeId(0)); self.type_names.push(TypeName { name, type_id: bc_type_id, @@ -171,7 +175,7 @@ impl TypeTableBuilder { TypeShape::Custom(sym) => { // Custom type annotation: @x :: Identifier → type Identifier = Node - let bc_type_id = QTypeId(slot_index as u16); + let bc_type_id = BytecodeTypeId(slot_index as u16); // Add TypeName entry for the custom type let name = strings.get_or_intern(*sym, interner)?; @@ -181,7 +185,11 @@ impl TypeTableBuilder { }); // Custom types alias Node - look up Node's actual bytecode ID - let node_bc_id = self.mapping.get(&TYPE_NODE).copied().unwrap_or(QTypeId(0)); + let node_bc_id = self + .mapping + .get(&TYPE_NODE) + .copied() + .unwrap_or(BytecodeTypeId(0)); self.type_defs[slot_index] = TypeDef { data: node_bc_id.0, count: 0, @@ -278,14 +286,14 @@ impl TypeTableBuilder { } } - /// Resolve a query TypeId to bytecode QTypeId. + /// Resolve a query TypeId to bytecode BytecodeTypeId. /// /// Handles Ref types by following the reference chain to the actual type. pub fn resolve_type( &self, type_id: TypeId, type_ctx: &TypeContext, - ) -> Result { + ) -> Result { // Check if already mapped if let Some(&bc_id) = self.mapping.get(&type_id) { return Ok(bc_id); @@ -300,7 +308,7 @@ impl TypeTableBuilder { } // If not found, default to first type (should not happen for well-formed types) - Ok(QTypeId(0)) + Ok(BytecodeTypeId(0)) } /// Resolve a field's type, handling optionality. @@ -308,7 +316,7 @@ impl TypeTableBuilder { &mut self, field_info: &FieldInfo, type_ctx: &TypeContext, - ) -> Result { + ) -> Result { let base_type = self.resolve_type(field_info.type_id, type_ctx)?; // If the field is optional, wrap it in Optional @@ -320,14 +328,17 @@ impl TypeTableBuilder { } /// Get or create an Optional wrapper for a base type. - fn get_or_create_optional(&mut self, base_type: QTypeId) -> Result { + fn get_or_create_optional( + &mut self, + base_type: BytecodeTypeId, + ) -> Result { // Check cache first if let Some(&optional_id) = self.optional_wrappers.get(&base_type) { return Ok(optional_id); } // Create new Optional wrapper at the next available index - let optional_id = QTypeId(self.type_defs.len() as u16); + let optional_id = BytecodeTypeId(self.type_defs.len() as u16); self.type_defs.push(TypeDef { data: base_type.0, @@ -350,8 +361,8 @@ impl TypeTableBuilder { Ok(()) } - /// Get the bytecode QTypeId for a query TypeId. - pub fn get(&self, type_id: TypeId) -> Option { + /// Get the bytecode BytecodeTypeId for a query TypeId. + pub fn get(&self, type_id: TypeId) -> Option { self.mapping.get(&type_id).copied() } diff --git a/crates/plotnik-lib/src/engine/materializer.rs b/crates/plotnik-lib/src/engine/materializer.rs index 7031aef7..88ac3ff4 100644 --- a/crates/plotnik-lib/src/engine/materializer.rs +++ b/crates/plotnik-lib/src/engine/materializer.rs @@ -1,6 +1,6 @@ //! Materializer transforms effect logs into output values. -use crate::bytecode::{QTypeId, StringsView, TypeKind, TypesView}; +use crate::bytecode::{StringsView, TypeId, TypeKind, TypesView}; use super::effect::RuntimeEffect; use super::value::{NodeHandle, Value}; @@ -9,7 +9,7 @@ use super::value::{NodeHandle, Value}; pub trait Materializer<'t> { type Output; - fn materialize(&self, effects: &[RuntimeEffect<'t>], result_type: QTypeId) -> Self::Output; + fn materialize(&self, effects: &[RuntimeEffect<'t>], result_type: TypeId) -> Self::Output; } /// Materializer that produces Value with resolved strings. @@ -33,11 +33,11 @@ impl<'ctx> ValueMaterializer<'ctx> { self.strings.get(member.name).to_owned() } - fn resolve_member_type(&self, idx: u16) -> QTypeId { + fn resolve_member_type(&self, idx: u16) -> TypeId { self.types.get_member(idx as usize).type_id } - fn is_void_type(&self, type_id: QTypeId) -> bool { + fn is_void_type(&self, type_id: TypeId) -> bool { self.types .get(type_id) .and_then(|def| def.type_kind()) @@ -45,7 +45,7 @@ impl<'ctx> ValueMaterializer<'ctx> { } /// Create initial builder based on result type. - fn builder_for_type(&self, type_id: QTypeId) -> Builder { + fn builder_for_type(&self, type_id: TypeId) -> Builder { let def = match self.types.get(type_id) { Some(d) => d, None => return Builder::Scalar(None), @@ -67,7 +67,7 @@ enum Builder { Object(Vec<(String, Value)>), Tagged { tag: String, - payload_type: QTypeId, + payload_type: TypeId, fields: Vec<(String, Value)>, }, } @@ -89,7 +89,7 @@ impl Builder { impl<'t> Materializer<'t> for ValueMaterializer<'_> { type Output = Value; - fn materialize(&self, effects: &[RuntimeEffect<'t>], result_type: QTypeId) -> Value { + fn materialize(&self, effects: &[RuntimeEffect<'t>], result_type: TypeId) -> Value { // Stack of containers being built let mut stack: Vec = vec![]; diff --git a/crates/plotnik-lib/src/engine/verify.rs b/crates/plotnik-lib/src/engine/verify.rs index 7e64ea32..7328f61f 100644 --- a/crates/plotnik-lib/src/engine/verify.rs +++ b/crates/plotnik-lib/src/engine/verify.rs @@ -4,7 +4,7 @@ //! Zero-cost in release builds. use crate::Colors; -use crate::bytecode::{Module, QTypeId, StringsView, TypesView}; +use crate::bytecode::{Module, StringsView, TypeId, TypesView}; use crate::type_system::TypeKind; use crate::typegen::typescript::{self, Config, VoidType}; @@ -17,7 +17,7 @@ use super::Value; /// /// `expected_type` should be the `result_type` from the entrypoint that was executed. #[cfg(debug_assertions)] -pub fn debug_verify_type(value: &Value, expected_type: QTypeId, module: &Module, colors: Colors) { +pub fn debug_verify_type(value: &Value, expected_type: TypeId, module: &Module, colors: Colors) { let types = module.types(); let strings = module.strings(); @@ -40,7 +40,7 @@ pub fn debug_verify_type(value: &Value, expected_type: QTypeId, module: &Module, #[inline(always)] pub fn debug_verify_type( _value: &Value, - _expected_type: QTypeId, + _expected_type: TypeId, _module: &Module, _colors: Colors, ) { @@ -50,7 +50,7 @@ pub fn debug_verify_type( #[cfg(debug_assertions)] fn verify_type( value: &Value, - expected: QTypeId, + expected: TypeId, types: &TypesView<'_>, strings: &StringsView<'_>, path: &mut String, @@ -107,14 +107,14 @@ fn verify_type( } TypeKind::Optional => { - let inner_type = QTypeId(type_def.data); + let inner_type = TypeId(type_def.data); if !matches!(value, Value::Null) { verify_type(value, inner_type, types, strings, path, errors); } } TypeKind::ArrayZeroOrMore => { - let inner_type = QTypeId(type_def.data); + let inner_type = TypeId(type_def.data); match value { Value::Array(items) => { for (i, item) in items.iter().enumerate() { @@ -134,7 +134,7 @@ fn verify_type( } TypeKind::ArrayOneOrMore => { - let inner_type = QTypeId(type_def.data); + let inner_type = TypeId(type_def.data); match value { Value::Array(items) => { if items.is_empty() { @@ -318,7 +318,7 @@ fn centered_header(label: &str, width: usize) -> String { #[cfg(debug_assertions)] fn panic_with_mismatch( value: &Value, - expected_type: QTypeId, + expected_type: TypeId, errors: &[String], module: &Module, colors: Colors, diff --git a/crates/plotnik-lib/src/engine/verify_tests.rs b/crates/plotnik-lib/src/engine/verify_tests.rs index 8f8143aa..ea95703c 100644 --- a/crates/plotnik-lib/src/engine/verify_tests.rs +++ b/crates/plotnik-lib/src/engine/verify_tests.rs @@ -2,14 +2,14 @@ use crate::Colors; use crate::QueryBuilder; -use crate::bytecode::{Module, QTypeId}; +use crate::bytecode::{Module, TypeId}; use crate::emit::emit_linked; use crate::engine::value::{NodeHandle, Value}; use super::debug_verify_type; /// Build a module from a query string and return with its first entrypoint's result type. -fn build_module(query: &str) -> (Module, QTypeId) { +fn build_module(query: &str) -> (Module, TypeId) { let lang = plotnik_langs::javascript(); let query_obj = QueryBuilder::one_liner(query) .parse() diff --git a/crates/plotnik-lib/src/typegen/typescript/analysis.rs b/crates/plotnik-lib/src/typegen/typescript/analysis.rs index 1f25ac82..f0d602f7 100644 --- a/crates/plotnik-lib/src/typegen/typescript/analysis.rs +++ b/crates/plotnik-lib/src/typegen/typescript/analysis.rs @@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet}; -use crate::bytecode::{QTypeId, TypeKind}; +use crate::bytecode::{TypeId, TypeKind}; use super::Emitter; @@ -14,7 +14,7 @@ impl Emitter<'_> { } } - fn collect_refs_recursive(&mut self, type_id: QTypeId) { + fn collect_refs_recursive(&mut self, type_id: TypeId) { // Cycle detection if !self.refs_visited.insert(type_id) { return; @@ -46,7 +46,7 @@ impl Emitter<'_> { } } TypeKind::ArrayZeroOrMore | TypeKind::ArrayOneOrMore | TypeKind::Optional => { - self.collect_refs_recursive(QTypeId(type_def.data)); + self.collect_refs_recursive(TypeId(type_def.data)); } TypeKind::Alias => { // Alias to Node @@ -55,9 +55,9 @@ impl Emitter<'_> { } } - pub(super) fn sort_topologically(&self, types: HashSet) -> Vec { - let mut deps: HashMap> = HashMap::new(); - let mut rdeps: HashMap> = HashMap::new(); + pub(super) fn sort_topologically(&self, types: HashSet) -> Vec { + let mut deps: HashMap> = HashMap::new(); + let mut rdeps: HashMap> = HashMap::new(); for &tid in &types { deps.entry(tid).or_default(); @@ -76,7 +76,7 @@ impl Emitter<'_> { // Kahn's algorithm let mut result = Vec::with_capacity(types.len()); - let mut queue: Vec = deps + let mut queue: Vec = deps .iter() .filter(|(_, d)| d.is_empty()) .map(|(&tid, _)| tid) @@ -102,7 +102,7 @@ impl Emitter<'_> { result } - pub(super) fn collect_reachable_types(&self, type_id: QTypeId, out: &mut HashSet) { + pub(super) fn collect_reachable_types(&self, type_id: TypeId, out: &mut HashSet) { if out.contains(&type_id) { return; } @@ -133,14 +133,14 @@ impl Emitter<'_> { out.insert(type_id); } TypeKind::ArrayZeroOrMore | TypeKind::ArrayOneOrMore | TypeKind::Optional => { - self.collect_reachable_types(QTypeId(type_def.data), out); + self.collect_reachable_types(TypeId(type_def.data), out); } } } /// Collect reachable types from enum variant payloads. /// Recurses into struct fields but doesn't add the payload struct itself. - fn collect_enum_variant_refs(&self, type_id: QTypeId, out: &mut HashSet) { + fn collect_enum_variant_refs(&self, type_id: TypeId, out: &mut HashSet) { let Some(type_def) = self.types.get(type_id) else { return; }; @@ -157,7 +157,7 @@ impl Emitter<'_> { } } - pub(super) fn get_direct_deps(&self, type_id: QTypeId) -> Vec { + pub(super) fn get_direct_deps(&self, type_id: TypeId) -> Vec { let Some(type_def) = self.types.get(type_id) else { return vec![]; }; @@ -174,12 +174,12 @@ impl Emitter<'_> { .flat_map(|member| self.unwrap_for_deps(member.type_id)) .collect(), TypeKind::ArrayZeroOrMore | TypeKind::ArrayOneOrMore | TypeKind::Optional => { - self.unwrap_for_deps(QTypeId(type_def.data)) + self.unwrap_for_deps(TypeId(type_def.data)) } } } - fn unwrap_for_deps(&self, type_id: QTypeId) -> Vec { + fn unwrap_for_deps(&self, type_id: TypeId) -> Vec { let Some(type_def) = self.types.get(type_id) else { return vec![]; }; @@ -191,7 +191,7 @@ impl Emitter<'_> { match kind { TypeKind::Void | TypeKind::Node | TypeKind::String => vec![], TypeKind::ArrayZeroOrMore | TypeKind::ArrayOneOrMore | TypeKind::Optional => { - self.unwrap_for_deps(QTypeId(type_def.data)) + self.unwrap_for_deps(TypeId(type_def.data)) } TypeKind::Struct | TypeKind::Enum | TypeKind::Alias => vec![type_id], } diff --git a/crates/plotnik-lib/src/typegen/typescript/convert.rs b/crates/plotnik-lib/src/typegen/typescript/convert.rs index 819748aa..a8fb65e7 100644 --- a/crates/plotnik-lib/src/typegen/typescript/convert.rs +++ b/crates/plotnik-lib/src/typegen/typescript/convert.rs @@ -1,12 +1,12 @@ //! Type to TypeScript string conversion. -use crate::bytecode::{QTypeId, TypeDef, TypeKind}; +use crate::bytecode::{TypeDef, TypeId, TypeKind}; use super::Emitter; use super::config::VoidType; impl Emitter<'_> { - pub(super) fn type_to_ts(&self, type_id: QTypeId) -> String { + pub(super) fn type_to_ts(&self, type_id: TypeId) -> String { let c = self.c(); let Some(type_def) = self.types.get(type_id) else { return "unknown".to_string(); @@ -38,24 +38,24 @@ impl Emitter<'_> { } } TypeKind::ArrayZeroOrMore => { - let elem_type = self.type_to_ts(QTypeId(type_def.data)); + let elem_type = self.type_to_ts(TypeId(type_def.data)); format!("{}{}[]{}", elem_type, c.dim, c.reset) } TypeKind::ArrayOneOrMore => { - let elem_type = self.type_to_ts(QTypeId(type_def.data)); + let elem_type = self.type_to_ts(TypeId(type_def.data)); format!( "{}[{}{}{}, ...{}{}{}[]]{}", c.dim, c.reset, elem_type, c.dim, c.reset, elem_type, c.dim, c.reset ) } TypeKind::Optional => { - let inner_type = self.type_to_ts(QTypeId(type_def.data)); + let inner_type = self.type_to_ts(TypeId(type_def.data)); format!("{} {}|{} null", inner_type, c.dim, c.reset) } } } - fn inline_composite(&self, _type_id: QTypeId, type_def: &TypeDef, kind: &TypeKind) -> String { + fn inline_composite(&self, _type_id: TypeId, type_def: &TypeDef, kind: &TypeKind) -> String { match kind { TypeKind::Struct => self.inline_struct(type_def), TypeKind::Enum => self.inline_enum(type_def), @@ -69,7 +69,7 @@ impl Emitter<'_> { return format!("{}{{}}{}", c.dim, c.reset); } - let mut fields: Vec<(String, QTypeId, bool)> = self + let mut fields: Vec<(String, TypeId, bool)> = self .types .members_of(type_def) .map(|member| { @@ -141,7 +141,7 @@ impl Emitter<'_> { variant_strs.join(&format!(" {}|{} ", c.dim, c.reset)) } - pub(super) fn inline_data_type(&self, type_id: QTypeId) -> String { + pub(super) fn inline_data_type(&self, type_id: TypeId) -> String { let c = self.c(); let Some(type_def) = self.types.get(type_id) else { return self.type_to_ts(type_id); @@ -162,7 +162,7 @@ impl Emitter<'_> { } } - pub(super) fn is_void_type(&self, type_id: QTypeId) -> bool { + pub(super) fn is_void_type(&self, type_id: TypeId) -> bool { self.types .get(type_id) .and_then(|def| def.type_kind()) diff --git a/crates/plotnik-lib/src/typegen/typescript/emitter.rs b/crates/plotnik-lib/src/typegen/typescript/emitter.rs index a2ed3fa3..5c7491e0 100644 --- a/crates/plotnik-lib/src/typegen/typescript/emitter.rs +++ b/crates/plotnik-lib/src/typegen/typescript/emitter.rs @@ -4,7 +4,7 @@ use std::collections::hash_map::Entry; use std::collections::{BTreeSet, HashMap, HashSet}; use crate::Colors; -use crate::bytecode::{EntrypointsView, Module, QTypeId, StringsView, TypesView}; +use crate::bytecode::{EntrypointsView, Module, StringsView, TypeId, TypesView}; use super::Config; @@ -16,15 +16,15 @@ pub struct Emitter<'a> { pub(super) config: Config, /// TypeId -> assigned name mapping - pub(super) type_names: HashMap, + pub(super) type_names: HashMap, /// Names already used (for collision avoidance) pub(super) used_names: BTreeSet, /// Track which builtin types are referenced pub(super) node_referenced: bool, /// Track which types have been emitted - pub(super) emitted: HashSet, + pub(super) emitted: HashSet, /// Types visited during builtin reference collection (cycle detection) - pub(super) refs_visited: HashSet, + pub(super) refs_visited: HashSet, /// Output buffer pub(super) output: String, } @@ -54,8 +54,8 @@ impl<'a> Emitter<'a> { self.prepare_emission(); // Collect all entrypoints and their result types - let mut primary_names: HashMap = HashMap::new(); - let mut aliases: Vec<(String, QTypeId)> = Vec::new(); + let mut primary_names: HashMap = HashMap::new(); + let mut aliases: Vec<(String, TypeId)> = Vec::new(); for i in 0..self.entrypoints.len() { let ep = self.entrypoints.get(i); diff --git a/crates/plotnik-lib/src/typegen/typescript/naming.rs b/crates/plotnik-lib/src/typegen/typescript/naming.rs index 980ad15d..cced6a9d 100644 --- a/crates/plotnik-lib/src/typegen/typescript/naming.rs +++ b/crates/plotnik-lib/src/typegen/typescript/naming.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use plotnik_core::utils::to_pascal_case; -use crate::bytecode::{QTypeId, TypeKind}; +use crate::bytecode::{TypeId, TypeKind}; use super::Emitter; @@ -17,7 +17,7 @@ pub(super) struct NamingContext { impl Emitter<'_> { pub(super) fn assign_generated_names(&mut self) { // Collect naming contexts from entrypoints → fields - let mut contexts: HashMap = HashMap::new(); + let mut contexts: HashMap = HashMap::new(); for i in 0..self.entrypoints.len() { let ep = self.entrypoints.get(i); @@ -34,7 +34,7 @@ impl Emitter<'_> { // Assign names to types that need them for i in 0..self.types.defs_count() { - let type_id = QTypeId(i as u16); + let type_id = TypeId(i as u16); if self.type_names.contains_key(&type_id) { continue; } @@ -55,9 +55,9 @@ impl Emitter<'_> { fn collect_naming_contexts( &self, - type_id: QTypeId, + type_id: TypeId, ctx: &NamingContext, - contexts: &mut HashMap, + contexts: &mut HashMap, ) { if contexts.contains_key(&type_id) { return; @@ -89,7 +89,7 @@ impl Emitter<'_> { contexts.entry(type_id).or_insert_with(|| ctx.clone()); } TypeKind::ArrayZeroOrMore | TypeKind::ArrayOneOrMore | TypeKind::Optional => { - self.collect_naming_contexts(QTypeId(type_def.data), ctx, contexts); + self.collect_naming_contexts(TypeId(type_def.data), ctx, contexts); } } } diff --git a/crates/plotnik-lib/src/typegen/typescript/render.rs b/crates/plotnik-lib/src/typegen/typescript/render.rs index 90fa9dc7..7925443c 100644 --- a/crates/plotnik-lib/src/typegen/typescript/render.rs +++ b/crates/plotnik-lib/src/typegen/typescript/render.rs @@ -2,7 +2,7 @@ use plotnik_core::utils::to_pascal_case; -use crate::bytecode::{QTypeId, TypeDef, TypeKind}; +use crate::bytecode::{TypeDef, TypeId, TypeKind}; use super::Emitter; @@ -35,7 +35,7 @@ impl Emitter<'_> { } } - pub(super) fn emit_generated_or_custom(&mut self, type_id: QTypeId) { + pub(super) fn emit_generated_or_custom(&mut self, type_id: TypeId) { if self.emitted.contains(&type_id) { return; } @@ -67,7 +67,7 @@ impl Emitter<'_> { } } - fn emit_generated_type_def(&mut self, type_id: QTypeId, name: &str) { + fn emit_generated_type_def(&mut self, type_id: TypeId, name: &str) { self.emitted.insert(type_id); let Some(type_def) = self.types.get(type_id) else { @@ -85,7 +85,7 @@ impl Emitter<'_> { } } - pub(super) fn emit_type_definition(&mut self, name: &str, type_id: QTypeId) { + pub(super) fn emit_type_definition(&mut self, name: &str, type_id: TypeId) { self.emitted.insert(type_id); let type_name = to_pascal_case(name); @@ -138,7 +138,7 @@ impl Emitter<'_> { )); // Collect fields and sort by name - let mut fields: Vec<(String, QTypeId, bool)> = self + let mut fields: Vec<(String, TypeId, bool)> = self .types .members_of(type_def) .map(|member| {