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.
// 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"`
// 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.
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"`
}
package compiler
-import "fmt"
+import (
+ "fmt"
+ "strings"
+)
func checkRecursive(contract *Contract) bool {
for _, clause := range contract.Clauses {
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{
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 {