% Using Base grammar for Rust include "rust.grm" % Note: different from the innersource rust grammar define func_return_entry [stringlit] '-> [id] end define define var_type_entry [id] '-> [id] end define % Main translation rule to match Rust programs function main export FuncReturnMap [repeat func_return_entry] % TODO: this can be extended with predefined funcs/user defined funcs "file_stem" -> 'Some "std :: str :: from_utf8" -> 'Ok ".parent" -> 'Some ".ok" -> 'Ok "fs :: read_to_string" -> 'Ok "read_to_string" -> 'Ok "spawn" -> 'Ok "wait_with_output" -> 'Ok "wait" -> 'Ok "parse_query" -> 'Ok "try_from" -> 'Ok "from_utf8" -> 'Ok "take" -> 'Some ".get" -> 'Some "splitup" -> 'Ok "file_stem" -> 'Some ".lock" -> 'Some ".last" -> 'Some ".next" -> 'Some export TempVarNo [number] 0 export VarTypeTable [repeat var_type_entry] _ export ArithInconsistentVars [repeat id] _ % export UseWrappingTag [id] % 'no replace [program] RustProgram [program] construct Message [id] _ [message "Congratulations, matched it successfully!"] by RustProgram [fixUnwrapUsedOnLetStmt1] % TEST: let _foo = read_to_string("address.txt").unwrap(); [fixUnwrapUsedOnLetStmt2] % TEST: let source = read_to_string(file).ok().unwrap(); [fixUnwrapUsedOnLetStmt3] % unwrap is in between and belong to Infix_Postfix_Expressions* % [fixUnwrapUsedOnLetStmt3] [fixUnwrapUsedOnExprStmt1] [fixUnwrapUsedOnExprStmt2] [fixUnwrapUsedOnExprStmt3] [fixUnwrapUsedOnTokenTree] % 处理unwrap在token tree中 let file_name = path % .join(format!("{}.rs.1",path.file_stem().unwrap().to_string_lossy())); % 需要统计unwrap used cases (i.e., stmt) in idiomatic projects, % So that we mainly fix in this selected cases with most occurrences (since unwrap can occur everywhere) [fixExhaustiveStruct] [fixAsConversion] %[fixIntArithmetic]拆成下面三个 [collectVarDefinedType] [collectTypeInconsistentArithmetic] [importWrapping] [modifyVarDefInWrapping] % modify var type in Wrapping end function rule fixUnwrapUsedOnLetStmt1 import FuncReturnMap [repeat func_return_entry] replace $ [repeat Statement] Stmt [Statement] Stmts [repeat Statement] deconstruct Stmt LetStmt [LetStatement] deconstruct not Stmt % ensure will only closes siblings _ [Expression] deconstruct LetStmt OuterAttr [OuterAttribute*] 'let Pat [Pattern] ColonType [COLON_Type?] '= RightExpr [Expression] '; % whether unwrap is in the end deconstruct RightExpr PrefixExpr [Prefix_Expressions*] ExprWOWB [ExpressionWithOrWithoutBlock] InPoExprs [Infix_Postfix_Expressions*] construct InPoExprsLength [number] _ [length InPoExprs] construct LastFuncStartIndex [number] InPoExprsLength [- 1] construct LastFuncEndIndex [number] InPoExprsLength [- 1] construct LastFuncName [Infix_Postfix_Expressions*] InPoExprs [select LastFuncStartIndex LastFuncEndIndex] construct LastFuncStr [stringlit] _ [quote LastFuncName] where LastFuncStr [= ".unwrap"] where InPoExprsLength [= 3] % ("address.txt") .unwrap () deconstruct RightExpr _ [Prefix_Expressions*] _ [ExpressionWithOrWithoutBlock] % ExprWOWB is fs :: read_to_string '( OptionalParams [CallParams?] ') '. 'unwrap() construct CloselyPreFunc [stringlit] _ [quote ExprWOWB] deconstruct * [func_return_entry] FuncReturnMap CloselyPreFunc -> EnclosePat [id] construct IfLetExprBlock [ExpressionStatement] 'if 'let EnclosePat '( Pat ') '= PrefixExpr ExprWOWB '( OptionalParams ') '{ Stmts '} by IfLetExprBlock end rule rule fixUnwrapUsedOnLetStmt2 import FuncReturnMap [repeat func_return_entry] replace $ [repeat Statement] Stmt [Statement] Stmts [repeat Statement] deconstruct Stmt LetStmt [LetStatement] deconstruct not Stmt % ensure will only closes siblings _ [Expression] deconstruct LetStmt OuterAttr [OuterAttribute*] 'let Pat [Pattern] ColonType [COLON_Type?] '= RightExpr [Expression] '; % whether unwrap is in the end deconstruct RightExpr PrefixExpr [Prefix_Expressions*] ExprWOWB [ExpressionWithOrWithoutBlock] InPoExprs [Infix_Postfix_Expressions*] construct InPoExprsLength [number] _ [length InPoExprs] construct LastFuncStartIndex [number] InPoExprsLength [- 1] construct LastFuncEndIndex [number] InPoExprsLength [- 1] construct LastFuncName [Infix_Postfix_Expressions*] InPoExprs [select LastFuncStartIndex LastFuncEndIndex] construct LastFuncStr [stringlit] _ [quote LastFuncName] where LastFuncStr [= ".unwrap"] where not InPoExprsLength [= 3] % .ok() .unwrap () construct PreFuncStartIndex [number] InPoExprsLength [- 3] construct PreFuncEndIndex [number] InPoExprsLength [- 3] construct CloseFuncName [Infix_Postfix_Expressions*] InPoExprs [select PreFuncStartIndex PreFuncEndIndex] construct CloselyPreFunc [stringlit] _ [quote CloseFuncName] deconstruct * [func_return_entry] FuncReturnMap CloselyPreFunc -> EnclosePat [id] construct Until [number] InPoExprsLength [- 2] %.ok construct removelastPara [Infix_Postfix_Expressions*] InPoExprs [head Until] construct IfLetExprBlock [ExpressionStatement] 'if 'let EnclosePat '( Pat ') '= PrefixExpr ExprWOWB removelastPara '{ Stmts '} by IfLetExprBlock end rule rule fixUnwrapUsedOnLetStmt3 import FuncReturnMap [repeat func_return_entry] replace $ [repeat Statement] Stmt [Statement] Stmts [repeat Statement] deconstruct Stmt LetStmt [LetStatement] deconstruct not Stmt % ensure will only closes siblings _ [Expression] deconstruct LetStmt OuterAttr [OuterAttribute*] 'let Pat [Pattern] ColonType [COLON_Type?] '= RightExpr [Expression] '; % whether contains unwrap deconstruct * [PathExprSegment] RightExpr 'unwrap Colon [COLON_COLON_GenericArgs?] % unwrap is not in the end deconstruct RightExpr PrefixExpr [Prefix_Expressions*] ExprWOWB [ExpressionWithOrWithoutBlock] InPoExprs [Infix_Postfix_Expressions*] construct InPoExprsLength [number] _ [length InPoExprs] construct LastFuncStartIndex [number] InPoExprsLength [- 1] construct LastFuncEndIndex [number] InPoExprsLength [- 1] construct LastFuncName [Infix_Postfix_Expressions*] InPoExprs [select LastFuncStartIndex LastFuncEndIndex] construct LastFuncStr [stringlit] _ [quote LastFuncName] where not LastFuncStr [= ".unwrap"] export IncreIndex [number] 0 construct UnwrapIndexes [repeat number] _ [checkUnwrapIndex1 each InPoExprs] % TODO: 这里是unwrap 在第三个repeat里 %construct Message [id] % _ [message UnwrapIndexes] deconstruct UnwrapIndexes II [number] III [number*] construct preII [number] II [- 1] construct postII [number] II [+ 2] construct LeftSlices [Infix_Postfix_Expressions*] InPoExprs [head preII] construct rightSlices [Infix_Postfix_Expressions*] InPoExprs [tail postII] export IncreIndex 0 construct TempStr [id] _ [quote 't_] [quote Pat] construct IPreFuncIndex [number] II [- 2] construct IPreFunc [Infix_Postfix_Expressions*] InPoExprs [select IPreFuncIndex IPreFuncIndex] deconstruct IPreFunc CloselyPreFuncName [Infix_Postfix_Expressions] _ [Infix_Postfix_Expressions*] %construct Message1 [id] % _ [message CloselyPreFuncName] construct CloselyPreFunc [stringlit] _ [quote CloselyPreFuncName] deconstruct * [func_return_entry] FuncReturnMap CloselyPreFunc -> EnclosePat [id] by 'if 'let EnclosePat '( TempStr ') = PrefixExpr ExprWOWB LeftSlices '{ 'let Pat '= TempStr rightSlices '; %'let nihao '= '2 '; Stmts '} end rule function checkUnwrapIndex1 InPoExpr [Infix_Postfix_Expressions] import IncreIndex [number] export IncreIndex IncreIndex [+ 1] deconstruct InPoExpr '.unwrap replace [repeat number] Indexes [repeat number] by Indexes [. IncreIndex] end function function checkUnwrapIndex2 TokenTree [TokenTree] import IncreIndex [number] export IncreIndex IncreIndex [+ 1] deconstruct TokenTree 'unwrap replace [repeat number] Indexes [repeat number] by Indexes [. IncreIndex] end function rule fixUnwrapUsedOnExprStmt1 import FuncReturnMap [repeat func_return_entry] import TempVarNo [number] export TempVarNo TempVarNo [+ 1] replace $ [repeat Statement] Stmt [Statement] Stmts [repeat Statement] deconstruct Stmt ExprStmt [ExpressionStatement] deconstruct not Stmt % ensure will only closes siblings _ [Expression] %Find smallest expr containing unwrap and unwrap is in the end deconstruct * [Expression] ExprStmt PrefixExpr [Prefix_Expressions*] ExprWOWB [ExpressionWithOrWithoutBlock] InPoExpr1 [Infix_Postfix_Expressions] '.unwrap _ [Infix_Postfix_Expressions] %InPoExprs [Infix_Postfix_Expressions*] %(construct InPoExprsStr [stringlit] _ [quote InPoExprs] construct InPoExprsStrLength [number] _ [# InPoExprsStr] construct InPoExprsStrLastStartIndex [number] InPoExprsStrLength [- 10] construct InPoExprsLastStr [stringlit] InPoExprsStr [: InPoExprsStrLastStartIndex InPoExprsStrLength] where InPoExprsStr [= ".unwrap ()"])% %check tail is .unwrap construct UnwrapBigPartStr [stringlit] _ [unparse ExprWOWB] [+ " "] [unparse InPoExpr1] [+ ".unwrap ()"] %find unwrap occurs construct ExprStmtStr [stringlit] _ [unparse ExprStmt] construct UnwrapBigPartIndex [number] _ [index ExprStmtStr UnwrapBigPartStr] %construct Message [id] % _ [message UnwrapBigPartIndex] deconstruct not UnwrapBigPartIndex 0 construct LeftEndIndex [number] UnwrapBigPartIndex [- 1] construct leftPart [stringlit] ExprStmtStr [: 1 LeftEndIndex] construct ExprStmtStrLength [number] _ [# ExprStmtStr] construct IfLetPosStr [stringlit] _ [unparse ExprWOWB] [+ " "] [unparse InPoExpr1] construct IfLetPos [id] _ [+ IfLetPosStr] construct UnwrapBigPartStrLength [number] _ [# UnwrapBigPartStr] construct RightStartIndex [number] UnwrapBigPartIndex [+ UnwrapBigPartStrLength] construct rightPart [stringlit] ExprStmtStr [: RightStartIndex ExprStmtStrLength] construct TempVarStr [id] _ [quote 't_] [quote TempVarNo] construct NewExprStmt [stringlit] _ [+ leftPart] [quote 't_] [quote TempVarNo] [+ rightPart] construct NewExpr [id] _ [+ NewExprStmt] construct CloselyPreFunc [stringlit] _ [quote ExprWOWB] deconstruct * [func_return_entry] FuncReturnMap CloselyPreFunc -> EnclosePat [id] export TempVarNo TempVarNo [+ 1] by 'if 'let EnclosePat '( TempVarStr ') '= IfLetPos '{ NewExpr Stmts '} end rule %unwrap occurs in which part rule fixUnwrapUsedOnExprStmt2 import FuncReturnMap [repeat func_return_entry] import TempVarNo [number] export TempVarNo TempVarNo [+ 1] replace $ [repeat Statement] Stmt [Statement] Stmts [repeat Statement] deconstruct Stmt ExprStmt [ExpressionStatement] deconstruct not Stmt % ensure will only closes siblings _ [Expression] %Find smallest expr containing unwrap and unwrap is in the end deconstruct * [Expression] ExprStmt PrefixExpr [Prefix_Expressions*] ExprWOWB [ExpressionWithOrWithoutBlock] InPoExprs1 [Infix_Postfix_Expressions] InPoExprs2 [Infix_Postfix_Expressions] '.unwrap _ [Infix_Postfix_Expressions] construct UnwrapBigPartStr [stringlit] _ [unparse PrefixExpr] [+ " "] [unparse ExprWOWB] [unparse InPoExprs1] [+ " "] [unparse InPoExprs2] [+ ".unwrap ()"] %find unwrap occurs construct ExprStmtStr [stringlit] _ [unparse ExprStmt] construct UnwrapBigPartIndex [number] _ [index ExprStmtStr UnwrapBigPartStr] %construct Message [id] % _ [message UnwrapBigPartIndex] deconstruct not UnwrapBigPartIndex 0 construct LeftEndIndex [number] UnwrapBigPartIndex [- 1] construct leftPart [stringlit] ExprStmtStr [: 1 LeftEndIndex] construct ExprStmtStrLength [number] _ [# ExprStmtStr] construct IfLetPosStr [stringlit] _ [unparse PrefixExpr] [unparse ExprWOWB] [unparse InPoExprs1] [unparse InPoExprs2] construct IfLetPos [id] _ [+ IfLetPosStr] construct UnwrapBigPartStrLength [number] _ [# UnwrapBigPartStr] construct RightStartIndex [number] UnwrapBigPartIndex [+ UnwrapBigPartStrLength] construct rightPart [stringlit] ExprStmtStr [: RightStartIndex ExprStmtStrLength] construct TempVarStr [id] _ [quote 't_] [quote TempVarNo] construct NewExprStmt [stringlit] _ [+ leftPart] [quote 't_] [quote TempVarNo] [+ rightPart] construct NewExpr [id] _ [+ NewExprStmt] construct CloselyPreFunc [stringlit] _ [quote InPoExprs1] deconstruct * [func_return_entry] FuncReturnMap CloselyPreFunc -> EnclosePat [id] export TempVarNo TempVarNo [+ 1] by 'if 'let EnclosePat '( TempVarStr ') '= IfLetPos '{ NewExpr Stmts '} end rule rule fixUnwrapUsedOnExprStmt3 % 当前先只处理ifExpression, 其他含{}的expression可修改此规则 import FuncReturnMap [repeat func_return_entry] import TempVarNo [number] export TempVarNo TempVarNo [+ 1] replace $ [repeat Statement] IfExprStmt [IfExpression] Stmts [repeat Statement] deconstruct IfExprStmt 'if ExcptExpr[ExpressionExceptStructExpression] BlockExpr [BlockExpression] ElseExpr [ElseExpression?] deconstruct ExcptExpr PrefixExpr [Prefix_Expressions*] ExprWOWB [ExpressionWithOrWithoutBlock] InPoExprs [Infix_Postfix_Expressions*] export IncreIndex [number] 0 construct UnwrapIndexes [repeat number] _ [checkUnwrapIndex1 each InPoExprs] deconstruct UnwrapIndexes II [number] III [number*] construct preII [number] II [- 1] construct postII [number] II [+ 2] construct LeftSlices [Infix_Postfix_Expressions*] InPoExprs [head preII] construct rightSlices [Infix_Postfix_Expressions*] InPoExprs [tail postII] export IncreIndex 0 construct IPreFuncIndex [number] II [- 2] construct IPreFunc [Infix_Postfix_Expressions*] InPoExprs [select IPreFuncIndex IPreFuncIndex] deconstruct IPreFunc CloselyPreFuncName [Infix_Postfix_Expressions] _ [Infix_Postfix_Expressions*] %construct Message1 [id] % _ [message CloselyPreFuncName] construct CloselyPreFunc [stringlit] _ [quote CloselyPreFuncName] deconstruct * [func_return_entry] FuncReturnMap CloselyPreFunc -> EnclosePat [id] construct TempVarStr [id] _ [quote 't_] [quote TempVarNo] export TempVarNo TempVarNo [+ 1] by 'if 'let EnclosePat '( TempVarStr ') = PrefixExpr ExprWOWB LeftSlices '{ 'if TempVarStr rightSlices BlockExpr ElseExpr Stmts '} end rule rule fixUnwrapUsedOnTokenTree %find the most closed pre comma % check in let expression import FuncReturnMap [repeat func_return_entry] import TempVarNo [number] export TempVarNo TempVarNo [+ 1] replace $ [repeat Statement] Stmt [Statement] Stmts [repeat Statement] deconstruct Stmt LetStmt [LetStatement] deconstruct not Stmt % ensure will only closes siblings _ [Expression] deconstruct LetStmt OuterAttr [OuterAttribute*] 'let Pat [Pattern] ColonType [COLON_Type?] '= RightExpr [Expression] '; % whether contains unwrap deconstruct * [token_or_key] RightExpr 'unwrap construct RightExprStr [stringlit] _ [unparse RightExpr] construct UnwrapStartIndex [number] _ [index RightExprStr ".unwrap ()"] deconstruct not UnwrapStartIndex 0 construct UnwrapRightStartIndex [number] UnwrapStartIndex [+ 10] construct CommaStartIndex [number] _ [index RightExprStr ","] % string between comma and unwrap will be put in if let expr deconstruct not CommaStartIndex 0 deconstruct * [TokenTree*] RightExpr TTs [TokenTree*] export IncreIndex [number] 0 construct UnwrapIndexes [repeat number] _ [checkUnwrapIndex2 each TTs] deconstruct UnwrapIndexes II [number] III [number*] export IncreIndex 0 construct IPreFuncIndex [number] II [- 3] construct IPreFunc [TokenTree*] TTs [select IPreFuncIndex IPreFuncIndex] deconstruct IPreFunc CloselyPreFuncName [TokenTree] _ [TokenTree*] construct CloselyPreFunc [stringlit] _ [quote CloselyPreFuncName] deconstruct * [func_return_entry] FuncReturnMap CloselyPreFunc -> EnclosePat [id] construct TempVarStr [stringlit] _ [quote 't_] [quote TempVarNo] construct TempVarId [id] _ [+ TempVarStr] construct leftSlices [stringlit] RightExprStr [: 1 CommaStartIndex] construct RightExprLength [number] _ [# RightExprStr] construct rightSlices [stringlit] RightExprStr [: UnwrapRightStartIndex RightExprLength] construct auxiliaryNum1 [number] CommaStartIndex [+ 2] construct auxiliaryNum2 [number] UnwrapRightStartIndex [- 11] construct RightExprStrInIfLet [stringlit] RightExprStr [: auxiliaryNum1 auxiliaryNum2] construct RightExprInIfLet [id] _ [+ RightExprStrInIfLet] construct NewRightStr [stringlit] leftSlices [+ TempVarStr] [+ rightSlices] construct NewRight [id] _ [+ NewRightStr] export TempVarNo TempVarNo [+ 1] by 'if 'let EnclosePat '( TempVarId ') = RightExprInIfLet '{ 'let Pat = NewRight ; Stmts '} end rule rule fixExhaustiveStruct replace $ [Item] OuterAttr [OuterAttribute*] VisOrMacroItem [VisItem_or_MacroItem] deconstruct VisOrMacroItem 'pub _ [Struct] deconstruct not OuterAttr '# '[ 'non_exhaustive '] construct NewOuterAttr [OuterAttribute] '# '[ 'non_exhaustive '] by NewOuterAttr OuterAttr VisOrMacroItem end rule rule fixAsConversion import TempVarNo [number] export TempVarNo TempVarNo [+ 1] replace $ [repeat Statement] Stmt [Statement] Stmts [repeat Statement] deconstruct not Stmt % ensure will only closes siblings _ [Expression] construct AllExprs [repeat Expression] _ [^ Stmt] % 最后一个Expression must be the closest and innermost one construct NumberOfExprs [number] _ [length AllExprs] construct LastExprRepeat [repeat Expression] AllExprs [tail NumberOfExprs] deconstruct LastExprRepeat LastExpr [Expression] _ [repeat Expression] %find substring containing as construct LastExprStr [stringlit] _ [quote LastExpr] construct AsStartIndex [number] _ [index LastExprStr "as"] % string between comma and unwrap will be put in if let expr deconstruct not AsStartIndex 0 % We find this as expression construct AsSubLeftStrEndIndex [number] AsStartIndex [- 2] construct AsSubLeftstr [stringlit] LastExprStr [: 1 AsSubLeftStrEndIndex] construct AsSubLeftId [id] _ [+ AsSubLeftstr] construct AsSubRightStrStartIndex [number] AsStartIndex [+ 3] construct LastExprStrLength [number] _ [# LastExprStr] construct AsSubRightstr [stringlit] LastExprStr [: AsSubRightStrStartIndex LastExprStrLength] construct AsSubRightId [id] _ [+ AsSubRightstr] construct StmtStr [stringlit] _ [quote Stmt] construct AsExprStartIndex [number] _ [index StmtStr LastExprStr] deconstruct not AsExprStartIndex 0 construct AsExprLeftStrIndex [number] AsExprStartIndex [- 1] construct AsExprLeftStr [stringlit] StmtStr [: 1 AsExprLeftStrIndex] construct AsRightExprStrStartIndex [number] AsExprStartIndex [+ LastExprStrLength] construct StmtStrLength [number] _ [# StmtStr] construct AsExprRightstr [stringlit] StmtStr [: AsRightExprStrStartIndex StmtStrLength] construct TempVarStr [stringlit] _ [quote 't_] [quote TempVarNo] construct TempVarId [id] _ [+ TempVarStr] construct NewStmtStr [stringlit] _ [+ AsExprLeftStr] [+ TempVarStr] [+ AsExprRightstr] construct NewStmtId [id] _ [+ NewStmtStr] export TempVarNo TempVarNo [+ 1] by 'if 'let 'Ok '( TempVarId ') = AsSubRightId ':: 'try_from '( AsSubLeftId ') '{ NewStmtId Stmts '} end rule rule collectVarDefinedType import VarTypeTable [repeat var_type_entry] replace $ [LetStatement] LetStmt [LetStatement] deconstruct LetStmt _ [OuterAttribute*] 'let Pat [id] ColonType [COLON_Type?] '= RightExpr [Expression] '; deconstruct ColonType ': TypeId [id] construct VarTypeEntry [var_type_entry] Pat -> TypeId export VarTypeTable VarTypeTable [. VarTypeEntry] %construct Message [id] % _ [message VarTypeTable] by LetStmt end rule rule collectTypeInconsistentArithmetic %dispose a+b, don't touch a+b+b import VarTypeTable [repeat var_type_entry] replace $ [Expression] PreExpr [Prefix_Expressions*] LeftVar [id] ArithExpr [Infix_ArithmeticOrLogicalExpression] where ArithExpr [_isAddOp] [_isMinusOp] [_isMultiplyOp] [isDivideOp] [isModOp] import RightVar [id] deconstruct * [var_type_entry] VarTypeTable LeftVar -> LeftVarType [id] deconstruct * [var_type_entry] VarTypeTable RightVar -> RightVarType [id] %construct Message [id] % _ [message LeftVarType] where LeftVarType [~= RightVarType] import ArithInconsistentVars [repeat id] export ArithInconsistentVars ArithInconsistentVars [. LeftVar] [. RightVar] %construct Message [id] % _ [message ArithInconsistentVars] by PreExpr LeftVar ArithExpr end rule rule importWrapping import ArithInconsistentVars [repeat id] replace $ [Crate] Items [Item*] construct Length [number] _ [length ArithInconsistentVars] where Length [> 0] by 'use 'std::num::Wrapping; Items end rule rule modifyVarDefInWrapping import ArithInconsistentVars [repeat id] replace $ [LetStatement] LetStmt [LetStatement] deconstruct LetStmt OuterAttrs [OuterAttribute*] 'let Pat [id] ColonType [COLON_Type?] '= RightExpr [Expression] '; %check pat is in ArithInconsistentVars deconstruct * [id] ArithInconsistentVars Pat by OuterAttrs 'let Pat '= 'Wrapping '( RightExpr ') '; end rule function _isAddOp match [Infix_ArithmeticOrLogicalExpression] '+ RightVar [id] export RightVar end function function _isMinusOp match [Infix_ArithmeticOrLogicalExpression] '- RightVar [id] export RightVar end function function _isMultiplyOp match [Infix_ArithmeticOrLogicalExpression] '* RightVar [id] export RightVar end function function isDivideOp match [Infix_ArithmeticOrLogicalExpression] '/ RightVar [id] export RightVar end function function isModOp match [Infix_ArithmeticOrLogicalExpression] '% RightVar [id] export RightVar end function % 可用as conversion's idea rewrite the transformations for unwraps % rule 会在每次子树替换后自动搜索整个新树