Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions crates/plotnik-lib/src/bytecode/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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();

Expand Down
4 changes: 2 additions & 2 deletions crates/plotnik-lib/src/bytecode/entrypoint.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand All @@ -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,
}

Expand Down
36 changes: 0 additions & 36 deletions crates/plotnik-lib/src/bytecode/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -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) |`
Expand Down Expand Up @@ -76,10 +68,6 @@ impl Symbol {
}
}

// =============================================================================
// Navigation Symbols
// =============================================================================

/// Format navigation command as a Symbol using the doc-specified triangles.
///
/// | Nav | Symbol | Notes |
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 {
Expand All @@ -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.
Expand All @@ -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:
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion crates/plotnik-lib/src/bytecode/ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
151 changes: 6 additions & 145 deletions crates/plotnik-lib/src/bytecode/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -459,7 +459,7 @@ impl MatchIR {
}
}

impl From<MatchIR> for Instruction {
impl From<MatchIR> for InstructionIR {
fn from(m: MatchIR) -> Self {
Self::Match(m)
}
Expand Down Expand Up @@ -517,7 +517,7 @@ impl CallIR {
}
}

impl From<CallIR> for Instruction {
impl From<CallIR> for InstructionIR {
fn from(c: CallIR) -> Self {
Self::Call(c)
}
Expand All @@ -543,7 +543,7 @@ impl ReturnIR {
}
}

impl From<ReturnIR> for Instruction {
impl From<ReturnIR> for InstructionIR {
fn from(r: ReturnIR) -> Self {
Self::Return(r)
}
Expand Down Expand Up @@ -577,7 +577,7 @@ impl TrampolineIR {
}
}

impl From<TrampolineIR> for Instruction {
impl From<TrampolineIR> for InstructionIR {
fn from(t: TrampolineIR) -> Self {
Self::Trampoline(t)
}
Expand All @@ -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);
}
}
Loading