Skip to main content
Constant folding is an experimental feature. The API may change in future versions.

What is Constant Folding?

Constant folding is an optimization technique that evaluates constant expressions at compile time rather than runtime. For example, the expression 1 + 2 can be replaced with 3, and "hello" .. " world" can become "hello world". This optimization:
  • Reduces runtime computation
  • Makes code easier to read in some cases
  • Can help with further optimizations
  • Preserves program behavior

ConstantFolder Class

The ConstantFolder is a LuaSyntaxRewriter that walks through syntax trees and replaces constant expressions with their computed values.

Usage

Use the ConstantFold extension method to apply constant folding to any syntax node:
using Loretta.CodeAnalysis.Lua;
using Loretta.CodeAnalysis.Lua.Experimental;

var code = @"
local x = 10 + 5
local y = 'Hello' .. ' ' .. 'World'
local z = 2 ^ 8
local w = not false
";

var tree = LuaSyntaxTree.ParseText(code);
var root = tree.GetRoot();

// Apply constant folding
var folded = root.ConstantFold(ConstantFoldingOptions.Default);

Console.WriteLine(folded.ToFullString());
// Output:
// local x = 15
// local y = 'Hello World'
// local z = 256
// local w = true

ConstantFoldingOptions

The ConstantFoldingOptions record allows you to configure constant folding behavior.

Available Options

ExtractNumbersFromStrings
bool
default:"false"
When enabled, the folder will extract numeric values from string literals when they’re used in numeric operations.

Presets

ConstantFoldingOptions.Default - The most conservative preset with all options disabled:
var folded = root.ConstantFold(ConstantFoldingOptions.Default);
ConstantFoldingOptions.All - Enables all folding options:
var folded = root.ConstantFold(ConstantFoldingOptions.All);

Custom Options

Create custom options by instantiating the record:
var options = new ConstantFoldingOptions(
    ExtractNumbersFromStrings: true
);

var folded = root.ConstantFold(options);

Supported Operations

The constant folder supports a wide range of Lua operations:

Arithmetic Operations

  • Addition: 1 + 23
  • Subtraction: 5 - 32
  • Multiplication: 4 * 520
  • Division: 10 / 25
  • Modulo: 10 % 31
  • Exponentiation: 2 ^ 38
  • Unary minus: -5-5

Bitwise Operations (Lua 5.3+)

  • Bitwise OR: 5 | 37
  • Bitwise AND: 5 & 31
  • Bitwise XOR: 5 ~ 36
  • Bitwise NOT: ~5-6
  • Left shift: 1 << 38
  • Right shift: 8 >> 22

String Operations

  • Concatenation: "hello" .. " " .. "world""hello world"
  • Length: #"hello"5
  • Boolean concatenation: "value: " .. true"value: true"

Comparison Operations

  • Equality: 5 == 5true
  • Inequality: 5 ~= 3true
  • Less than: 3 < 5true
  • Less than or equal: 3 <= 3true
  • Greater than: 5 > 3true
  • Greater than or equal: 5 >= 5true

Logical Operations

  • NOT: not falsetrue
  • AND: true and 55, false and 5false
  • OR: true or 5true, false or 55

Table Operations

  • Member access on constant tables: {x = 5}.x5
  • Element access on constant tables: {["key"] = 10}["key"]10

Other Optimizations

  • Removes redundant parentheses: ((5))5

Before and After Example

var code = @"
local PI = 3.14159
local radius = 10
local area = PI * (radius ^ 2)
local message = 'The area is: ' .. 'approximately'
local isValid = not (radius < 0)
local flags = 0x01 | 0x02 | 0x04
";

var tree = LuaSyntaxTree.ParseText(code);
var folded = tree.GetRoot().ConstantFold(ConstantFoldingOptions.Default);

Console.WriteLine(folded.ToFullString());
Before:
local PI = 3.14159
local radius = 10
local area = PI * (radius ^ 2)
local message = 'The area is: ' .. 'approximately'
local isValid = not (radius < 0)
local flags = 0x01 | 0x02 | 0x04
After:
local PI = 3.14159
local radius = 10
local area = PI * 100
local message = 'The area is: approximately'
local isValid = not false
local flags = 7

Limitations

The constant folder has important limitations:

Special Values

  • NaN and Infinity: Operations that produce NaN or Infinity are not folded to preserve safety
  • Example: 0 / 0 is not folded because it produces NaN

Dynamic Values

  • Function calls cannot be folded: math.sqrt(16) remains as-is
  • Variable references cannot be folded: x + 1 where x is a variable
  • Indexing non-constant tables: someTable[key] remains as-is

Scope Limitations

  • Only literal values and expressions built from literals are folded
  • No cross-statement or cross-function analysis is performed

Type Coercion

  • String-to-number coercion requires ExtractNumbersFromStrings option
  • Complex type coercions may not be supported

When to Use Constant Folding

Good Use Cases

  • Code generators: Pre-compute values in generated code
  • Optimization pipelines: As part of a larger optimization strategy
  • Dead code elimination: Simplify conditional expressions for further analysis
  • Build-time optimization: Optimize code during build/deployment

When to Avoid

  • Debugging: Folded constants can make debugging harder
  • Source mapping: May complicate source map generation
  • Readability: Sometimes the original expression is clearer than the folded value
  • Float precision: Be cautious with floating-point operations where precision matters

See Also

Build docs developers (and LLMs) love