OSDN Git Service

add the replacement of defined variable for AST and adjusting the structural format...
authoroysheng <33340252+oysheng@users.noreply.github.com>
Thu, 27 Dec 2018 08:23:17 +0000 (16:23 +0800)
committerPaladz <yzhu101@uottawa.ca>
Thu, 27 Dec 2018 08:23:17 +0000 (16:23 +0800)
* add paramenters for function argment expression

* modify struct

* optimise

* replace the temporary variable for its expression

* optimise

* optimise code for expression

* adjusting syntactic format

* optimise lock statements expression

* fix the assign expression

* optimise equitycmd

* modify json name for blockheight

compiler/ast.go
compiler/checks.go
compiler/cmd/equitycmd/equitycmd.go
compiler/compile.go

index fba7f21..f5f91d0 100644 (file)
@@ -63,9 +63,8 @@ type Clause struct {
 
        statements []statement
 
-       // BlockHeight is the list of expressions passed to greater()/less() in this
-       // clause.
-       BlockHeight []string `json:"blockheight,omitempty"`
+       // BlockHeight is the list of expressions passed to above()/below() in this clause.
+       BlockHeight []string `json:"block_height,omitempty"`
 
        // HashCalls is the list of hash functions and their arguments used
        // in this clause.
@@ -74,13 +73,9 @@ type Clause struct {
        // Values is the list of values unlocked or relocked in this clause.
        Values []ValueInfo `json:"values"`
 
-       // Conditions is the list of condition for if-else statements which body contains
-       // the lock or unlock statement in this clause.
-       Conditions map[string]Condition `json:"conditions"`
-
-       // CondValues is the map of values unlocked or relocked in this clause's
+       // CondValues is the list of condition values unlocked or relocked in this clause's
        // if-else statements which body contains the lock or unlock statement.
-       CondValues map[string][]ValueInfo `json:"cond_values"`
+       CondValues []CondValueInfo `json:"cond_values"`
 
        // Contracts is the list of contracts called by this clause.
        Contracts []string `json:"contracts,omitempty"`
@@ -106,9 +101,12 @@ type ValueInfo struct {
        // the contract value instead, this is empty.
        Amount string `json:"amount,omitempty"`
 
-       // Params is the list of parameters for amount expression. If the value
-       // of amount is a variable, this is empty.
-       Params []*Param `json:"params,omitempty"`
+       // AmountParams is the list of parameters for Amount expression.
+       // If the value of amount is a variable, this is empty.
+       AmountParams []*Param `json:"amount_params,omitempty"`
+
+       // ContractCalls is the list of arguments for program which is a contract.
+       ContractCalls []CallArgs `json:"contract_calls,omitempty"`
 }
 
 // HashCall describes a call to a hash function.
@@ -123,12 +121,39 @@ type HashCall struct {
        ArgType string `json:"arg_type"`
 }
 
-// Condition describes a condition expression.
-type Condition struct {
-       // Source is the string format of condition expression.
+// CondValueInfo describes a struct for if-else statements which body
+// contains the lock or unlock statement.
+type CondValueInfo struct {
+       // condition is the condition expression for if-else statements.
+       Condition ExpressionInfo `json:"condition"`
+
+       // TrueBodyValues is the list of values unlocked or relocked in the trueBody
+       // for if-else statements.
+       TrueBodyValues []ValueInfo `json:"true_body"`
+
+       // FalseBodyValues is the list of values unlocked or relocked in the falseBody
+       // for if-else statements.
+       FalseBodyValues []ValueInfo `json:"false_body"`
+}
+
+// ExpressionInfo describes a operational expression.
+type ExpressionInfo struct {
+       // Source is the string format of operational expression.
        Source string `json:"source"`
 
-       // Params is the list of parameters for condition expression.
+       // Params is the list of parameters for operational expression.
+       Params []*Param `json:"params,omitempty"`
+}
+
+// CallArgs describes a argument expression for function or contract call.
+type CallArgs struct {
+       // Source is the string format of argument expression.
+       Source string `json:"source"`
+
+       // Position is the position of argument expression.
+       Position int `json:"position"`
+
+       // Params is the list of parameters for argument expression.
        Params []*Param `json:"params,omitempty"`
 }
 
index 2a4d663..0eda118 100644 (file)
@@ -1,6 +1,9 @@
 package compiler
 
-import "fmt"
+import (
+       "fmt"
+       "strings"
+)
 
 func checkRecursive(contract *Contract) bool {
        for _, clause := range contract.Clauses {
@@ -39,63 +42,95 @@ func checkStatRecursive(stmt statement, contractName string) bool {
        return false
 }
 
-func calClauseValues(contract *Contract, env *environ, stmt statement, conditions map[string]Condition, condValues map[string][]ValueInfo, index *int) (valueInfo *ValueInfo) {
+func calClauseValues(contract *Contract, env *environ, stmt statement, condValues *[]CondValueInfo, tempVariables map[string]ExpressionInfo) (valueInfo *ValueInfo) {
        switch s := stmt.(type) {
        case *ifStatement:
-               *index++
-               strIndex := fmt.Sprintf("%d", *index)
-
                conditionCounts := make(map[string]int)
                s.condition.countVarRefs(conditionCounts)
+               condExpr := s.condition.String()
+               params := getParams(env, conditionCounts, &condExpr, tempVariables)
+               condition := ExpressionInfo{Source: condExpr, Params: params}
 
-               params := []*Param{}
-               for v := range conditionCounts {
-                       if entry := env.lookup(v); entry != nil && (entry.r == roleContractParam || entry.r == roleContractValue || entry.r == roleClauseParam || entry.r == roleClauseVariable) {
-                               params = append(params, &Param{Name: v, Type: entry.t})
-                       }
-               }
-
-               condition := Condition{Source: s.condition.String(), Params: params}
-               conditions["condition_"+strIndex] = condition
-
-               trueValues := []ValueInfo{}
+               var trueValues []ValueInfo
                for _, trueStmt := range s.body.trueBody {
-                       trueValue := calClauseValues(contract, env, trueStmt, conditions, condValues, index)
+                       var trueValue *ValueInfo
+                       trueValue = calClauseValues(contract, env, trueStmt, condValues, tempVariables)
                        if trueValue != nil {
                                trueValues = append(trueValues, *trueValue)
                        }
                }
-               condValues["truebody_"+strIndex] = trueValues
 
+               var falseValues []ValueInfo
                if len(s.body.falseBody) != 0 {
-                       falseValues := []ValueInfo{}
                        for _, falseStmt := range s.body.falseBody {
-                               falseValue := calClauseValues(contract, env, falseStmt, conditions, condValues, index)
+                               var falseValue *ValueInfo
+                               falseValue = calClauseValues(contract, env, falseStmt, condValues, tempVariables)
                                if falseValue != nil {
                                        falseValues = append(falseValues, *falseValue)
                                }
                        }
-                       condValues["falsebody_"+strIndex] = falseValues
                }
+               condValue := CondValueInfo{Condition: condition, TrueBodyValues: trueValues, FalseBodyValues: falseValues}
+               *condValues = append([]CondValueInfo{condValue}, *condValues...)
 
-       case *lockStatement:
-               valueInfo = &ValueInfo{
-                       Amount:  s.lockedAmount.String(),
-                       Asset:   s.lockedAsset.String(),
-                       Program: s.program.String(),
+       case *defineStatement:
+               if s.expr != nil {
+                       defineCounts := make(map[string]int)
+                       s.expr.countVarRefs(defineCounts)
+                       defineExpr := s.expr.String()
+                       params := getParams(env, defineCounts, &defineExpr, tempVariables)
+                       tempVariables[s.variable.Name] = ExpressionInfo{Source: defineExpr, Params: params}
                }
 
+       case *assignStatement:
+               assignCounts := make(map[string]int)
+               s.expr.countVarRefs(assignCounts)
+               assignExpr := s.expr.String()
+               params := getParams(env, assignCounts, &assignExpr, tempVariables)
+               tempVariables[s.variable.Name] = ExpressionInfo{Source: assignExpr, Params: params}
+
+       case *lockStatement:
+               valueInfo = &ValueInfo{Asset: s.lockedAsset.String()}
                lockCounts := make(map[string]int)
                s.lockedAmount.countVarRefs(lockCounts)
-               if _, ok := lockCounts[s.lockedAmount.String()]; !ok {
-                       params := []*Param{}
-                       for v := range lockCounts {
-                               if entry := env.lookup(v); entry != nil && (entry.r == roleContractParam || entry.r == roleContractValue || entry.r == roleClauseParam || entry.r == roleClauseVariable) {
-                                       params = append(params, &Param{Name: v, Type: entry.t})
+               lockedAmountExpr := s.lockedAmount.String()
+               if _, ok := lockCounts[lockedAmountExpr]; !ok {
+                       valueInfo.AmountParams = getParams(env, lockCounts, &lockedAmountExpr, tempVariables)
+               } else if _, ok := tempVariables[lockedAmountExpr]; ok {
+                       valueInfo.AmountParams = tempVariables[lockedAmountExpr].Params
+                       lockedAmountExpr = tempVariables[lockedAmountExpr].Source
+               }
+               valueInfo.Amount = lockedAmountExpr
+
+               programExpr := s.program.String()
+               if res, ok := s.program.(*callExpr); ok {
+                       if bi := referencedBuiltin(res.fn); bi == nil {
+                               if v, ok := res.fn.(varRef); ok {
+                                       if entry := env.lookup(string(v)); entry != nil && entry.t == contractType {
+                                               programExpr = fmt.Sprintf("%s(", string(v))
+                                               for i := 0; i < len(res.args); i++ {
+                                                       argExpr := res.args[i].String()
+                                                       argCounts := make(map[string]int)
+                                                       res.args[i].countVarRefs(argCounts)
+                                                       if _, ok := argCounts[argExpr]; !ok {
+                                                               params := getParams(env, argCounts, &argExpr, tempVariables)
+                                                               valueInfo.ContractCalls = append(valueInfo.ContractCalls, CallArgs{Source: argExpr, Position: i, Params: params})
+                                                       } else if _, ok := tempVariables[argExpr]; ok {
+                                                               valueInfo.ContractCalls = append(valueInfo.ContractCalls, CallArgs{Source: tempVariables[argExpr].Source, Position: i, Params: tempVariables[argExpr].Params})
+                                                               argExpr = tempVariables[argExpr].Source
+                                                       }
+
+                                                       if i == len(res.args)-1 {
+                                                               programExpr = fmt.Sprintf("%s%s)", programExpr, argExpr)
+                                                       } else {
+                                                               programExpr = fmt.Sprintf("%s%s, ", programExpr, argExpr)
+                                                       }
+                                               }
+                                       }
                                }
                        }
-                       valueInfo.Params = params
                }
+               valueInfo.Program = programExpr
 
        case *unlockStatement:
                valueInfo = &ValueInfo{
@@ -107,6 +142,36 @@ func calClauseValues(contract *Contract, env *environ, stmt statement, condition
        return valueInfo
 }
 
+func getParams(env *environ, counts map[string]int, expr *string, tempVariables map[string]ExpressionInfo) (params []*Param) {
+       for v := range counts {
+               if entry := env.lookup(v); entry != nil && (entry.r == roleContractParam || entry.r == roleContractValue || entry.r == roleClauseParam) {
+                       params = append(params, &Param{Name: v, Type: entry.t})
+               } else if entry.r == roleClauseVariable {
+                       if expr != nil {
+                               *expr = strings.Replace(*expr, v, tempVariables[v].Source, -1)
+                       }
+
+                       if _, ok := tempVariables[v]; ok {
+                               for _, param := range tempVariables[v].Params {
+                                       if ok := checkParams(param, params); !ok {
+                                               params = append(params, &Param{Name: param.Name, Type: param.Type})
+                                       }
+                               }
+                       }
+               }
+       }
+       return params
+}
+
+func checkParams(param *Param, params []*Param) bool {
+       for _, p := range params {
+               if p.Name == param.Name {
+                       return true
+               }
+       }
+       return false
+}
+
 func prohibitSigParams(contract *Contract) error {
        for _, p := range contract.Params {
                if p.Type == sigType {
index a567fa2..b48221b 100644 (file)
@@ -90,7 +90,7 @@ func main() {
        fmt.Fprintf(buf, "}\n\n")
 
        for _, contract := range contracts {
-               fmt.Fprintf(buf, "// contract %s(%s) locks %s\n", contract.Name, paramsStr(contract.Params), contract.Value)
+               fmt.Fprintf(buf, "// contract %s(%s) locks %s of %s\n", contract.Name, paramsStr(contract.Params), contract.Value.Amount, contract.Value.Asset)
                fmt.Fprintf(buf, "//\n")
                maxWidth := 0
                for _, step := range contract.Steps {
index 778d138..62aa4e3 100644 (file)
@@ -279,15 +279,13 @@ func compileClause(b *builder, contractStk stack, contract *Contract, env *envir
                }
        }
 
-       conditions := make(map[string]Condition)
-       condValues := make(map[string][]ValueInfo)
-       index := 0
+       var condValues []CondValueInfo
+       tempVariables := map[string]ExpressionInfo{}
        for _, stmt := range clause.statements {
-               valueInfo := calClauseValues(contract, env, stmt, conditions, condValues, &index)
+               valueInfo := calClauseValues(contract, env, stmt, &condValues, tempVariables)
                if valueInfo != nil {
                        clause.Values = append(clause.Values, *valueInfo)
                } else {
-                       clause.Conditions = conditions
                        clause.CondValues = condValues
                }
        }