Index

Compiler

MMO\client\scs ยท 1 symbol ยท generated 30 Sep 2026

class

Compiler

Compiler.php:26

The Simple CSS compiler: one instance compiles one stylesheet.

class MMO\client\scs\Compiler
Namespace
MMO\client\scs
It runs the pipeline the language is specified with -- parse, register the definitions, evaluate the compile-time expressions (including the php bridge), expand the reusable styles, resolve the themes, the nesting and the responsive blocks, sort by `@order`, emit css: ```text .scs -> Lexer -> Parser -> ast -> Compiler (+ Evaluator) -> Emitter -> css ``` Applications normally go through [`SCSCompiler`](https://mmoframework.fr/documentation/mmo.client/php/SCSCompiler.md#scscompiler), the configurable module that owns the options, the authorized php functions and the caching -- this class is what it drives.
$compiler = new Compiler(['screens' => ['tablet' => '768px']]); echo $compiler->compile('@let $s = 16px' . "\n" . '.card {padding: $s}')->css();

Index

CSS_FUNCTIONSThe css functions a value may call.
DECLARATION_AT_RULESat-rules whose body is a declaration block rather than a set of rules
MAX_DEPTH
MAX_ITERATIONShow many times a single @for may run, so a mistyped range cannot hang a page
NESTED_AT_RULESat-rules whose body holds rules that must not be prefixed by the enclosing selector
OPTIONSthe options a @config instruction is allowed to set
PAGE_MARGIN_AT_RULESThe sixteen margin boxes of @page.
context
emitter
evaluator
expanding
files
functions
global
imported
index
namespace
namespaces
options
registry
scopes
sources
styles
themes
tokens
atRule($node, $scope, $frame)A css at-rule the language does not interpret: @media, @supports, @keyframes, @font-face...
bind($params, $args, $parent, $node, $name)Bind the arguments of a @style or a @fn call to a new scope.
callFunction($name, $args, $node, $namespace)Call an @fn.
callPhp($node, $args, $scope, $selector)Call an authorized php function (PhpFunctionRegistry).
circular($key, $node)
compile($source, $filename)Compile a .scs source.
component($node, $scope, $frame)`@component button { ...
configure($node)Apply a @config instruction.
context()
declare($node, $scope, $frame)Emit a declaration into the frame's rule.
declareNamespace($filename, $statements, $alias, $merge, $node)Give a file its namespace, and remember it: from @namespace, else from an as alias, else from the file name (lib.scs holds lib), else the anonymous namespace of a source with no name of itsโ€ฆ
define($kind, $namespace, $node)Register a @style or a @fn in a namespace.
emitter()
error($message, $context, $location, $previous)Build a located compilation error, with the source line it happened on.
evaluate($expression, $selector)Evaluate a single scs expression, without generating any css.
exec($statements, $scope, $frame)Execute a list of statements.
execNode($statement, $scope, $frame)
execStatement($statement, $scope, $frame)
hasFunction($name, $namespace)
hoist($statements)Step 4 of the pipeline: register @config, @theme paths, @style and @fn before anything is generated, so they can be referenced regardless of where they are declared.
import($node, $directory, $namespace)Resolve, read and parse an @imported file.
isCssFunction($name)
Key($namespace, $name) static
load($source, $filename)Parse a source and merge everything it @imports, in place.
lookup($kind, $namespace, $name)Find a @style or a @fn: qualified, in the namespace it names; unqualified, in the namespace of the file the reference is written in.
loop($node, $scope, $frame)@for $i in 1..6 / @for $key:$value in $collection.
merge($ast, $directory, $namespace)
namespaceOf($node)
NamespaceOfFile($filename) static
namespaceScope($namespace)
options()
query($target, $scope, $frame)Turn a @screen target into a media query.
registry()
resolve($path, $directory, $node)
scope()
scopeOf($namespace)
selectors($selector, $frame)Resolve a (possibly nested) selector against the frame it is declared in.
split($selector)Split a selector list on its top level commas (a comma inside :is(...) or [attr=","] is not one).
theme($node, $scope, $frame)@theme { ... } -- emit the design tokens as css custom properties.
themeValue($path)Resolve a $path against the declared design tokens.
undefined($kind, $namespace, $name, $node)The error for a reference that resolves to nothing -- naming the namespace the definition really lives in, which is the whole point of writing them down.
undefinedFunction($name, $node)The error for a call that resolves to nothing -- an @fn of another namespace, or a typo.
useStyle($node, $scope, $frame)@use lib::center / @use size(48px, 48px) -- expand a reusable style in place.
variableName($path)
variant($node, $scope, $frame)`@variant primary { ...
__construct($options, $context, $registry)

Constants7

CSS_FUNCTIONS

The css functions a value may call. Anything else is reported as an undefined function in strictFunctions mode (the default), which is what catches a misspelled @fn instead of emitting css no browser understands. A vendor prefixed (-webkit-...) or custom (--...) function is always allowed.

const CSS_FUNCTIONS = [โ€ฆ114 items]
See
Parser::CSS_FUNCTIONS for the ones whose arguments are additionally kept as written.

DECLARATION_AT_RULES

at-rules whose body is a declaration block rather than a set of rules

const DECLARATION_AT_RULES = [โ€ฆ6 items]

MAX_DEPTH

const MAX_DEPTH = 100

MAX_ITERATIONS

how many times a single @for may run, so a mistyped range cannot hang a page

const MAX_ITERATIONS = 100000

NESTED_AT_RULES

at-rules whose body holds rules that must not be prefixed by the enclosing selector

const NESTED_AT_RULES = ['@keyframes', '@-webkit-keyframes']

OPTIONS

the options a @config instruction is allowed to set

const OPTIONS = [โ€ฆ10 items]

PAGE_MARGIN_AT_RULES

The sixteen margin boxes of @page. They hold declarations, like @page itself, but they are written *inside* it -- `@page

const PAGE_MARGIN_AT_RULES = [โ€ฆ16 items]{@bottom-center {content: counter(page)}}` -- so the enclosing `@page` becomes a wrapper for them rather than the rule they add to. Read as an ordinary at-rule they wrapped their own parent instead, and `@bottom-center {@page {...}}` is not css any browser or print engine reads.

Properties18

emitter

protected MMO\client\scs\Emitter $emitter
Type
Emitter

evaluator

protected MMO\client\scs\Evaluator $evaluator
Type
Evaluator

expanding

protected array $expanding = []
Type
array

files

protected array $files = []
Type
array

functions

protected array $functions = []
Type
array

global

protected MMO\client\scs\Scope $global
Type
Scope

imported

protected array $imported = []
Type
array

index

protected array $index = ['style' => [], 'function' => []]
Type
array

namespace

protected string $namespace = ''
Type
string

namespaces

protected array $namespaces = []
Type
array

options

protected array $options
Type
array

scopes

protected array $scopes = []
Type
array

sources

protected array $sources = []
Type
array

styles

protected array $styles = []
Type
array

themes

protected array $themes = []
Type
array

tokens

protected array $tokens = []
Type
array

Methods46

atRule($node, $scope, $frame)

Compiler.php:762

A css at-rule the language does not interpret: @media, @supports, @keyframes, @font-face...

protected function atRule( MMO\client\scs\nodes\AtRuleNode $node, MMO\client\scs\Scope $scope, MMO\client\scs\Frame $frame ): void
$nodeAtRuleNode
$scopeScope
$frameFrame
returnsvoid

bind($params, $args, $parent, $node, $name)

Compiler.php:1010

Bind the arguments of a @style or a @fn call to a new scope.

protected function bind( array $params, array $args, MMO\client\scs\Scope $parent, MMO\client\scs\nodes\Node $node, string $name ): MMO\client\scs\Scope
$paramsarray[['name' => string, 'default' => ?Node], ...]
$argsarray
$parentScopethe definition's scope
$nodeNodethe call, for error reporting
$namestring
returnsScope

callFunction($name, $args, $node, $namespace)

Compiler.php:945

Call an @fn.

function callFunction( string $name, array $args, MMO\client\scs\nodes\CallNode $node, ?string $namespace = null ): MMO\client\scs\Value
$namestring
$argsarray
$nodeCallNode
$namespace = nullnull | stringthe namespace written before ::, null for an unqualified call
returnsValue

callPhp($node, $args, $scope, $selector)

Compiler.php:978

Call an authorized php function (PhpFunctionRegistry).

function callPhp( MMO\client\scs\nodes\CallNode $node, array $args, MMO\client\scs\Scope $scope, ?string $selector = null ): MMO\client\scs\Value
$nodeCallNode
$argsarray
$scopeScope
$selector = nullnull | stringthe resolved selector, given to context-aware functions
returnsValue

circular($key, $node)

Compiler.php:1032
protected function circular(string $key, MMO\client\scs\nodes\Node $node): MMO\client\exceptions\eSCS
$keystring
$nodeNode
returnseSCS

compile($source, $filename)

Compiler.php:155

Compile a .scs source.

function compile(string $source, string $filename = '<scs>'): MMO\client\scs\Result
$sourcestring
$filename = '<scs>'stringthe source's name, used by @import resolution and error reporting
returnsResult
throwson any compilation error

component($node, $scope, $frame)

Compiler.php:653

@component button { ... } -- a name becomes a selector through the componentSelector option, an explicit selector is used as written.

protected function component( MMO\client\scs\nodes\ComponentNode $node, MMO\client\scs\Scope $scope, MMO\client\scs\Frame $frame ): void
$nodeComponentNode
$scopeScope
$frameFrame
returnsvoid

configure($node)

Compiler.php:493

Apply a @config instruction.

protected function configure(MMO\client\scs\nodes\ConfigNode $node): void
$nodeConfigNode
returnsvoid

declare($node, $scope, $frame)

Compiler.php:637

Emit a declaration into the frame's rule.

protected function declare( MMO\client\scs\nodes\DeclarationNode $node, MMO\client\scs\Scope $scope, MMO\client\scs\Frame $frame ): void
$nodeDeclarationNode
$scopeScope
$frameFrame
returnsvoid

declareNamespace($filename, $statements, $alias, $merge, $node)

Compiler.php:258

Give a file its namespace, and remember it: from @namespace, else from an as alias, else from the file name (lib.scs holds lib), else the anonymous namespace of a source with no name of its own.

protected function declareNamespace( string $filename, array $statements, ?string $alias = null, ?string $merge = null, ?MMO\client\scs\nodes\Node $node = null ): string
$filenamestring
$statementsarraythe file's top level statements, read for a @namespace instruction
$alias = nullnull | stringthe name the importing file registers it under
$merge = nullnull | stringthe namespace to merge it into (@import ... as self)
$node = nullnull | Nodethe @import reporting the error
returnsstringthe namespace

define($kind, $namespace, $node)

Compiler.php:419

Register a @style or a @fn in a namespace.

protected function define(string $kind, string $namespace, MMO\client\scs\nodes\Node $node): void
$kindstring'style' or 'function'
$namespacestring
$nodeNode
returnsvoid

error($message, $context, $location, $previous)

Compiler.php:210

Build a located compilation error, with the source line it happened on.

function error( string $message, array $context = [], ?MMO\client\scs\SourceLocation $location = null, ?Throwable $previous = null ): MMO\client\exceptions\eSCS
$messagestringa {placeholder} message
$context = []array
$location = nullnull | SourceLocation
$previous = nullnull | Throwable
returnseSCS

evaluate($expression, $selector)

Compiler.php:188

Evaluate a single scs expression, without generating any css.

function evaluate(string $expression, ?string $selector = null): MMO\client\scs\Value
$expressionstringex: php::calculatePadding(), $spacing
$selector = nullnull | stringthe selector context-aware php functions should see
returnsValue
$compiler->evaluate('$spacing * 2');

exec($statements, $scope, $frame)

Compiler.php:525

Execute a list of statements.

protected function exec( array $statements, MMO\client\scs\Scope $scope, MMO\client\scs\Frame $frame ): ?MMO\client\scs\Value
$statementsarray
$scopeScope
$frameFrame
returnsnull | Valuethe value of a return statement, when one was reached (inside a @fn)

execNode($statement, $scope, $frame)

Compiler.php:544
protected function execNode( MMO\client\scs\nodes\Node $statement, MMO\client\scs\Scope $scope, MMO\client\scs\Frame $frame ): ?MMO\client\scs\Value
$statementNode
$scopeScope
$frameFrame
returnsnull | Value

execStatement($statement, $scope, $frame)

Compiler.php:533
protected function execStatement( MMO\client\scs\nodes\Node $statement, MMO\client\scs\Scope $scope, MMO\client\scs\Frame $frame ): ?MMO\client\scs\Value
$statementNode
$scopeScope
$frameFrame
returnsnull | Value

hasFunction($name, $namespace)

Compiler.php:920
function hasFunction(string $name, ?string $namespace = null): bool
$namestring
$namespace = nullnull | stringthe namespace written before ::, null for an unqualified call
returnsbooltrue when an @fn answers to this name here

hoist($statements)

Compiler.php:399

Step 4 of the pipeline: register @config, @theme paths, @style and @fn before anything is generated, so they can be referenced regardless of where they are declared.

protected function hoist(array $statements): void
$statementsarray
returnsvoid

import($node, $directory, $namespace)

Compiler.php:333

Resolve, read and parse an @imported file.

protected function import( MMO\client\scs\nodes\ImportNode $node, string $directory, string $namespace = '' ): array
$nodeImportNode
$directorystring
$namespace = ''string
returnsarraythe imported statements, empty when the file was already imported

isCssFunction($name)

Compiler.php:929
function isCssFunction(string $name): bool
$namestring
returnsbooltrue when an unknown function may be emitted as a plain css function
$compiler->isCssFunction('linear-gradient'); // true

Key($namespace, $name)

staticCompiler.php:323
static function Key(string $namespace, string $name): string
$namespacestring
$namestring
returnsstringthe key a definition is registered under

load($source, $filename)

Compiler.php:224

Parse a source and merge everything it @imports, in place.

protected function load(string $source, string $filename): array
$sourcestring
$filenamestring
returnsarraythe flattened top level statements

lookup($kind, $namespace, $name)

Compiler.php:437

Find a @style or a @fn: qualified, in the namespace it names; unqualified, in the namespace of the file the reference is written in.

protected function lookup(string $kind, ?string $namespace, string $name): ?array
$kindstring'style' or 'function'
$namespacenull | string
$namestring
returnsnull | arraythe registration, null when nothing declares this name here

loop($node, $scope, $frame)

Compiler.php:715

@for $i in 1..6 / @for $key:$value in $collection.

protected function loop( MMO\client\scs\nodes\ForNode $node, MMO\client\scs\Scope $scope, MMO\client\scs\Frame $frame ): ?MMO\client\scs\Value
$nodeForNode
$scopeScope
$frameFrame
returnsnull | Value

merge($ast, $directory, $namespace)

Compiler.php:237
protected function merge( MMO\client\scs\nodes\StylesheetNode $ast, string $directory, string $namespace ): array
$astStylesheetNode
$directorystringthe directory @import paths are relative to
$namespacestringthe namespace of the file being merged, for its @import ... as self
returnsarray

namespaceOf($node)

Compiler.php:314
protected function namespaceOf(MMO\client\scs\nodes\Node $node): string
$nodeNode
returnsstringthe namespace the node was written in

NamespaceOfFile($filename)

staticCompiler.php:287
static function NamespaceOfFile(string $filename): string
$filenamestring
returnsstringthe namespace a file is named after: parts/buttons.scs is buttons, a source with no usable file name (an inline stylesheet) is the anonymous namespace

namespaceScope($namespace)

Compiler.php:295
function namespaceScope(string $namespace): ?MMO\client\scs\Scope
$namespacestring
returnsnull | Scopethe top level variables of a declared namespace, null when nothing declares it

query($target, $scope, $frame)

Compiler.php:873

Turn a @screen target into a media query.

protected function query( MMO\client\scs\nodes\ValueListNode $target, MMO\client\scs\Scope $scope, MMO\client\scs\Frame $frame ): string
$targetValueListNodetablet, 455px, (max-width: 600px) or print
$scopeScope
$frameFrame
returnsstring

resolve($path, $directory, $node)

Compiler.php:374
protected function resolve(string $path, string $directory, MMO\client\scs\nodes\Node $node): string
$pathstring
$directorystring
$nodeNode
returnsstringthe resolved, existing filename
throwswhen the file cannot be found

scopeOf($namespace)

Compiler.php:303
protected function scopeOf(?string $namespace): MMO\client\scs\Scope
$namespacenull | string
returnsScopethe scope holding the top level variables of a namespace

selectors($selector, $frame)

Compiler.php:817

Resolve a (possibly nested) selector against the frame it is declared in.

protected function selectors(string $selector, MMO\client\scs\Frame $frame): array
$selectorstringthe rendered selector, ex: &:hover, .title
$frameFrame
returnsarray

split($selector)

Compiler.php:839

Split a selector list on its top level commas (a comma inside :is(...) or [attr=","] is not one).

protected function split(string $selector): array
$selectorstring
returnsarray

theme($node, $scope, $frame)

Compiler.php:682

@theme { ... } -- emit the design tokens as css custom properties.

protected function theme( MMO\client\scs\nodes\ThemeNode $node, MMO\client\scs\Scope $scope, MMO\client\scs\Frame $frame ): voidWith `emitThemes` off the tokens are still registered -- `$colors.primary` keeps resolving to `var(--colors-primary)` -- but no `:root` rule is generated. That is what lets a stylesheet compiled *inside* a shadow root ([`JHSCompiler`](https://mmoframework.fr/documentation/mmo.client/php/JHSCompiler.md#jhscompiler)) reference the document's tokens without redeclaring the whole palette in every custom element.
$nodeThemeNode
$scopeScope
$frameFrame
returnsvoid

themeValue($path)

Compiler.php:899

Resolve a $path against the declared design tokens.

function themeValue(string $path): ?MMO\client\scs\Value
$pathstringex: colors.primary
returnsnull | Valuevar(--colors-primary), or the token's value in resolveThemeValues mode, or null when no theme declares this path

undefined($kind, $namespace, $name, $node)

Compiler.php:451

The error for a reference that resolves to nothing -- naming the namespace the definition really lives in, which is the whole point of writing them down.

protected function undefined( string $kind, ?string $namespace, string $name, MMO\client\scs\nodes\Node $node ): MMO\client\exceptions\eSCS
$kindstring
$namespacenull | string
$namestring
$nodeNode
returnseSCS

undefinedFunction($name, $node)

Compiler.php:488

The error for a call that resolves to nothing -- an @fn of another namespace, or a typo.

function undefinedFunction(string $name, MMO\client\scs\nodes\CallNode $node): MMO\client\exceptions\eSCS
$namestring
$nodeCallNode
returnseSCS

useStyle($node, $scope, $frame)

Compiler.php:697

@use lib::center / @use size(48px, 48px) -- expand a reusable style in place.

protected function useStyle( MMO\client\scs\nodes\UseNode $node, MMO\client\scs\Scope $scope, MMO\client\scs\Frame $frame ): void
$nodeUseNode
$scopeScope
$frameFrame
returnsvoid

variableName($path)

Compiler.php:889
protected function variableName(string $path): string
$pathstring
returnsstringthe css custom property a design token is emitted as

variant($node, $scope, $frame)

Compiler.php:661

@variant primary { ... } -- emitted as {selector}--{variant}.

protected function variant( MMO\client\scs\nodes\VariantNode $node, MMO\client\scs\Scope $scope, MMO\client\scs\Frame $frame ): void
$nodeVariantNode
$scopeScope
$frameFrame
returnsvoid