pub enum NodeKind {
Show 70 variants
Program {
statements: Vec<Node>,
},
ExpressionStatement {
expression: Box<Node>,
},
VariableDeclaration {
declarator: String,
variable: Box<Node>,
attributes: Vec<String>,
initializer: Option<Box<Node>>,
},
VariableListDeclaration {
declarator: String,
variables: Vec<Node>,
attributes: Vec<String>,
initializer: Option<Box<Node>>,
},
NestedVariableList {
items: Vec<Node>,
},
Variable {
sigil: String,
name: String,
},
VariableWithAttributes {
variable: Box<Node>,
attributes: Vec<String>,
},
Assignment {
lhs: Box<Node>,
rhs: Box<Node>,
op: String,
},
Binary {
op: String,
left: Box<Node>,
right: Box<Node>,
},
Ternary {
condition: Box<Node>,
then_expr: Box<Node>,
else_expr: Box<Node>,
},
Unary {
op: String,
operand: Box<Node>,
},
Diamond,
Ellipsis,
Undef,
Readline {
filehandle: Option<String>,
},
Glob {
pattern: String,
},
Typeglob {
name: String,
},
Number {
value: String,
},
String {
value: String,
interpolated: bool,
},
Heredoc {
delimiter: String,
content: String,
interpolated: bool,
indented: bool,
command: bool,
body_span: Option<ByteSpan>,
},
ArrayLiteral {
elements: Vec<Node>,
},
HashLiteral {
pairs: Vec<(Node, Node)>,
},
Block {
statements: Vec<Node>,
},
Eval {
block: Box<Node>,
},
Do {
block: Box<Node>,
},
Defer {
block: Box<Node>,
},
Try {
body: Box<Node>,
catch_blocks: Vec<(Option<String>, Box<Node>)>,
finally_block: Option<Box<Node>>,
},
If {
condition: Box<Node>,
then_branch: Box<Node>,
elsif_branches: Vec<(Box<Node>, Box<Node>)>,
else_branch: Option<Box<Node>>,
keyword: Option<String>,
},
LabeledStatement {
label: String,
statement: Box<Node>,
},
While {
condition: Box<Node>,
body: Box<Node>,
continue_block: Option<Box<Node>>,
keyword: Option<String>,
},
Tie {
variable: Box<Node>,
package: Box<Node>,
args: Vec<Node>,
},
Untie {
variable: Box<Node>,
},
For {
init: Option<Box<Node>>,
condition: Option<Box<Node>>,
update: Option<Box<Node>>,
body: Box<Node>,
continue_block: Option<Box<Node>>,
},
Foreach {
variable: Box<Node>,
list: Box<Node>,
body: Box<Node>,
continue_block: Option<Box<Node>>,
},
Given {
expr: Box<Node>,
body: Box<Node>,
},
When {
condition: Box<Node>,
body: Box<Node>,
},
Default {
body: Box<Node>,
},
StatementModifier {
statement: Box<Node>,
modifier: String,
condition: Box<Node>,
},
Subroutine {
name: Option<String>,
name_span: Option<ByteSpan>,
declarator: Option<String>,
prototype: Option<Box<Node>>,
signature: Option<Box<Node>>,
attributes: Vec<String>,
body: Box<Node>,
},
Prototype {
content: String,
},
Signature {
parameters: Vec<Node>,
},
MandatoryParameter {
variable: Box<Node>,
},
OptionalParameter {
variable: Box<Node>,
default_value: Box<Node>,
},
SlurpyParameter {
variable: Box<Node>,
},
NamedParameter {
variable: Box<Node>,
},
Method {
name: String,
name_span: Option<ByteSpan>,
signature: Option<Box<Node>>,
attributes: Vec<String>,
body: Box<Node>,
},
Return {
value: Option<Box<Node>>,
},
LoopControl {
op: String,
label: Option<String>,
},
Goto {
target: Box<Node>,
},
MethodCall {
object: Box<Node>,
method: String,
args: Vec<Node>,
},
FunctionCall {
name: String,
args: Vec<Node>,
},
IndirectCall {
method: String,
object: Box<Node>,
args: Vec<Node>,
},
Regex {
pattern: String,
replacement: Option<String>,
modifiers: String,
has_embedded_code: bool,
},
Match {
expr: Box<Node>,
pattern: String,
modifiers: String,
has_embedded_code: bool,
negated: bool,
},
Substitution {
expr: Box<Node>,
pattern: String,
replacement: String,
modifiers: String,
has_embedded_code: bool,
negated: bool,
},
Transliteration {
expr: Box<Node>,
search: String,
replace: String,
modifiers: String,
negated: bool,
},
Package {
name: String,
name_span: ByteSpan,
block: Option<Box<Node>>,
},
Use {
module: String,
args: Vec<String>,
has_filter_risk: bool,
},
No {
module: String,
args: Vec<String>,
has_filter_risk: bool,
},
PhaseBlock {
phase: String,
phase_span: Option<ByteSpan>,
block: Box<Node>,
},
DataSection {
marker: String,
body: Option<String>,
},
Class {
name: String,
name_span: Option<ByteSpan>,
parents: Vec<String>,
body: Box<Node>,
},
Format {
name: String,
name_span: Option<ByteSpan>,
body: String,
},
Identifier {
name: String,
},
Error {
message: String,
expected: Vec<TokenKind>,
found: Option<Token>,
partial: Option<Box<Node>>,
},
MissingExpression,
MissingStatement,
MissingIdentifier,
MissingBlock,
UnknownRest,
}Expand description
Comprehensive enumeration of all Perl language constructs supported by the parser.
This enum represents every possible AST node type that can be parsed from Perl code during the Parse → Index → Navigate → Complete → Analyze workflow. Each variant captures the semantic meaning and structural relationships needed for complete script analysis and transformation.
§LSP Workflow Integration
Node kinds are processed differently across workflow stages:
- Parse: All variants are produced by the parser
- Index: Symbol-bearing variants feed workspace indexing
- Navigate: Call and reference variants support navigation features
- Complete: Expression variants provide completion context
- Analyze: Semantic variants drive diagnostics and refactoring
§Examples
Pattern-match on node kinds to extract semantic information:
use perl_ast::{Node, NodeKind, SourceLocation};
let loc = SourceLocation { start: 0, end: 5 };
let node = Node::new(
NodeKind::Variable { sigil: "$".to_string(), name: "foo".to_string() },
loc,
);
assert!(matches!(
&node.kind,
NodeKind::Variable { sigil, name } if sigil == "$" && name == "foo"
));Use kind_name() for debugging and diagnostics:
use perl_ast::NodeKind;
let kind = NodeKind::Number { value: "99".to_string() };
assert_eq!(kind.kind_name(), "Number");
let kind = NodeKind::Variable { sigil: "@".to_string(), name: "list".to_string() };
assert_eq!(kind.kind_name(), "Variable");§Performance Considerations
The enum design optimizes for large codebases:
- Box pointers minimize stack usage for recursive structures
- Vector storage enables efficient bulk operations on child nodes
- Clone operations optimized for concurrent analysis workflows
- Pattern matching performance tuned for common Perl constructs
Variants§
Program
Top-level program containing all statements in an Perl script
This is the root node for any parsed Perl script content, containing all top-level statements found during the Parse stage of LSP workflow.
ExpressionStatement
Statement wrapper for expressions that appear at statement level
Used during Analyze stage to distinguish between expressions used as statements versus expressions within other contexts during Perl parsing.
VariableDeclaration
Variable declaration with scope declarator in Perl script processing
Represents declarations like my $var, our $global, local $dynamic, etc.
Critical for Analyze stage symbol table construction during Perl parsing.
Fields
VariableListDeclaration
Multiple variable declaration in a single statement
Handles constructs like my ($x, $y) = @values common in Perl script processing.
Supports efficient bulk variable analysis during Navigate stage operations.
Fields
NestedVariableList
Nested variable list within a lexical list declaration.
Represents a parenthesised group of variables inside a my/our/state
list declaration, such as the ($b, $c) in my ($a, ($b, $c)) = ....
A nested group with exactly one item is returned unwrapped (as the item
itself), so this variant only appears for two-or-more-item groups.
Variable
Perl variable reference (scalar, array, hash, etc.) in Perl parsing workflow
Fields
VariableWithAttributes
Variable with additional attributes for enhanced LSP workflow
Fields
Assignment
Assignment operation for LSP data processing workflows
Fields
Binary
Binary operation for Perl parsing workflow calculations
Ternary
Ternary conditional expression for Perl parsing workflow logic
Fields
Unary
Unary operation for Perl parsing workflow
Diamond
Diamond operator for file input in Perl parsing workflow
Ellipsis
Ellipsis operator for Perl parsing workflow
Undef
Undef value for Perl parsing workflow
Readline
Readline operation for LSP file processing
Glob
Glob pattern for LSP workspace file matching
Typeglob
Typeglob expression: *foo or *main::bar
Provides access to all symbol table entries for a given name.
Number
Numeric literal in Perl code (integer, float, hex, octal, binary)
Represents all numeric literal forms: 42, 3.14, 0x1A, 0o755, 0b1010.
String
String literal with optional interpolation
Handles both single-quoted ('literal') and double-quoted ("$interpolated") strings.
Fields
Heredoc
Heredoc string literal for multi-line content
Supports all heredoc forms: <<EOF, <<'EOF', <<"EOF", <<~EOF (indented).
Fields
ArrayLiteral
Array literal expression: (1, 2, 3) or [1, 2, 3]
HashLiteral
Hash literal expression: (key => 'value') or {key => 'value'}
Block
Block of statements: { ... }
Used for control structures, subroutine bodies, and bare blocks.
Eval
Eval block for exception handling: eval { ... }
Do
Do block for file inclusion or expression evaluation: do { ... } or do "file"
Defer
Defer block for deferred cleanup on scope exit (Perl 5.36+ experimental, stable in 5.40)
Try
Try-catch-finally for modern exception handling (Syntax::Keyword::Try style)
Fields
If
If-elsif-else conditional statement
Fields
LabeledStatement
Statement with a label for loop control: LABEL: while (...)
Fields
While
While loop: while (condition) { ... }
Fields
Tie
Tie operation for binding variables to objects: tie %hash, 'Package', @args
Fields
Untie
Untie operation for unbinding variables: untie %hash
For
C-style for loop: for (init; cond; update) { ... }
Fields
Foreach
Foreach loop: foreach my $item (@list) { ... }
Fields
Given
Given statement for switch-like matching (Perl 5.10+)
Fields
When
When clause in given/switch: when ($pattern) { ... }
Default
Default clause in given/switch: default { ... }
StatementModifier
Statement modifier syntax: print "ok" if $condition
Fields
Subroutine
Subroutine declaration (function) including name, prototype, signature and body.
Fields
name_span: Option<ByteSpan>Source location span of the subroutine name
§Usage Notes
- Always corresponds to the name field
- Provides constant-time position information
- Essential for precise editor interactions
declarator: Option<String>Optional scope declarator: “my”, “our”, or “state” for lexical/package-scoped subs
§Lexical Subroutines
- Perl 5.18+ feature:
my sub helper { ... },our sub global { ... },state sub memo { ... } - Distinguishes lexical scope binding from package-scoped subroutines
- Essential for scope tracking, renaming, and dead code detection
§Values
None— package-scoped subroutine (no declarator)Some("my")— lexical subroutine with lexical bindingSome("our")— package-scoped subroutine with explicit package declarationSome("state")— persistent lexical subroutine (persistent across invocations)
Prototype
Subroutine prototype specification: sub foo ($;@) { ... }
Signature
Subroutine signature (Perl 5.20+): sub foo ($x, $y = 0) { ... }
MandatoryParameter
Mandatory signature parameter: $x in sub foo ($x) { }
OptionalParameter
Optional signature parameter with default: $y = 0 in sub foo ($y = 0) { }
SlurpyParameter
Slurpy parameter collecting remaining args: @rest or %opts in signature
NamedParameter
Named parameter placeholder in signature (future Perl feature)
Method
Method declaration (Perl 5.38+ with use feature 'class')
Fields
Return
Return statement: return; or return $value;
LoopControl
Loop control statement: next, last, or redo
Fields
Goto
Goto statement: goto LABEL, goto &sub, or goto $expr
MethodCall
Method call: $obj->method(@args) or $obj->method
Fields
FunctionCall
Function call: foo(@args) or foo()
Fields
IndirectCall
Indirect object call (legacy syntax): new Class @args
Regex
Regex literal: /pattern/modifiers or qr/pattern/modifiers
Fields
Match
Match operation: $str =~ /pattern/modifiers or $str !~ /pattern/modifiers
Fields
Substitution
Substitution operation: $str =~ s/pattern/replacement/modifiers
Fields
Transliteration
Transliteration operation: $str =~ tr/search/replace/ or y///
Fields
Package
Package declaration (e.g. package Foo;) and optional inline block form.
Fields
Use
Use statement for module loading: use Module qw(imports);
Fields
No
No statement for disabling features: no strict;
Fields
PhaseBlock
Phase block for compile/runtime hooks: BEGIN, END, CHECK, INIT, UNITCHECK
Fields
DataSection
Data section marker: __DATA__ or __END__
Fields
Class
Class declaration (Perl 5.38+ with use feature 'class')
Fields
Format
Format declaration for legacy report generation
Fields
Identifier
Bare identifier (bareword or package-qualified name)
Error
Parse error placeholder with error message and recovery context
Fields
MissingExpression
Missing expression where one was expected.
Emitted by recover_missing_infix_rhs when a binary operator has no
right-hand-side (e.g. 1 + at end of input). This is the only
Missing* variant currently emitted by the production parser.
MissingStatement
RESERVED — not currently emitted by the parser.
Retained for API symmetry and future error-recovery work. If recovery starts emitting this variant, add real parser fixture tests before shipping. Do not pattern-match on this variant expecting it to appear in normal parse output.
MissingIdentifier
RESERVED — not currently emitted by the parser.
Retained for API symmetry and future error-recovery work. If recovery starts emitting this variant, add real parser fixture tests before shipping. Do not pattern-match on this variant expecting it to appear in normal parse output.
MissingBlock
RESERVED — not currently emitted by the parser.
Retained for API symmetry and future error-recovery work. If recovery starts emitting this variant, add real parser fixture tests before shipping. Do not pattern-match on this variant expecting it to appear in normal parse output.
UnknownRest
Lexer budget exceeded marker preserving partial parse results
Used when recursion or token limits are hit to preserve already-parsed content.
Implementations§
Source§impl NodeKind
impl NodeKind
Sourcepub const ALL_KIND_NAMES: &'static [&'static str] = NodeKind::VARIANTS
pub const ALL_KIND_NAMES: &'static [&'static str] = NodeKind::VARIANTS
Canonical list of all kind_name() strings, in declaration order.
Auto-derived from the NodeKind enum via strum::VariantNames — adding a new
variant automatically updates this list. No manual maintenance required.
Every consumer that needs the full set of NodeKind names should reference this constant instead of maintaining a hand-written copy.
Sourcepub const RECOVERY_KIND_NAMES: &'static [&'static str]
pub const RECOVERY_KIND_NAMES: &'static [&'static str]
Subset of ALL_KIND_NAMES that represent synthetic/recovery nodes.
These kinds are only produced by parse_with_recovery() on malformed
input and should not be expected in clean parses.
Sourcepub fn kind_name(&self) -> &'static str
pub fn kind_name(&self) -> &'static str
Get the name of this NodeKind as a static string.
Useful for diagnostics, logging, and human-readable AST dumps.
§Examples
use perl_ast::NodeKind;
let kind = NodeKind::Variable { sigil: "$".to_string(), name: "x".to_string() };
assert_eq!(kind.kind_name(), "Variable");
let kind = NodeKind::Program { statements: vec![] };
assert_eq!(kind.kind_name(), "Program");Source§impl NodeKind
impl NodeKind
Sourcepub fn category(&self) -> NodeKindCategory
pub fn category(&self) -> NodeKindCategory
Return the high-level NodeKindCategory for this variant.
The match is exhaustive with no wildcard arm — adding a new
NodeKind variant is a compile error until this function is updated.
Sourcepub fn flags(&self) -> NodeKindFlags
pub fn flags(&self) -> NodeKindFlags
Return the full NodeKindFlags for this variant.
The match is exhaustive with no wildcard arm — adding a new
NodeKind variant is a compile error until this function is updated.
See NodeKindFlags for the precise semantics of each flag.
§Invariant
The returned flags always satisfy flags.validate().is_ok().
Sourcepub fn is_executable(&self) -> bool
pub fn is_executable(&self) -> bool
Returns true if this node kind represents executable code.
Sourcepub fn introduces_scope(&self) -> bool
pub fn introduces_scope(&self) -> bool
Returns true if this node kind introduces a new lexical scope.
Sourcepub fn declares_symbol(&self) -> bool
pub fn declares_symbol(&self) -> bool
Returns true if this node kind declares a symbol into a scope or
symbol table.
Sourcepub fn references_symbol(&self) -> bool
pub fn references_symbol(&self) -> bool
Returns true if this node kind references a symbol.
Sourcepub fn safe_for_breakpoint(&self) -> bool
pub fn safe_for_breakpoint(&self) -> bool
Returns true if this node kind can host a debugger breakpoint.
This is a variant-level flag. Consumers must AND it with positional
checks (heredoc body interior, POD block, __DATA__ section, etc.)
before accepting a breakpoint request.
Sourcepub fn is_recovery(&self) -> bool
pub fn is_recovery(&self) -> bool
Returns true if this node kind is a synthetic recovery artifact.
Recovery nodes should never be offered to editor features such as hover, go-to-definition, or breakpoint placement.
Sourcepub fn contains_children(&self) -> bool
pub fn contains_children(&self) -> bool
Returns true if this node kind can host Node children worth walking
during AST traversal.
This is a structural flag: it is true for every variant that has
at least one Node-typed field (Box<Node>, Vec<Node>,
Option<Box<Node>>, …), regardless of whether a particular instance
populates them. A traversal filter may safely skip nodes for which this
returns false — they are always leaves under
Node::for_each_child.