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
131 changes: 131 additions & 0 deletions crates/plotnik-lib/src/bytecode/dump_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
//! Tests for bytecode dump functionality.

use crate::Query;
use indoc::indoc;

#[test]
fn dump_minimal() {
let input = "Test = (identifier) @id";

let res = Query::expect_valid_linked_bytecode(input);

insta::assert_snapshot!(res, @r#"
[header]
linked = true

[strings]
S00 "Beauty will save the world"
S01 "id"
S02 "Test"
S03 "identifier"

[types.defs]
T00 = void
T01 = Node
T02 = str
T03 = Struct(M0, 1) ; { id }

[types.members]
M0 = (S01, T01) ; id: Node

[types.names]
N0 = (S02, T03) ; Test

[entry]
Test = 01 :: T03

[code]
00 𝜀 ◼

Test:
01 𝜀 02
02 *↓ (identifier) 03
03 𝜀 [Node Set(M0)] ◼
"#);
}

#[test]
fn dump_multiple_entrypoints() {
let input = indoc! {r#"
Expression = [(identifier) @name (number) @value]
Root = (function_declaration name: (identifier) @name)
"#};

let res = Query::expect_valid_linked_bytecode(input);

// Verify key sections exist
assert!(res.contains("[header]"));
assert!(res.contains("[strings]"));
assert!(res.contains("[types.defs]"));
assert!(res.contains("[types.members]"));
assert!(res.contains("[types.names]"));
assert!(res.contains("[entry]"));
assert!(res.contains("[code]"));

// Verify both entrypoints appear
assert!(res.contains("Expression"));
assert!(res.contains("Root"));

// Verify code section has entrypoint labels
assert!(res.contains("Expression:"));
assert!(res.contains("Root:"));
}

#[test]
fn dump_with_field_constraints() {
let input = indoc! {r#"
Test = (binary_expression
left: (_) @left
right: (_) @right)
"#};

let res = Query::expect_valid_linked_bytecode(input);

// Should have field references in code section
assert!(res.contains("left:"));
assert!(res.contains("right:"));
}

#[test]
fn dump_with_quantifier() {
let input = "Test = (identifier)* @items";

let res = Query::expect_valid_linked_bytecode(input);

// Should have array type
assert!(res.contains("Array") || res.contains("[]"));
}

#[test]
fn dump_with_alternation() {
let input = "Test = [(identifier) @id (string) @str]";

let res = Query::expect_valid_linked_bytecode(input);

// Should have code section with branching
assert!(res.contains("[code]"));
}

#[test]
fn dump_comprehensive() {
// A query that exercises most features:
// - Multiple definitions (entrypoints)
// - Field constraints (node_fields)
// - Multiple node types (node_types)
// - Captures with types (type_defs, type_members)
// - Alternation (branching in code)
let input = indoc! {r#"
Ident = (identifier) @name :: string
Expression = [
Literal: (number) @value
Variable: (identifier) @name
]
Assignment = (assignment_expression
left: (identifier) @target
right: (Expression) @value)
"#};

let res = Query::expect_valid_linked_bytecode(input);

insta::assert_snapshot!(res);
}
2 changes: 2 additions & 0 deletions crates/plotnik-lib/src/bytecode/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub use module::{

pub use dump::dump;

#[cfg(test)]
mod dump_tests;
#[cfg(test)]
mod instructions_tests;
#[cfg(test)]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
source: crates/plotnik-lib/src/bytecode/dump_tests.rs
expression: res
---
[header]
linked = true

[strings]
S00 "Beauty will save the world"
S01 "name"
S02 "value"
S03 "Literal"
S04 "Variable"
S05 "target"
S06 "Ident"
S07 "Expression"
S08 "Assignment"
S09 "identifier"
S10 "number"
S11 "assignment_expression"
S12 "left"
S13 "right"

[types.defs]
T00 = void
T01 = Node
T02 = str
T03 = Struct(M0, 1) ; { name }
T04 = Struct(M1, 1) ; { value }
T05 = Struct(M2, 1) ; { name }
T06 = Enum(M3, 2) ; Literal | Variable
T07 = Struct(M5, 2) ; { value, target }

[types.members]
M0 = (S01, T02) ; name: str
M1 = (S02, T01) ; value: Node
M2 = (S01, T01) ; name: Node
M3 = (S03, T04) ; Literal: T04
M4 = (S04, T05) ; Variable: T05
M5 = (S02, T06) ; value: Expression
M6 = (S05, T01) ; target: Node

[types.names]
N0 = (S06, T03) ; Ident
N1 = (S07, T06) ; Expression
N2 = (S08, T07) ; Assignment

[entry]
Assignment = 08 :: T07
Expression = 05 :: T06
Ident = 01 :: T03

[code]
00 𝜀 ◼

Ident:
01 𝜀 02
02 *↓ (identifier) 03
03 𝜀 [Text Set(M0)] ◼

Expression:
05 𝜀 06
06 𝜀 23, 30

Assignment:
08 𝜀 09
09 *↓ (assignment_expression) 10
10 𝜀 left: _ 11
11 *↓ (identifier) 12
12 𝜀 [Node Set(M1)] 14
14 𝜀 right: _ ▶(Expression)
15 𝜀 [Node Set(M0)] 17
17 *↑¹ ◼
18 𝜀 [EndE] ◼
20 𝜀 [Node] 18
22 *↓ (number) 20
23 𝜀 [E(M0)] 22
25 𝜀 [EndE] ◼
27 𝜀 [Node] 25
29 *↓ (identifier) 27
30 𝜀 [E(M1)] 29
Loading