Reference this for the Layers EBNF grammar rules.

(*  EBNF - Layers *)

(*  ===== LEXICAL GRAMMAR =====
    Defines tokens from characters.

    - Horizontal whitespace and comments are discarded.
    - Leading indentation is emitted as INDENT/DEDENT;
        line ends as NEWLINE.
    - If a token begins with a digit, or a `-` followed
        by a digit, it is a number.
    - `true` and `false` are reserved for bool, never
        lexed as a word.
    - Lines containing only whitespace and/or comments
        produce no tokens.
    - Parser accepts CRLF and LF; serializer emits LF.
    - At end of file, a final NEWLINE is emitted if the
        last line lacks one, followed by DEDENTs until
        indentation returns to column zero. Lastly, an
        ENDFILE is emitted. *)

bin             = "0" | "1" ;
dec             = bin | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
hex             = dec | "a" | "b" | "c" | "d" | "e" | "f" |
                        "A" | "B" | "C" | "D" | "E" | "F" ;
alphanum        = hex | "g" | "h" | "i" | "j" | "k" | "l" |
                        "G" | "H" | "I" | "J" | "K" | "L" |
                  "m" | "n" | "o" | "p" | "q" | "r" | "s" |
                  "M" | "N" | "O" | "P" | "Q" | "R" | "S" |
                  "t" | "u" | "v" | "w" | "x" | "y" | "z" |
                  "T" | "U" | "V" | "W" | "X" | "Y" | "Z" ;

number          = [ "-" ], dec, { dec }, [".", dec, { dec } ] ;

any-char        = ? any Unicode scalar value ? ;
lf-char         = ? U+000A LINE FEED ? ;
cr-char         = ? U+000D CARRIAGE RETURN ? ;
string-char     = any-char - ( '"' | "\" | lf-char | cr-char ) ;
escape          = "\", ( '"' | "\" | "n" | "t" ) ;
string          = '"', { string-char | escape }, '"' ;

color           = "#", hex, hex, hex, [ hex ] |
                  "#", hex, hex, hex, hex, hex, hex, [ hex, hex ] ;

wordchar        = alphanum | "-" | "_" ;
word            = wordchar, { wordchar } ;

bool            = "true" | "false" ;

comment         = "//", { any-char - ( lf-char | cr-char ) } ;

NEWLINE         = [ cr-char ], lf-char ;
INDENT          = ? increase in leading-space count ? ;
DEDENT          = ? decrease in leading-space count ? ;
ENDFILE         = ? end of input ? ;

(* ===== SYNTACTIC GRAMMAR =====
    - Adjacent words in a name are joined with single spaces,
    - EXCEPT empty words in expansion where there's nothing
        to join.
    - Specifically, an item is the name of either a layer or
        an attribute.
    - A reference is shaped like a declaration whose segments
        are plain words; expansion in references is invalid. *)

words           = word, { word } ;
expansion       = "(", [ words ], { ",", [ words ] }, ")" ;
expandable      = word | expansion ;
name            = expandable, { expandable } ;
traversal       = name, { "/", name }, "/" ;
group           = name, "." ;
item            = name ;
declaration     = [ traversal ], [ group ], item ;
reference       = [ words, { "/", words }, "/" ], [ words, "." ], words ;

value           = number | string | color | bool ;
expression      = value | reference ;

conditions      = "@", word, { "&", word } ;
state           = conditions, ":", expression ;

attr            = declaration, ":", expression,
                  ( [ state, { state } ], NEWLINE |
                  NEWLINE, INDENT, state, NEWLINE, { state, NEWLINE }, DEDENT ) ;

group-set       = [ traversal ], group, NEWLINE, INDENT, attr, { attr }, DEDENT ;
state-set       = conditions, ":", NEWLINE,
                  INDENT, ( attr | group-set ), { ( attr | group-set ) }, DEDENT ;

statement       = layer | attr | group-set | state-set ;
definition      = NEWLINE, INDENT, statement, { statement }, DEDENT ;
layer           = declaration, [ "<<" , reference ], ( NEWLINE | ":", definition ) ;

file            = { statement }, ENDFILE ;
Appearance
Theme
—