Skip to content

Commit 7943b78

Browse files
authored
Merge pull request #51 from anboralabs/language-refactor
Language refactor
2 parents a0fd2c0 + 7c9df72 commit 7943b78

17 files changed

+335
-78
lines changed

build.gradle

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44
id 'java'
55
id 'org.jetbrains.intellij' version '0.6.5'
66
id 'org.jetbrains.kotlin.jvm' version '1.4.10'
7-
id "org.jetbrains.grammarkit" version "2020.2.1"
7+
id "org.jetbrains.grammarkit" version "2020.3.2"
88
}
99

1010
grammarKit {
@@ -13,7 +13,7 @@ grammarKit {
1313
}
1414

1515
group 'co.anbora.labs'
16-
version '2.4.0-SNAPSHOT'
16+
version '2.5.0-SNAPSHOT'
1717

1818
repositories {
1919
mavenCentral()
@@ -61,7 +61,7 @@ sourceSets {
6161

6262
// See https://github.com/JetBrains/gradle-intellij-plugin/
6363
intellij {
64-
version = 'LATEST-EAP-SNAPSHOT'
64+
version = '2020.3.3'
6565
}
6666

6767
tasks.withType(JavaCompile) { options.encoding = 'UTF-8' }
@@ -77,6 +77,12 @@ publishPlugin {
7777
patchPluginXml {
7878
changeNotes """
7979
<ul>
80+
<li><b>2.5.0</b> <em>(2021-03-17)</em> - Added basic code completation</li>
81+
<ul>
82+
<li>Added basic code completation </li>
83+
<li>Fixed issue with access index array </li>
84+
</ul>
85+
</li>
8086
<li><b>2.4.0</b> <em>(2021-02-14)</em> - Added code folding</li>
8187
<ul>
8288
<li>Added code folding </li>

src/main/grammar/FirebaseRules.bnf

Lines changed: 121 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,25 @@
1313
elementTypeClass="co.anbora.labs.firebase.lang.core.psi.FirebaseElementType"
1414
tokenTypeClass="co.anbora.labs.firebase.lang.core.psi.FirebaseTokenType"
1515

16+
extends(".+Expression") = Expression
17+
1618
tokens = [
1719
WHITE_SPACE='WHITE_SPACE'
1820
LP = '('
1921
RP = ')'
2022
LB = '['
2123
RB = ']'
24+
LEFT_BRACE = '{'
25+
RIGHT_BRACE = '}'
2226
number='regexp:\d+(\.\d*)?'
2327
string="regexp:('([^'\\]|\\.)*'|\"([^\"\\]|\\.)*\")"
28+
SLASH = '/'
2429
op = '->'
2530
COLON = ':'
2631
COMMA = ','
2732
EQ = '='
2833
DOT = '.'
34+
DOT_COMMA = ';'
2935
char = 'regexp:[\n\r\u2028\u2029]'
3036
LINE_COMMENT='LINE_COMMENT'
3137
BLOCK_COMMENT='BLOCK_COMMENT'
@@ -34,57 +40,150 @@
3440
}
3541

3642
root ::= !<<eof>> property
43+
{pin=1}
3744

38-
property ::= RuleVersionStatement? (FunctionStatement)* ServiceStatement
45+
private property ::= RuleVersionDef? (FunctionDef)* ServiceDef {
46+
pin=1
47+
}
3948

40-
RuleVersionStatement ::= RULES_VERSION EQ VERSIONS DOT_COMMA
49+
// top-level recovery
50+
private Item_first ::= function | match | service | allow
51+
private Item_recover ::= !('}' | <<eof>> | Item_first)
4152

42-
ServiceStatement ::= SERVICE_KEYWORD SERVICE_NAME ServiceBlock
53+
RuleVersionDef ::= RULES_VERSION EQ VERSIONS DOT_COMMA {
54+
pin=1
55+
}
4356

44-
ServiceBlock ::= LEFT_BRACE (MatchStatement)+ RIGHT_BRACE
57+
//Service Definition Begin
58+
ServiceDef ::= SERVICE_KEYWORD SERVICE_NAME ServiceBlock
59+
{
60+
pin=1
61+
recoverWhile=ServiceDef_recover
62+
}
63+
private ServiceDef_recover ::= !(SERVICE_KEYWORD SERVICE_NAME)
4564

46-
MatchStatement ::= MATCH_KEYWORD FullPathStatement MatchBlock
65+
ServiceBlock ::= LEFT_BRACE ServiceBlockItems RIGHT_BRACE
66+
{
67+
pin=1
68+
}
69+
private ServiceBlockItems ::= !('}' | <<eof>>) ServiceItems+
70+
{
71+
pin=1
72+
recoverWhile=Item_recover
73+
}
74+
private ServiceItems ::= MatchDef | FunctionDef
75+
//Service Definition End
4776

48-
MatchBlock ::= LEFT_BRACE (AllowStatement|MatchStatement|FunctionStatement)+ RIGHT_BRACE
77+
//Match Definition Begin
78+
MatchDef ::= MATCH_KEYWORD FullPathStatement MatchBlock
79+
{
80+
pin=1
81+
}
4982

50-
FullPathStatement ::= (SLASH PathStatement)+
83+
MatchBlock ::= LEFT_BRACE MatchBlockItems RIGHT_BRACE
84+
{
85+
pin=1
86+
}
87+
private MatchBlockItems ::= !('}' | <<eof>>) MatchItems+ {
88+
pin=1
89+
recoverWhile=Item_recover
90+
}
91+
private MatchItems ::= AllowStatement | MatchDef | FunctionDef
92+
93+
FullPathStatement ::= FullPathStatementItem+
94+
{
95+
pin=1
96+
}
97+
98+
private FullPathStatementItem ::= !('{') SLASH PathStatement {
99+
pin=1
100+
recoverWhile=FullPathStatementItem_recover
101+
}
102+
private FullPathStatementItem_recover ::= !(SLASH | '{' | IDENTIFIER | PATH_VARIABLE)
103+
//Match Definition End
51104

52105
PathStatement ::= (IDENTIFIER|PATH_VARIABLE)
53106

107+
//Allow Statement Begin
54108
AllowStatement ::= ALLOW_KEYWORD PermissionStatement COLON ConditionalStatement DOT_COMMA
109+
{
110+
pin=1
111+
}
55112

56-
PermissionKeyWord ::= (GET_KEYWORD|READ_KEYWORD|WRITE_KEYWORD|LIST_KEYWORD
57-
|CREATE_KEYWORD|UPDATE_KEYWORD|DELETE_KEYWORD)
113+
PermissionKeyWord ::= (GET_KEYWORD | READ_KEYWORD | WRITE_KEYWORD | LIST_KEYWORD
114+
| CREATE_KEYWORD | UPDATE_KEYWORD | DELETE_KEYWORD)
58115

59-
PermissionStatement ::= PermissionKeyWord (COMMA PermissionKeyWord)*
116+
PermissionStatement ::= PermissionStatementItem+
117+
{
118+
pin=1
119+
}
120+
private PermissionStatementItem ::= !(':') PermissionKeyWord (',' | &':') {
121+
pin=1
122+
recoverWhile=Permission_recover
123+
}
124+
private Permission_recover ::= !(':' | GET_KEYWORD | READ_KEYWORD | WRITE_KEYWORD | LIST_KEYWORD
125+
| CREATE_KEYWORD | UPDATE_KEYWORD | DELETE_KEYWORD)
60126

61-
ConditionalStatement ::= IF_KEYWORD ConditionalExpression
127+
ConditionalStatement ::= IF_KEYWORD ConditionalExpression {
128+
pin=1
129+
}
62130

63131
ConditionalExpression ::= Expression (BooleanOperator Expression)*
132+
//Allow Statement End
64133

65134
ObjectStatement ::= IDENTIFIER(DOT IDENTIFIER)*
66135

67-
ObjectMethodCallStatement ::= (BuiltInFunctionStatement|ArrayLiteralStatement (DOT IDENTIFIER)*|ObjectStatement)FunctionParameterStatement?
136+
ObjectMethodCallStatement ::= (BuiltInFunctionStatement|ArrayLiteralStatement (DOT IDENTIFIER)*|ObjectStatement)FunctionParameterStatement?ArrayLiteralStatement?
68137

69138
CallFunctionStatement ::= ObjectMethodCallStatement (DOT ObjectMethodCallStatement)*
70139

71-
FunctionDeclarationStatement ::= IDENTIFIER FunctionParameterStatement
72-
73-
FunctionParameterStatement ::= LP ParameterStatement? RP
74-
75-
ParameterStatement ::= Expression(COMMA Expression)*
76-
77140
FullBuiltInParameterStatement ::= (SLASH PathBuiltInParameterStatement)+
78141

79142
PathBuiltInParameterStatement ::= (IDENTIFIER|PATH_BUILT_IN)
80143

81144
BuiltInFunctionStatement ::= (GET_KEYWORD|EXITS_KEYWORD)
82145

83-
FunctionStatement ::= FUNCTION_KEYWORD FunctionDeclarationStatement FunctionBlock
146+
//Function Definition Begin
147+
FunctionDef ::= FUNCTION_KEYWORD IDENTIFIER FunctionParameterList FunctionBlock
148+
{
149+
pin=1
150+
}
84151

85-
FunctionBlock ::= LEFT_BRACE (VariableStatement*) ReturnStatement RIGHT_BRACE
152+
FunctionParameterList ::= '(' FunctionParameter_with_recover* ')'
153+
{
154+
pin = 1
155+
}
156+
157+
private FunctionParameter_with_recover ::= !(')' | '{' | ';') FunctionParameter (',' | &')')
158+
{
159+
pin = 1
160+
recoverWhile = FunctionParameter_recover
161+
}
162+
private FunctionParameter_recover ::= !(')' | '{' | ';' | IDENTIFIER)
86163

87-
ReturnStatement ::= RETURN_KEYWORD ConditionalExpression DOT_COMMA
164+
FunctionParameter ::= IDENTIFIER
165+
{
166+
pin = 1
167+
}
168+
169+
FunctionBlock ::= LEFT_BRACE FunctionBlockItems RIGHT_BRACE
170+
{
171+
pin = 1
172+
}
173+
private FunctionBlockItems ::= !('}' | <<eof>>) VariableStatement* ReturnStatement
174+
{
175+
pin = 1
176+
recoverWhile = Item_recover
177+
}
178+
//Function Definition Ends
179+
180+
FunctionParameterStatement ::= LP ParameterStatement? RP
181+
182+
ParameterStatement ::= Expression(COMMA Expression)*
183+
184+
ReturnStatement ::= RETURN_KEYWORD ConditionalExpression DOT_COMMA {
185+
pin=1
186+
}
88187

89188
Expression ::= BooleanStatement
90189
| CallFunctionStatement
@@ -95,6 +194,7 @@ Expression ::= BooleanStatement
95194
| ParenthesizedExpression
96195
| NegatedExpression
97196
| FullBuiltInParameterStatement
197+
{ name="expr" }
98198

99199
ParenthesizedExpression ::=
100200
LP ConditionalExpression RP

src/main/kotlin/co/anbora/labs/firebase/ide/formatter/processor.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package co.anbora.labs.firebase.ide.formatter
22

3-
import co.anbora.labs.firebase.lang.core.FirebaseRulesLanguage
3+
import co.anbora.labs.firebase.lang.FirebaseRulesLanguage
44
import co.anbora.labs.firebase.lang.core.psi.FirebaseRulesTypes.*
55
import com.intellij.formatting.*
66
import com.intellij.lang.ASTNode
@@ -69,9 +69,9 @@ fun ASTNode.isBetweenBraces(): Boolean {
6969

7070
fun ASTNode.isComposeBlock(): Boolean {
7171
val elementType: IElementType = this.elementType
72-
return elementType == SERVICE_STATEMENT ||
73-
elementType == MATCH_STATEMENT ||
74-
elementType == FUNCTION_STATEMENT
72+
return elementType == SERVICE_DEF ||
73+
elementType == MATCH_DEF ||
74+
elementType == FUNCTION_DEF
7575
}
7676

7777
fun ASTNode?.isWhitespaceOrEmpty() = this == null || textLength == 0 || elementType == TokenType.WHITE_SPACE
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
package co.anbora.labs.firebase.lang.core
1+
package co.anbora.labs.firebase.lang
22

33
import co.anbora.labs.firebase.ide.icons.FirebaseIcons
4-
import com.intellij.lang.Language
54
import com.intellij.openapi.fileTypes.LanguageFileType
65
import javax.swing.Icon
76

8-
object FirebaseRulesLanguage: Language("firebase_rules")
9-
107
object FirebaseFileType: LanguageFileType(FirebaseRulesLanguage) {
118

129
const val EXTENSION = "rules"
@@ -19,4 +16,4 @@ object FirebaseFileType: LanguageFileType(FirebaseRulesLanguage) {
1916

2017
override fun getIcon(): Icon = FirebaseIcons.FILE
2118

22-
}
19+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package co.anbora.labs.firebase.lang
2+
3+
import com.intellij.lang.Language
4+
5+
object FirebaseRulesLanguage: Language("firebase_rules")
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package co.anbora.labs.firebase.lang.core
2+
3+
import co.anbora.labs.firebase.lang.core.psi.*
4+
import com.intellij.patterns.PatternCondition
5+
import com.intellij.patterns.PlatformPatterns
6+
import com.intellij.patterns.PsiElementPattern
7+
import com.intellij.patterns.StandardPatterns
8+
import com.intellij.psi.PsiComment
9+
import com.intellij.psi.PsiElement
10+
import com.intellij.psi.PsiErrorElement
11+
import com.intellij.psi.PsiWhiteSpace
12+
import com.intellij.psi.util.PsiTreeUtil
13+
import com.intellij.util.ProcessingContext
14+
15+
object FirebasePsiPatterns {
16+
17+
fun onStatementBeginning(vararg startWords: String): PsiElementPattern.Capture<PsiElement> =
18+
PlatformPatterns.psiElement().with(OnStatementBeginning(*startWords))
19+
20+
fun toplevel(): PsiElementPattern.Capture<PsiElement> =
21+
psiElementWithParent<FirebaseFile>()
22+
23+
fun serviceStatement(): PsiElementPattern.Capture<PsiElement> =
24+
psiElementWithParent<FirebaseRulesServiceDef>()
25+
26+
fun pathStatement(): PsiElementPattern.Capture<PsiElement> =
27+
psiElementWithParent<FirebaseRulesPathStatement>()
28+
29+
fun permissionStatement(): PsiElementPattern.Capture<PsiElement> =
30+
psiElementWithParent<FirebaseRulesPermissionStatement>()
31+
32+
fun allowStatement(): PsiElementPattern.Capture<PsiElement> =
33+
psiElementWithParent<FirebaseRulesAllowStatement>()
34+
35+
inline fun <reified I : PsiElement> psiElementWithParent() =
36+
PlatformPatterns.psiElement().withParent(
37+
StandardPatterns.or(
38+
psiElement<I>(),
39+
psiElement<PsiErrorElement>().withParent(psiElement<I>())
40+
)
41+
)
42+
43+
inline fun <reified I : PsiElement> psiElementWithAncestor() =
44+
PlatformPatterns.psiElement().withAncestor(0,
45+
StandardPatterns.or(
46+
psiElement<I>(),
47+
psiElement<PsiErrorElement>().withAncestor(0, psiElement<I>())
48+
)
49+
)
50+
51+
inline fun <reified I : PsiElement> psiElementInside() =
52+
PlatformPatterns.psiElement().inside(
53+
StandardPatterns.or(
54+
psiElement<I>(),
55+
psiElement<PsiErrorElement>().withParent(psiElement<I>())
56+
)
57+
)
58+
59+
60+
private class OnStatementBeginning(vararg startWords: String) :
61+
PatternCondition<PsiElement>("on statement beginning") {
62+
val myStartWords = startWords
63+
override fun accepts(t: PsiElement, context: ProcessingContext?): Boolean {
64+
val prev = t.prevVisibleOrNewLine
65+
return if (myStartWords.isEmpty())
66+
prev == null || prev is PsiWhiteSpace
67+
else {
68+
prev != null && prev.node.text in myStartWords
69+
}
70+
}
71+
}
72+
}
73+
74+
val PsiElement.leftLeaves: Sequence<PsiElement>
75+
get() {
76+
return generateSequence(this, PsiTreeUtil::prevLeaf).drop(1)
77+
}
78+
79+
private val PsiElement.prevVisibleOrNewLine: PsiElement?
80+
get() {
81+
return leftLeaves
82+
.filterNot { it is PsiComment || it is PsiErrorElement }
83+
.filter { it !is PsiWhiteSpace || it.textContains('\n') }
84+
.firstOrNull()
85+
86+
}
87+
88+
inline fun <reified I : PsiElement> psiElement(): PsiElementPattern.Capture<I> {
89+
return PlatformPatterns.psiElement(I::class.java)
90+
}

0 commit comments

Comments
 (0)