Code Generation¶
ORCA uses a PHP-based code generation toolchain to convert XML module definitions into C headers, property hash tables, and Lua binding code. This means that the .xml file is the single source of truth for every module's public API — you never edit the generated .h, _properties.h, or _export.c files by hand.
Prerequisites¶
The toolchain depends on two git submodules:
# Pull both submodules (one-time after cloning)
git submodule update --init --recursive
# Install the pyphp Python package (one-time)
pip install -e tools/pyphp
| Submodule | Path | Purpose |
|---|---|---|
platform |
libs/platform |
Cross-platform abstraction layer |
pyphp |
tools/pyphp |
Python-to-PHP bridge for running the templates |
Running Code Generation¶
From the tools/ directory:
cd tools
make # Regenerate all modules: headers + export files + property tables
make docs # Regenerate API documentation Markdown pages
make dtd # Regenerate docs/schemas/orca.dtd (UI element schema)
To regenerate a single template manually:
cd tools
python3 -m pyphp.pyphp templates/header.php ../source/core/core.xml
python3 -m pyphp.pyphp templates/properties.php ../source/core/core.xml
python3 -m pyphp.pyphp templates/export.php ../source/core/core.xml
python3 -m pyphp.pyphp templates/docs.php ../source/core/core.xml
What Gets Generated¶
For each module listed in tools/Makefile, three files are produced:
| Generated file | Template | Contents |
|---|---|---|
<module>.h |
templates/header.php |
Enum typedefs, struct declarations, function prototypes, Lua push/check helpers |
<module>_properties.h |
templates/properties.php |
FNV1a hash constants for every property and event; GetXxx(obj) accessor macros |
<module>_export.c |
templates/export.php |
Enum↔string converters, Lua wrapper functions, luaopen_orca_<module>() |
When make docs is run, one additional file per module is written under docs/api/:
| Generated file | Template | Contents |
|---|---|---|
docs/api/<module>/README.md |
templates/docs.php |
Markdown API reference for the module |
Module XML Format¶
Every module XML file follows this skeleton:
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "https://corepunch.github.io/orca/schemas/module.dtd">
<module name="mymodule" namespace="orca" on-luaopen="on_mymodule_registered">
<!-- Pull in types from another module -->
<require file="../geometry/geometry.xml"/>
<!-- Enumerate a C enum — note: <enums> wraps <enum name="..."> types -->
<enums>
<enum name="Direction">
<value name="Horizontal">Left-to-right layout</value>
<value name="Vertical">Top-to-bottom layout</value>
</enum>
</enums>
<!-- Declare a C struct with Lua bindings -->
<struct name="MyStruct">
<fields>
<field name="X" type="float"/>
</fields>
<methods>
<method name="Normalize" lua="true">
<summary>Normalize the vector in-place.</summary>
</method>
</methods>
</struct>
<!-- Declare an abstract interface (global functions grouped by prefix) -->
<interface name="Object" prefix="OBJ_" export="Object">
<methods>
<method name="Create" static="true" lua="true">
<summary>Create a new Object.</summary>
<returns type="Object" pointer="true"/>
</method>
</methods>
</interface>
<!-- Declare a component (attach-only: must use addComponent) -->
<class name="MyComponent" attach-only="true">
<summary>Moves an object at a configurable speed.</summary>
<handles>
<handle message="Object.Start"/>
<handle message="Object.Animate"/>
</handles>
<properties>
<property name="Speed" type="float" default="1.0">Movement speed</property>
</properties>
<messages>
<message name="OnValueChanged" routing="Direct"/>
</messages>
</class>
</module>
See the Module XML Guide for a complete element reference.
PHP Data Model¶
The templates access the parsed XML through the Model class defined in tools/model/module.php:
$model = new Model($argv[1]); // parse the XML file
$model->getInterfaces(); // array of Interface objects
$model->getStructs(); // array of Struct objects
$model->getEnums(); // array of Enum objects
$model->getComponents(); // array of Component (class) objects
$model->getFunctions(); // array of Method objects (global functions)
$model->getEvents(); // array of Event objects
Templates iterate these collections to emit C or Markdown output.
Template Architecture¶
Templates live in tools/templates/ and are plain PHP scripts executed by pyphp. The entry point is tools/templates/index.php, which routes to controller classes in tools/templates/controllers/:
| Controller | Actions | Purpose |
|---|---|---|
CodegenController |
header, export, properties |
Generate C files |
DocsController |
docs |
Generate Markdown API docs |
DtdController |
dtd |
Generate the XML DTD schema |
The header and export outputs are each split into focused sub-templates:
Header sub-templates (tools/templates/header/):
| Template | Variables | Output |
|---|---|---|
preamble.php |
module, namespace, includes, … | #pragma once, includes, forward declarations |
enums.php |
enums | Enum typedef + string converters |
declarations.php |
structs, functions, prefix, interfaces | Function prototypes |
structs.php |
structs | Struct typedef + method stubs |
components.php |
components | Component struct + accessor macros |
footer.php |
— | Closing guards |
Export sub-templates (tools/templates/):
| Template | Purpose |
|---|---|
export_preamble.php |
#include directives |
export_enums.php |
Enum ↔ string conversion functions |
export_interfaces.php |
Lua wrappers for interface methods |
export_structs.php |
Lua wrappers for struct methods |
export_components.php |
Component registration + property accessors |
export_functions.php |
Wrappers for global functions |
export_luaopen.php |
luaopen_orca_<module>() function |
pyphp Limitations¶
The pyphp Python-PHP bridge supports most PHP syntax but has a few quirks to be aware of when editing templates:
- No
(string)$expr— usestrval($expr)instead - No negated
issetin conditions —if (!isset($arr[$key]))silently runs the body unconditionally; workaround:$v = isset($arr[$k]) ? $arr[$k] : ""; if ($v === "") { … } - No ternary as a dict value — hoist to a variable first:
$ns = $x ? $a : $b; $vars = ["ns" => $ns]; - No
new $varName()— onlynew ConcreteClass()works; same restriction applies to$obj->$method() ?>eats the following newline — useecho "…\n"inside PHP blocks when emitting C code that must end with a newline
Key Files¶
| File | Role |
|---|---|
docs/schemas/module.dtd |
XML schema — update when adding new XML elements |
tools/model/module.php |
PHP data model — add methods to parse new elements |
tools/templates/docs.php |
Docs generator — add rendering for new elements |
tools/templates/header.php |
Orchestrates header sub-templates |
tools/templates/export.php |
Orchestrates export sub-templates |
source/core/core.xml |
Reference example with topics and 70+ methods |