Skip to main content

Overview

Full Moon provides powerful parsing functions that convert Lua source code into an Abstract Syntax Tree (AST). The parser is lossless, meaning it preserves all whitespace, comments, and formatting.

Basic Parsing

The simplest way to parse Lua code is using the parse function:
use full_moon::parse;

fn main() -> Result<(), Vec<full_moon::Error>> {
    let ast = parse("local x = 1")?;
    println!("Parsed successfully!");
    Ok(())
}

How It Works

The parse function:
  • Uses the most complete Lua version enabled in your feature set
  • Returns Result<Ast, Vec<Error>>
  • Fails if the code cannot be tokenized or is invalid Lua
The parse function automatically selects the appropriate Lua version based on your enabled features. For explicit version control, use parse_fallible with a pinned LuaVersion.

Error Handling

Parsing can fail with two types of errors:
pub enum Error {
    /// Issue creating an AST (tokenizing succeeded)
    AstError(ast::AstError),
    /// Issue when tokenizing
    TokenizerError(tokenizer::TokenizerError),
}

Getting Error Details

use full_moon::parse;

let result = parse("local x = ");

match result {
    Ok(ast) => println!("Success!"),
    Err(errors) => {
        for error in errors {
            println!("Error: {}", error.error_message());
            let (start, end) = error.range();
            println!("Range: {:?} to {:?}", start, end);
        }
    }
}

Fallible Parsing

For resilient parsing that always produces some AST (even if invalid), use parse_fallible:
use full_moon::{parse_fallible, LuaVersion};

let ast_result = parse_fallible("if x == 2 code()", LuaVersion::new());

// Always produces an AST
let ast = ast_result.ast();

// Check for errors
if !ast_result.errors().is_empty() {
    println!("Found {} errors", ast_result.errors().len());
}
Partial ASTs from parse_fallible may contain phantom tokens (tokens not in the original code) to make the structure valid. These have null positions unless you call Ast::update_positions.

Partial AST Guarantees

When using parse_fallible with errors:
1

Phantom Tokens

Tokens may be inserted that aren’t in the code (e.g., a missing then token). These have null positions initially.
2

Invalid Output

The printed AST may not be valid Lua. Example: local x = if produces local x = when printed.
3

No Stability Guarantees

Partial AST structures may change between full-moon versions (but are consistent within a version).

Pinning Lua Versions

Explicitly control which Lua version to parse:
use full_moon::{parse_fallible, LuaVersion};

// Parse as Lua 5.1
let lua51 = LuaVersion::lua51();
let ast = parse_fallible(code, lua51);

// Parse as Lua 5.4 (with 5.2, 5.3 features)
let lua54 = LuaVersion::lua54();
let ast = parse_fallible(code, lua54);

// Parse as Luau (Roblox Lua)
let luau = LuaVersion::luau();
let ast = parse_fallible(code, luau);
The LuaVersion::new() constructor automatically selects the most feature-rich version based on your enabled Cargo features.

Working with the AST

Once parsed, you can traverse and inspect the AST:
use full_moon::parse;

let ast = parse("local x = 1; return x")?;

// Access the block (root node)
let block = ast.nodes();

// Iterate through statements
for stmt in block.stmts() {
    println!("Statement: {}", stmt);
}

// Access the last statement (return/break)
if let Some(last_stmt) = block.last_stmt() {
    println!("Last statement: {}", last_stmt);
}

Converting Back to Code

Full Moon is lossless - you can convert the AST back to source code:
use full_moon::parse;

let code = "local x = 1";
let ast = parse(code)?;

// Convert back to string (preserves formatting exactly)
let output = ast.to_string();
assert_eq!(code, output);

Performance Tips

Reuse Parsers

If parsing many files, the parser is stateless - you can call parse repeatedly without overhead.

Use parse_fallible

For tools like linters that need to work with partial code, parse_fallible provides better UX.

Next Steps

Modifying the AST

Learn how to modify and transform AST nodes

Error Handling

Deep dive into error handling patterns

Build docs developers (and LLMs) love