Skip to main content

Overview

The LuaSyntaxVisitor<TResult> class provides a generic visitor pattern implementation for traversing Lua syntax trees. It visits a single node and produces a value of type TResult. This class is ideal when you need to extract or compute information from syntax nodes.

Namespace

Loretta.CodeAnalysis.Lua

Syntax

public abstract partial class LuaSyntaxVisitor<TResult>

Type Parameters

  • TResult: The type of value returned by the Visit methods.

When to Use

Use LuaSyntaxVisitor<TResult> when you need to:
  • Extract specific information from syntax nodes
  • Compute values based on the syntax tree structure
  • Implement pattern matching over syntax nodes
  • Return a result from visiting each node
Use LuaSyntaxWalker instead when you:
  • Need to automatically traverse child nodes
  • Don’t need to return values from visits
  • Want to perform operations at specific tree depths (nodes, tokens, trivia)

Key Methods

Visit

public virtual TResult? Visit(SyntaxNode? node)
Visits the specified node and returns a result. Returns default(TResult) if the node is null. Parameters:
  • node: The syntax node to visit
Returns: The result of visiting the node

DefaultVisit

public virtual TResult? DefaultVisit(SyntaxNode node)
Provides default behavior when visiting a node. Returns default(TResult) by default. Override this to provide common behavior for all node types.

Visit Methods

The visitor provides specialized Visit methods for each syntax node type. Override the appropriate method to handle specific node types:

Expression Visitors

  • VisitAnonymousFunctionExpression - Function expressions
  • VisitBinaryExpression - Binary operations (+, -, *, etc.)
  • VisitUnaryExpression - Unary operations (-, not, #, etc.)
  • VisitLiteralExpression - Literals (numbers, strings, true, false, nil)
  • VisitIdentifierName - Variable names
  • VisitMemberAccessExpression - Member access (table.field)
  • VisitElementAccessExpression - Element access (table[key])
  • VisitFunctionCallExpression - Function calls
  • VisitMethodCallExpression - Method calls (object:method())
  • VisitTableConstructorExpression - Table constructors
  • VisitParenthesizedExpression - Parenthesized expressions
  • VisitIfExpression - If expressions (ternary-like)
  • VisitVarArgExpression - Variadic arguments (…)
  • VisitInterpolatedStringExpression - Interpolated strings
  • VisitTypeCastExpression - Type casts

Statement Visitors

  • VisitAssignmentStatement - Variable assignments
  • VisitCompoundAssignmentStatement - Compound assignments (+=, -=, etc.)
  • VisitLocalVariableDeclarationStatement - Local variable declarations
  • VisitFunctionDeclarationStatement - Function declarations
  • VisitLocalFunctionDeclarationStatement - Local function declarations
  • VisitIfStatement - If statements
  • VisitWhileStatement - While loops
  • VisitRepeatUntilStatement - Repeat-until loops
  • VisitNumericForStatement - Numeric for loops
  • VisitGenericForStatement - Generic for loops
  • VisitDoStatement - Do blocks
  • VisitReturnStatement - Return statements
  • VisitBreakStatement - Break statements
  • VisitContinueStatement - Continue statements
  • VisitGotoStatement - Goto statements
  • VisitGotoLabelStatement - Goto labels
  • VisitExpressionStatement - Expression statements
  • VisitEmptyStatement - Empty statements (lone semicolons)

Type System Visitors (Typed Lua)

  • VisitSimpleTypeName - Simple type names
  • VisitCompositeTypeName - Composite type names
  • VisitFunctionType - Function types
  • VisitTableType - Table types
  • VisitArrayType - Array types
  • VisitUnionType - Union types
  • VisitIntersectionType - Intersection types
  • VisitNilableType - Nilable types
  • VisitLiteralType - Literal types
  • VisitTypeofType - Typeof types
  • VisitParenthesizedType - Parenthesized types

Other Visitors

  • VisitCompilationUnit - Root node of a syntax tree
  • VisitStatementList - List of statements
  • VisitParameterList - Function parameters
  • VisitEqualsValuesClause - The = values part of assignments
  • VisitElseIfClause - Elseif clauses in if statements
  • VisitElseClause - Else clauses in if statements
  • And many more…

Examples

Example 1: Count Specific Node Types

using Loretta.CodeAnalysis.Lua;
using Loretta.CodeAnalysis.Lua.Syntax;

public class NodeCounter : LuaSyntaxVisitor<int>
{
    public override int DefaultVisit(SyntaxNode node)
    {
        // Sum up counts from child nodes
        int count = 0;
        foreach (var child in node.ChildNodes())
        {
            count += Visit(child);
        }
        return count;
    }

    public override int VisitFunctionCallExpression(FunctionCallExpressionSyntax node)
    {
        // Count this function call plus any nested ones
        return 1 + DefaultVisit(node);
    }
}

// Usage
var code = @"
function test()
    print('hello')
    string.format('%s', 'world')
end
";

var tree = LuaSyntaxTree.ParseText(code, new LuaParseOptions(LuaSyntaxOptions.All));
var counter = new NodeCounter();
int functionCallCount = counter.Visit(tree.GetRoot());
Console.WriteLine($"Function calls: {functionCallCount}"); // Output: Function calls: 2

Example 2: Extract String Literals

public class StringLiteralCollector : LuaSyntaxVisitor<List<string>>
{
    public override List<string> DefaultVisit(SyntaxNode node)
    {
        var strings = new List<string>();
        foreach (var child in node.ChildNodes())
        {
            strings.AddRange(Visit(child) ?? new List<string>());
        }
        return strings;
    }

    public override List<string> VisitLiteralExpression(LiteralExpressionSyntax node)
    {
        var strings = new List<string>();
        
        if (node.Token.Value is string str)
        {
            strings.Add(str);
        }
        
        // Also check children
        strings.AddRange(DefaultVisit(node));
        return strings;
    }
}

// Usage
var code = @"
local msg = 'hello'
print('world', 'test')
";

var tree = LuaSyntaxTree.ParseText(code, new LuaParseOptions(LuaSyntaxOptions.All));
var collector = new StringLiteralCollector();
var strings = collector.Visit(tree.GetRoot());
foreach (var s in strings)
{
    Console.WriteLine(s);
}
// Output:
// hello
// world
// test

Example 3: Find All Global Variables

public class GlobalVariableFinder : LuaSyntaxVisitor<HashSet<string>>
{
    public override HashSet<string> DefaultVisit(SyntaxNode node)
    {
        var globals = new HashSet<string>();
        foreach (var child in node.ChildNodes())
        {
            var childGlobals = Visit(child);
            if (childGlobals != null)
            {
                globals.UnionWith(childGlobals);
            }
        }
        return globals;
    }

    public override HashSet<string> VisitIdentifierName(IdentifierNameSyntax node)
    {
        var globals = new HashSet<string>();
        
        // Simple heuristic: if it's a common Lua global, collect it
        var name = node.Name;
        if (IsLikelyGlobal(name))
        {
            globals.Add(name);
        }
        
        return globals;
    }

    private bool IsLikelyGlobal(string name)
    {
        // Common Lua globals
        var knownGlobals = new[] { "print", "error", "assert", "type", "tonumber", 
                                   "tostring", "pairs", "ipairs", "next", "select" };
        return knownGlobals.Contains(name);
    }
}

// Usage
var code = @"
local x = 10
print(x)
assert(type(x) == 'number')
";

var tree = LuaSyntaxTree.ParseText(code, new LuaParseOptions(LuaSyntaxOptions.All));
var finder = new GlobalVariableFinder();
var globals = finder.Visit(tree.GetRoot());
foreach (var global in globals)
{
    Console.WriteLine($"Global: {global}");
}
// Output:
// Global: print
// Global: assert
// Global: type

Differences from LuaSyntaxWalker

FeatureLuaSyntaxVisitor (generic)LuaSyntaxWalker
Returns valuesYes (TResult)No (void)
Auto-traverses childrenNo (manual)Yes (automatic)
Depth controlNoYes (Node, Token, Trivia, StructuredTrivia)
Use caseExtract/compute informationPerform operations during traversal
Override patternOverride specific Visit methodsOverride specific Visit methods
Default behaviorReturns default(TResult)Visits all children

See Also

Build docs developers (and LLMs) love