Skip to content

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.

INFO

Compilation happens once per template change. Rendering is a cached PHP include.

Compilation Pipeline

PriorityStagePurposeNotes
1ParserConverts template source into a Sugar AST.Uses PhpToken for PHP-aware tokenization and preserves line/column for error reporting.
2TemplateInheritancePassApplies s:extends and merges blocks.Optional, requires a template loader.
3DirectiveExtractionPassPulls out s:* directives and validates placement.Produces directive nodes from attributes.
4DirectivePairingPassPairs directives like if/elseif/else and forelse/empty.Ensures correct sibling relationships.
5DirectiveCompilationPassRewrites directive nodes into executable AST nodes.Produces control flow, attributes, and output nodes.
6ComponentExpansionPassResolves component tags into their AST.Optional, requires a template loader.
7ComponentVariantAdjustmentPassNormalizes component slot variables for variants.Only used when compiling components.
8ContextAnalysisPassDetermines output context for escaping decisions.Tags output nodes with HTML/attribute/URL/JS/CSS contexts.
9CodeGeneratorEmits pure PHP from the final AST.Output is ready for opcache.

TIP

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.

php
use Sugar\Ast\ElementNode;
use Sugar\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.

text
HTML element + s:* attributes

Directive nodes (validated)
text
Directive nodes

RawPhpNode / OutputNode / ElementNode

WARNING

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 are expanded into their template AST before code generation. That means components participate in the same directive and context logic as the parent template.

File Caching Flow

Caching flow diagram

INFO

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.