diff --git a/Python/Python.sublime-syntax b/Python/Python.sublime-syntax index ee9400c416..35ee5c01b0 100644 --- a/Python/Python.sublime-syntax +++ b/Python/Python.sublime-syntax @@ -411,12 +411,136 @@ contexts: pop: true comments: + # Type-ignore can only be used by itself. + - match: '(#)\s*(type)(:)\s*(ignore)\b' + scope: comment.line.type-hint.python + captures: + 1: punctuation.definition.comment.python + 2: keyword.other.annotation.type-comment.python + 3: punctuation.separator.annotation.type-comment.python + 4: keyword.other.annotation.type-comment.ignore.python + push: comments-afterignore + - match: '(#)\s*(type)(:)' + scope: comment.line.type-hint.python + captures: + 1: punctuation.definition.comment.python + 2: keyword.other.annotation.type-comment.python + 3: punctuation.separator.annotation.type-comment.python + push: type-comment - match: "#" scope: punctuation.definition.comment.python - push: - - meta_scope: comment.line.number-sign.python + push: comments-basic-remainder + + comments-basic: + - match: "#" + scope: punctuation.definition.comment.python + set: comments-basic-remainder + + comments-basic-remainder: + - meta_scope: comment.line.number-sign.python + - match: \n + pop: true + + comments-afterignore: + - meta_content_scope: comment.line.type-hint.python + - match: \n + pop: true + - match: '(?=#)' + set: comments-basic + - match: \[ + # Mypy's # type: ignore[error-code1, error-code2] + scope: punctuation.section.brackets.begin.python + set: + - meta_content_scope: comment.line.type-hint.python - match: \n pop: true + - match: \[ + scope: invalid.illegal.python + - match: '[a-zA-Z_-][a-zA-Z_0-9-]+' + scope: constant.other.error-code.python + - match: '[0-9]\w*' + scope: invalid.illegal.python + - match: ',' + scope: punctuation.separator.sequence.python + - match: \] + scope: punctuation.section.brackets.end.python + set: + # Don't allow a second block. + - meta_content_scope: comment.line.type-hint.python + - match: \n + pop: true + - match: '(?=#)' + set: comments-basic + - match: \S + scope: invalid.illegal.python + - match: \S + scope: invalid.illegal.python + + type-comment: + - meta_content_scope: comment.line.type-hint.python + - match: \n + pop: true + - match: '(?=#)' + set: comments-basic + # Don't use expressions here, only a few types are reasonable + # as annotations. + - include: constants + - include: builtin-exceptions + - include: builtin-types + - include: builtin-functions + - match: '{{identifier}}' + scope: support.class.python + - match: '\s*(\[)' + captures: + 1: meta.item-access.python punctuation.section.brackets.begin.python + push: + - meta_content_scope: meta.item-access.arguments.python + - match: (?=\n) + pop: true + - match: \] + scope: meta.item-access.python punctuation.section.brackets.end.python + pop: true + - match: ':' + scope: punctuation.separator.slice.python + - match: '(?=#)' + - include: type-comment + - match: '\(' + scope: punctuation.section.parens.begin.python + push: + - meta_content_scope: meta.function.parameters.python + - match: (?=\n) + pop: true + - match: \) + scope: punctuation.section.parens.end.python + pop: true + - match: \( + scope: invalid.illegal.stray.brace.round.python + - match: \*{3,} + scope: invalid.illegal.syntax.python + - match: \*\* + scope: keyword.operator.unpacking.mapping.python + - match: \* + scope: keyword.operator.unpacking.sequence.python + - match: '->' + scope: invalid.illegal.stray.return.arrow.python + - include: type-comment + - match: '->' + scope: meta.function.return-type.python punctuation.separator.sequence.python + set: + - meta_content_scope: comment.line.type-hint.python meta.function.return-type.python + - match: '->' + scope: invalid.illegal.stray.return.arrow.python + - include: type-comment + - match: ',' + scope: punctuation.separator.sequence.python + - match: \) + scope: invalid.illegal.stray.brace.round.python + - match: \] + scope: invalid.illegal.stray.brace.square.python + - match: \} + scope: invalid.illegal.stray.brace.curly.python + - match: \S + scope: invalid.illegal.python constants: - match: \b(None|True|False|Ellipsis|NotImplemented|__debug__)\b diff --git a/Python/syntax_test_python.py b/Python/syntax_test_python.py index b33335f30b..ce95391287 100644 --- a/Python/syntax_test_python.py +++ b/Python/syntax_test_python.py @@ -1487,6 +1487,95 @@ class Starship: # ^ punctuation.separator.annotation.variable.python # ^ keyword.operator.assignment +# Type comments - type: ignore must be by itself. + +primes = 5 # type: ignore # type: not-a-type-comment +# ^^^^^^^^^^^^^^^ comment.line.type-hint - comment.line.number-sign +# ^ punctuation.definition.comment +# ^^^^ keyword.other.annotation.type-comment +# ^ punctuation.separator.annotation.type-comment +# ^^^^^^ keyword.other.annotation.type-comment.ignore +# ^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.number-sign - comment.line.type-hint +# ^ punctuation.definition.comment + +# This is not a type-ignore comment. +value = 3 # type: ignore_class_starting_with_ignore +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.type-hint - comment.line.number-sign +# ^ punctuation.definition.comment +# ^^^^ keyword.other.annotation.type-comment +# ^ punctuation.separator.annotation.type-comment +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ support.class + +# Mypy ignore extension +value = 3 # type: ignore[error-code-1, 4noint][error] # foo +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.type-hint - comment.line.number-sign +# ^^^^^^ keyword.other.annotation.type-comment.ignore +# ^ punctuation.section.brackets.begin +# ^^^^^^^^^^^^ constant.other.error-code +# ^ punctuation.separator.sequence +# ^^^^^^ invalid.illegal +# ^ punctuation.section.brackets.end +# ^^^^^^^ invalid.illegal +# ^^^^^ comment.line.number-sign - comment.line.type-hint + +# With/for allow commas +for a, b in lst: # type: (str, int) +# ^ comment.line.type-hint punctuation.separator.sequence + + +primes = 5 # type: List[Dict[property:str, ...]] # comment +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.type-hint - comment.line.number-sign +# ^ punctuation.definition.comment +# ^^^^ keyword.other.annotation.type-comment +# ^ punctuation.separator.annotation.type-comment +# ^^^^ support.class +# ^^^^^^^^^^^^^^^^^^^^^^^^^ meta.item-access +# ^punctuation.section.brackets.begin +# ^^^^^^^^^^^^^^^^^^^^^^^ meta.item-access.arguments +# ^^^^ support.class +# ^ meta.item-access punctuation.section.brackets.begin +# ^^^^^^^^ support.function.builtin +# ^ punctuation.separator.slice +# ^^^ support.type +# ^ punctuation.separator.sequence +# ^^^ constant.language +# ^ punctuation.section.brackets.end +# ^ punctuation.section.brackets.end +# ^^^^^^^^^^ comment.line.number-sign +# ^ punctuation.definition.comment + +# Python 2.7 function annotations. +def function(a, b, *c, **d): + # type: (int, str, List[str], bool) -> Dict[str, str] # type: noncomment +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ comment.line.type-hint +# ^ punctuation.section.parens.begin +# ^^^ meta.function.parameters support.type +# ^ meta.function.parameters punctuation.separator.sequence +# ^^^^ meta.function.parameters support.class +# ^^^^ meta.function.parameters support.type +# ^ punctuation.section.parens.end +# ^^^^^^^^^^^^^^^^^^ meta.function.return-type +# ^^ punctuation.separator.sequence +# ^^^^ support.class +# ^^^^^^^^^^^^^^^^^^ comment.line.number-sign - comment.line.type-hint +# ^ punctuation.definition.comment + +class TypeCommentTest: + member = [] # type: List[dict] + + def __del__(self) -> None: +# ^^^^ constant.language +# ^ punctuation.section + pass +# ^^^^ keyword.control + +class TypeCommentTest2: + member = [] # type: List[dict] + + def __del__(self) -> None: + pass +# ^^^^ keyword.control + ################## # Assignment Expressions