Skip to content

The AST Schema

Every handler invocation receives one entity AST node, JSON-encoded. Call json.decode(input) to get a Lua table. This page describes the fields available on the most common node kinds. The full per-kind schema is auto-generated and available under AST Schemas.

What the engine adds before the handler sees the JSON

Section titled “What the engine adds before the handler sees the JSON”

The engine takes the codex toJSON output and:

  1. Removes “heavy” fields the handler rarely needs: memberFunctions, staticMemberFunctions, constructors, destructors, operators, nestedTypes, statements. Use the native introspection API (get_node, get_base_classes, etc.) to retrieve them on demand.
  2. Adds _namespaces (array of namespace strings, outermost first).
  3. Adds _registryId (an opaque integer; pass it to get_node, get_base_classes, etc.).
  4. Adds params (a copy of rule.params from the config).
{
"kind": "Struct",
"identifier": {
"name": "ConnectionOptions",
"templateArguments": []
},
"_namespaces": ["network", "internal"],
"memberVariables": [ /* see below */ ],
"attributes": [
{ "ns": "codegen", "name": "MarkdownDocs", "arguments": [] }
]
}
FieldTypeDescription
kindstring"Struct", "Class", or "Union"
identifier.namestringUnqualified type name
identifier.templateArgumentsarrayTemplate parameter / argument nodes (if templated)
_namespacesstring[]Enclosing namespace stack, outermost first
memberVariablesarrayMember variable nodes (see below)
attributesarrayC++ attributes on this declaration. Each entry has ns, name, arguments
local ns = table.concat(node._namespaces, "::")
local qualified = ns ~= "" and (ns .. "::" .. node.identifier.name) or node.identifier.name
-- result: "network::internal::ConnectionOptions"

enum declarations with a body have kind = "EnumeratorSpecifier" (the codex NodeKind::EnumSpecifier stringified):

{
"kind": "EnumeratorSpecifier",
"identifier": { "name": "Color" },
"_namespaces": [],
"isScoped": true,
"isForwardDeclaration": false,
"enumerators": [
{ "name": "Red", "value": null },
{ "name": "Green", "value": null },
{ "name": "Blue", "value": "2" }
]
}
FieldTypeDescription
isScopedbooltrue for enum class, false for unscoped enum
isForwardDeclarationbooltrue for declarations without a body
enumeratorsarrayEnumerator nodes
enumerators[].namestringEnumerator identifier
enumerators[].valuestring | nullExplicit value as source text, or null

Forward declarations have kind = "Enumerator" (codex NodeKind::Enum). Anchor-triggered handlers also receive the appropriate kind via the same payload.

{
"kind": "Variable",
"identifier": { "name": "port" },
"typeSignature": {
"identifier": {
"name": "uint16_t",
"templateArguments": []
},
"isConst": false,
"isPointer": false,
"isReference": false
}
}

For groups of variables sharing a type (int x, y, z;), the kind is "VariableGroup" with a variables array. Always handle both:

for _, var in ipairs(node.memberVariables or {}) do
if var.kind == "Variable" then
process(var)
elseif var.kind == "VariableGroup" then
for _, v in ipairs(var.variables or {}) do process(v) end
end
end
local function typeName(tSig)
if not tSig or not tSig.identifier then return "?" end
local name = tSig.identifier.name
local args = tSig.identifier.templateArguments or {}
-- e.g. name = "vector", args = [{ identifier = { name = "string" }, ... }]
return name
end

Template arguments are themselves type-signature-shaped — navigate them recursively.

Use the ast-dump tool to dump any header in the codex JSON form:

Terminal window
ast-dump -m codex -i include/color.hpp

The shape printed is the same the handler decodes, minus the _namespaces, _registryId, and params synthetic keys, and minus the heavy fields the engine strips.

Key Takeaways
  • Structs/classes/unions carry _namespaces (outermost-first), memberVariables, and attributes (note: attributes, the C++ term, not annotations).
  • Enum declarations with a body have kind = "EnumeratorSpecifier"; forward declarations have kind = "Enumerator".
  • Member variables have a typeSignature; templates recurse via identifier.templateArguments.
  • Heavy fields are stripped before the handler sees the JSON; recover them with the native introspection API.
  • Use ast-dump -m codex -i <file> to preview the exact JSON your handler will receive.