Skip to main content
This guide gets you from zero to parsing Lua code in under 5 minutes. You’ll learn how to parse code, inspect the syntax tree, and check for errors.

Prerequisites

Before starting, make sure you have:
  • .NET 6.0 SDK or later installed
  • A code editor (Visual Studio, VS Code, or Rider)
  • The Loretta.CodeAnalysis.Lua NuGet package installed
If you haven’t installed Loretta yet, see the installation guide.
1

Parse Lua code

Create a new C# file and add the following code to parse a simple Lua script:
using Loretta.CodeAnalysis.Lua;
using Loretta.CodeAnalysis.Lua.Syntax;

// Your Lua source code
var luaCode = @"
local x = 10
local y = 20
local sum = x + y
print(sum)
";

// Parse the code into a syntax tree
var syntaxTree = LuaSyntaxTree.ParseText(luaCode);
The LuaSyntaxTree.ParseText method is your main entry point. It takes a string of Lua code and returns a syntax tree representing the parsed structure.
2

Get the root node

Every syntax tree has a root node that represents the entire file:
// Get the root of the syntax tree
var root = syntaxTree.GetRoot();

Console.WriteLine($"Root node type: {root.GetType().Name}");
// Output: Root node type: CompilationUnitSyntax
The root is always a CompilationUnitSyntax, which contains all the statements in your Lua file plus the end-of-file token.
3

Inspect the syntax tree

Now let’s explore the parsed structure. We’ll find all local variable declarations:
using System.Linq;

// Find all local variable declarations
var localDeclarations = root.DescendantNodes()
    .OfType<LocalVariableDeclarationStatementSyntax>();

foreach (var localDecl in localDeclarations)
{
    // Get the variable names
    var variableNames = localDecl.Names
        .Select(name => name.Name.Text);
    
    Console.WriteLine($"Local variables: {string.Join(", ", variableNames)}");
}
Output:
Local variables: x
Local variables: y
Local variables: sum
The DescendantNodes() method traverses the entire tree, and OfType<T>() filters to specific node types.
4

Check for syntax errors

Loretta automatically detects syntax errors during parsing. Check for diagnostics:
// Get all diagnostics (errors and warnings)
var diagnostics = syntaxTree.GetDiagnostics();

if (diagnostics.Any())
{
    Console.WriteLine("Errors found:");
    foreach (var diagnostic in diagnostics)
    {
        var lineSpan = diagnostic.Location.GetLineSpan();
        Console.WriteLine($"  Line {lineSpan.StartLinePosition.Line + 1}: {diagnostic.GetMessage()}");
    }
}
else
{
    Console.WriteLine("No syntax errors!");
}
For our valid code, this outputs:
No syntax errors!
Try changing luaCode to something invalid like "local x =" (missing value) and run again to see error reporting in action.

Complete example

Here’s a complete working example that puts it all together:
using Loretta.CodeAnalysis.Lua;
using Loretta.CodeAnalysis.Lua.Syntax;
using System;
using System.Linq;

class Program
{
    static void Main()
    {
        // Parse Lua code
        var luaCode = @"
local function greet(name)
    print('Hello, ' .. name)
end

greet('World')
";

        var syntaxTree = LuaSyntaxTree.ParseText(luaCode);
        var root = syntaxTree.GetRoot();

        // Check for errors
        var diagnostics = syntaxTree.GetDiagnostics();
        if (diagnostics.Any())
        {
            Console.WriteLine("Syntax errors found:");
            foreach (var diagnostic in diagnostics)
            {
                Console.WriteLine($"  {diagnostic}");
            }
            return;
        }

        // Analyze the code
        Console.WriteLine("Code analysis:");
        
        // Count function declarations
        var functionCount = root.DescendantNodes()
            .OfType<LocalFunctionDeclarationStatementSyntax>()
            .Count();
        Console.WriteLine($"  Functions: {functionCount}");

        // Count function calls
        var callCount = root.DescendantNodes()
            .OfType<FunctionCallExpressionSyntax>()
            .Count();
        Console.WriteLine($"  Function calls: {callCount}");

        // List all identifiers
        var identifiers = root.DescendantTokens()
            .Where(t => t.Kind() == SyntaxKind.IdentifierToken)
            .Select(t => t.Text)
            .Distinct();
        Console.WriteLine($"  Identifiers: {string.Join(", ", identifiers)}");
    }
}
Output:
Code analysis:
  Functions: 1
  Function calls: 2
  Identifiers: greet, name, print, World

Choose your Lua version

By default, Loretta accepts all syntax features (LuaSyntaxOptions.All). To parse code for a specific Lua version, use LuaParseOptions:
using Loretta.CodeAnalysis.Lua;

// Parse as Lua 5.1
var lua51Options = new LuaParseOptions(LuaSyntaxOptions.Lua51);
var tree51 = LuaSyntaxTree.ParseText(luaCode, lua51Options);

// Parse as Luau (Roblox Lua)
var luauOptions = new LuaParseOptions(LuaSyntaxOptions.Luau);
var treeLuau = LuaSyntaxTree.ParseText(luaCode, luauOptions);

// Parse as GLua (Garry's Mod)
var gmodOptions = new LuaParseOptions(LuaSyntaxOptions.GMod);
var treeGMod = LuaSyntaxTree.ParseText(luaCode, gmodOptions);
Available presets:
  • LuaSyntaxOptions.Lua51 - Lua 5.1
  • LuaSyntaxOptions.Lua52 - Lua 5.2
  • LuaSyntaxOptions.Lua53 - Lua 5.3
  • LuaSyntaxOptions.Lua54 - Lua 5.4
  • LuaSyntaxOptions.LuaJIT20 - LuaJIT 2.0
  • LuaSyntaxOptions.LuaJIT21 - LuaJIT 2.1-beta3
  • LuaSyntaxOptions.GMod - Garry’s Mod Lua (GLua)
  • LuaSyntaxOptions.Luau / LuaSyntaxOptions.Roblox - Roblox Luau
  • LuaSyntaxOptions.FiveM - FiveM (Lua 5.3 + hash strings)
  • LuaSyntaxOptions.All - All features enabled (default)
Each preset configures which language features are accepted during parsing.

Next steps

Now that you can parse Lua code, explore these topics:

Core concepts

Understand syntax trees, nodes, tokens, and trivia

Syntax tree navigation

Learn how to traverse and query syntax trees

Code transformation

Rewrite and transform Lua code

Error handling

Work with parse errors and diagnostics

Common tasks

Parse from a file

using Loretta.CodeAnalysis.Text;
using System.IO;

var filePath = "script.lua";
var sourceText = SourceText.From(File.ReadAllText(filePath));
var syntaxTree = LuaSyntaxTree.ParseText(sourceText, path: filePath);

Parse with specific encoding

using System.Text;

var encoding = Encoding.UTF8;
var syntaxTree = LuaSyntaxTree.ParseText(luaCode, encoding: encoding);

Get syntax errors only

var errors = syntaxTree.GetDiagnostics()
    .Where(d => d.Severity == DiagnosticSeverity.Error);

Troubleshooting

”The type or namespace name ‘Loretta’ could not be found”

Make sure you’ve installed the NuGet package:
dotnet add package Loretta.CodeAnalysis.Lua

Unexpected parse errors

Verify you’re using the correct syntax preset for your Lua version. Features like continue, compound assignment, or type annotations are only available in certain Lua dialects.

Performance with large files

For very large files, consider parsing on a background thread and passing a CancellationToken:
var cancellationToken = new CancellationToken();
var tree = LuaSyntaxTree.ParseText(largeCode, cancellationToken: cancellationToken);

Build docs developers (and LLMs) love