package compiler import ( "encoding/hex" "fmt" "strconv" "strings" chainjson "github.com/vapor/encoding/json" ) // Contract is a compiled Equity contract. type Contract struct { // Name is the contract name. Name string `json:"name"` // Params is the list of contract parameters. Params []*Param `json:"params,omitempty"` // Clauses is the list of contract clauses. Clauses []*Clause `json:"clauses"` // Value is the name of the value locked by the contract. Value ValueInfo `json:"value"` // Body is the optimized bytecode of the contract body. This is not // a complete program! Use instantiate to turn this (plus some // arguments) into a program. Body chainjson.HexBytes `json:"body_bytecode"` // Opcodes is the human-readable string of opcodes corresponding to // Body. Opcodes string `json:"body_opcodes,omitempty"` // Recursive tells whether this contract calls itself. (This is // used to select between two possible instantiation options.) Recursive bool `json:"recursive"` // Pre-optimized list of instruction steps, with stack snapshots. Steps []Step `json:"-"` } // Param is a contract or clause parameter. type Param struct { // Name is the parameter name. Name string `json:"name"` // Type is the declared parameter type. Type typeDesc `json:"type"` // InferredType, if available, is a more-specific type than Type, // inferred from the logic of the contract. InferredType typeDesc `json:"inferred_type,omitempty"` } // Clause is a compiled contract clause. type Clause struct { // Name is the clause name. Name string `json:"name"` // Params is the list of clause parameters. Params []*Param `json:"params,omitempty"` statements []statement // BlockHeight is the list of expressions passed to greater()/less() in this // clause. BlockHeight []string `json:"blockheight,omitempty"` // HashCalls is the list of hash functions and their arguments used // in this clause. HashCalls []HashCall `json:"hash_calls,omitempty"` // Values is the list of values unlocked or relocked in this clause. Values []ValueInfo `json:"values"` // Contracts is the list of contracts called by this clause. Contracts []string `json:"contracts,omitempty"` } // HashCall describes a call to a hash function. type HashCall struct { // HashType is "sha3" or "sha256". HashType string `json:"hash_type"` // Arg is the expression passed to the hash function. Arg string `json:"arg"` // ArgType is the type of Arg. ArgType string `json:"arg_type"` } // IfBody describes a if ... else ... struct type IfStatmentBody struct { // if statements body trueBody []statement // else statements body falseBody []statement } type statement interface { countVarRefs(map[string]int) } type defineStatement struct { variable *Param expr expression } func (s defineStatement) countVarRefs(counts map[string]int) { s.expr.countVarRefs(counts) } type assignStatement struct { variable *Param expr expression } func (s assignStatement) countVarRefs(counts map[string]int) { s.expr.countVarRefs(counts) } type ifStatement struct { condition expression body *IfStatmentBody } func (s ifStatement) countVarRefs(counts map[string]int) { s.condition.countVarRefs(counts) } type verifyStatement struct { expr expression } func (s verifyStatement) countVarRefs(counts map[string]int) { s.expr.countVarRefs(counts) } type lockStatement struct { lockedAmount expression lockedAsset expression program expression // Added as a decoration, used by CHECKOUTPUT index int64 } func (s lockStatement) countVarRefs(counts map[string]int) { s.lockedAmount.countVarRefs(counts) s.lockedAsset.countVarRefs(counts) s.program.countVarRefs(counts) } type unlockStatement struct { unlockedAmount expression unlockedAsset expression } func (s unlockStatement) countVarRefs(counts map[string]int) { s.unlockedAmount.countVarRefs(counts) s.unlockedAsset.countVarRefs(counts) } type expression interface { String() string typ(*environ) typeDesc countVarRefs(map[string]int) } type binaryExpr struct { left, right expression op *binaryOp } func (e binaryExpr) String() string { return fmt.Sprintf("(%s %s %s)", e.left, e.op.op, e.right) } func (e binaryExpr) typ(*environ) typeDesc { return e.op.result } func (e binaryExpr) countVarRefs(counts map[string]int) { e.left.countVarRefs(counts) e.right.countVarRefs(counts) } type unaryExpr struct { op *unaryOp expr expression } func (e unaryExpr) String() string { return fmt.Sprintf("%s%s", e.op.op, e.expr) } func (e unaryExpr) typ(*environ) typeDesc { return e.op.result } func (e unaryExpr) countVarRefs(counts map[string]int) { e.expr.countVarRefs(counts) } type callExpr struct { fn expression args []expression } func (e callExpr) String() string { var argStrs []string for _, a := range e.args { argStrs = append(argStrs, a.String()) } return fmt.Sprintf("%s(%s)", e.fn, strings.Join(argStrs, ", ")) } func (e callExpr) typ(env *environ) typeDesc { if b := referencedBuiltin(e.fn); b != nil { switch b.name { case "sha3": if len(e.args) == 1 { switch e.args[0].typ(env) { case strType: return sha3StrType case pubkeyType: return sha3PubkeyType } } case "sha256": if len(e.args) == 1 { switch e.args[0].typ(env) { case strType: return sha256StrType case pubkeyType: return sha256PubkeyType } } } return b.result } if e.fn.typ(env) == predType { return boolType } if e.fn.typ(env) == contractType { return progType } return nilType } func (e callExpr) countVarRefs(counts map[string]int) { e.fn.countVarRefs(counts) for _, a := range e.args { a.countVarRefs(counts) } } type varRef string func (v varRef) String() string { return string(v) } func (e varRef) typ(env *environ) typeDesc { if entry := env.lookup(string(e)); entry != nil { return entry.t } return nilType } func (e varRef) countVarRefs(counts map[string]int) { counts[string(e)]++ } type bytesLiteral []byte func (e bytesLiteral) String() string { return "0x" + hex.EncodeToString([]byte(e)) } func (bytesLiteral) typ(*environ) typeDesc { return "String" } func (bytesLiteral) countVarRefs(map[string]int) {} type integerLiteral int64 func (e integerLiteral) String() string { return strconv.FormatInt(int64(e), 10) } func (integerLiteral) typ(*environ) typeDesc { return "Integer" } func (integerLiteral) countVarRefs(map[string]int) {} type booleanLiteral bool func (e booleanLiteral) String() string { if e { return "true" } return "false" } func (booleanLiteral) typ(*environ) typeDesc { return "Boolean" } func (booleanLiteral) countVarRefs(map[string]int) {} type listExpr []expression func (e listExpr) String() string { var elts []string for _, elt := range e { elts = append(elts, elt.String()) } return fmt.Sprintf("[%s]", strings.Join(elts, ", ")) } func (listExpr) typ(*environ) typeDesc { return "List" } func (e listExpr) countVarRefs(counts map[string]int) { for _, elt := range e { elt.countVarRefs(counts) } }