Skip to content

Commit 9595525

Browse files
Dave Bartolomeoaeisenberg
authored andcommitted
Fix highlighting after disembodied IPA branch
Fixes #543 ```ql newtype TA = TB() private predicate foo() { any() } ``` Our TextMate grammar didn't realize that the newtype declaration ended after the closing paren of the branch's parameter list, so the `private` modifier was highlighted incorrectly. It's surprisingly tricky to get TextMate to handle this correctly, so I wound up just treating the IPA declaration head (`newtype TA`), the branch head (`= TB`), the branch parameter list, and the branch body as directly children of the module body. This is kind of hacky, but it does fix the bug without introducing any new cases where we have incorrect highlighting of valid code.
1 parent 16fab7f commit 9595525

File tree

1 file changed

+53
-22
lines changed

1 file changed

+53
-22
lines changed

extensions/ql-vscode/syntaxes/ql.tmLanguage.yml

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ repository:
9999
comment-start:
100100
match: '// | /\*'
101101

102+
# A pattern that can start a run of whitespace or a comment.
103+
# Commonly used as a negative lookahead in the `end` regex of a nonterminal, when searching for
104+
# tokens that can't start a child of that nonterminal.
105+
whitespace-or-comment-start:
106+
match: '\s | $ | (?#comment-start)'
107+
102108
# All tokens that can appear in any context.
103109
non-context-sensitive:
104110
patterns:
@@ -113,7 +119,7 @@ repository:
113119
name: keyword.operator.relational.ql
114120

115121
comparison-operator:
116-
match: '=|\!-'
122+
match: '=|\!\='
117123
name: keyword.operator.comparison.ql
118124

119125
arithmetic-operator:
@@ -610,6 +616,12 @@ repository:
610616
- include: '#import-directive'
611617
- include: '#import-as-clause'
612618
- include: '#module-declaration'
619+
- include: '#newtype-declaration'
620+
# See the comment on newtype-declaration for why we include these next three nonterminals at the
621+
# module-member level instead of as part of the newtype-declaration.
622+
- include: '#newtype-branch-name-with-prefix'
623+
- include: '#predicate-parameter-list'
624+
- include: '#predicate-body'
613625
- include: '#class-declaration'
614626
- include: '#select-clause'
615627
- include: '#predicate-or-field-declaration'
@@ -781,7 +793,7 @@ repository:
781793
bindingset-annotation:
782794
beginPattern: '#bindingset'
783795
# Ends after the next `]`, or when we encounter something other than a `[`.
784-
end: '(?! \s | (?#comment-start) | \[ ) |
796+
end: '(?! (?#whitespace-or-comment-start) | \[ ) |
785797
(?<=\])'
786798
name: meta.block.bindingset-annotation.ql
787799
patterns:
@@ -802,7 +814,7 @@ repository:
802814
language-annotation:
803815
beginPattern: '#language'
804816
# Ends after the next `]`, or when we encounter something other than a `[`.
805-
end: '(?! \s | (?#comment-start) | \[ ) |
817+
end: '(?! (?#whitespace-or-comment-start) | \[ ) |
806818
(?<=\])'
807819
name: meta.block.language-annotation.ql
808820
patterns:
@@ -824,7 +836,7 @@ repository:
824836
pragma-annotation:
825837
beginPattern: '#pragma'
826838
# Ends after the next `]`, or when we encounter something other than a `[`.
827-
end: '(?! \s | (?#comment-start) | \[ ) |
839+
end: '(?! (?#whitespace-or-comment-start) | \[ ) |
828840
(?<=\])'
829841
name: meta.block.pragma-annotation.ql
830842
patterns:
@@ -841,34 +853,53 @@ repository:
841853
name: storage.modifier.ql
842854

843855
# The declaration of an IPA type.
856+
# This only includes the `newtype` keyword and the identifier for the IPA type itself. The
857+
# branches of the IPA type are modeled as separate nonterminals contained directly in the module
858+
# body. This is kind of hacky, but without it, we don't seem to have a way to get TextMate to
859+
# handle this:
860+
# ```ql
861+
# newtype TRoot =
862+
# TBranch1(int x) {
863+
# x = 5
864+
# } or
865+
# TBranch2() // No body
866+
#
867+
# TOther getOther() { any() }
868+
# ```
869+
# If the branches are within the newtype declaration node, it's very hard to get the upper-id for
870+
# the name of the IPA type to be included in the newtype declaration node, without also including
871+
# the `TOther` upper-id in the declaration node.
844872
newtype-declaration:
845873
beginPattern: '#newtype'
846-
# Ends when we see something other than one of:
847-
# - An upper-id (branch name)
848-
# - A comment
849-
# - Whitespace
850-
# - `=`
851-
# - `(`
852-
end: '(?! \s | (?#upper-id) | (?#comment-start) | \= | \( )'
853-
name: meta.block.newtype.ql
874+
# We're expecting a newtype-declaration-without-keyword immediately after the `newtype` keyword,
875+
# so end if we see anything other than the upper-id that starts it, or whitespace, or a comment.
876+
# An upper-id can't start anything else at module scope, so once we see the rest of this
877+
# newtype-declaration, whatever comes next should end this block.
878+
end: '(?#upper-id)'
879+
endCaptures:
880+
'0':
881+
name: entity.name.type.ql
882+
name: meta.block.newtype-declaration.ql
854883
patterns:
855884
- include: '#non-context-sensitive'
856-
- include: '#newtype-branch'
857885

858-
# The branch of an IPA type.
859-
newtype-branch:
860-
begin: '(?#upper-id)'
886+
# A branch of an IPA type, including just the `=` or `or` prefix and the name of the branch.
887+
# The parameter list and body are separate nonterminals contained directly within the module body.
888+
# See the comment for newtype-declaration for why.
889+
newtype-branch-name-with-prefix:
890+
begin: '\= | (?#or)'
861891
beginCaptures:
892+
'0':
893+
patterns:
894+
- include: '#or'
895+
- include: '#comparison-operator'
896+
end: '(?#upper-id)'
897+
endCaptures:
862898
'0':
863899
name: entity.name.type.ql
864-
# Ends after a `}`, or when we encounter something other than a `{`.
865-
end: '(?<=\}) | (?! \s | (?#comment-start) | \{ )'
866-
name: meta.block.newtype-branch.ql
900+
name: meta.block.newtype-branch-name-with-prefix.ql
867901
patterns:
868-
- include: '#predicate-body'
869902
- include: '#non-context-sensitive'
870-
- match: '(?#upper-id)'
871-
name: entity.name.type.ql
872903

873904
# The declaration of a class, include an alias.
874905
class-declaration:

0 commit comments

Comments
 (0)