github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/equity/compiler/checks.go (about) 1 package compiler 2 3 import "fmt" 4 5 func checkRecursive(contract *Contract) bool { 6 for _, clause := range contract.Clauses { 7 for _, stmt := range clause.statements { 8 if result := checkStatRecursive(stmt, contract.Name); result { 9 return true 10 } 11 } 12 } 13 return false 14 } 15 16 func checkStatRecursive(stmt statement, contractName string) bool { 17 switch s := stmt.(type) { 18 case *ifStatement: 19 for _, trueStmt := range s.body.trueBody { 20 if result := checkStatRecursive(trueStmt, contractName); result { 21 return true 22 } 23 } 24 25 for _, falseStmt := range s.body.falseBody { 26 if result := checkStatRecursive(falseStmt, contractName); result { 27 return true 28 } 29 } 30 31 case *lockStatement: 32 if c, ok := s.program.(*callExpr); ok { 33 if references(c.fn, contractName) { 34 return true 35 } 36 } 37 } 38 39 return false 40 } 41 42 func prohibitSigParams(contract *Contract) error { 43 for _, p := range contract.Params { 44 if p.Type == sigType { 45 return fmt.Errorf("contract parameter \"%s\" has type Signature, but contract parameters cannot have type Signature", p.Name) 46 } 47 } 48 return nil 49 } 50 51 func requireAllParamsUsedInClauses(params []*Param, clauses []*Clause) error { 52 for _, p := range params { 53 used := false 54 for _, c := range clauses { 55 err := requireAllParamsUsedInClause([]*Param{p}, c) 56 if err == nil { 57 used = true 58 break 59 } 60 } 61 62 if !used { 63 return fmt.Errorf("parameter \"%s\" is unused", p.Name) 64 } 65 } 66 return nil 67 } 68 69 func requireAllParamsUsedInClause(params []*Param, clause *Clause) error { 70 for _, p := range params { 71 used := false 72 for _, stmt := range clause.statements { 73 if used = checkParamUsedInStatement(p, stmt); used { 74 break 75 } 76 } 77 78 if !used { 79 return fmt.Errorf("parameter \"%s\" is unused in clause \"%s\"", p.Name, clause.Name) 80 } 81 } 82 return nil 83 } 84 85 func checkParamUsedInStatement(param *Param, stmt statement) (used bool) { 86 switch s := stmt.(type) { 87 case *ifStatement: 88 if used = references(s.condition, param.Name); used { 89 return used 90 } 91 92 for _, st := range s.body.trueBody { 93 if used = checkParamUsedInStatement(param, st); used { 94 break 95 } 96 } 97 98 if !used { 99 for _, st := range s.body.falseBody { 100 if used = checkParamUsedInStatement(param, st); used { 101 break 102 } 103 } 104 } 105 106 case *defineStatement: 107 used = references(s.expr, param.Name) 108 case *assignStatement: 109 used = references(s.expr, param.Name) 110 case *verifyStatement: 111 used = references(s.expr, param.Name) 112 case *lockStatement: 113 used = references(s.lockedAmount, param.Name) || references(s.lockedAsset, param.Name) || references(s.program, param.Name) 114 case *unlockStatement: 115 used = references(s.unlockedAmount, param.Name) || references(s.unlockedAsset, param.Name) 116 } 117 118 return used 119 } 120 121 func references(expr expression, name string) bool { 122 switch e := expr.(type) { 123 case *binaryExpr: 124 return references(e.left, name) || references(e.right, name) 125 case *unaryExpr: 126 return references(e.expr, name) 127 case *callExpr: 128 if references(e.fn, name) { 129 return true 130 } 131 for _, a := range e.args { 132 if references(a, name) { 133 return true 134 } 135 } 136 return false 137 case varRef: 138 return string(e) == name 139 case listExpr: 140 for _, elt := range []expression(e) { 141 if references(elt, name) { 142 return true 143 } 144 } 145 return false 146 } 147 return false 148 } 149 150 func referencedBuiltin(expr expression) *builtin { 151 if v, ok := expr.(varRef); ok { 152 for _, b := range builtins { 153 if string(v) == b.name { 154 return &b 155 } 156 } 157 } 158 return nil 159 } 160 161 func assignIndexes(clause *Clause) error { 162 var nextIndex int64 163 for i, stmt := range clause.statements { 164 if nextIndex = assignStatIndexes(stmt, nextIndex, i != len(clause.statements)-1); nextIndex < 0 { 165 return fmt.Errorf("Not support that the number of lock/unlock statement is not equal between ifbody and elsebody when the if-else is not the last statement in clause \"%s\"", clause.Name) 166 } 167 } 168 169 return nil 170 } 171 172 func assignStatIndexes(stat statement, nextIndex int64, nonFinalFlag bool) int64 { 173 switch stmt := stat.(type) { 174 case *ifStatement: 175 trueIndex := nextIndex 176 falseIndex := nextIndex 177 for _, trueStmt := range stmt.body.trueBody { 178 trueIndex = assignStatIndexes(trueStmt, trueIndex, nonFinalFlag) 179 } 180 181 for _, falseStmt := range stmt.body.falseBody { 182 falseIndex = assignStatIndexes(falseStmt, falseIndex, nonFinalFlag) 183 } 184 185 if trueIndex != falseIndex && nonFinalFlag { 186 return -1 187 } else if trueIndex == falseIndex { 188 nextIndex = trueIndex 189 } 190 191 case *lockStatement: 192 stmt.index = nextIndex 193 nextIndex++ 194 195 case *unlockStatement: 196 nextIndex++ 197 } 198 199 return nextIndex 200 } 201 202 func typeCheckClause(contract *Contract, clause *Clause, env *environ) error { 203 for _, s := range clause.statements { 204 if err := typeCheckStatement(s, contract.Value, clause.Name, env); err != nil { 205 return err 206 } 207 } 208 return nil 209 } 210 211 func typeCheckStatement(stat statement, contractValue ValueInfo, clauseName string, env *environ) error { 212 switch stmt := stat.(type) { 213 case *ifStatement: 214 for _, trueStmt := range stmt.body.trueBody { 215 if err := typeCheckStatement(trueStmt, contractValue, clauseName, env); err != nil { 216 return err 217 } 218 } 219 220 for _, falseStmt := range stmt.body.falseBody { 221 if err := typeCheckStatement(falseStmt, contractValue, clauseName, env); err != nil { 222 return err 223 } 224 } 225 226 case *defineStatement: 227 if stmt.expr != nil && stmt.expr.typ(env) != stmt.variable.Type && !isHashSubtype(stmt.expr.typ(env)) { 228 return fmt.Errorf("expression in define statement in clause \"%s\" has type \"%s\", must be \"%s\"", 229 clauseName, stmt.expr.typ(env), stmt.variable.Type) 230 } 231 232 case *assignStatement: 233 if stmt.expr.typ(env) != stmt.variable.Type && !isHashSubtype(stmt.expr.typ(env)) { 234 return fmt.Errorf("expression in assign statement in clause \"%s\" has type \"%s\", must be \"%s\"", 235 clauseName, stmt.expr.typ(env), stmt.variable.Type) 236 } 237 238 case *verifyStatement: 239 if t := stmt.expr.typ(env); t != boolType { 240 return fmt.Errorf("expression in verify statement in clause \"%s\" has type \"%s\", must be Boolean", clauseName, t) 241 } 242 243 case *lockStatement: 244 if t := stmt.lockedAmount.typ(env); !(t == intType || t == amountType) { 245 return fmt.Errorf("lockedAmount expression \"%s\" in lock statement in clause \"%s\" has type \"%s\", must be Integer", stmt.lockedAmount, clauseName, t) 246 } 247 if t := stmt.lockedAsset.typ(env); t != assetType { 248 return fmt.Errorf("lockedAsset expression \"%s\" in lock statement in clause \"%s\" has type \"%s\", must be Asset", stmt.lockedAsset, clauseName, t) 249 } 250 if t := stmt.program.typ(env); t != progType { 251 return fmt.Errorf("program in lock statement in clause \"%s\" has type \"%s\", must be Program", clauseName, t) 252 } 253 254 case *unlockStatement: 255 if t := stmt.unlockedAmount.typ(env); !(t == intType || t == amountType) { 256 return fmt.Errorf("unlockedAmount expression \"%s\" in unlock statement of clause \"%s\" has type \"%s\", must be Integer", stmt.unlockedAmount, clauseName, t) 257 } 258 if t := stmt.unlockedAsset.typ(env); t != assetType { 259 return fmt.Errorf("unlockedAsset expression \"%s\" in unlock statement of clause \"%s\" has type \"%s\", must be Asset", stmt.unlockedAsset, clauseName, t) 260 } 261 if stmt.unlockedAmount.String() != contractValue.Amount || stmt.unlockedAsset.String() != contractValue.Asset { 262 return fmt.Errorf("amount \"%s\" of asset \"%s\" expression in unlock statement of clause \"%s\" must be the contract valueAmount \"%s\" of valueAsset \"%s\"", 263 stmt.unlockedAmount.String(), stmt.unlockedAsset.String(), clauseName, contractValue.Amount, contractValue.Asset) 264 } 265 } 266 267 return nil 268 }