diff --git a/Lua/Lua.sublime-syntax b/Lua/Lua.sublime-syntax index f94a6ee77e..9fed54df48 100644 --- a/Lua/Lua.sublime-syntax +++ b/Lua/Lua.sublime-syntax @@ -9,82 +9,29 @@ file_extensions: first_line_match: |- (?xi: - ^ \#! .* {{shebang_language}} # shebang - | ^ \s* -- .*? -\*- .*? \blua\b .*? -\*- # editorconfig + ^ \#! .* {{shebang_language}} # shebang + | {{leading_wspace}} -- .*? -\*- .*? {{shebang_language}} .*? -\*- # editorconfig ) -variables: - shebang_language: \blua\b - - reserved_word: |- - (?x:(?: - and|break|do|elseif|else|end|false|for|function|goto|if|in| - local|nil|not|or|repeat|return|then|true|until|while - ){{identifier_break}}) - reserved_word_statement: |- # excludes 'not', 'true', 'nil', 'false', 'function' - (?x:(?: - and|break|do|elseif|else|end|for|goto|if|in| - local|or|repeat|return|then|until|while - ){{identifier_break}}) - metamethod: |- # http://lua-users.org/wiki/MetatableEvents - (?x:__(?: - # special - index|newindex|call|tostring|len|i?pairs|gc|close - # math operators - |unm|add|sub|mul|i?div|mod|pow|concat - # bitwise operators - |band|bor|bxor|bnot|shl|shr - # comparison - |eq|lt|le - ){{identifier_break}}) - # __metatable and __mode don't use functions - metaproperty: (?:__(?:metatable|mode|name){{identifier_break}}) - - identifier_start: '[A-Za-z_]' - identifier_char: '[A-Za-z0-9_]' - identifier_break: (?!{{identifier_char}}) - identifier_raw: (?:{{identifier_start}}{{identifier_char}}*) - identifier: (?:(?!{{reserved_word}}){{identifier_raw}}) - - trailing_expression_char: '[,\]})]' - - function_args_begin: (?:\(|"|'|\[=*\[|\{) - function_call_ahead: (?=\s*{{function_args_begin}}) - function_assignment_ahead: (?=\s*=\s*function{{identifier_break}}) - - dec_exponent: (?:[Ee][-+]?\d*) - hex_exponent: (?:[Pp][-+]?\d*) - - doc_comment_tag: |- - (?x:@(?: - alias|async|author|class|classmod|copyright|deprecated|diagnostic|field - |fixme|function|generic|language|lfunction|license|local|module|nodiscard - |overload|param|raise|release|return|script|section|see|submodule|table - |todo|tparam|treturn|type|usage|vararg|version|warning|within - )\b) - doc_comment_custom_tag: (?:@\w+\b) +###[ CONTEXTS ]################################################################ contexts: + prototype: + - include: comments + main: - meta_include_prototype: false - match: '' push: [statements, shebang] - else-pop: - - match: (?=\S) - pop: 1 - - immediately-pop: - - match: '' - pop: 1 - - prototype: - - include: comments +###[ COMMENTS ]################################################################ comments: - include: block-comments - include: line-comments +###[ COMMENTS / BLOCK COMMENTS ]############################################### + block-comments: - match: --\[\[-- scope: punctuation.definition.comment.begin.lua @@ -99,7 +46,7 @@ contexts: - match: \]\] scope: punctuation.definition.comment.end.lua pop: 1 - - match: ^\s*(@section)\s+(.*?\S)\s*(?=\]\]|$) + - match: '{{leading_wspace}}(@section)\s+(.*?\S)\s*(?=\]\]|$)' captures: 1: entity.name.tag.documentation.lua 2: entity.name.section.lua @@ -107,10 +54,10 @@ contexts: captures: 1: entity.name.tag.documentation.lua 2: variable.parameter.lua - - match: ^\s*({{doc_comment_tag}}) + - match: '{{leading_wspace}}({{doc_comment_tag}})' captures: 1: entity.name.tag.documentation.lua - - match: ^\s*({{doc_comment_custom_tag}}) + - match: '{{leading_wspace}}({{doc_comment_custom_tag}})' captures: 1: entity.name.tag.documentation.custom.lua @@ -121,6 +68,8 @@ contexts: scope: punctuation.definition.comment.end.lua pop: 1 +###[ COMMENTS / LINE COMMENTS ]################################################ + line-comments: - match: -{3,} scope: comment.line.documentation.lua punctuation.definition.comment.lua @@ -154,7 +103,7 @@ contexts: set: maybe-line-doc-comment maybe-line-doc-comment: - - match: ^\s*(?=--(?!\[(=*)\[)) + - match: '{{leading_wspace}}(?=--(?!\[(=*)\[))' set: - match: -{2,} scope: punctuation.definition.comment.lua @@ -165,8 +114,9 @@ contexts: line-comment-body: - meta_include_prototype: false - meta_scope: comment.line.lua - - match: \n - pop: 1 + - include: eol-pop + +###[ COMMENTS / SHEBANG ]###################################################### shebang: - meta_include_prototype: false @@ -182,8 +132,9 @@ contexts: - meta_scope: comment.line.shebang.lua - match: '{{shebang_language}}' scope: constant.language.shebang.lua - - match: $\n? - pop: 1 + - include: eol-pop + +###[ STATEMENTS ]############################################################## statements: - match: ; @@ -226,6 +177,8 @@ contexts: scope: keyword.control.end.lua pop: 1 +###[ FUNCTIONS ]############################################################### + function-parameter-list: - match: \( scope: punctuation.section.group.begin.lua @@ -275,6 +228,8 @@ contexts: pop: 1 - include: else-pop +###[ CONTROL STATEMENTS ]##################################################### + control-statements: - match: do{{identifier_break}} scope: keyword.control.lua @@ -364,6 +319,8 @@ contexts: set: if-block - include: statements +###[ EXPRESSIONS ]############################################################# + expression: - match: '' set: @@ -468,7 +425,11 @@ contexts: push: expression-begin accessor: - - match: '[.:]' + - match: ':' + scope: punctuation.accessor.lua + push: property-method + + - match: '\.' scope: punctuation.accessor.lua push: property @@ -502,6 +463,17 @@ contexts: - include: reserved-word-pop - include: else-pop + property-method: + - match: '(?:find|gmatch|gsub|match){{identifier_break}}' + scope: meta.property.lua meta.function-call.lua variable.function.lua + set: + - match: (?={{function_args_begin}}) + set: + - function-arguments-meta + - function-arguments-pattern-at1 + - include: else-pop + - include: property + function-arguments-meta: - meta_scope: meta.function-call.arguments.lua - include: immediately-pop @@ -541,6 +513,8 @@ contexts: scope: invalid.unexpected-keyword.lua pop: 1 +###[ CONSTANTS ]############################################################### + builtin: - match: false{{identifier_break}} scope: constant.language.boolean.false.lua @@ -576,6 +550,8 @@ contexts: - include: builtin-modules +###[ VARIABLES ]############################################################### + variable: - match: '{{identifier}}{{function_assignment_ahead}}' scope: entity.name.function.lua @@ -589,6 +565,8 @@ contexts: scope: variable.other.lua pop: 1 +###[ LITERALS / NUMBERS ]###################################################### + number: - match: (0[Xx])(\h*(?:(\.)\h*{{hex_exponent}}?|{{hex_exponent}})) scope: meta.number.float.hexadecimal.lua @@ -616,6 +594,8 @@ contexts: scope: meta.number.integer.decimal.lua constant.numeric.value.lua pop: 1 +###[ LITERALS / STRINGS ]###################################################### + string: - include: single-quoted-string - include: double-quoted-string @@ -683,6 +663,40 @@ contexts: - match: \\. scope: invalid.illegal.invalid-escape.lua + # pop the context once one escaped character has been matched + string-escape-pop: + - match: \\[abfnrtv\\'"\[\]\n] + scope: constant.character.escape.lua + pop: 1 + + - match: \\x\h\h + scope: constant.character.escape.hexadecimal.lua + pop: 1 + + - match: \\\d{1,3} + scope: constant.character.escape.decimal.lua + pop: 1 + + # unicode can make multiple, but that is a bit hard to handle + - match: \\u\{\h+\} + scope: constant.character.escape.unicode.lua + pop: 1 + + # \z turns into nothing, so we don't pop + - match: \\z + push: + - meta_scope: constant.character.escape.whitespace.lua + - include: else-pop + + - match: \n + scope: invalid.illegal.unclosed-string.lua + pop: 2 + - match: \\. + scope: invalid.illegal.invalid-escape.lua + pop: 1 + +###[ PARENTHESIZED EXPRESSIONS ]############################################### + parenthesized-expression: - match: \( scope: punctuation.section.group.begin.lua @@ -692,9 +706,19 @@ contexts: scope: punctuation.section.group.end.lua pop: 1 - include: reserved-word-expression-pop + - match: (?="(?:{{string_char_escape}}|[^\\"])*"\s*\)\s*:\s*format{{identifier_break}}) + push: fmtstr-expression + - match: (?='(?:{{string_char_escape}}|[^\\'])*'\s*\)\s*:\s*format{{identifier_break}}) + push: fmtstr-expression + - match: (?="(?:{{string_char_escape}}|[^\\"])*"\s*\)\s*:\s*(?:pack|unpack|packsize){{identifier_break}}) + push: packstr-expression + - match: (?='(?:{{string_char_escape}}|[^\\'])*'\s*\)\s*:\s*(?:pack|unpack|packsize){{identifier_break}}) + push: packstr-expression - match: (?=\S) push: expression +###[ MAPPINGS ]################################################################ + table-constructor: - match: \{ scope: punctuation.section.block.begin.lua @@ -707,46 +731,55 @@ contexts: - match: '[,;]' scope: punctuation.separator.field.lua - - match: \[(?!=*\[) - scope: punctuation.section.brackets.begin.lua - push: - - clear_scopes: 1 - - meta_scope: meta.mapping.key.lua meta.brackets.lua - - match: \] - scope: punctuation.section.brackets.end.lua - pop: 1 - - match: (?=\S) - push: expression - - - match: (?={{identifier}}\s*=(?!=)) - push: - - clear_scopes: 1 - - meta_scope: meta.mapping.key.lua - - match: (?:({{metamethod}})|{{identifier}})(?=\s*=\s*function\b) - scope: entity.name.function.lua - captures: - 1: support.function.metamethod.lua - pop: 1 - - match: '{{metamethod}}' - scope: entity.name.function.lua support.function.metamethod.lua - pop: 1 - - match: '{{metaproperty}}' - scope: string.unquoted.key.lua support.other.metaproperty.lua - pop: 1 - - match: '{{identifier}}' - scope: string.unquoted.key.lua - pop: 1 + - include: table-constructor-body-brackets + - include: table-constructor-body-mapping-key + - include: table-constructor-body-mapping-value - - match: =(?!=) - scope: meta.mapping.lua punctuation.separator.key-value.lua - push: - - - clear_scopes: 1 - - meta_content_scope: meta.mapping.value.lua - - include: immediately-pop - - expression + table-constructor-body-brackets: + - match: \[(?!=*\[) + scope: punctuation.section.brackets.begin.lua + push: + - clear_scopes: 1 + - meta_scope: meta.mapping.key.lua meta.brackets.lua + - match: \] + scope: punctuation.section.brackets.end.lua + pop: 1 - match: (?=\S) push: expression + table-constructor-body-mapping-key: + - match: (?={{identifier}}\s*=(?!=)) + push: + - clear_scopes: 1 + - meta_scope: meta.mapping.key.lua + - match: (?:({{metamethod}})|{{identifier}})(?=\s*=\s*function\b) + scope: entity.name.function.lua + captures: + 1: support.function.metamethod.lua + pop: 1 + - match: '{{metamethod}}' + scope: entity.name.function.lua support.function.metamethod.lua + pop: 1 + - match: '{{metaproperty}}' + scope: string.unquoted.key.lua support.other.metaproperty.lua + pop: 1 + - match: '{{identifier}}' + scope: string.unquoted.key.lua + pop: 1 + + table-constructor-body-mapping-value: + - match: =(?!=) + scope: meta.mapping.lua punctuation.separator.key-value.lua + push: + - - clear_scopes: 1 + - meta_content_scope: meta.mapping.value.lua + - include: immediately-pop + - expression + - match: (?=\S) + push: expression + +###[ FUNCTION DECLARATIONS ]################################################### + function-literal: - match: function{{identifier_break}} scope: keyword.declaration.function.lua @@ -760,185 +793,744 @@ contexts: - meta_scope: meta.function.lua - include: immediately-pop + function-arguments-pattern-at2: + - include: string + - include: table-constructor + + - match: \( + scope: punctuation.section.group.begin.lua + set: function-arguments-pattern-at2-body + + function-arguments-pattern-at2-body: + - meta_scope: meta.group.lua + - match: \) + scope: punctuation.section.group.end.lua + pop: 1 + - include: reserved-word-expression-pop + - match: (?=\S) + push: + - expression-list-end-pattern-next + - expression-begin + + function-arguments-pattern-at1: + - include: pattern-string + - include: table-constructor + + - match: \( + scope: punctuation.section.group.begin.lua + set: function-arguments-pattern-at1-body + + function-arguments-pattern-at1-body: + - meta_scope: meta.group.lua + - match: \) + scope: punctuation.section.group.end.lua + pop: 1 + - include: reserved-word-expression-pop + - match: (?=\S) + push: + - expression-list-end + - pattern-expression + + function-arguments-fmtstr-at1: + - include: fmtstr-string + - include: table-constructor + + - match: \( + scope: punctuation.section.group.begin.lua + set: function-arguments-fmtstr-at1-body + + function-arguments-fmtstr-at1-body: + - meta_scope: meta.group.lua + - match: \) + scope: punctuation.section.group.end.lua + pop: 1 + - include: reserved-word-expression-pop + - match: (?=\S) + push: + - expression-list-end + - fmtstr-expression + + function-arguments-packstr-at1: + - include: packstr-string + - include: table-constructor + + - match: \( + scope: punctuation.section.group.begin.lua + set: function-arguments-packstr-at1-body + + function-arguments-packstr-at1-body: + - meta_scope: meta.group.lua + - match: \) + scope: punctuation.section.group.end.lua + pop: 1 + - include: reserved-word-expression-pop + - match: (?=\S) + push: + - expression-list-end + - packstr-expression + +###[ PATTERNS ]################################################################ + + pattern-expression: + - include: pattern-string + - include: expression-begin + + expression-list-end-pattern-next: + - match: ',' + scope: punctuation.separator.comma.lua + set: + - expression-list-end + - pattern-expression + - include: expression-end + + pattern-shared-charclass: + - meta_include_prototype: false + - match: \%(?i:[acdglpsuwxz]) + scope: keyword.control.character-class.lua + - match: \%f + scope: keyword.control.anchor.lua + + - match: (\%)(\d) + captures: + 1: keyword.other.backref-and-recursion.lua + 2: variable.other.backref-and-recursion.lua + push: pattern-shared-norepetition + + # other alphabetic characters are not defined + # this skips `f` and `b` as they are special patterns + - match: \%(?i:[ehijkmnoqrtvy]) + scope: invalid.illegal.invalid-escape.lua + + pattern-shared: + - meta_include_prototype: false + # start anchor is handled separately as ^ doesn't match the start of the string + # It needs to be the end of the string (which $ matches when it is an embedded pattern) + - match: \$$(?!\n) + scope: keyword.control.anchor.lua + - match: '\(\)' + scope: punctuation.section.brackets.lua + - match: '[+*?\-]' + scope: keyword.operator.quantifier.lua + push: pattern-shared-norepetition + - match: \. + scope: keyword.other.any.lua + + + pattern-shared-norepetition: + - meta_include_prototype: false + - match: '[+*?\-]' + pop: 1 + - include: immediately-pop + +###[ PATTERNS / QUOTED PATTERNS ]############################################## + + # the pattern implementation is split into quoted and unquoted as escapes are only processed + # in quoted strings. + pattern-quoted: + - meta_include_prototype: false + - include: string-content + - include: pattern-shared + - match: '\(' + scope: punctuation.section.group.begin.lua + push: + - pattern-shared-norepetition + - pattern-quoted-nested + - pattern-shared-norepetition + - match: '(\[)(\^)?\]?' + captures: + 1: punctuation.definition.set.begin.lua + 2: keyword.operator.logical.lua + push: pattern-quoted-set-body + - include: pattern-quoted-charclass + + pattern-quoted-charclass: + - meta_include_prototype: false + - include: pattern-shared-charclass + - match: \%b + scope: keyword.control.balanced.lua + push: + - pattern-quoted-balanced-char + - pattern-quoted-balanced-char + - match: \%[^'"\\] + scope: constant.character.escape.lua + + # this one is split so that it works with quoted strings + - match: \% + scope: constant.character.escape.lua + push: + - meta_include_prototype: false + - match: '[''"]' + scope: constant.character.escape.lua + pop: 1 + - include: else-pop + + pattern-quoted-balanced-char: + - meta_include_prototype: false + - include: string-escape-pop + - match: . + scope: keyword.control.balanced.lua + pop: 1 + + pattern-quoted-nested: + - meta_include_prototype: false + - meta_scope: meta.group.lua meta.mode.basic.lua + - match: '\)' + scope: punctuation.section.group.end.lua + pop: 1 + - include: pattern-quoted + + pattern-quoted-set-body: + - meta_include_prototype: false + - meta_scope: meta.set.lua + - match: '\]' + scope: punctuation.definition.set.end.lua + pop: 1 + - include: pattern-quoted-set-ranges + - include: pattern-quoted-charclass + - include: string-content + + pattern-quoted-set-ranges: + - meta_include_prototype: false + # These only work with direct characters. Lua doesn't support percent escapes in sets + - match: (?=({{string_char_escape}}|[^%\]\-])-({{string_char_escape}}|[^\]])) + push: + - pattern-quoted-set-range-end + - pattern-quoted-set-range-begin + + pattern-quoted-set-range-begin: + - meta_include_prototype: false + - match: '-' + scope: punctuation.separator.sequence.lua + pop: 1 + - include: string-content + + pattern-quoted-set-range-end: + - meta_include_prototype: false + - meta_scope: constant.other.range.lua + - include: string-escape-pop + - match: . + pop: 1 + +###[ PATTERNS / UNQUOTED PATTERNS ]############################################ + + pattern-unquoted: + - meta_include_prototype: false + - include: pattern-shared + - match: '\(' + scope: punctuation.section.group.begin.lua + push: + - pattern-shared-norepetition + - pattern-unquoted-nested + - pattern-shared-norepetition + - match: '(\[)(\^)?\]?' + captures: + 1: punctuation.definition.set.begin.lua + 2: keyword.operator.logical.lua + push: pattern-unquoted-set-body + - include: pattern-unquoted-charclass + + pattern-unquoted-charclass: + - meta_include_prototype: false + - include: pattern-shared-charclass + - match: \%b.?.? + scope: keyword.control.balanced.lua + - match: \%.? + scope: constant.character.escape.lua + + pattern-unquoted-nested: + - meta_include_prototype: false + - meta_scope: meta.group.lua meta.mode.basic.lua + - match: '\)' + scope: punctuation.section.group.end.lua + pop: 1 + - include: pattern-unquoted + + pattern-unquoted-set-body: + - meta_include_prototype: false + - meta_scope: meta.set.lua + - match: '\]' + scope: punctuation.definition.set.end.lua + pop: 1 + - include: pattern-unquoted-set-ranges + - include: pattern-unquoted-charclass + + pattern-unquoted-set-ranges: + - meta_include_prototype: false + # These only work with direct characters. Lua doesn't support percent escapes in sets + - match: (?=[^%\]\-]-[^\]]) + push: + - pattern-unquoted-set-range-end + - pattern-unquoted-set-range-begin + + pattern-unquoted-set-range-begin: + - meta_include_prototype: false + - match: '-' + scope: punctuation.separator.sequence.lua + pop: 1 + + pattern-unquoted-set-range-end: + - meta_include_prototype: false + - meta_scope: constant.other.range.lua + - match: . + pop: 1 + +###[ PATTERNS / STRING PATTERNS ]############################################## + + # this gets included in expressions that want to have a pattern string + pattern-string: + - match: \[(=*)\[ + scope: punctuation.definition.string.begin.lua + set: + - pattern-multiline-string-body + - pattern-test-first-caret-multiline + - match: \' + scope: punctuation.definition.string.begin.lua + set: + - pattern-single-quoted-string-body + - pattern-test-first-caret + - match: \" + scope: punctuation.definition.string.begin.lua + set: + - pattern-double-quoted-string-body + - pattern-test-first-caret + + pattern-test-first-caret: + - meta_include_prototype: false + - match: (\^)[+*?\-]? + captures: + 1: keyword.control.anchor.lua + pop: 1 + + # eat these because they can't be a repetition at the start + - match: '[+*?\-]' + pop: 1 + # it seems to require this match rather than immediately-pop + # in order to work with the multiline below + - match: (?=[^\^]) + pop: 1 + + pattern-test-first-caret-multiline: + - meta_include_prototype: false + - match: $\n? + set: pattern-test-first-caret + - include: pattern-test-first-caret + + pattern-single-quoted-string-body: + - meta_include_prototype: false + - meta_scope: meta.string.lua string.quoted.single.lua + - include: single-quoted-string-body + - match: \$(?=\') + scope: keyword.control.anchor.lua + - match: '' + push: pattern-quoted + with_prototype: + - match: (?=\$?\') + pop: 1 + + pattern-double-quoted-string-body: + - meta_include_prototype: false + - meta_scope: meta.string.lua string.quoted.double.lua + - include: double-quoted-string-body + - match: \$(?=\") + scope: keyword.control.anchor.lua + - match: '' + push: pattern-quoted + with_prototype: + - match: (?=\$?\") + pop: 1 + + pattern-multiline-string-body: + - meta_include_prototype: false + - meta_scope: meta.string.lua string.quoted.multiline.lua + - include: multiline-string-body + - match: '' + embed: pattern-unquoted + # we don't seem to be able to use the capture to get the right one + # this means that patterns that contain something that matches this + # will lose their context half way through. + escape: (?=\]=*\]) + +###[ PATTERNS / STRING PATTERNS / FMT STRING ]################################# + + fmtstr-expression: + - include: fmtstr-string + - include: expression-begin + + fmtstr-string: + - match: \[(=*)\[ + scope: punctuation.definition.string.begin.lua + set: multiline-string-body + with_prototype: + - include: fmtstr-embed + + - match: \' + scope: punctuation.definition.string.begin.lua + set: single-quoted-string-body + with_prototype: + - include: fmtstr-embed + + - match: \" + scope: punctuation.definition.string.begin.lua + set: double-quoted-string-body + with_prototype: + - include: fmtstr-embed + + fmtstr-embed: + - meta_include_prototype: false + - match: '%%' + scope: constant.character.escape.lua + + - match: '%' + scope: constant.other.placeholder.lua + push: fmtstr-pattern + + fmtstr-pattern: + - meta_include_prototype: false + # these characters never appear in a format pattern so it can be simpler + - match: (?=[\\\"\'\]]) + pop: 1 + - match: '[-+#0-9. ]' + scope: constant.other.placeholder.lua + - match: '[cdiuoxXaAfeEgGpqs]' + scope: constant.other.placeholder.lua + pop: 1 + - match: '.' + scope: invalid.illegal.invalid-format.lua + pop: 1 + +###[ PATTERNS / STRING PATTERNS / PACK STR ]################################### + + packstr-expression: + - include: packstr-string + - include: expression-begin + + packstr-string: + - match: \[(=*)\[ + scope: punctuation.definition.string.begin.lua + set: multiline-string-body + with_prototype: + - include: packstr-pattern + + - match: \' + scope: punctuation.definition.string.begin.lua + set: single-quoted-string-body + with_prototype: + - include: packstr-pattern + + - match: \" + scope: punctuation.definition.string.begin.lua + set: double-quoted-string-body + with_prototype: + - include: packstr-pattern + + packstr-pattern: + - meta_include_prototype: false + - match: '[=<>]|![0-9]*' + scope: storage.modifier.lua + + - match: '[bBhHlLjJTfdnz]|[Iis][0-9]*|c[0-9]+' + scope: storage.type.lua + + - match: '[xX]' + scope: punctuation.separator.padding.lua + + - match: (?:[^\\\"\'\]\s]) + scope: invalid.illegal.invalid-storage.lua + +###[ MODULES ]################################################################# + builtin-modules: - match: coroutine{{identifier_break}} scope: support.constant.builtin.lua - set: - - match: \. - scope: punctuation.accessor.lua - set: - - match: |- - (?x: - create|isyieldable|resume|running|status|wrap|yield|close - ){{identifier_break}} - scope: meta.property.lua support.function.builtin.lua - pop: 1 - - include: property - - include: else-pop + set: builtin-module-coroutine-body - match: package{{identifier_break}} scope: support.constant.builtin.lua - set: - - match: \. - scope: punctuation.accessor.lua - set: - - match: |- - (?x: - config|cpath|loaded|path|preload|searchers|loaders - ){{identifier_break}} - scope: meta.property.lua support.constant.builtin.lua - pop: 1 - - match: |- - (?x: - loadlib|searchpath|seeall - ){{identifier_break}} - scope: meta.property.lua support.function.builtin.lua - pop: 1 - - include: property - - include: else-pop + set: builtin-module-package-body - match: string{{identifier_break}} scope: support.constant.builtin.lua - set: - - match: \. - scope: punctuation.accessor.lua - set: - - match: |- - (?x: - byte|char|dump|find|format|gmatch|gsub|len|lower|match|pack - |packsize|rep|reverse|sub|unpack|upper - ){{identifier_break}} - scope: meta.property.lua support.function.builtin.lua - pop: 1 - - include: property - - include: else-pop + set: builtin-module-string-body - match: utf8{{identifier_break}} scope: support.constant.builtin.lua - set: - - match: \. - scope: punctuation.accessor.lua - set: - - match: |- - (?x: - charpattern - ){{identifier_break}} - scope: meta.property.lua support.constant.builtin.lua - pop: 1 - - match: |- - (?x: - char|codes|codepoint|len|offset - ){{identifier_break}} - scope: meta.property.lua support.function.builtin.lua - pop: 1 - - include: property - - include: else-pop + set: builtin-module-utf8-body - match: table{{identifier_break}} scope: support.constant.builtin.lua - set: - - match: \. - scope: punctuation.accessor.lua - set: - - match: |- - (?x: - concat|insert|move|pack|remove|sort|unpack|maxn - ){{identifier_break}} - scope: meta.property.lua support.function.builtin.lua - pop: 1 - - include: property - - include: else-pop + set: builtin-module-table-body - match: math{{identifier_break}} scope: support.constant.builtin.lua - set: - - match: \. - scope: punctuation.accessor.lua - set: - - match: |- - (?x: - huge|maxinteger|mininteger|pi - ){{identifier_break}} - scope: meta.property.lua support.constant.builtin.lua - pop: 1 - - match: |- - (?x: - abs|acos|asin|atan|ceil|cos|deg|exp|floor|fmod|log|max|min - |modf|rad|random|randomseed|sin|sqrt|tan|tointeger|type|ult - |atan2|cosh|frexp|ldexp|log10|pow|sinh|tanh - ){{identifier_break}} - scope: meta.property.lua support.function.builtin.lua - pop: 1 - - include: property - - include: else-pop + set: builtin-module-math-body - match: io{{identifier_break}} scope: support.constant.builtin.lua - set: - - match: \. - scope: punctuation.accessor.lua - set: - - match: |- - (?x: - stderr|stdin|stdout - ){{identifier_break}} - scope: meta.property.lua support.constant.builtin.lua - pop: 1 - - match: |- - (?x: - close|flush|input|lines|open|output|popen|read|tmpfile|type|write - ){{identifier_break}} - scope: meta.property.lua support.function.builtin.lua - pop: 1 - - include: property - - include: else-pop + set: builtin-module-io-body - match: os{{identifier_break}} scope: support.constant.builtin.lua - set: - - match: \. - scope: punctuation.accessor.lua - set: - - match: |- - (?x: - clock|date|difftime|execute|exit|getenv|remove|rename - |setlocale|time|tmpname - ){{identifier_break}} - scope: meta.property.lua support.function.builtin.lua - pop: 1 - - include: property - - include: else-pop + set: builtin-module-os-body - match: debug{{identifier_break}} scope: support.constant.builtin.lua - set: - - match: \. - scope: punctuation.accessor.lua - set: - - match: |- - (?x: - debug|gethook|getinfo|getlocal|getmetatable|getregistry - |getupvalue|getuservalue|sethook|setlocal|setmetatable - |setupvalue|setuservalue|traceback|upvalueid|upvaluejoin - |getfenv|setfenv - ){{identifier_break}} - scope: meta.property.lua support.function.builtin.lua - pop: 1 - - include: property - - include: else-pop + set: builtin-module-debug-body - match: bit32{{identifier_break}} scope: support.constant.builtin.lua + set: builtin-module-bit32-body + + builtin-module-coroutine-body: + - match: \. + scope: punctuation.accessor.lua + set: + - match: |- + (?x: + create|isyieldable|resume|running|status|wrap|yield|close + ){{identifier_break}} + scope: meta.property.lua support.function.builtin.lua + pop: 1 + - include: property + - include: else-pop + + builtin-module-package-body: + - match: \. + scope: punctuation.accessor.lua + set: + - match: |- + (?x: + config|cpath|loaded|path|preload|searchers|loaders + ){{identifier_break}} + scope: meta.property.lua support.constant.builtin.lua + pop: 1 + - match: |- + (?x: + loadlib|searchpath|seeall + ){{identifier_break}} + scope: meta.property.lua support.function.builtin.lua + pop: 1 + - include: property + - include: else-pop + + builtin-module-string-body: + - match: \. + scope: punctuation.accessor.lua set: - - match: \. - scope: punctuation.accessor.lua + - match: (?:find|gmatch|gsub|match){{identifier_break}} + scope: meta.property.lua support.function.builtin.lua set: - - match: |- - (?x: - arshift|band|bnot|bor|btest|bxor|extract|lrotate|lshift - |replace|rrotate|rshift - ){{identifier_break}} - scope: meta.property.lua support.function.builtin.lua - pop: 1 - - include: property - - include: else-pop + - match: (?={{function_args_begin}}) + set: + - function-arguments-meta + - function-arguments-pattern-at2 + - include: else-pop + - match: (?:format){{identifier_break}} + scope: meta.property.lua support.function.builtin.stringy.lua + set: + - match: (?={{function_args_begin}}) + set: + - function-arguments-meta + - function-arguments-fmtstr-at1 + - include: else-pop + - match: (?:pack|unpack|packsize){{identifier_break}} + scope: meta.property.lua support.function.builtin.stringy.lua + set: + - match: (?={{function_args_begin}}) + set: + - function-arguments-meta + - function-arguments-packstr-at1 + - include: else-pop + - match: |- + (?x: + byte|char|dump|len|lower + |rep|reverse|sub|upper + ){{identifier_break}} + scope: meta.property.lua support.function.builtin.lua + pop: 1 + - include: property + - include: else-pop + + builtin-module-utf8-body: + - match: \. + scope: punctuation.accessor.lua + set: + - match: |- + (?x: + charpattern + ){{identifier_break}} + scope: meta.property.lua support.constant.builtin.lua + pop: 1 + - match: |- + (?x: + char|codes|codepoint|len|offset + ){{identifier_break}} + scope: meta.property.lua support.function.builtin.lua + pop: 1 + - include: property + - include: else-pop + + builtin-module-table-body: + - match: \. + scope: punctuation.accessor.lua + set: + - match: |- + (?x: + concat|insert|move|pack|remove|sort|unpack|maxn + ){{identifier_break}} + scope: meta.property.lua support.function.builtin.lua + pop: 1 + - include: property + - include: else-pop + + builtin-module-math-body: + - match: \. + scope: punctuation.accessor.lua + set: + - match: |- + (?x: + huge|maxinteger|mininteger|pi + ){{identifier_break}} + scope: meta.property.lua support.constant.builtin.lua + pop: 1 + - match: |- + (?x: + abs|acos|asin|atan|ceil|cos|deg|exp|floor|fmod|log|max|min + |modf|rad|random|randomseed|sin|sqrt|tan|tointeger|type|ult + |atan2|cosh|frexp|ldexp|log10|pow|sinh|tanh + ){{identifier_break}} + scope: meta.property.lua support.function.builtin.lua + pop: 1 + - include: property + - include: else-pop + + builtin-module-io-body: + - match: \. + scope: punctuation.accessor.lua + set: + - match: |- + (?x: + stderr|stdin|stdout + ){{identifier_break}} + scope: meta.property.lua support.constant.builtin.lua + pop: 1 + - match: |- + (?x: + close|flush|input|lines|open|output|popen|read|tmpfile|type|write + ){{identifier_break}} + scope: meta.property.lua support.function.builtin.lua + pop: 1 + - include: property + - include: else-pop + + builtin-module-os-body: + - match: \. + scope: punctuation.accessor.lua + set: + - match: |- + (?x: + clock|date|difftime|execute|exit|getenv|remove|rename + |setlocale|time|tmpname + ){{identifier_break}} + scope: meta.property.lua support.function.builtin.lua + pop: 1 + - include: property + - include: else-pop + + builtin-module-debug-body: + - match: \. + scope: punctuation.accessor.lua + set: + - match: |- + (?x: + debug|gethook|getinfo|getlocal|getmetatable|getregistry + |getupvalue|getuservalue|sethook|setlocal|setmetatable + |setupvalue|setuservalue|traceback|upvalueid|upvaluejoin + |getfenv|setfenv + ){{identifier_break}} + scope: meta.property.lua support.function.builtin.lua + pop: 1 + - include: property + - include: else-pop + + builtin-module-bit32-body: + - match: \. + scope: punctuation.accessor.lua + set: + - match: |- + (?x: + arshift|band|bnot|bor|btest|bxor|extract|lrotate|lshift + |replace|rrotate|rshift + ){{identifier_break}} + scope: meta.property.lua support.function.builtin.lua + pop: 1 + - include: property + - include: else-pop + +###[ PROTOTYPES ]############################################################## + + eol-pop: + - match: '$\n?' + pop: 1 + + else-pop: + - match: (?=\S) + pop: 1 + + immediately-pop: + - match: '' + pop: 1 + +###[ VARIABLES ]############################################################### + +variables: + shebang_language: (?:\blua\b) + leading_wspace: (?:^\s*) + reserved_word: |- + (?x:(?: + and|break|do|elseif|else|end|false|for|function|goto|if|in| + local|nil|not|or|repeat|return|then|true|until|while + ){{identifier_break}}) + reserved_word_statement: |- # excludes 'not', 'true', 'nil', 'false', 'function' + (?x:(?: + and|break|do|elseif|else|end|for|goto|if|in| + local|or|repeat|return|then|until|while + ){{identifier_break}}) + metamethod: |- # http://lua-users.org/wiki/MetatableEvents + (?x:__(?: + # special + index|newindex|call|tostring|len|i?pairs|gc|close + # math operators + |unm|add|sub|mul|i?div|mod|pow|concat + # bitwise operators + |band|bor|bxor|bnot|shl|shr + # comparison + |eq|lt|le + ){{identifier_break}}) + # __metatable and __mode don't use functions + metaproperty: (?:__(?:metatable|mode|name){{identifier_break}}) + + identifier_start: '[A-Za-z_]' + identifier_char: '[A-Za-z0-9_]' + identifier_break: (?!{{identifier_char}}) + identifier_raw: (?:{{identifier_start}}{{identifier_char}}*) + identifier: (?:(?!{{reserved_word}}){{identifier_raw}}) + + trailing_expression_char: '[,\]})]' + + function_args_begin: (?:\(|"|'|\[=*\[|\{) + function_call_ahead: (?=\s*{{function_args_begin}}) + function_assignment_ahead: (?=\s*=\s*function{{identifier_break}}) + + dec_exponent: (?:[Ee][-+]?\d*) + hex_exponent: (?:[Pp][-+]?\d*) + + doc_comment_tag: |- + (?x:@(?: + alias|async|author|class|classmod|copyright|deprecated|diagnostic|field + |fixme|function|generic|language|lfunction|license|local|module|nodiscard + |overload|param|raise|release|return|script|section|see|submodule|table + |todo|tparam|treturn|type|usage|vararg|version|warning|within + )\b) + doc_comment_custom_tag: (?:@\w+\b) + + string_char_escape: \\(?:[abfnrtv\\'"\[\]\n]|x\h\h|\d{1,3}|u\{\h+\}) diff --git a/Lua/tests/syntax_test_lua.lua b/Lua/tests/syntax_test_lua.lua index 10d7dcb17c..b56b835b2c 100644 --- a/Lua/tests/syntax_test_lua.lua +++ b/Lua/tests/syntax_test_lua.lua @@ -789,3 +789,55 @@ -- ^^^^^^^^^^^^ meta.string string.quoted.double.lua -- ^ punctuation.separator.comma.lua -- ^ punctuation.section.group.end.lua + +-- basic tests for patterns + local a = ('test'):match('^()t?$-e*s+%+()$') +-- ^ keyword.control.anchor +-- ^^ punctuation.section.brackets.lua +-- ^ keyword.operator.quantifier +-- ^ keyword.operator.quantifier +-- ^ keyword.operator.quantifier +-- ^ keyword.operator.quantifier +-- ^^ constant.character.escape.lua +-- ^ keyword.control.anchor + + local b = string.format('%#0.9f %-5q %% %# 5.3d %i %p', 15.4) +-- ^^^^^^ constant.other.placeholder.lua +-- ^^^^ constant.other.placeholder.lua +-- ^^ constant.character.escape.lua +-- ^^^^^^^ constant.other.placeholder.lua +-- ^^ constant.other.placeholder.lua +-- ^^ constant.other.placeholder.lua + + local c = string.pack('< = !3 i f s b c1 d f h i1 j l n s1 x z X'); +-- ^ storage.modifier.lua +-- ^ storage.modifier.lua +-- ^^ storage.modifier.lua +-- ^ storage.type.lua +-- ^ storage.type.lua +-- ^ storage.type.lua +-- ^ storage.type.lua +-- ^^ storage.type.lua +-- ^ storage.type.lua +-- ^ storage.type.lua +-- ^ storage.type.lua +-- ^^ storage.type.lua +-- ^ storage.type.lua +-- ^ storage.type.lua +-- ^ storage.type.lua +-- ^^ storage.type.lua +-- ^ punctuation.separator.padding.lua +-- ^ storage.type.lua +-- ^ punctuation.separator.padding.lua + + ("%q %d"):format(test); +-- ^ punctuation.section.group.begin.lua +-- ^^ constant.other.placeholder.lua +-- ^^ constant.other.placeholder.lua +-- ^ punctuation.section.group.end.lua + + ("< = !5 f"):pack(test); +-- ^ storage.modifier.lua +-- ^ storage.modifier.lua +-- ^^ storage.modifier.lua +-- ^ storage.type.lua diff --git a/Lua/tests/syntax_test_lua_patterns.lua b/Lua/tests/syntax_test_lua_patterns.lua new file mode 100644 index 0000000000..11c7479fef --- /dev/null +++ b/Lua/tests/syntax_test_lua_patterns.lua @@ -0,0 +1,220 @@ +-- SYNTAX TEST "Packages/Lua/Lua.sublime-syntax" + +-------------------- +-- Anchors and escapes +-------------------- + +(''):match('\'') +-- ^^ constant.character.escape.lua + +(''):match(' \'') +-- ^^ constant.character.escape.lua + +(''):match(" \"") +-- ^^ constant.character.escape.lua + +(''):match('^foo ^bbar$ %f[test] %b() $') +-- ^ keyword.control.anchor.lua +-- ^ - keyword.control.anchor.lua +-- ^ - keyword.control.anchor.lua +-- ^^ keyword.control.anchor.lua +-- ^ punctuation.definition.set.begin.lua +-- ^ punctuation.definition.set.end.lua +-- ^^^^^^ meta.set.lua +-- ^^^^ keyword.control.balanced.lua +-- ^ keyword.control.anchor.lua + +(''):match[[^foo ^bbar$ %f[test] %b() $]] +-- ^ keyword.control.anchor.lua +-- ^ - keyword.control.anchor.lua +-- ^ - keyword.control.anchor.lua +-- ^^ keyword.control.anchor.lua +-- ^ punctuation.definition.set.begin.lua +-- ^ punctuation.definition.set.end.lua +-- ^^^^^^ meta.set.lua +-- ^^^^ keyword.control.balanced.lua +-- ^ keyword.control.anchor.lua + + +(''):match('%^foo ^bbar$ %$') +-- ^ - keyword.control.anchor.lua +-- ^ - keyword.control.anchor.lua + +(''):match[[%^foo ^bbar$ %$]] +-- ^^ constant.character.escape.lua +-- ^ - keyword.control.anchor.lua +-- ^ - keyword.control.anchor.lua +-- ^^ constant.character.escape.lua + +(''):match[[ +^testing$]] +-- <- keyword.control.anchor.lua +-- ^ keyword.control.anchor.lua + +(''):match('%1') +-- ^ keyword.other.backref-and-recursion +-- ^ variable.other.backref-and-recursion + +(''):match('%W') +-- ^^ keyword.control.character-class + +(''):match('%f[test]') +-- ^^ keyword.control.anchor + +(''):match('% ') +-- ^^ constant.character.escape.lua + +(''):match('%"') +-- ^^ constant.character.escape.lua + +(''):match("%'") +-- ^^ constant.character.escape.lua + +(''):match('%\x1b') +-- ^ constant.character.escape.lua +-- ^^^^ constant.character.escape.hexadecimal.lua + +(''):match('%\1234') +-- ^ constant.character.escape.lua +-- ^^^^ constant.character.escape.decimal.lua +-- ^ - constant.character.escape.decimal.lua + +(''):match('%\r %\n') +-- ^^^ constant.character.escape.lua +-- ^^^ constant.character.escape.lua + +(''):match("%\u{2d}") +-- ^ constant.character.escape.lua +-- ^^^^^^ constant.character.escape.unicode.lua + +-- note: this pattern only repeats the first byte of the UTF-8 character. +(''):match("%\u{2013}") +-- ^ constant.character.escape.lua +-- ^^^^^^^^ constant.character.escape.unicode.lua + +-- invalid patterns that we allow because of highlighting concerns + +(''):match('%') +-- ^ constant.character.escape.lua +-- ^ punctuation.definition.string.end.lua + +(''):match("%") +-- ^ constant.character.escape.lua +-- ^ punctuation.definition.string.end.lua + +(''):match[[%]] +-- ^ constant.character.escape.lua +-- ^^ punctuation.definition.string.end.lua + + +-------------------- +-- Quantifiers +-------------------- + +(''):match('\x00**++--??') +-- ^^^^ constant.character.escape +-- ^ keyword.operator.quantifier.lua +-- ^ - keyword.operator.quantifier.lua +-- ^ keyword.operator.quantifier.lua +-- ^ - keyword.operator.quantifier.lua +-- ^ keyword.operator.quantifier.lua +-- ^ - keyword.operator.quantifier.lua +-- ^ keyword.operator.quantifier.lua +-- ^ - keyword.operator.quantifier.lua + +(''):match('(ab)+') +-- ^ - keyword.operator.quantifier.lua + +(''):match('?(?abc)') +-- ^ - keyword.operator.quantifier.lua +-- ^ - keyword.operator.quantifier.lua + +(''):match('hello**') +-- ^ keyword.operator.quantifier.lua +-- ^ - keyword.operator.quantifier.lua + +(''):match(')') +-- ^ - punctuation.section.group.end.lua + +-------------------- +-- Sets +-------------------- + +(''):match(' [b-c]') +-- ^^^^^ meta.set.lua +-- ^ punctuation.definition.set.begin.lua +-- ^ punctuation.definition.set.end.lua +-- ^^^ constant.other.range.lua +-- ^ punctuation.separator.sequence.lua + +(''):match('[\x00-\123]') +-- ^ meta.set.lua punctuation.definition.set.begin.lua +-- ^^^^^^^^^^^ meta.set.lua +-- ^^^^^^^^^ constant.other.range +-- ^^^^ constant.character.escape +-- ^ punctuation.separator.sequence - constant.character +-- ^^^^ constant.character.escape +-- ^ punctuation.definition.set.end.lua + +(''):match('[^][]') +-- ^ keyword.operator.logical.lua +-- ^ - punctuation.definition.set.end.lua +-- ^ - punctuation.definition.set.begin.lua + +(''):match('[^abc%w\w0-9]') +-- ^^^^^^^^^^^^ meta.set.lua +-- ^ punctuation.definition.set.begin.lua +-- ^ keyword.operator.logical.lua +-- ^^ keyword.control.character-class.lua +-- ^^ invalid.illegal.invalid-escape.lua +-- ^^^ constant.other.range.lua +-- ^ punctuation.separator.sequence.lua +-- ^ punctuation.definition.set.end.lua + +(''):match('[a-c-x]') +-- ^^^ constant.other.range +-- ^^ - constant.other.range + +(''):match('[]-]') +-- ^ punctuation.definition.set.begin.lua +-- ^ - punctuation +-- ^ - constant.other.range +-- ^ punctuation.definition.set.end.lua + +(''):match('[-a-n]') +-- ^ punctuation.definition.set.begin.lua +-- ^ - constant.other.range +-- ^^^ constant.other.range +-- ^ punctuation.definition.set.end.lua + +(''):match('[%-a]') +-- ^ punctuation.definition.set.begin.lua +-- ^^^ - constant.other.range +-- ^ punctuation.definition.set.end.lua + +(''):match('[a-z%-9]') +-- ^^^ - constant.other.range +-- ^ punctuation.definition.set.end.lua + +(''):match('[%--z]') +-- ^^ - comment +-- ^^ constant.character.escape.lua + +(''):match('[a-%z]') +-- ^ punctuation.definition.set.begin.lua +-- ^^^ constant.other.range +-- ^ - constant.other.range +-- ^ punctuation.definition.set.end.lua + +(''):match('[a-%-]') +-- ^ punctuation.definition.set.begin.lua +-- ^^^ constant.other.range +-- ^ - constant.other.range +-- ^ punctuation.definition.set.end.lua + +------------------ +-- Other various tests +------------------ +(''):match[[[]] +-- ^ punctuation.definition.set.begin.lua +-- ^^ punctuation.definition.string.end.lua