Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git
<?php
class LanguageDefinitions {
  public static function get( string $lang ): array {
    $int        = '(-?\b\d+(\.\d+)?\b)';
    $str        = '("(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\')';
    $float      = '(-?\d+(\.\d+)?([eE][+-]?\d+)?)';
    $normalized = strtolower( $lang );
    $result     = [];
    $rules      = [
      'gradle' => [
        'comment'       => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'string_interp' => '/("(?:\\\\.|[^"\\\\])*"|""".*?""")/',
        'string'        => '/(\'(?:\\\\.|[^\'\\\\])*\'|\'\'\'.*?\'\'\'' .
                           '|\/.*?\/)/',
        'keyword'       => '/\b(?:def|task|group|version|ext|return|if|' .
                           'else)\b/',
        'function'      => '/\b(apply|plugin|sourceCompatibility|' .
                           'targetCompatibility|repositories|dependencies|' .
                           'test|plugins|buildscript|allprojects|' .
                           'subprojects|project|implementation|api|' .
                           'compileOnly|runtimeOnly|testImplementation|' .
                           'testRuntimeOnly|mavenCentral|google|jcenter|' .
                           'classpath)\b|\b([a-zA-Z_][a-zA-Z0-9_]*)\s*' .
                           '(?=\(|{)/',
        'variable'      => '/(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{[^}]+\})/',
        'boolean'       => '/\b(?:true|false|null)\b/',
        'number'        => '/' . $int . '/',
      ],
      'tex' => [
        'comment'  => '/(%[^\r\n]*)/m',
        'math'     => '/(\$\$?.*?\$\$?)/s',
        'keyword'  => '/(\\\\(?:def|edef|gdef|xdef|let|futurelet|if|else|' .
                      'fi|ifnum|ifdim|ifodd|ifmmode|ifx|ifeof|iftrue|' .
                      'iffalse|ifcase|or|loop|repeat|newif|expandafter|' .
                      'noexpand|csname|endcsname|string|number|the|long|' .
                      'outer|global|par|advance|hsize|vsize|hoffset|' .
                      'voffset|displaywidth|parindent|baselineskip|' .
                      'leftskip|rightskip|hangindent|hangafter|parshape|' .
                      'pageno|nopagenumbers|folio|headline|footline|hbox|' .
                      'vbox|vtop|vcenter|rlap|llap|hskip|vskip|hfil|hfill|' .
                      'hfilneg|vfil|vfill|mskip|quad|qquad|enspace|' .
                      'thinspace|enskip|strut|phantom|vphantom|hphantom|' .
                      'smash|raise|lower|moveleft|moveright|halign|valign|' .
                      'noalign|openup|cr|crcr|omit|span|multispan|tabskip|' .
                      'settabs|matrix|pmatrix|bordermatrix|eqalign|' .
                      'displaylines|eqno|leqno|cases|left|right|over|atop|' .
                      'choose|brace|brack|root|of|buildrel|input|end|bye|' .
                      'item|itemitem|indent|noindent|narrower|rm|bf|tt|sl|' .
                      'it|font|char|magnification|magstep|magstephalf|day|' .
                      'month|year|jobname|romannumeral|uppercase|lowercase|' .
                      'footnote|topinsert|pageinsert|midinsert|endinsert|' .
                      'underbar|hfuzz|vfuzz|overfullrule|raggedright|' .
                      'raggedbottom|everypar|everymath|everydisplay|' .
                      'everycr))\b/',
        'function' => '/(\\\\[a-zA-Z@]+|\\\\[^a-zA-Z@])/',
        'variable' => '/(#[0-9])/',
      ],
      'php' => [
        'tag'           => '/(<\?php|<\?|=\?>|\?>)/',
        'string_interp' => '/("(?:\\\\.|[^"\\\\])*")/',
        'string'        => '/(\'(?:\\\\.|[^\'\\\\])*\')/',
        'comment'       => '/(\/\/[^\r\n]*|#[^\r\n]*|\/\*.*?\*\/)/ms',
        'type'          => '/\b(?:array|bool|callable|float|int|iterable|' .
                           'mixed|never|object|string|void)\b/',
        'keyword'       => '/\b(?:abstract|and|as|break|case|catch|class|' .
                           'clone|const|continue|declare|default|die|do|' .
                           'echo|else|elseif|empty|enddeclare|endfor|' .
                           'endforeach|endif|endswitch|endwhile|enum|eval|' .
                           'exit|extends|final|finally|fn|for|foreach|' .
                           'function|global|goto|if|implements|include|' .
                           'include_once|instanceof|insteadof|interface|' .
                           'isset|list|match|namespace|new|or|print|' .
                           'private|protected|public|readonly|require|' .
                           'require_once|return|static|switch|throw|trait|' .
                           'try|unset|use|var|while|xor|yield)\b/',
        'function'      => '/\b([a-zA-Z_\x7f-\xff]' .
                           '[a-zA-Z0-9_\x7f-\xff]*)\s*(?=\()/',
        'variable'      => '/(\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/',
        'number'        => '/' . $int . '/',
        'boolean'       => '/\b(true|false|null)\b/i',
      ],
      'bash' => [
        'string_interp' => '/("(?:\\\\.|[^"\\\\])*")/',
        'string'        => '/(\'.*?\')/',
        'comment'       => '/(#[^\n]*)/',
        'keyword'       => '/(?<!-)\b(?:alias|bg|bind|break|builtin|case|' .
                           'cd|command|compgen|complete|continue|coproc|' .
                           'declare|dirs|disown|do|done|echo|elif|else|' .
                           'enable|esac|eval|exec|exit|export|fc|fg|fi|' .
                           'for|function|getopts|hash|help|history|if|' .
                           'jobs|kill|let|local|logout|popd|printf|pushd|' .
                           'pwd|read|readonly|return|select|set|shift|' .
                           'shopt|source|suspend|test|then|time|times|' .
                           'trap|type|typeset|ulimit|umask|unalias|unset|' .
                           'until|wait|while)\b/',
        'function'      => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'variable'      => '/(\$[a-zA-Z_][a-zA-Z0-9_]*|\$\{[^}]+\})/',
        'number'        => '/' . $int . '/',
      ],
      'batch' => [
        'comment'  => '/((?i:rem)\b[^\n]*|::[^\n]*)/',
        'string'   => '/("[^"]*")/',
        'keyword'  => '/(?i)\b(?:if|else|goto|for|in|do|exit|echo|pause|' .
                      'set|shift|start|cd|dir|copy|del|md|rd|cls|setlocal|' .
                      'endlocal|enabledelayedexpansion|defined|exist|not|' .
                      'errorlevel|setx|findstr|reg|nul|tokens|usebackq|' .
                      'equ|neq|lss|leq|gtr|geq)\b/',
        'function' => '/(?i)\b(call)\b/',
        'variable' => '/(![\w-]+!|%[\w\(\)-]+%|%%[~a-zA-Z]+|' .
                      '%[~a-zA-Z0-9]+)/',
        'label'    => '/(^\s*:[a-zA-Z0-9_-]+)/m',
        'number'   => '/' . $int . '/',
      ],
      'c' => [
        'string'       => '/' . $str . '/',
        'comment'      => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'include'      => '/(^\s*#include[^\r\n]*)/m',
        'preprocessor' => '/(^\s*#(?!include\b)[^\r\n]*)/m',
        'type'         => '/\b(?:char|double|float|int|long|short|void|' .
                          'signed|unsigned)\b/',
        'keyword'      => '/\b(?:auto|break|case|const|continue|default|' .
                          'do|else|enum|extern|for|goto|if|noreturn|' .
                          'register|return|sizeof|static|struct|switch|' .
                          'typedef|union|volatile|while)\b/',
        'function'     => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'       => '/' . $int . '/',
      ],
      'cpp' => [
        'string'       => '/' . $str . '/',
        'comment'      => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'include'      => '/(^\s*#include[^\r\n]*)/m',
        'preprocessor' => '/(^\s*#(?!include\b)[^\r\n]*)/m',
        'type'         => '/\b(?:bool|char|char8_t|char16_t|char32_t|' .
                          'double|float|int|long|short|signed|unsigned|' .
                          'void|wchar_t)\b/',
        'keyword'      => '/\b(?:alignas|alignof|and|and_eq|asm|auto|' .
                          'bitand|bitor|break|case|catch|class|co_await|' .
                          'co_return|co_yield|compl|concept|const|' .
                          'consteval|constexpr|constinit|const_cast|' .
                          'continue|decltype|default|delete|do|' .
                          'dynamic_cast|else|enum|explicit|export|extern|' .
                          'for|friend|goto|if|inline|mutable|namespace|' .
                          'new|noexcept|noreturn|not|not_eq|nullptr|' .
                          'operator|or|or_eq|private|protected|public|' .
                          'register|reinterpret_cast|requires|return|' .
                          'sizeof|static|static_assert|static_cast|' .
                          'struct|switch|template|this|thread_local|' .
                          'throw|try|typedef|typeid|typename|union|using|' .
                          'virtual|volatile|while|xor|xor_eq)\b/',
        'boolean'      => '/\b(?:true|false)\b/',
        'function'     => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'       => '/' . $int . '/',
      ],
      'java' => [
        'class'    => '/(@[a-zA-Z_][a-zA-Z0-9_]*)/',
        'string'   => '/' . $str . '/',
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'type'     => '/\b(?:boolean|byte|char|double|float|int|long|' .
                      'short|void)\b/',
        'keyword'  => '/\b(?:abstract|assert|break|case|catch|class|' .
                      'const|continue|default|do|else|enum|extends|final|' .
                      'finally|for|goto|if|implements|import|instanceof|' .
                      'interface|native|new|non-sealed|package|permits|' .
                      'private|protected|public|record|return|sealed|' .
                      'static|strictfp|super|switch|synchronized|this|' .
                      'throw|throws|transient|try|var|volatile|while|' .
                      'yield)\b/',
        'boolean'  => '/\b(?:true|false|null)\b/',
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'go' => [
        'string'   => '/("(?:\\\\.|[^"\\\\])*"|`.*?`)/s',
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'type'     => '/\b(?:bool|byte|complex64|complex128|error|' .
                      'float32|float64|int|int8|int16|int32|int64|rune|' .
                      'string|uint|uint8|uint16|uint32|uint64|uintptr)\b/',
        'keyword'  => '/\b(?:break|case|chan|const|continue|default|' .
                      'defer|else|fallthrough|for|func|go|goto|if|import|' .
                      'interface|map|package|range|return|select|struct|' .
                      'switch|type|var)\b/',
        'boolean'  => '/\b(?:true|false|nil|iota)\b/',
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'rust' => [
        'string'   => '/' . $str . '/',
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'type'     => '/\b(?:bool|char|f32|f64|i8|i16|i32|i64|i128|isize|' .
                      'str|u8|u16|u32|u64|u128|usize)\b/',
        'keyword'  => '/\b(?:as|async|await|break|const|continue|crate|' .
                      'dyn|else|enum|extern|fn|for|if|impl|in|let|loop|' .
                      'match|mod|move|mut|pub|ref|return|self|Self|' .
                      'static|struct|super|trait|type|union|unsafe|use|' .
                      'where|while)\b/',
        'boolean'  => '/\b(?:true|false)\b/',
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'python' => [
        'string'   => '/(\'\'\'.*?\'\'\'|""".*?"""|"(?:\\\\.|[^"\\\\])*"|' .
                      '\'(?:\\\\.|[^\'\\\\])*\')/s',
        'comment'  => '/(#[^\r\n]*)/m',
        'type'     => '/\b(?:bool|bytearray|bytes|complex|dict|float|' .
                      'frozenset|int|list|memoryview|object|range|set|' .
                      'str|tuple)\b/',
        'keyword'  => '/\b(?:and|as|assert|async|await|break|class|' .
                      'continue|def|del|elif|else|except|finally|for|' .
                      'from|global|if|import|in|is|lambda|nonlocal|not|' .
                      'or|pass|raise|return|try|while|with|yield)\b/',
        'boolean'  => '/\b(?:False|None|True)\b/',
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'ruby' => [
        'string_interp' => '/("(?:\\\\.|[^"\\\\])*")/',
        'string'        => '/(\'(?:\\\\.|[^\'\\\\])*\')/',
        'comment'       => '/(#[^\r\n]*)/m',
        'keyword'       => '/\b(?:alias|and|begin|break|case|class|def|' .
                           'defined|do|else|elsif|end|ensure|for|if|in|' .
                           'module|next|not|or|redo|rescue|retry|return|' .
                           'self|super|then|undef|unless|until|when|' .
                           'while|yield)\b/',
        'boolean'       => '/\b(?:true|false|nil)\b/',
        'function'      => '/\b([a-zA-Z_][a-zA-Z0-9_]*[?!]?)\s*(?=\()/',
        'variable'      => '/(@[a-zA-Z_]\w*|\$[a-zA-Z_]\w*)/',
        'number'        => '/' . $int . '/',
      ],
      'lua' => [
        'string'   => '/("(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\'|' .
                      '\[\[.*?\]\])/s',
        'comment'  => '/(--\[\[.*?\]\]|--[^\r\n]*)/ms',
        'keyword'  => '/\b(?:and|break|do|else|elseif|end|for|function|' .
                      'if|in|local|not|or|repeat|return|then|until|' .
                      'while)\b/',
        'boolean'  => '/\b(?:false|nil|true)\b/',
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'javascript' => [
        'regex'    => '/(\/(?![/*])(?:\\\\.|[^\\/\r\n])+\/[a-zA-Z]*)/',
        'string'   => '/("(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\'|' .
                      '`(?:\\\\.|[^`\\\\])*`)/s',
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'keyword'  => '/\b(?:as|async|await|break|case|catch|class|' .
                      'const|continue|debugger|default|delete|do|else|' .
                      'enum|export|extends|finally|for|from|function|if|' .
                      'import|in|instanceof|let|new|of|return|static|' .
                      'super|switch|this|throw|try|typeof|var|void|' .
                      'while|with|yield)\b/',
        'boolean'  => '/\b(?:true|false|null|undefined)\b/',
        'function' => '/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'typescript' => [
        'regex'    => '/(\/(?![/*])(?:\\\\.|[^\\/\r\n])+\/[a-zA-Z]*)/',
        'string'   => '/("(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\'|' .
                      '`(?:\\\\.|[^`\\\\])*`)/s',
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'type'     => '/\b(?:boolean|number|string|void|any|never|' .
                      'unknown|object|symbol|bigint)\b/',
        'keyword'  => '/\b(?:abstract|as|break|case|catch|class|const|' .
                      'continue|debugger|declare|default|delete|do|else|' .
                      'enum|export|extends|finally|for|from|function|if|' .
                      'implements|import|in|instanceof|interface|is|let|' .
                      'module|namespace|new|of|package|private|' .
                      'protected|public|readonly|require|return|static|' .
                      'super|switch|this|throw|try|type|typeof|var|' .
                      'while|with|yield)\b/',
        'boolean'  => '/\b(?:true|false|null|undefined)\b/',
        'function' => '/\b([a-zA-Z_$][a-zA-Z0-9_$]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'html' => [
        'comment'   => '/(<!--[\s\S]*?-->)/',
        'string'    => '/' . $str . '/',
        'tag'       => '/<\/?[!a-zA-Z0-9:-]+|\s*\/?>/',
        'attribute' => '/[a-zA-Z0-9:-]+(?=\=)/',
      ],
      'xml' => [
        'comment'   => '/(<!--[\s\S]*?-->)/',
        'string'    => '/' . $str . '/',
        'tag'       => '/<\/?[!a-zA-Z0-9:-]+|\s*\/?>|<\?xml|\?>/',
        'attribute' => '/[a-zA-Z0-9:-]+(?=\=)/',
      ],
      'xslt' => [
        'comment'   => '/(<!--[\s\S]*?-->)/',
        'string'    => '/' . $str . '/',
        'keyword'   => '/<\/?[a-zA-Z0-9-]*:?(?:accept|accumulator|' .
                       'accumulator-rule|analyze-string|apply-imports|' .
                       'apply-templates|assert|attribute|attribute-set|' .
                       'break|call-template|catch|character-map|choose|' .
                       'comment|context-item|copy|copy-of|' .
                       'decimal-format|document|element|evaluate|' .
                       'expose|fallback|for-each|for-each-group|fork|' .
                       'function|global-context-item|if|import|include|' .
                       'iterate|key|map|map-entry|matching-substring|' .
                       'merge|merge-action|merge-key|merge-source|' .
                       'message|mode|namespace|namespace-alias|' .
                       'next-iteration|next-match|' .
                       'non-matching-substring|on-empty|on-non-empty|' .
                       'otherwise|output|output-character|override|' .
                       'package|param|perform-sort|preserve-space|' .
                       'processing-instruction|result-document|sequence|' .
                       'sort|source-document|strip-space|stylesheet|' .
                       'template|text|transform|try|use-package|' .
                       'value-of|variable|when|where-populated|' .
                       'with-param)\b/',
        'function'  => '/\b[a-zA-Z_][a-zA-Z0-9_-]*\s*(?=\()/',
        'variable'  => '/\$[a-zA-Z0-9_-]+/',
        'tag'       => '/<\/?[!a-zA-Z0-9:-]+|\s*\/?>|<\?xml|\?>/',
        'attribute' => '/[a-zA-Z0-9:-]+(?=\=)/',
      ],
      'css' => [
        'comment'  => '/(\/\*.*?\*\/)/s',
        'tag'      => '/(?<=^|\}|\{)\s*([a-zA-Z0-9_\-#\.\s,>+~]+)(?=\{)/m',
        'property' => '/([a-zA-Z-]+)(?=\s*:)/',
        'string'   => '/' . $str . '/',
        'number'   => '/(-?(\d*\.)?\d+(px|em|rem|%|vh|vw|s|ms|deg))/',
      ],
      'json' => [
        'attribute' => '/("(?:\\\\.|[^"\\\\])*")(?=\s*:)/',
        'string'    => '/("(?:\\\\.|[^"\\\\])*")/',
        'boolean'   => '/\b(true|false|null)\b/',
        'number'    => '/\b(-?\d+(\.\d+)?([eE][+-]?\d+)?)\b/',
      ],
      'sql' => [
        'string'   => '/(\'.*?\')/',
        'comment'  => '/(--[^\r\n]*|\/\*.*?\*\/)/ms',
        'type'     => '/(?i)\b(?:BIGINT|BIT|BOOLEAN|CHAR|DATE|DATETIME|' .
                      'DECIMAL|DOUBLE|FLOAT|INT|INTEGER|MONEY|NUMERIC|' .
                      'REAL|SMALLINT|TEXT|TIME|TIMESTAMP|TINYINT|' .
                      'VARCHAR)\b/',
        'keyword'  => '/(?i)\b(ADD|ALTER|AND|AS|ASC|BEGIN|BETWEEN|BY|' .
                      'CASE|CHECK|COLUMN|COMMIT|CONSTRAINT|CREATE|' .
                      'DATABASE|DEFAULT|DELETE|DESC|DISTINCT|DROP|ELSE|' .
                      'END|EXISTS|FOREIGN|FROM|FULL|FUNCTION|GRANT|' .
                      'GROUP|HAVING|IF|IN|INDEX|INNER|INSERT|INTO|IS|' .
                      'JOIN|KEY|LEFT|LIKE|LIMIT|NOT|NULL|OFFSET|ON|OR|' .
                      'ORDER|OUTER|PRIMARY|PROCEDURE|REFERENCES|REVOKE|' .
                      'RIGHT|ROLLBACK|SCHEMA|SELECT|SET|TABLE|THEN|' .
                      'TRANSACTION|TRIGGER|TRUNCATE|UNION|UNIQUE|' .
                      'UPDATE|VALUES|VIEW|WHEN|WHERE)\b/',
        'boolean'  => '/(?i)\b(NULL|TRUE|FALSE)\b/',
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'yaml' => [
        'comment'       => '/(#[^\r\n]*)/m',
        'variable'      => '/^(\s*[a-zA-Z0-9_-]+:)/m',
        'string_interp' => '/((?<=:)\s*[^\r\n]*)/',
        'number'        => '/' . $float . '/',
      ],
      'properties' => [
        'comment'       => '/(^[ \t]*[#!][^\r\n]*)/m',
        'variable'      => '/(^[ \t]*[^:=\s]+)(?=[ \t]*[:=])/m',
        'string_interp' => '/((?<=[=:])\s*[^\r\n]*)/',
      ],
      'ini' => [
        'comment'   => '/(^[ \t]*[;#][^\r\n]*)/m',
        'keyword'   => '/(^\[[^\]\r\n]+\])/m',
        'variable'  => '/(^[ \t]*[a-zA-Z0-9_\.\-]+)(?=\s*=)/m',
        'string'    => '/((?<==)\s*[^\r\n]*)/',
      ],
      'toml' => [
        'comment'   => '/(#[^\r\n]*)/',
        'keyword'   => '/(^\[[^\]\r\n]+\])/m',
        'variable'  => '/(\b[a-zA-Z0-9_-]+\b)(?=\s*=)/',
        'string'    => '/(' . $str . '|"""[\s\S]*?"""|' .
                       '\'\'\'[\s\S]*?\'\'\')/',
        'boolean'   => '/\b(true|false)\b/',
        'date'      => '/(\d{4}-\d{2}-\d{2}(?:[Tt ]\d{2}:\d{2}:\d{2}' .
                       '(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?)?)/',
        'number'    => '/' . $float . '/',
      ],
      'markdown' => [
        'code'      => '/(^(?:    |\t)[^\n]*(?:\n(?:    |\t)[^\n]*)*)/',
        'comment'   => '/(```[\s\S]*?```|~~~[\s\S]*?~~~)/',
        'math'      => '/(\$((?:[^`\n$]|`[^`\n]*`)+)\$)/',
        'keyword'   => '/^(#{1,6})(?=\s)/m',
        'string'    => '/(\*\*[^\n*]+\*\*|__[^\n_]+__)/',
        'attribute' => '/(?<!\*)(\*[^\n*]+\*)(?!\*)|' .
                       '(?<!_)(_[^\n_]+_)(?!_)/',
        'function'  => '/(`[^`\n]+`)/',
        'variable'  => '/(\[[^\]]+\]\([^\)]+\))/',
        'operator'  => '/^(\s*[-*+](?=\s)|\s*\d+\.(?=\s))/m',
      ],
      'rmd' => [
        'code'      => '/(^(?:    |\t)[^\n]*(?:\n(?:    |\t)[^\n]*)*)/',
        'comment'   => '/(```\{r[^\}]*\}[\s\S]*?```)/',
        'math'      => '/(\$((?:[^`\n$]|`[^`\n]*`)+)\$)/',
        'keyword'   => '/^(#{1,6})(?=\s)/m',
        'string'    => '/(\*\*[^\n*]+\*\*|__[^\n_]+__)/',
        'attribute' => '/(?<!\*)(\*[^\n*]+\*)(?!\*)|' .
                       '(?<!_)(_[^\n_]+_)(?!_)/',
        'function'  => '/(`[^`\n]+`)/',
        'variable'  => '/(\[[^\]]+\]\([^\)]+\))/',
        'operator'  => '/^(\s*[-*+](?=\s)|\s*\d+\.(?=\s))/m',
      ],
      'r' => [
        'string'   => '/' . $str . '/',
        'comment'  => '/(#[^\r\n]*)/m',
        'keyword'  => '/\b(?:if|else|repeat|while|function|for|in|next|' .
                      'break)\b/',
        'boolean'  => '/\b(?:TRUE|FALSE|NULL|Inf|NaN|NA)\b/',
        'function' => '/\b([a-zA-Z_.][a-zA-Z0-9_.]*)\s*(?=\()/',
        'number'   => '/' . $float . '/',
      ],
      'csharp' => [
        'string'       => '/(@"(?:""|[^"])*"|' . $str . ')/',
        'comment'      => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'preprocessor' => '/(^\s*#[^\r\n]*)/m',
        'type'         => '/\b(?:bool|byte|char|decimal|double|float|' .
                          'int|long|object|sbyte|short|string|uint|' .
                          'ulong|ushort|void)\b/',
        'keyword'      => '/\b(?:abstract|as|base|break|case|catch|' .
                          'checked|class|const|continue|default|' .
                          'delegate|do|else|enum|event|explicit|extern|' .
                          'false|finally|fixed|for|foreach|goto|if|' .
                          'implicit|in|interface|internal|is|lock|' .
                          'namespace|new|null|operator|out|override|' .
                          'params|private|protected|public|readonly|ref|' .
                          'return|sealed|sizeof|stackalloc|static|' .
                          'struct|switch|this|throw|true|try|typeof|' .
                          'unchecked|unsafe|using|virtual|volatile|' .
                          'while)\b/',
        'function'     => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'       => '/' . $int . '/',
      ],
      'kotlin' => [
        'string'   => '/("""[\s\S]*?"""|' . $str . ')/',
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'type'     => '/\b(?:Boolean|Byte|Char|Double|Float|Int|Long|' .
                      'Short|String|Void|Unit|Any|Nothing)\b/',
        'keyword'  => '/\b(?:as|break|class|continue|do|else|false|for|' .
                      'fun|if|in|interface|is|null|object|package|' .
                      'return|super|this|throw|true|try|typealias|' .
                      'typeof|val|var|when|while)\b/',
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'scala' => [
        'string'   => '/("""[\s\S]*?"""|' . $str . ')/',
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'type'     => '/\b(?:Boolean|Byte|Char|Double|Float|Int|Long|' .
                      'Short|String|Unit|Any|AnyRef|AnyVal|Nothing|' .
                      'Null|void)\b/',
        'keyword'  => '/\b(?:abstract|case|catch|class|def|do|else|' .
                      'extends|false|final|finally|for|forSome|if|' .
                      'implicit|import|lazy|match|new|null|object|' .
                      'override|package|private|protected|return|' .
                      'sealed|super|this|throw|trait|try|true|type|val|' .
                      'var|while|with|yield)\b/',
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'groovy' => [
        'string'        => '/(\'\'\'[\s\S]*?\'\'\'|""".*?"""|' .
                           '"(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\'' .
                           '|\/[^\/]+\/)/',
        'comment'       => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'type'          => '/\b(?:boolean|byte|char|double|float|int|' .
                           'long|short|void)\b/',
        'keyword'       => '/\b(?:def|as|assert|break|case|catch|class|' .
                           'const|continue|default|do|else|enum|extends|' .
                           'false|finally|for|goto|if|implements|import|' .
                           'in|instanceof|interface|new|null|package|' .
                           'return|super|switch|this|throw|throws|trait|' .
                           'true|try|var|while)\b/',
        'function'      => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'        => '/' . $int . '/',
      ],
      'dart' => [
        'string'   => '/(r?\'\'\'[\s\S]*?\'\'\'|r?"""[\s\S]*?"""|' .
                      '"(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\')/',
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'type'     => '/\b(?:void|bool|int|double|num|dynamic)\b/',
        'keyword'  => '/\b(?:abstract|as|assert|async|await|break|case|' .
                      'catch|class|const|continue|default|do|else|enum|' .
                      'export|extends|extension|external|factory|false|' .
                      'final|finally|for|get|if|implements|import|in|' .
                      'interface|is|library|mixin|new|null|on|operator|' .
                      'part|rethrow|return|set|static|super|switch|' .
                      'sync|this|throw|true|try|typedef|var|while|with|' .
                      'yield)\b/',
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'swift' => [
        'string'   => '/("""[\s\S]*?"""|' . $str . ')/',
        'comment'  => '/(\/\/[^\r\n]*|\/\*.*?\*\/)/ms',
        'type'     => '/\b(?:Int|Double|Float|Bool|String|Void|' .
                      'Character|Any|AnyObject)\b/',
        'keyword'  => '/\b(?:associatedtype|class|deinit|enum|' .
                      'extension|fileprivate|func|import|init|inout|' .
                      'internal|let|open|operator|private|protocol|' .
                      'public|rethrows|static|struct|subscript|' .
                      'typealias|var|break|case|continue|default|defer|' .
                      'do|else|fallthrough|for|guard|if|in|repeat|' .
                      'return|switch|where|while|as|catch|false|is|nil|' .
                      'super|self|Self|throw|throws|true|try)\b/',
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'perl' => [
        'comment'  => '/(#[^\r\n]*)/',
        'string'   => '/(' . $str . '|`[^`]*`)/',
        'variable' => '/([$@%](?:\{[a-zA-Z_]\w*\}|[a-zA-Z_]\w*))/',
        'keyword'  => '/\b(?:my|local|our|state|use|sub|package|if|' .
                      'else|elsif|unless|while|until|for|foreach|do|' .
                      'last|next|redo|goto|continue|return|print|' .
                      'printf|say|die|warn|eval|try|catch)\b/',
        'number'   => '/' . $float . '/',
      ],
      'powershell' => [
        'comment'  => '/(<#[\s\S]*?#>|#[^\r\n]*)/',
        'string'   => '/(@"(?:""|[^"])*"@|@\'(?:[^[\'])*\'@|' .
                      '"(?:`.|[^"`])*"|\'(?:[^[\'])*\')/',
        'variable' => '/(\$[a-zA-Z0-9_]+)/',
        'keyword'  => '/(?i)\b(?:Begin|Break|Catch|Class|Continue|Data|' .
                      'Define|Do|DynamicParam|Else|ElseIf|End|Exit|' .
                      'Filter|Finally|For|ForEach|From|Function|If|In|' .
                      'InlineScript|Hidden|Parallel|Param|Process|' .
                      'Return|Sequence|Switch|Throw|Trap|Try|Until|' .
                      'Using|Var|While|Workflow)\b/',
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_-]*)\s*(?=\()/',
        'number'   => '/' . $int . '/',
      ],
      'containerfile' => [
        'comment' => '/(#[^\r\n]*)/',
        'string'  => '/' . $str . '/',
        'keyword' => '/(?i)^\s*(?:FROM|MAINTAINER|RUN|CMD|LABEL|EXPOSE|' .
                     'ENV|ADD|COPY|ENTRYPOINT|VOLUME|USER|WORKDIR|ARG|' .
                     'ONBUILD|STOPSIGNAL|HEALTHCHECK|SHELL)\b/m',
      ],
      'makefile' => [
        'comment'  => '/(#[^\r\n]*)/',
        'variable' => '/(\$+[{(][^})]+[})])/',
        'keyword'  => '/(?i)\b(?:include|define|endef|export|override|' .
                      'ifdef|ifndef|ifeq|ifneq|else|endif|vpath)\b/',
        'function' => '/^([a-zA-Z0-9._-]+):/m',
      ],
      'diff' => [
        'comment'  => '/^(?:---| \+\+\+|index|diff).*/m',
        'meta'     => '/^(?:@@).*/m',
        'inserted' => '/(^\+.*)/m',
        'deleted'  => '/(^-.*)/m',
      ],
      'fortran' => [
        'comment'  => '/(^[Cc*][^\r\n]*|![^\r\n]*)/m',
        'string'   => '/(\'.*?\')/',
        'boolean'  => '/\B(\.(?:TRUE|FALSE)\.)\B/i',
        'operator' => '/\B(\.(?:EQ|NE|LT|LE|GT|GE|NOT|' .
                      'AND|OR|EQV|NEQV)\.)\B/i',
        'type'     => '/(?i)\b(?:INTEGER(?:\*[0-9]+)?|' .
                      'REAL(?:\*[0-9]+)?|DOUBLE PRECISION|' .
                      'COMPLEX|LOGICAL(?:\*[0-9]+)?|CHARACTER)\b/',
        'keyword'  => '/(?i)\b(?:IMPLICIT|COMMON|CALL|GO\s*TO|IF|' .
                      'READ|PRINT|WRITE|STOP|REWIND|FORMAT|END|' .
                      'SUBROUTINE|RETURN|EQUIVALENCE|DATA|' .
                      'BLOCK\s*DATA|FUNCTION|DO|CONTINUE|THEN|ELSE|' .
                      'ELSEIF|ENDIF|SAVE|DIMENSION|PAUSE|ASSIGN|TO)\b/',
        'function' => '/\b([a-zA-Z_][a-zA-Z0-9_]*)\s*(?=\()/',
        'number'   => '/\b(\d+(\.\d+)?([eEdD][+-]?\d+)?)\b/',
        'label'    => '/^[ \t]*([0-9]+)/m'
      ]
    ];

    if( array_key_exists( $normalized, $rules ) ) {
      $result = $rules[$normalized];
    }

    return $result;
  }
}