Architecture #
Sugar turns templates into a small, predictable PHP AST and then emits optimized PHP code. The pipeline is designed to keep parsing and compilation deterministic, while runtime stays fast and cache-friendly.
Compilation happens once per template change. Rendering is a cached PHP include.
Compilation Pipeline #
| Priority Enum | Stage | Purpose | Notes |
|---|---|---|---|
| — | Parser | Converts template source into a Sugar AST. | Uses PhpToken for PHP-aware tokenization and preserves line/column for error reporting. |
DIRECTIVE_EXTRACTION |
DirectiveExtractionPass | Pulls out s:* directives and validates placement. |
Produces directive nodes from attributes. |
DIRECTIVE_PAIRING |
DirectivePairingPass | Pairs directives like if/elseif/else and forelse/empty. |
Ensures correct sibling relationships. |
DIRECTIVE_COMPILATION |
DirectiveCompilationPass | Rewrites directive nodes into executable AST nodes. | Produces control flow, attributes, and output nodes. |
INHERITANCE_COMPILATION |
InheritanceCompilationPass | Compiles s:extends, s:block, s:parent, s:append, s:prepend, and s:include to runtime calls. |
Uses loader path resolution and tracks inheritance dependencies. |
POST_DIRECTIVE_COMPILATION |
ComponentExpansionPass | Rewrites component tags/directives into runtime component render calls. | Registered by ComponentExtension (optional, requires a template loader). |
PHP_NORMALIZATION |
PhpNormalizationPass | Normalizes raw PHP blocks before context analysis. | Hoists leading import statements to file scope and de-duplicates equivalent imports. |
CONTEXT_ANALYSIS |
ContextAnalysisPass | Determines output context for escaping decisions. | Tags output nodes with HTML/attribute/URL/JS/CSS contexts. |
| — | CodeGenerator | Emits pure PHP from the final AST. | Output is ready for opcache. |
If a template compiles, it will render deterministically. All runtime behavior is inside the generated PHP.
AST Shape #
Sugar keeps a small set of nodes so transformations remain predictable. Directives compile into nodes that the code generator can output without re-parsing.
use Sugar\Core\Ast\ElementNode;
use Sugar\Core\Ast\RawPhpNode;
$element = new ElementNode(
tag: 'div',
attributes: [],
children: [new RawPhpNode('echo $name;', 12, 8)],
selfClosing: false,
line: 12,
column: 1,
);
Why AST nodes matter
Errors point to the source line/column, and transformations are composable because every pass consumes and returns nodes.
Directive Lifecycle #
Directives are extracted first and compiled later. This keeps validation separate from code generation.
HTML element + s:* attributes
↓
Directive nodes (validated)
Directive nodes
↓
RawPhpNode / OutputNode / ElementNode
Directive compilation must be side-effect free. Any runtime work belongs in the generated PHP.
Context-Aware Escaping #
The context pass marks output nodes so the escaper can pick the right strategy. This lets the generator emit fast, context-safe code without guessing at runtime.
Example contexts
-
HTML text uses
htmlspecialchars(). - Attribute values are escaped with attribute-aware rules.
-
URL parts use
rawurlencode().
Component Expansion #
Component tags and s:component directives are transformed into runtime calls during compilation. At render time, the ComponentRenderer service resolves/compiles component templates and delegates to the same runtime template renderer used by inheritance.
Inheritance Runtime #
Inheritance is runtime-driven: compiled templates emit calls into TemplateRenderer and BlockManager for block registration, overrides, and include/extends orchestration. This keeps inheritance semantics explicit in generated PHP while preserving cache/dependency tracking.
File Caching Flow #

Cache entries store compiled PHP and dependency metadata, so debug mode can recompile only when inputs change.
Sugar caches by a template path hash and writes a compiled PHP file plus a metadata file. In production, the cache is treated as immutable; in debug mode, dependency timestamps are checked to decide whether a recompilation is needed.
What gets cached
- The generated PHP code ready for opcache.
- A dependency list for templates, layouts, and components.
- The original template path hash for quick lookup.
Debug and Errors #
Sugar keeps line/column data through all passes so errors can point back to the original template, even after component expansion.
When you enable debug mode, the engine can render compilation errors as HTML with highlighted source using the HtmlTemplateExceptionRenderer.
Typical error sources
- Unknown directives or invalid placement during extraction.
- Invalid component names or missing templates during expansion.
- Unsafe output when context detection finds ambiguous output.