- for _, s := range clause.statements {
- switch stmt := s.(type) {
- case *verifyStatement:
- stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.expr)
- if err != nil {
- return errors.Wrapf(err, "in verify statement in clause \"%s\"", clause.Name)
- }
- stk = b.addVerify(stk)
-
- // special-case reporting of certain function calls
- if c, ok := stmt.expr.(*callExpr); ok && len(c.args) == 1 {
- if b := referencedBuiltin(c.fn); b != nil {
- switch b.name {
- case "below":
- clause.BlockHeight = append(clause.BlockHeight, c.args[0].String())
- case "above":
- clause.BlockHeight = append(clause.BlockHeight, c.args[0].String())
- }
+ for _, stat := range clause.statements {
+ if stk, err = compileStatement(b, stk, contract, env, clause, counts, stat, sequence); err != nil {
+ return err
+ }
+ }
+
+ err = requireAllValuesDisposedOnce(contract, clause)
+ if err != nil {
+ return err
+ }
+ err = typeCheckClause(contract, clause, env)
+ if err != nil {
+ return err
+ }
+ err = requireAllParamsUsedInClause(clause.Params, clause)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func compileStatement(b *builder, stk stack, contract *Contract, env *environ, clause *Clause, counts map[string]int, stat statement, sequence *int) (stack, error) {
+ var err error
+ switch stmt := stat.(type) {
+ case *ifStatement:
+ // sequence add 1 when the statement is ifStatement
+ *sequence++
+ strSequence := fmt.Sprintf("%d", *sequence)
+
+ // compile condition expression
+ stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.condition)
+ if err != nil {
+ return stk, errors.Wrapf(err, "in check condition of ifStatement in clause \"%s\"", clause.Name)
+ }
+
+ // jump to falseBody when condition is false, while the JUMPIF instruction will be run success when
+ // the value of dataStack is true, therefore add this check
+ conditionExpr := stk.str
+ stk = b.addBoolean(stk, false)
+ stk = b.addEqual(stk, fmt.Sprintf("(%s == false)", conditionExpr)) // stack: [... <condition_result == false>]
+
+ // add label
+ var label string
+ if len(stmt.body.falseBody) != 0 {
+ label = "else_" + strSequence
+ } else {
+ label = "endif_" + strSequence
+ }
+ stk = b.addJumpIf(stk, label)
+ b.addJumpTarget(stk, "if_"+strSequence)
+
+ // temporary store stack and counts for falseBody
+ condStk := stk
+ elseCounts := make(map[string]int)
+ for k, v := range counts {
+ elseCounts[k] = v
+ }
+
+ // compile trueBody statements
+ if len(stmt.body.trueBody) != 0 {
+ for _, st := range stmt.body.trueBody {
+ st.countVarRefs(counts)
+ }
+
+ // modify value amount because of using only once
+ if counts[contract.Value.Amount] > 1 {
+ counts[contract.Value.Amount] = 1
+ }
+
+ // modify value asset because of using only once
+ if counts[contract.Value.Asset] > 1 {
+ counts[contract.Value.Asset] = 1
+ }
+
+ for _, st := range stmt.body.trueBody {
+ if stk, err = compileStatement(b, stk, contract, env, clause, counts, st, sequence); err != nil {
+ return stk, err