Skip to content

Commit

Permalink
Support Tact 1.3.0, closes #177
Browse files Browse the repository at this point in the history
  • Loading branch information
andreypfau committed Jul 10, 2024
1 parent 0803c2e commit bd33263
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 29 deletions.
30 changes: 28 additions & 2 deletions src/main/grammar/TactLexer.flex
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import static org.ton.intellij.tact.psi.TactElementTypes.*;

%s IN_BLOCK_COMMENT
%s IN_NAME_ATTRIBUTE
%s STRING

%unicode

Expand All @@ -78,13 +79,27 @@ INTEGER_LITERAL_HEX = 0[xX] {HEX_DIGIT} (_?{HEX_DIGIT})*
INTEGER_LITERAL_BIN = 0[bB] {BIN_DIGIT} (_?{BIN_DIGIT})*
INTEGER_LITERAL_OCT = 0[oO] {OCT_DIGIT} (_?{OCT_DIGIT})*
INTEGER_LITERAL= {INTEGER_LITERAL_HEX} | {INTEGER_LITERAL_BIN} | {INTEGER_LITERAL_OCT} | {INTEGER_LITERAL_DEC}
STRING_LITERAL=(\"([^\"\r\n\\]|\\.)*\")
IDENTIFIER=[a-zA-Z_][a-zA-Z0-9_]*
FUNC_IDENTIFIER=[a-zA-Z_][a-zA-Z0-9_?!:&']*

REGULAR_STRING_PART=[^\\\"]+
ESCAPE_SEQUENCE=\\\\ // backslash
| \\\" // double quote
| \\n // newline
| \\r // carriage return
| \\t // tab
| \\v // vertical tab
| \\b // backspace
| \\f // form feed
| \\u\{ {HEX_DIGIT} {HEX_DIGIT}? {HEX_DIGIT}? {HEX_DIGIT}? {HEX_DIGIT}? {HEX_DIGIT}? \} // unicode escape
| \\u {HEX_DIGIT} {HEX_DIGIT} {HEX_DIGIT} {HEX_DIGIT} // hex escape
| \\x {HEX_DIGIT} {HEX_DIGIT} // hex escape
| \\[^\n] // any other character

%%
<YYINITIAL> {
{WHITE_SPACE} { return WHITE_SPACE; }
\" { yybegin(STRING); return OPEN_QUOTE; }

"/*" { yybegin(IN_BLOCK_COMMENT); yypushback(2); }
"//".* { return LINE_COMMENT; }
Expand Down Expand Up @@ -118,6 +133,7 @@ FUNC_IDENTIFIER=[a-zA-Z_][a-zA-Z0-9_?!:&']*
"=" { return EQ; }
"?" { return Q; }
"!" { return EXCL; }
"~" { return TILDE; }
"+=" { return PLUSLET; }
"-=" { return MINUSLET; }
"*=" { return TIMESLET; }
Expand Down Expand Up @@ -165,14 +181,17 @@ FUNC_IDENTIFIER=[a-zA-Z_][a-zA-Z0-9_?!:&']*
"primitive" { return PRIMITIVE_KEYWORD; }
"self" { return SELF_KEYWORD; }
"map" { return MAP_KEYWORD; }
"try" { return TRY_KEYWORD; }
"catch" { return CATCH_KEYWORD; }
"foreach" { return FOREACH_KEYWORD; }
"in" { return IN_KEYWORD; }
"bounced" { return zzBlockDepth == 1 && zzContractScope ? BOUNCED_KEYWORD : IDENTIFIER; }
"init" { return zzBlockDepth == 1 && zzParenDepth == 0 ? INIT_KEYWORD : IDENTIFIER; }
"get" { return zzBlockDepth <= 1 ? GET_KEYWORD : IDENTIFIER; }
"@interface" { return INTERFACE_MACRO; }
"@name" { yybegin(IN_NAME_ATTRIBUTE); yypushback(5); }

{INTEGER_LITERAL} { return INTEGER_LITERAL; }
{STRING_LITERAL} { return STRING_LITERAL; }
{IDENTIFIER} { return IDENTIFIER; }
}

Expand All @@ -190,6 +209,13 @@ FUNC_IDENTIFIER=[a-zA-Z_][a-zA-Z0-9_?!:&']*
[^] { }
}

<STRING> {
{REGULAR_STRING_PART} { return REGULAR_STRING_PART; }
{ESCAPE_SEQUENCE} { return ESCAPE_SEQUENCE; }
\" { yybegin(YYINITIAL); return CLOSE_QUOTE; }
[^] { yybegin(YYINITIAL); yypushback(1); }
}

<IN_NAME_ATTRIBUTE> {
"@name" { return NAME_MACRO; }
"(" { zzParenDepth++; return LPAREN; }
Expand Down
63 changes: 42 additions & 21 deletions src/main/grammar/TactParser.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
EQ = '='
Q = '?'
EXCL = '!'
TILDE = '~'

EQEQ = '=='
EXCLEQ = '!='
Expand Down Expand Up @@ -97,19 +98,27 @@
GET_KEYWORD = 'get'
SELF_KEYWORD = 'self'
BOUNCED_KEYWORD = 'bounced'
TRY_KEYWORD = 'try'
CATCH_KEYWORD = 'catch'
FOREACH_KEYWORD = 'foreach'
IN_KEYWORD = 'in'

INTERFACE_MACRO = '@interface'
NAME_MACRO = '@name'

ESCAPE_SEQUENCE = 'regexp:\\\\.'
WHITE_SPACE = 'regexp:\s+'
INTEGER_LITERAL = 'regexp:(0[xX][0-9a-fA-F][0-9a-fA-F_]*\b)|(\b[0-9_]+\b)'
STRING_LITERAL = 'regexp:(\"([^\"\r\n\\]|\\.)*\")'
STRING_PART = 'regexp:(\"([^\"\r\n\\]|\\.)*\")'
BOOLEAN_LITERAL = 'regexp:(true|false)'
NULL_LITERAL = 'null'
IDENTIFIER = 'regexp:\p{Alpha}\w*'
FUNC_IDENTIFIER = 'regexp:\p{Alpha}\w*'
BLOCK_COMMENT = 'regexp:/\*(\*(?!/)|[^*])*\*/'
LINE_COMMENT = 'regexp://(.*)'
OPEN_QUOTE = 'regexp:"'
CLOSE_QUOTE = 'regexp:"'
REGULAR_STRING_PART = 'regexp:([^"\r\n\\]|\\.)*'
]
}

Expand All @@ -130,7 +139,10 @@ private RootItem_recover ::= !Item_first

private Item_first ::= 'import' | 'struct' | 'message' | '@interface' | 'contract' | 'trait' | 'get' | 'mutates' | 'extends' | 'virtual' | 'override' | 'inline' | 'abstract' | 'fun' | '@name' | 'native' | 'const' | 'receive' | 'bounced' | 'external'

Import ::= 'import' STRING_LITERAL ';' {pin=1}
Import ::= 'import' StringLiteral ';' {pin=1}

StringLiteral ::= OPEN_QUOTE StringLiteralPart* CLOSE_QUOTE
StringLiteralPart ::= REGULAR_STRING_PART | ESCAPE_SEQUENCE

Primitive ::= 'primitive' IDENTIFIER !'?' ';' {
pin=2
Expand All @@ -150,7 +162,7 @@ ReferencedType ::= IDENTIFIER '?'? {
mixin = "org.ton.intellij.tact.psi.impl.TactReferencedTypeImplMixin"
}

BouncedType ::= 'bounced' '<' <<comma_separated_list ReferencedType>> '>' {pin=1}
BouncedType ::= 'bounced' '<' ReferencedType '>' {pin=1}
MapType ::= 'map' '<' MapTypeItem ',' MapTypeItem '>' {
pin=1
}
Expand Down Expand Up @@ -216,7 +228,7 @@ MessageId ::= '(' INTEGER_LITERAL ')' {
BlockFields ::= '{' Field* '}' {pin=1}

// Contract
WithClause ::= 'with' <<comma_separated_list Type>> {pin=1}
WithClause ::= 'with' <<trailing_comma_separated_list Type>> {pin=1}
Contract ::= ContractAttribute* 'contract' IDENTIFIER WithClause? ContractBody {
pin = 2
implements = [
Expand Down Expand Up @@ -293,7 +305,7 @@ NameAttribute ::= '@name' '(' FUNC_IDENTIFIER ')' {
pin=1
}

FunctionParameters ::= '(' [ (SelfParameter ',' <<comma_separated_list FunctionParameter>>) | (SelfParameter) | <<comma_separated_list FunctionParameter>> ] ')' {pin=1}
FunctionParameters ::= '(' [ (SelfParameter ',' <<trailing_comma_separated_list FunctionParameter>>) | (SelfParameter ','?) | <<trailing_comma_separated_list FunctionParameter>> ] ')' {pin=1}
FunctionParameter ::= IDENTIFIER TypeAscription {
pin=1
implements=[
Expand Down Expand Up @@ -326,7 +338,7 @@ ExternalFunction ::= 'external' (StringId|FunctionParameters) Block {
]
mixin="org.ton.intellij.tact.psi.impl.TactExternalFunctionImplMixin"
}
StringId ::= '(' STRING_LITERAL ')' {pin=2}
StringId ::= '(' StringLiteral ')' {pin=2}

// Statements
Statement ::= AssignStatement
Expand All @@ -337,7 +349,10 @@ Statement ::= AssignStatement
| ConditionStatement
| WhileStatement
| RepeatStatement
| UntilStatement {
| UntilStatement
| TryStatement
| ForEachStatement
{
// extends = 'org.ton.intellij.tact.psi.TactStubbedElementImpl<?>'
// stubClass = "com.intellij.psi.stubs.StubBase<?>"
}
Expand Down Expand Up @@ -380,6 +395,9 @@ ElseBranch ::= 'else' (Block | ConditionStatement) {pin=1}
WhileStatement ::= 'while' Condition Block {pin=1}
RepeatStatement ::= 'repeat' Condition Block {pin=1}
UntilStatement ::= 'do' Block 'until' Condition ';' {pin=1}
TryStatement ::= 'try' Block CatchClause? {pin=1}
CatchClause ::= 'catch' '(' IDENTIFIER ')' Block {pin=1}
ForEachStatement ::= 'foreach' '(' IDENTIFIER ',' IDENTIFIER 'in' Expression ')' Block {pin=1}

Condition ::= '(' Expression ')' {
pin=1
Expand All @@ -389,21 +407,22 @@ Condition ::= '(' Expression ')' {
Expression ::= TernaryExpression
| BoolOrBinExpression
| BoolAndBinExpression
| BitOrBinExpression
| BitXorBinExpression
| BitAndBinExpression
| CompBinExpression
| RelCompBinExpression
| BitShiftBinExpression
| BitAndBinExpression
| BitOrBinExpression
| AddBinExpression
| MulBinExpression
| UnaryExpression
| NotNullExpression
| DotExpression
| CallExpression
| ParenExpression
| StructExpression
| IntegerExpression
| BooleanExpression
| CallExpression
| ReferenceExpression !'('
| NullExpression
| SelfExpression
Expand All @@ -412,7 +431,7 @@ Expression ::= TernaryExpression
// extends = 'org.ton.intellij.tact.psi.TactStubbedElementImpl<?>'
// stubClass = "com.intellij.psi.stubs.StubBase<?>"
}
private Expression_first ::= '-' | '+' | '!' | IDENTIFIER | '(' | INTEGER_LITERAL | BOOLEAN_LITERAL | 'null' | 'intOf' | STRING_LITERAL
private Expression_first ::= '-' | '+' | '!' | IDENTIFIER | '(' | INTEGER_LITERAL | 'null' | 'intOf' | StringLiteral

TernaryExpression ::= Expression '?' Expression ':' Expression {
pin=2
Expand All @@ -439,11 +458,12 @@ fake BinOp ::= '||' | '&&'

BoolOrBinExpression ::= Expression BoolOrBinOp Expression
BoolAndBinExpression ::= Expression BoolAndBinOp Expression
BitOrBinExpression ::= Expression BitOrBinOp Expression
BitXorBinExpression ::= Expression BitXorBinOp Expression
BitAndBinExpression ::= Expression BitAndBinOp Expression
CompBinExpression ::= Expression CompBinOp Expression
RelCompBinExpression ::= Expression RelCompBinOp Expression
BitShiftBinExpression ::= Expression BitShiftBinOp Expression
BitAndBinExpression ::= Expression BitAndBinOp Expression
BitOrBinExpression ::= Expression BitOrBinOp Expression
AddBinExpression ::= Expression AddBinOp Expression
MulBinExpression ::= Expression MulBinOp Expression

Expand All @@ -454,17 +474,18 @@ RelCompBinOp ::= '>' | '>=' | '<' | '<=' { name = "operator" }
BitShiftBinOp ::= '>>' | '<<' { name = "operator" }
BitAndBinOp ::= '&' { name = "operator" }
BitOrBinOp ::= '|' { name = "operator" }
BitXorBinOp ::= '^' { name = "operator" }
AddBinOp ::= ('+' !'+') | ('-' !'-') { name = "operator" }
MulBinOp ::= '*' | '/' | '%' { name = "operator" }

UnaryExpression ::= ('-'|'+'|'!') Expression
UnaryExpression ::= ('-'|'+'|'!'|'~') Expression
NotNullExpression ::= Expression '!!'

DotExpression ::= Expression '.' CallOrField
private CallOrField ::= () (CallExpression | FieldExpression) {
pin=1
}
CallExpression ::= IDENTIFIER '(' [<<comma_separated_list Expression>>] ')' {
CallExpression ::= IDENTIFIER '(' [<<trailing_comma_separated_list Expression>>] ')' {
pin=2
mixin="org.ton.intellij.tact.psi.impl.TactCallExpressionImplMixin"
}
Expand All @@ -473,15 +494,14 @@ FieldExpression ::= IDENTIFIER !'(' {
mixin="org.ton.intellij.tact.psi.impl.TactFieldExpressionImplMixin"
}

StaticCallExpression ::= IDENTIFIER '(' [<<comma_separated_list Expression>>] ')'
ParenExpression ::= '(' ParenExpressionItem ')' {pin=1}
private ParenExpressionItem ::= Expression

StructExpression ::= IDENTIFIER '{' [<<comma_separated_list StructExpressionField_with_recover>>] '}' {
StructExpression ::= IDENTIFIER '{' [<<trailing_comma_separated_list StructExpressionField_with_recover>>] '}' {
pin=2
mixin = "org.ton.intellij.tact.psi.impl.TactStructExpressionImplMixin"
}
StructExpressionField ::= IDENTIFIER ':' Expression {pin=1}
StructExpressionField ::= IDENTIFIER (':' Expression)? {pin=1}
private StructExpressionField_with_recover ::= !('}') StructExpressionField {
pin=1
// recoverWhile=StructExpressionField_recover
Expand All @@ -496,10 +516,11 @@ ReferenceExpression ::= IDENTIFIER {
}
NullExpression ::= 'null'
SelfExpression ::= 'self'
InitOfExpression ::= 'initOf' IDENTIFIER '(' [<<comma_separated_list Expression>>] ')' {
InitOfExpression ::= 'initOf' IDENTIFIER '(' [<<trailing_comma_separated_list Expression>>] ')' {
pin = 1
mixin = "org.ton.intellij.tact.psi.impl.TactInitOfExpressionImplMixin"
}
StringExpression ::= STRING_LITERAL
StringExpression ::= StringLiteral

private meta comma_separated_list ::= <<param>> ( ',' <<param>> )*
//private meta comma_separated_list ::= <<param>> ( ',' <<param>> )*
private meta trailing_comma_separated_list ::= <<param>> (',' (<<param>> | &')'))*
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ enum class TactColor(

NUMBER("Number", Default.NUMBER),
STRING("String", Default.STRING),
STRING_ESCAPE("String Escape", Default.VALID_STRING_ESCAPE),
KEYWORD("Keyword", Default.KEYWORD),
PRIMITIVE_TYPES("Primitive types", Default.KEYWORD),
FUNCTION_DECLARATION("Function declaration", Default.FUNCTION_DECLARATION),
Expand All @@ -36,6 +37,7 @@ enum class TactColor(
GLOBAL_VARIABLE("Global variable", Default.GLOBAL_VARIABLE),
LOCAL_VARIABLE("Local variable", Default.LOCAL_VARIABLE),
MACRO("Macro", Default.METADATA),

PARAMETER("Parameter", Default.PARAMETER),
IDENTIFIER("Identifier", Default.IDENTIFIER),
TYPE_PARAMETER("Type parameter", TextAttributesKey.find("TYPE_PARAMETER_NAME_ATTRIBUTES")),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.ton.intellij.tact.highlighting

import com.intellij.lexer.LayeredLexer
import com.intellij.lexer.StringLiteralLexer
import org.ton.intellij.tact.psi.TactElementTypes

class TactHighlightingLexer : LayeredLexer(TactLexer()) {
init {
registerLayer(
StringLiteralLexer(
'"',
TactElementTypes.STRING_LITERAL
)
)

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.ton.intellij.tact.highlighting

import com.intellij.lexer.FlexAdapter
import org.ton.intellij.tact.parser._TactLexer

class TactLexer : FlexAdapter(_TactLexer())
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package org.ton.intellij.tact.highlighting

import com.intellij.lexer.FlexAdapter
import com.intellij.lexer.Lexer
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.fileTypes.SyntaxHighlighterBase
import com.intellij.psi.tree.IElementType
import org.ton.intellij.tact.parser._TactLexer
import org.ton.intellij.tact.psi.TACT_KEYWORDS
import org.ton.intellij.tact.psi.TACT_MACROS
import org.ton.intellij.tact.psi.TACT_STRING_LITERALS
import org.ton.intellij.tact.psi.TactElementTypes

class TactSyntaxHighlighter : SyntaxHighlighterBase() {
override fun getHighlightingLexer(): Lexer = FlexAdapter(_TactLexer())
override fun getHighlightingLexer(): Lexer = TactLexer()

override fun getTokenHighlights(tokenType: IElementType): Array<TextAttributesKey> = when (tokenType) {
TactElementTypes.INTEGER_LITERAL -> TactColor.NUMBER
Expand All @@ -25,6 +23,7 @@ class TactSyntaxHighlighter : SyntaxHighlighterBase() {
TactElementTypes.LBRACK, TactElementTypes.RBRACK -> TactColor.BRACKETS
TactElementTypes.LPAREN, TactElementTypes.RPAREN -> TactColor.PARENTHESES
TactElementTypes.BOOLEAN_LITERAL, TactElementTypes.NULL_LITERAL -> TactColor.KEYWORD
TactElementTypes.ESCAPE_SEQUENCE -> TactColor.STRING_ESCAPE
in TACT_STRING_LITERALS -> TactColor.STRING
in TACT_MACROS -> TactColor.MACRO
in TACT_KEYWORDS -> TactColor.KEYWORD
Expand Down
3 changes: 2 additions & 1 deletion src/main/kotlin/org/ton/intellij/tact/project/TactLibrary.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ private fun makeStdlibLibrary(project: Project): TactLibrary? {
}
return TactLibrary("stdlib", sourceRoots, version)
}
return TactLibrary("stdlib", sourceRoots)
}
return TactLibrary("stdlib", sourceRoots)
return null
}
8 changes: 6 additions & 2 deletions src/main/kotlin/org/ton/intellij/tact/psi/TactTokenType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ val TACT_REGULAR_COMMENTS = tokenSetOf(BLOCK_COMMENT, LINE_COMMENT)
val TACT_DOC_COMMENTS = tokenSetOf()
val TACT_COMMENTS = TokenSet.orSet(TACT_REGULAR_COMMENTS, TACT_DOC_COMMENTS)

val TACT_STRING_LITERALS = tokenSetOf(STRING_LITERAL)
val TACT_STRING_LITERALS = tokenSetOf(OPEN_QUOTE, CLOSE_QUOTE, REGULAR_STRING_PART)
val TACT_MACROS = tokenSetOf(NAME_MACRO, INTERFACE_MACRO)

val TACT_KEYWORDS = tokenSetOf(
Expand Down Expand Up @@ -48,5 +48,9 @@ val TACT_KEYWORDS = tokenSetOf(
SELF_KEYWORD,
INIT_KEYWORD,
BOUNCED_KEYWORD,
MAP_KEYWORD
MAP_KEYWORD,
FOREACH_KEYWORD,
IN_KEYWORD,
TRY_KEYWORD,
CATCH_KEYWORD
)

0 comments on commit bd33263

Please sign in to comment.