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+)?)';

    $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' => [
        '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' => [
        '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 . '/',
      ],
      'xml' => [
        'comment'   => '/()/',
        'string'    => '/' . $str . '/',
        'tag'       => '/(<\/?[!a-zA-Z0-9:-]+|\s*\/?>|<\?xml|\?>)/',
        'attribute' => '/([a-zA-Z0-9:-]+)(?=\=)/',
      ],
      'html' => [
        'comment'   => '/()/',
        'string'    => '/' . $str . '/',
        'tag'       => '/(<\/?[!a-zA-Z0-9:-]+|\s*\/?>)/',
        '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',
      ]
    ];

    return $rules[strtolower( $lang )] ?? [];
  }
}