Skip to content

Commit

Permalink
Compound assignments (#220)
Browse files Browse the repository at this point in the history
* compound assignments parser support

* name resolution for assign bin expr
  • Loading branch information
mkurnikov authored Oct 26, 2024
1 parent f068d1f commit 550e420
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 7 deletions.
26 changes: 19 additions & 7 deletions src/main/grammars/MoveParser.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,10 @@

// Contextual tokens
LT_EQ = '<='
LT_LT_EQ = '<<='
LT_LT = '<<'
GT_EQ = '>='
GT_GT_EQ = '>>='
GT_GT = '>>'
OR_OR = '||'
AND_AND = '&&'
Expand Down Expand Up @@ -866,6 +868,7 @@ private CodeBlock_items_recover ::= !('}' | <<eof>>)
///////////////////////////////////////////////////////////////////////////////////////////////////
// from lowest to highest
Expr ::= AssignmentExpr
| AssignBinExpr
| RangeExpr
| (ForallQuantExpr | ExistsQuantExpr | ChooseQuantExpr)
| CastLikeExpr_items
Expand All @@ -880,7 +883,7 @@ Expr ::= AssignmentExpr
| AddExpr_items
| MulExpr_items
| ControlFlowExpr_items
| UnaryExpr
| UnaryExpr_items
| BorrowExpr
| AtomExpr

Expand All @@ -893,25 +896,32 @@ fake BinaryExpr ::= Expr BinaryOp Expr {
}

//noinspection BnfUnusedRule
fake BinaryOp ::= '<==>' | '==>' | '='
fake BinaryOp ::= '<<=' | '>>=' | '|=' | '^=' | '&=' | '+=' | '-=' | '*=' | '/=' | '%='
| '<==>' | '==>' | '='
| '==' | '!='
| '<' | '>' | '<=' | '>='
| '<<' | '>>'
| '+' | '-' | '*' | '/' | '%'
| '||' | '&&' | '|' | '&' | '^'


AssignBinExpr ::= Expr AssignBinOp Expr { rightAssociative = true }
AssignBinOp ::= gtgteq | ltlteq | '|=' | '^=' | '&=' | '+=' | '-=' | '*=' | '/=' | '%='
{
name = "operator"
}
AssignBinaryOp ::= gtgteq | ltlteq | '|=' | '^=' | '&=' | '+=' | '-=' | '*=' | '/=' | '%='

private MulExpr_items ::= DivBinExpr | MulBinExpr | ModBinExpr
private AddExpr_items ::= PlusBinExpr | MinusBinExpr
private LogicalEqExpr_items ::=
EqualsBinExpr | NotEqualsBinExpr
| LessEqualsBinExpr | LessBinExpr | GreaterEqualsBinExpr | GreaterBinExpr

private ControlFlowExpr_items ::= IfExpr | LoopExpr | MatchExpr | WhileExpr | ForExpr
private UnaryExpr ::= CopyExpr | MoveExpr | DerefExpr | BangExpr
| ReturnExpr | ContinueExpr | BreakExpr | AbortExpr
private AtomExpr ::=
AnnotatedExpr
private UnaryExpr_items ::= CopyExpr | MoveExpr | DerefExpr | BangExpr
| ReturnExpr | ContinueExpr | BreakExpr | AbortExpr
private AtomExpr ::= AnnotatedExpr
| TupleLitOrParenExpr
| StructLitExpr
| VectorLitExpr
Expand Down Expand Up @@ -1541,7 +1551,7 @@ UpdateSpecStmt ::= update UpdateExpr_items '=' Expr ';' {
"org.move.lang.core.psi.MslOnlyElement"
]
}
private UpdateExpr_items ::= UnaryExpr | BorrowExpr | AtomExpr
private UpdateExpr_items ::= UnaryExpr_items | BorrowExpr | AtomExpr

IncludeItem ::= SchemaIncludeItem | AndIncludeItem | IfElseIncludeItem | ImplyIncludeItem
{
Expand Down Expand Up @@ -1718,8 +1728,10 @@ TypeQuantBinding ::= PatBinding ':' Type {
// Meta rules
///////////////////////////////////////////////////////////////////////////////////////////////////

private gtgteq ::= <<gtgteqImpl>>
private gtgt ::= <<gtgtImpl>>
private gteq ::= <<gteqImpl>>
private ltlteq ::= <<ltlteqImpl>>
private ltlt ::= <<ltltImpl>>
private lteq ::= <<lteqImpl>>
private oror ::= <<ororImpl>>
Expand Down
6 changes: 6 additions & 0 deletions src/main/kotlin/org/move/lang/core/MoveParserUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,18 @@ object MoveParserUtil: GeneratedParserUtilBase() {
candidate
}

@JvmStatic
fun gtgteqImpl(b: PsiBuilder, level: Int): Boolean = collapse(b, GT_GT_EQ, GT, GT, EQ)

@JvmStatic
fun gtgtImpl(b: PsiBuilder, level: Int): Boolean = collapse(b, GT_GT, GT, GT)

@JvmStatic
fun gteqImpl(b: PsiBuilder, level: Int): Boolean = collapse(b, GT_EQ, GT, EQ)

@JvmStatic
fun ltlteqImpl(b: PsiBuilder, level: Int): Boolean = collapse(b, LT_LT_EQ, LT, LT, EQ)

@JvmStatic
fun ltltImpl(b: PsiBuilder, level: Int): Boolean = collapse(b, LT_LT, LT, LT)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,11 @@ class TypeInferenceWalker(
"||", "&&", "==>", "<==>" -> inferLogicBinaryExprTy(binaryExpr)
"^", "|", "&" -> inferBitOpsExprTy(binaryExpr)
"<<", ">>" -> inferBitShiftsExprTy(binaryExpr)

"+=", "-=", "*=", "/=", "%=" -> inferArithmeticBinaryExprTy(binaryExpr)
"|=", "^=", "&=" -> inferBitOpsExprTy(binaryExpr)
">>=", "<<=" -> inferBitShiftsExprTy(binaryExpr)

else -> TyUnknown
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class CompleteParsingTest: MvParsingTestCase("complete") {
fun `test dot dot pattern`() = doTest()

fun `test loop invariants`() = doTest()
fun `test assign bin expr`() = doTest()

// feature declaration is required here, as it's a parser-level feature
// @ResourceAccessControl()
Expand Down
23 changes: 23 additions & 0 deletions src/test/kotlin/org/move/lang/resolve/ResolveVariablesTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -730,4 +730,27 @@ module 0x1::string_tests {
}
}
""")

fun `test compound assigment lhs binding`() = checkByCode("""
module 0x1::m {
fun main() {
let x = 1;
//X
x += 1;
//^
}
}
""")

fun `test compound assigment rhs binding`() = checkByCode("""
module 0x1::m {
fun main() {
let x = 1;
let y = 2;
//X
x += y;
//^
}
}
""")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module 0x1::assign_bin_expr {
fun main() {
x += 1;
x -= 1;
x *= 1;
x /= 1;
x %= 1;

x &= 1;
x |= 1;
x ^= 1;

x <<= 1;
x >>= 1;
}
}
163 changes: 163 additions & 0 deletions src/test/resources/org/move/lang/parser/complete/assign_bin_expr.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
FILE
MvModuleImpl(MODULE)
PsiElement(module)('module')
PsiWhiteSpace(' ')
MvAddressRefImpl(ADDRESS_REF)
PsiElement(DIEM_ADDRESS)('0x1')
PsiElement(::)('::')
PsiElement(IDENTIFIER)('assign_bin_expr')
PsiWhiteSpace(' ')
PsiElement({)('{')
PsiWhiteSpace('\n ')
MvFunctionImpl(FUNCTION)
PsiElement(fun)('fun')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('main')
MvFunctionParameterListImpl(FUNCTION_PARAMETER_LIST)
PsiElement(()('(')
PsiElement())(')')
PsiWhiteSpace(' ')
MvCodeBlockImpl(CODE_BLOCK)
PsiElement({)('{')
PsiWhiteSpace('\n ')
MvExprStmtImpl(EXPR_STMT)
MvBinaryExprImpl(BINARY_EXPR[+=])
MvPathExprImpl(PATH_EXPR)
MvPathImpl(PATH)
PsiElement(IDENTIFIER)('x')
PsiWhiteSpace(' ')
MvBinaryOpImpl(BINARY_OP)
PsiElement(+)('+')
PsiElement(=)('=')
PsiWhiteSpace(' ')
MvLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('1')
PsiElement(;)(';')
PsiWhiteSpace('\n ')
MvExprStmtImpl(EXPR_STMT)
MvBinaryExprImpl(BINARY_EXPR[-=])
MvPathExprImpl(PATH_EXPR)
MvPathImpl(PATH)
PsiElement(IDENTIFIER)('x')
PsiWhiteSpace(' ')
MvBinaryOpImpl(BINARY_OP)
PsiElement(-)('-')
PsiElement(=)('=')
PsiWhiteSpace(' ')
MvLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('1')
PsiElement(;)(';')
PsiWhiteSpace('\n ')
MvExprStmtImpl(EXPR_STMT)
MvBinaryExprImpl(BINARY_EXPR[*=])
MvPathExprImpl(PATH_EXPR)
MvPathImpl(PATH)
PsiElement(IDENTIFIER)('x')
PsiWhiteSpace(' ')
MvBinaryOpImpl(BINARY_OP)
PsiElement(*)('*')
PsiElement(=)('=')
PsiWhiteSpace(' ')
MvLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('1')
PsiElement(;)(';')
PsiWhiteSpace('\n ')
MvExprStmtImpl(EXPR_STMT)
MvBinaryExprImpl(BINARY_EXPR[/=])
MvPathExprImpl(PATH_EXPR)
MvPathImpl(PATH)
PsiElement(IDENTIFIER)('x')
PsiWhiteSpace(' ')
MvBinaryOpImpl(BINARY_OP)
PsiElement(/)('/')
PsiElement(=)('=')
PsiWhiteSpace(' ')
MvLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('1')
PsiElement(;)(';')
PsiWhiteSpace('\n ')
MvExprStmtImpl(EXPR_STMT)
MvBinaryExprImpl(BINARY_EXPR[%=])
MvPathExprImpl(PATH_EXPR)
MvPathImpl(PATH)
PsiElement(IDENTIFIER)('x')
PsiWhiteSpace(' ')
MvBinaryOpImpl(BINARY_OP)
PsiElement(%)('%')
PsiElement(=)('=')
PsiWhiteSpace(' ')
MvLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('1')
PsiElement(;)(';')
PsiWhiteSpace('\n\n ')
MvExprStmtImpl(EXPR_STMT)
MvBinaryExprImpl(BINARY_EXPR[&=])
MvPathExprImpl(PATH_EXPR)
MvPathImpl(PATH)
PsiElement(IDENTIFIER)('x')
PsiWhiteSpace(' ')
MvBinaryOpImpl(BINARY_OP)
PsiElement(&)('&')
PsiElement(=)('=')
PsiWhiteSpace(' ')
MvLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('1')
PsiElement(;)(';')
PsiWhiteSpace('\n ')
MvExprStmtImpl(EXPR_STMT)
MvBinaryExprImpl(BINARY_EXPR[|=])
MvPathExprImpl(PATH_EXPR)
MvPathImpl(PATH)
PsiElement(IDENTIFIER)('x')
PsiWhiteSpace(' ')
MvBinaryOpImpl(BINARY_OP)
PsiElement(|)('|')
PsiElement(=)('=')
PsiWhiteSpace(' ')
MvLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('1')
PsiElement(;)(';')
PsiWhiteSpace('\n ')
MvExprStmtImpl(EXPR_STMT)
MvBinaryExprImpl(BINARY_EXPR[^=])
MvPathExprImpl(PATH_EXPR)
MvPathImpl(PATH)
PsiElement(IDENTIFIER)('x')
PsiWhiteSpace(' ')
MvBinaryOpImpl(BINARY_OP)
PsiElement(^)('^')
PsiElement(=)('=')
PsiWhiteSpace(' ')
MvLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('1')
PsiElement(;)(';')
PsiWhiteSpace('\n\n ')
MvExprStmtImpl(EXPR_STMT)
MvBinaryExprImpl(BINARY_EXPR[<<=])
MvPathExprImpl(PATH_EXPR)
MvPathImpl(PATH)
PsiElement(IDENTIFIER)('x')
PsiWhiteSpace(' ')
MvBinaryOpImpl(BINARY_OP)
PsiElement(<<=)('<<=')
PsiWhiteSpace(' ')
MvLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('1')
PsiElement(;)(';')
PsiWhiteSpace('\n ')
MvExprStmtImpl(EXPR_STMT)
MvBinaryExprImpl(BINARY_EXPR[>>=])
MvPathExprImpl(PATH_EXPR)
MvPathImpl(PATH)
PsiElement(IDENTIFIER)('x')
PsiWhiteSpace(' ')
MvBinaryOpImpl(BINARY_OP)
PsiElement(>>=)('>>=')
PsiWhiteSpace(' ')
MvLitExprImpl(LIT_EXPR)
PsiElement(INTEGER_LITERAL)('1')
PsiElement(;)(';')
PsiWhiteSpace('\n ')
PsiElement(})('}')
PsiWhiteSpace('\n')
PsiElement(})('}')

0 comments on commit 550e420

Please sign in to comment.