OSDN Git Service

remove exp (#143)
authorPaladz <yzhu101@uottawa.ca>
Wed, 29 Nov 2017 03:19:15 +0000 (11:19 +0800)
committerGitHub <noreply@github.com>
Wed, 29 Nov 2017 03:19:15 +0000 (11:19 +0800)
17 files changed:
exp/Readme.md [deleted file]
exp/ivy/compiler/ast.go [deleted file]
exp/ivy/compiler/builder.go [deleted file]
exp/ivy/compiler/builder_test.go [deleted file]
exp/ivy/compiler/builtins.go [deleted file]
exp/ivy/compiler/checks.go [deleted file]
exp/ivy/compiler/checks_test.go [deleted file]
exp/ivy/compiler/cmd/ivyc/ivyc.go [deleted file]
exp/ivy/compiler/compile.go [deleted file]
exp/ivy/compiler/compile_test.go [deleted file]
exp/ivy/compiler/doc.go [deleted file]
exp/ivy/compiler/environ.go [deleted file]
exp/ivy/compiler/ivytest/ivytest.go [deleted file]
exp/ivy/compiler/optimize.go [deleted file]
exp/ivy/compiler/parse.go [deleted file]
exp/ivy/compiler/stack.go [deleted file]
exp/ivy/compiler/types.go [deleted file]

diff --git a/exp/Readme.md b/exp/Readme.md
deleted file mode 100644 (file)
index c638c37..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-Experimental tree
-=================
-
-Code in this tree may be committed to `main` with minimal review, but may not be imported by production code.
-
-A thorough code review is required to move code out of this tree and into Chain Core proper.
diff --git a/exp/ivy/compiler/ast.go b/exp/ivy/compiler/ast.go
deleted file mode 100644 (file)
index 22e6e41..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-package compiler
-
-import (
-       "encoding/hex"
-       "fmt"
-       "strconv"
-       "strings"
-
-       chainjson "github.com/bytom/encoding/json"
-)
-
-// Contract is a compiled Ivy 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 string `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:"declared_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"`
-
-       // Reqs is the list of requirements (from the clause's "requires"
-       // section).
-       Reqs []*ClauseReq `json:"reqs,omitempty"`
-
-       statements []statement
-
-       // MinTimes is the list of expressions passed to after() in this
-       // clause.
-       MinTimes []string `json:"mintimes,omitempty"`
-
-       // MaxTimes is the list of expressions passed to before() in this
-       // clause.
-       MaxTimes []string `json:"maxtimes,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"`
-}
-
-// ClauseReq describes a payment requirement of a clause (one of the
-// things after the "requires" keyword).
-type ClauseReq struct {
-       Name string `json:"name"`
-
-       assetExpr, amountExpr expression
-
-       // Asset is the expression describing the required asset.
-       Asset string `json:"asset"`
-
-       // Amount is the expression describing the required amount.
-       Amount string `json:"amount"`
-}
-
-type statement interface {
-       countVarRefs(map[string]int)
-}
-
-type verifyStatement struct {
-       expr expression
-}
-
-func (s verifyStatement) countVarRefs(counts map[string]int) {
-       s.expr.countVarRefs(counts)
-}
-
-type lockStatement struct {
-       locked  expression
-       program expression
-
-       // Added as a decoration, used by CHECKOUTPUT
-       index int64
-}
-
-func (s lockStatement) countVarRefs(counts map[string]int) {
-       s.locked.countVarRefs(counts)
-       s.program.countVarRefs(counts)
-}
-
-type unlockStatement struct {
-       expr expression
-}
-
-func (s unlockStatement) countVarRefs(counts map[string]int) {
-       s.expr.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)
-       }
-}
diff --git a/exp/ivy/compiler/builder.go b/exp/ivy/compiler/builder.go
deleted file mode 100644 (file)
index 180896f..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-package compiler
-
-import (
-       "fmt"
-       "strconv"
-       "strings"
-)
-
-type builder struct {
-       items         []*builderItem
-       pendingVerify *builderItem
-}
-
-type builderItem struct {
-       opcodes string
-       stk     stack
-}
-
-func (b *builder) add(opcodes string, newstack stack) stack {
-       if b.pendingVerify != nil {
-               b.items = append(b.items, b.pendingVerify)
-               b.pendingVerify = nil
-       }
-       item := &builderItem{opcodes: opcodes, stk: newstack}
-       if opcodes == "VERIFY" {
-               b.pendingVerify = item
-       } else {
-               b.items = append(b.items, item)
-       }
-       return newstack
-}
-
-func (b *builder) addRoll(stk stack, n int) stack {
-       b.addInt64(stk, int64(n))
-       return b.add("ROLL", stk.roll(n))
-}
-
-func (b *builder) addDup(stk stack) stack {
-       return b.add("DUP", stk.dup())
-}
-
-func (b *builder) addInt64(stk stack, n int64) stack {
-       s := strconv.FormatInt(n, 10)
-       return b.add(s, stk.add(s))
-}
-
-func (b *builder) addNumEqual(stk stack, desc string) stack {
-       return b.add("NUMEQUAL", stk.dropN(2).add(desc))
-}
-
-func (b *builder) addJumpIf(stk stack, label string) stack {
-       return b.add(fmt.Sprintf("JUMPIF:$%s", label), stk.drop())
-}
-
-func (b *builder) addJumpTarget(stk stack, label string) stack {
-       return b.add("$"+label, stk)
-}
-
-func (b *builder) addDrop(stk stack) stack {
-       return b.add("DROP", stk.drop())
-}
-
-func (b *builder) forgetPendingVerify() {
-       b.pendingVerify = nil
-}
-
-func (b *builder) addJump(stk stack, label string) stack {
-       return b.add(fmt.Sprintf("JUMP:$%s", label), stk)
-}
-
-func (b *builder) addVerify(stk stack) stack {
-       return b.add("VERIFY", stk.drop())
-}
-
-func (b *builder) addData(stk stack, data []byte) stack {
-       var s string
-       switch len(data) {
-       case 0:
-               s = "0"
-       case 1:
-               s = strconv.FormatInt(int64(data[0]), 10)
-       default:
-               s = fmt.Sprintf("0x%x", data)
-       }
-       return b.add(s, stk.add(s))
-}
-
-func (b *builder) addAmount(stk stack) stack {
-       return b.add("AMOUNT", stk.add("<amount>"))
-}
-
-func (b *builder) addAsset(stk stack) stack {
-       return b.add("ASSET", stk.add("<asset>"))
-}
-
-func (b *builder) addCheckOutput(stk stack, desc string) stack {
-       return b.add("CHECKOUTPUT", stk.dropN(6).add(desc))
-}
-
-func (b *builder) addBoolean(stk stack, val bool) stack {
-       if val {
-               return b.add("TRUE", stk.add("true"))
-       }
-       return b.add("FALSE", stk.add("false"))
-}
-
-func (b *builder) addOps(stk stack, ops string, desc string) stack {
-       return b.add(ops, stk.add(desc))
-}
-
-func (b *builder) addToAltStack(stk stack) (stack, string) {
-       t := stk.top()
-       return b.add("TOALTSTACK", stk.drop()), t
-}
-
-func (b *builder) addTxSigHash(stk stack) stack {
-       return b.add("TXSIGHASH", stk.add("<txsighash>"))
-}
-
-func (b *builder) addFromAltStack(stk stack, alt string) stack {
-       return b.add("FROMALTSTACK", stk.add(alt))
-}
-
-func (b *builder) addSwap(stk stack) stack {
-       return b.add("SWAP", stk.swap())
-}
-
-func (b *builder) addCheckMultisig(stk stack, n int, desc string) stack {
-       return b.add("CHECKMULTISIG", stk.dropN(n).add(desc))
-}
-
-func (b *builder) addOver(stk stack) stack {
-       return b.add("OVER", stk.over())
-}
-
-func (b *builder) addPick(stk stack, n int) stack {
-       b.addInt64(stk, int64(n))
-       return b.add("PICK", stk.pick(n))
-}
-
-func (b *builder) addCatPushdata(stk stack, desc string) stack {
-       return b.add("CATPUSHDATA", stk.dropN(2).add(desc))
-}
-
-func (b *builder) addCat(stk stack, desc string) stack {
-       return b.add("CAT", stk.dropN(2).add(desc))
-}
-
-func (b *builder) opcodes() string {
-       var ops []string
-       for _, item := range b.items {
-               ops = append(ops, item.opcodes)
-       }
-       return strings.Join(ops, " ")
-}
-
-// This is for producing listings like:
-// 5                 |  [... <clause selector> borrower lender deadline balanceAmount balanceAsset 5]
-// ROLL              |  [... borrower lender deadline balanceAmount balanceAsset <clause selector>]
-// JUMPIF:$default   |  [... borrower lender deadline balanceAmount balanceAsset]
-// $repay            |  [... borrower lender deadline balanceAmount balanceAsset]
-// 0                 |  [... borrower lender deadline balanceAmount balanceAsset 0]
-// 0                 |  [... borrower lender deadline balanceAmount balanceAsset 0 0]
-// 3                 |  [... borrower lender deadline balanceAmount balanceAsset 0 0 3]
-// ROLL              |  [... borrower lender deadline balanceAsset 0 0 balanceAmount]
-// 3                 |  [... borrower lender deadline balanceAsset 0 0 balanceAmount 3]
-// ROLL              |  [... borrower lender deadline 0 0 balanceAmount balanceAsset]
-// 1                 |  [... borrower lender deadline 0 0 balanceAmount balanceAsset 1]
-// 6                 |  [... borrower lender deadline 0 0 balanceAmount balanceAsset 1 6]
-// ROLL              |  [... borrower deadline 0 0 balanceAmount balanceAsset 1 lender]
-// CHECKOUTPUT       |  [... borrower deadline checkOutput(payment, lender)]
-// VERIFY            |  [... borrower deadline]
-// 1                 |  [... borrower deadline 1]
-// 0                 |  [... borrower deadline 1 0]
-// AMOUNT            |  [... borrower deadline 1 0 <amount>]
-// ASSET             |  [... borrower deadline 1 0 <amount> <asset>]
-// 1                 |  [... borrower deadline 1 0 <amount> <asset> 1]
-// 6                 |  [... borrower deadline 1 0 <amount> <asset> 1 6]
-// ROLL              |  [... deadline 1 0 <amount> <asset> 1 borrower]
-// CHECKOUTPUT       |  [... deadline checkOutput(collateral, borrower)]
-// JUMP:$_end        |  [... borrower lender deadline balanceAmount balanceAsset]
-// $default          |  [... borrower lender deadline balanceAmount balanceAsset]
-// 2                 |  [... borrower lender deadline balanceAmount balanceAsset 2]
-// ROLL              |  [... borrower lender balanceAmount balanceAsset deadline]
-// MINTIME LESSTHAN  |  [... borrower lender balanceAmount balanceAsset after(deadline)]
-// VERIFY            |  [... borrower lender balanceAmount balanceAsset]
-// 0                 |  [... borrower lender balanceAmount balanceAsset 0]
-// 0                 |  [... borrower lender balanceAmount balanceAsset 0 0]
-// AMOUNT            |  [... borrower lender balanceAmount balanceAsset 0 0 <amount>]
-// ASSET             |  [... borrower lender balanceAmount balanceAsset 0 0 <amount> <asset>]
-// 1                 |  [... borrower lender balanceAmount balanceAsset 0 0 <amount> <asset> 1]
-// 7                 |  [... borrower lender balanceAmount balanceAsset 0 0 <amount> <asset> 1 7]
-// ROLL              |  [... borrower balanceAmount balanceAsset 0 0 <amount> <asset> 1 lender]
-// CHECKOUTPUT       |  [... borrower balanceAmount balanceAsset checkOutput(collateral, lender)]
-// $_end             |  [... borrower lender deadline balanceAmount balanceAsset]
-
-type (
-       Step struct {
-               Opcodes string `json:"opcodes"`
-               Stack   string `json:"stack"`
-       }
-)
-
-func (b *builder) steps() []Step {
-       var result []Step
-       for _, item := range b.items {
-               result = append(result, Step{item.opcodes, item.stk.String()})
-       }
-       return result
-}
diff --git a/exp/ivy/compiler/builder_test.go b/exp/ivy/compiler/builder_test.go
deleted file mode 100644 (file)
index 63ec6b1..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-package compiler
-
-// func TestBuilder(t *testing.T) {
-//     cases := []struct {
-//             name    string
-//             f       func(*builder)
-//             wantHex string
-//     }{
-//             {
-//                     "single pushdata",
-//                     func(b *builder) {
-//                             b.addInt64(1)
-//                     },
-//                     "51",
-//             },
-//             {
-//                     "pushdata and verify",
-//                     func(b *builder) {
-//                             b.addInt64(1)
-//                             b.addOp(vm.OP_VERIFY)
-//                     },
-//                     "51",
-//             },
-//             {
-//                     "pushdata, verify, second pushdata",
-//                     func(b *builder) {
-//                             b.addInt64(1)
-//                             b.addOp(vm.OP_VERIFY)
-//                             b.addInt64(2)
-//                     },
-//                     "516952",
-//             },
-//     }
-//     for _, c := range cases {
-//             t.Run(c.name, func(t *testing.T) {
-//                     b := newBuilder()
-//                     c.f(b)
-//                     got, err := b.build()
-//                     if err != nil {
-//                             t.Fatal(err)
-//                     }
-//                     want, err := hex.DecodeString(c.wantHex)
-//                     if err != nil {
-//                             t.Fatal(err)
-//                     }
-//                     if !bytes.Equal(got, want) {
-//                             t.Errorf("got %x, want %x", got, want)
-//                     }
-//             })
-//     }
-// }
diff --git a/exp/ivy/compiler/builtins.go b/exp/ivy/compiler/builtins.go
deleted file mode 100644 (file)
index d0b70e3..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-package compiler
-
-type builtin struct {
-       name    string
-       opcodes string
-       args    []typeDesc
-       result  typeDesc
-}
-
-var builtins = []builtin{
-       {"sha3", "SHA3", []typeDesc{nilType}, hashType},
-       {"sha256", "SHA256", []typeDesc{nilType}, hashType},
-       {"size", "SIZE SWAP DROP", []typeDesc{nilType}, intType},
-       {"abs", "ABS", []typeDesc{intType}, intType},
-       {"min", "MIN", []typeDesc{intType, intType}, intType},
-       {"max", "MAX", []typeDesc{intType, intType}, intType},
-       {"checkTxSig", "TXSIGHASH SWAP CHECKSIG", []typeDesc{pubkeyType, sigType}, boolType},
-       {"concat", "CAT", []typeDesc{nilType, nilType}, strType},
-       {"concatpush", "CATPUSHDATA", []typeDesc{nilType, nilType}, strType},
-       {"before", "MAXTIME GREATERTHAN", []typeDesc{timeType}, boolType},
-       {"after", "MINTIME LESSTHAN", []typeDesc{timeType}, boolType},
-       {"checkTxMultiSig", "", []typeDesc{listType, listType}, boolType}, // WARNING WARNING WOOP WOOP special case
-}
-
-type binaryOp struct {
-       op         string
-       precedence int
-       opcodes    string
-
-       left, right, result typeDesc
-}
-
-var binaryOps = []binaryOp{
-       // disjunctions disallowed (for now?)
-       // {"||", 1, "BOOLOR", "Boolean", "Boolean", "Boolean"},
-
-       // and disallow this too
-       // {"&&", 2, "BOOLAND", "Boolean", "Boolean", "Boolean"},
-
-       {">", 3, "GREATERTHAN", "Integer", "Integer", "Boolean"},
-       {"<", 3, "LESSTHAN", "Integer", "Integer", "Boolean"},
-       {">=", 3, "GREATERTHANOREQUAL", "Integer", "Integer", "Boolean"},
-       {"<=", 3, "LESSTHANOREQUAL", "Integer", "Integer", "Boolean"},
-
-       {"==", 3, "EQUAL", "", "", "Boolean"},
-       {"!=", 3, "EQUAL NOT", "", "", "Boolean"},
-
-       {"^", 4, "XOR", "", "", ""},
-       {"|", 4, "OR", "", "", ""},
-
-       {"+", 4, "ADD", "Integer", "Integer", "Integer"},
-       {"-", 4, "SUB", "Integer", "Integer", "Integer"},
-
-       // {"&^", 5, "INVERT AND", "", "", ""},
-       {"&", 5, "AND", "", "", ""},
-
-       {"<<", 5, "LSHIFT", "Integer", "Integer", "Integer"},
-       {">>", 5, "RSHIFT", "Integer", "Integer", "Integer"},
-
-       {"%", 5, "MOD", "Integer", "Integer", "Integer"},
-       {"*", 5, "MUL", "Integer", "Integer", "Integer"},
-       {"/", 5, "DIV", "Integer", "Integer", "Integer"},
-}
-
-type unaryOp struct {
-       op      string
-       opcodes string
-
-       operand, result typeDesc
-}
-
-var unaryOps = []unaryOp{
-       {"-", "NEGATE", "Integer", "Integer"},
-
-       // not not allowed (for now?)
-       // {"!", "NOT", "Boolean", "Boolean"},
-
-       {"~", "INVERT", "", ""},
-}
diff --git a/exp/ivy/compiler/checks.go b/exp/ivy/compiler/checks.go
deleted file mode 100644 (file)
index d1a1c1a..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-package compiler
-
-import "fmt"
-
-func checkRecursive(contract *Contract) bool {
-       for _, clause := range contract.Clauses {
-               for _, stmt := range clause.statements {
-                       if l, ok := stmt.(*lockStatement); ok {
-                               if c, ok := l.program.(*callExpr); ok {
-                                       if references(c.fn, contract.Name) {
-                                               return true
-                                       }
-                               }
-                       }
-               }
-       }
-       return false
-}
-
-func prohibitSigParams(contract *Contract) error {
-       for _, p := range contract.Params {
-               if p.Type == sigType {
-                       return fmt.Errorf("contract parameter \"%s\" has type Signature, but contract parameters cannot have type Signature", p.Name)
-               }
-       }
-       return nil
-}
-
-func prohibitValueParams(contract *Contract) error {
-       for _, p := range contract.Params {
-               if p.Type == valueType {
-                       return fmt.Errorf("Value-typed contract parameter \"%s\" must appear in a \"locks\" clause", p.Name)
-               }
-       }
-       for _, c := range contract.Clauses {
-               for _, p := range c.Params {
-                       if p.Type == valueType {
-                               return fmt.Errorf("Value-typed parameter \"%s\" of clause \"%s\" must appear in a \"requires\" clause", p.Name, c.Name)
-                       }
-               }
-       }
-       return nil
-}
-
-func requireAllParamsUsedInClauses(params []*Param, clauses []*Clause) error {
-       for _, p := range params {
-               used := false
-               for _, c := range clauses {
-                       err := requireAllParamsUsedInClause([]*Param{p}, c)
-                       if err == nil {
-                               used = true
-                               break
-                       }
-               }
-               if !used {
-                       return fmt.Errorf("parameter \"%s\" is unused", p.Name)
-               }
-       }
-       return nil
-}
-
-func requireAllParamsUsedInClause(params []*Param, clause *Clause) error {
-       for _, p := range params {
-               used := false
-               for _, stmt := range clause.statements {
-                       switch s := stmt.(type) {
-                       case *verifyStatement:
-                               used = references(s.expr, p.Name)
-                       case *lockStatement:
-                               used = references(s.locked, p.Name) || references(s.program, p.Name)
-                       case *unlockStatement:
-                               used = references(s.expr, p.Name)
-                       }
-                       if used {
-                               break
-                       }
-               }
-               if !used {
-                       for _, r := range clause.Reqs {
-                               if references(r.amountExpr, p.Name) || references(r.assetExpr, p.Name) {
-                                       used = true
-                                       break
-                               }
-                       }
-               }
-               if !used {
-                       return fmt.Errorf("parameter \"%s\" is unused in clause \"%s\"", p.Name, clause.Name)
-               }
-       }
-       return nil
-}
-
-func references(expr expression, name string) bool {
-       switch e := expr.(type) {
-       case *binaryExpr:
-               return references(e.left, name) || references(e.right, name)
-       case *unaryExpr:
-               return references(e.expr, name)
-       case *callExpr:
-               if references(e.fn, name) {
-                       return true
-               }
-               for _, a := range e.args {
-                       if references(a, name) {
-                               return true
-                       }
-               }
-               return false
-       case varRef:
-               return string(e) == name
-       case listExpr:
-               for _, elt := range []expression(e) {
-                       if references(elt, name) {
-                               return true
-                       }
-               }
-               return false
-       }
-       return false
-}
-
-func requireAllValuesDisposedOnce(contract *Contract, clause *Clause) error {
-       err := valueDisposedOnce(contract.Value, clause)
-       if err != nil {
-               return err
-       }
-       for _, req := range clause.Reqs {
-               err = valueDisposedOnce(req.Name, clause)
-               if err != nil {
-                       return err
-               }
-       }
-       return nil
-}
-
-func valueDisposedOnce(name string, clause *Clause) error {
-       var count int
-       for _, s := range clause.statements {
-               switch stmt := s.(type) {
-               case *unlockStatement:
-                       if references(stmt.expr, name) {
-                               count++
-                       }
-               case *lockStatement:
-                       if references(stmt.locked, name) {
-                               count++
-                       }
-               }
-       }
-       switch count {
-       case 0:
-               return fmt.Errorf("value \"%s\" not disposed in clause \"%s\"", name, clause.Name)
-       case 1:
-               return nil
-       default:
-               return fmt.Errorf("value \"%s\" disposed multiple times in clause \"%s\"", name, clause.Name)
-       }
-}
-
-func referencedBuiltin(expr expression) *builtin {
-       if v, ok := expr.(varRef); ok {
-               for _, b := range builtins {
-                       if string(v) == b.name {
-                               return &b
-                       }
-               }
-       }
-       return nil
-}
-
-func assignIndexes(clause *Clause) {
-       var nextIndex int64
-       for _, s := range clause.statements {
-               switch stmt := s.(type) {
-               case *lockStatement:
-                       stmt.index = nextIndex
-                       nextIndex++
-
-               case *unlockStatement:
-                       nextIndex++
-               }
-       }
-}
-
-func typeCheckClause(contract *Contract, clause *Clause, env *environ) error {
-       for _, s := range clause.statements {
-               switch stmt := s.(type) {
-               case *verifyStatement:
-                       if t := stmt.expr.typ(env); t != boolType {
-                               return fmt.Errorf("expression in verify statement in clause \"%s\" has type \"%s\", must be Boolean", clause.Name, t)
-                       }
-
-               case *lockStatement:
-                       if t := stmt.locked.typ(env); t != valueType {
-                               return fmt.Errorf("expression in lock statement in clause \"%s\" has type \"%s\", must be Value", clause.Name, t)
-                       }
-                       if t := stmt.program.typ(env); t != progType {
-                               return fmt.Errorf("program in lock statement in clause \"%s\" has type \"%s\", must be Program", clause.Name, t)
-                       }
-
-               case *unlockStatement:
-                       if t := stmt.expr.typ(env); t != valueType {
-                               return fmt.Errorf("expression \"%s\" in unlock statement of clause \"%s\" has type \"%s\", must be Value", stmt.expr, clause.Name, t)
-                       }
-                       if stmt.expr.String() != contract.Value {
-                               return fmt.Errorf("expression in unlock statement of clause \"%s\" must be the contract value", clause.Name)
-                       }
-               }
-       }
-       return nil
-}
diff --git a/exp/ivy/compiler/checks_test.go b/exp/ivy/compiler/checks_test.go
deleted file mode 100644 (file)
index 79e9282..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-package compiler
-
-import "testing"
-
-func TestRequireAllParamsUsedInClauses(t *testing.T) {
-       clauses := []*Clause{
-               &Clause{
-                       statements: []statement{
-                               &verifyStatement{expr: varRef("foo")},
-                               &verifyStatement{
-                                       expr: &binaryExpr{
-                                               left:  varRef("foo"),
-                                               right: varRef("bar"),
-                                       },
-                               },
-                               &lockStatement{
-                                       locked:  varRef("baz"),
-                                       program: varRef("foo"),
-                               },
-                       },
-               },
-               &Clause{
-                       statements: []statement{
-                               &verifyStatement{expr: varRef("foo")},
-                               &verifyStatement{
-                                       expr: &binaryExpr{
-                                               left:  varRef("foo"),
-                                               right: varRef("plugh"),
-                                       },
-                               },
-                               &lockStatement{
-                                       locked:  varRef("xyzzy"),
-                                       program: varRef("foo"),
-                               },
-                       },
-               },
-       }
-
-       cases := []struct {
-               name   string
-               params []string
-               want   string
-       }{
-               {
-                       name:   "contract param used in both clauses",
-                       params: []string{"foo"},
-               },
-               {
-                       name:   "contract param used in one clause",
-                       params: []string{"bar"},
-               },
-               {
-                       name:   "contract param used in no clauses",
-                       params: []string{"y2"},
-                       want:   "parameter \"y2\" is unused",
-               },
-       }
-       for _, c := range cases {
-               t.Run(c.name, func(t *testing.T) {
-                       var params []*Param
-                       for _, p := range c.params {
-                               params = append(params, &Param{Name: p})
-                       }
-                       err := requireAllParamsUsedInClauses(params, clauses)
-                       if err == nil && c.want == "" {
-                               return
-                       }
-                       if err == nil {
-                               t.Errorf("got err==nil, want %s", c.want)
-                               return
-                       }
-                       if err.Error() != c.want {
-                               t.Errorf("got %s, want %s", err, c.want)
-                       }
-               })
-       }
-}
diff --git a/exp/ivy/compiler/cmd/ivyc/ivyc.go b/exp/ivy/compiler/cmd/ivyc/ivyc.go
deleted file mode 100644 (file)
index 92b2e2a..0000000
+++ /dev/null
@@ -1,216 +0,0 @@
-package main
-
-import (
-       "bytes"
-       "flag"
-       "fmt"
-       "log"
-       "os"
-       "strings"
-
-       "github.com/bytom/exp/ivy/compiler"
-)
-
-func main() {
-       packageName := flag.String("package", "main", "Go package name for generated file")
-       flag.Parse()
-
-       contracts, err := compiler.Compile(os.Stdin)
-       if err != nil {
-               log.Fatal(err)
-       }
-
-       fmt.Printf("package %s\n\n", *packageName)
-
-       imports := map[string]bool{
-               "bytes":        true,
-               "encoding/hex": true,
-               "fmt":          true,
-               "chain/exp/ivy/compiler": true,
-               "chain/protocol/vm":      true,
-       }
-
-       buf := new(bytes.Buffer)
-
-       if len(contracts) == 1 {
-               fmt.Fprintf(buf, "var %s_body_bytes []byte\n\n", contracts[0].Name)
-       } else {
-               fmt.Fprintf(buf, "var (\n")
-               for _, contract := range contracts {
-                       fmt.Fprintf(buf, "\t%s_body_bytes []byte\n", contract.Name)
-               }
-               fmt.Fprintf(buf, ")\n\n")
-       }
-
-       fmt.Fprintf(buf, "func init() {\n")
-       for _, contract := range contracts {
-               fmt.Fprintf(buf, "\t%s_body_bytes, _ = hex.DecodeString(\"%x\")\n", contract.Name, contract.Body)
-       }
-       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, "//\n")
-               maxWidth := 0
-               for _, step := range contract.Steps {
-                       if len(step.Opcodes) > maxWidth {
-                               maxWidth = len(step.Opcodes)
-                       }
-               }
-               format := fmt.Sprintf("// %%-%d.%ds  %%s\n", maxWidth, maxWidth)
-               for _, step := range contract.Steps {
-                       fmt.Fprintf(buf, format, step.Opcodes, step.Stack)
-               }
-               fmt.Fprintf(buf, "\n")
-
-               fmt.Fprintf(buf, "// PayTo%s instantiates contract %s as a program with specific arguments.\n", contract.Name, contract.Name)
-               goParams, newImports := asGoParams(contract.Params)
-               for _, imp := range newImports {
-                       imports[imp] = true
-               }
-               fmt.Fprintf(buf, "func PayTo%s(%s) ([]byte, error) {\n", contract.Name, goParams)
-               fmt.Fprintf(buf, "\t_contractParams := []compiler.Param{\n")
-               for _, param := range contract.Params {
-                       fmt.Fprintf(buf, "\t\t{Name: \"%s\", Type: \"%s\"},\n", param.Name, param.Type)
-               }
-               fmt.Fprintf(buf, "\t}\n")
-               fmt.Fprintf(buf, "\tvar _contractArgs []compiler.ContractArg\n")
-               for _, param := range contract.Params {
-                       switch param.Type {
-                       case "Amount":
-                               fmt.Fprintf(buf, "\t_%s := int64(%s)\n", param.Name, param.Name)
-                               fmt.Fprintf(buf, "\t_contractArgs = append(_contractArgs, compiler.ContractArg{I: &_%s})\n", param.Name)
-                       case "Asset":
-                               fmt.Fprintf(buf, "\t_%s := %s[:]\n", param.Name, param.Name)
-                               fmt.Fprintf(buf, "\t_contractArgs = append(_contractArgs, compiler.ContractArg{S: &_%s})\n", param.Name)
-                       case "Boolean", "Hash", "Program", "PublicKey", "Signature", "String":
-                               fmt.Fprintf(buf, "\t_contractArgs = append(_contractArgs, compiler.ContractArg{S: &%s})\n", param.Name)
-                       case "Integer":
-                               fmt.Fprintf(buf, "\t_contractArgs = append(_contractArgs, compiler.ContractArg{I: &%s})\n", param.Name)
-                       case "Time":
-                               fmt.Fprintf(buf, "\t_%s := %s.UnixNano() / time.Millisecond\n", param.Name, param.Name)
-                               fmt.Fprintf(buf, "\t_contractArgs = append(_contractArgs, compiler.ContractArg{I: &_%s})\n", param.Name)
-                       }
-               }
-               fmt.Fprintf(buf, "\treturn compiler.Instantiate(_contractParams, %s_body_bytes, %v, _contractArgs)\n", contract.Name, contract.Recursive)
-               fmt.Fprintf(buf, "}\n\n")
-
-               fmt.Fprintf(buf, "// ParsePayTo%s parses the arguments out of an instantiation of contract %s.\n", contract.Name, contract.Name)
-               fmt.Fprintf(buf, "// If the input is not an instantiation of %s, returns an error.\n", contract.Name)
-               fmt.Fprintf(buf, "func ParsePayTo%s(prog []byte) ([][]byte, error) {\n", contract.Name)
-               fmt.Fprintf(buf, "\tvar result [][]byte\n")
-               fmt.Fprintf(buf, "\tinsts, err := vm.ParseProgram(prog)\n")
-               fmt.Fprintf(buf, "\tif err != nil {\n")
-               fmt.Fprintf(buf, "\t\treturn nil, err\n")
-               fmt.Fprintf(buf, "\t}\n")
-               fmt.Fprintf(buf, "\tfor i := 0; i < %d; i++ {\n", len(contract.Params))
-               fmt.Fprintf(buf, "\t\tif len(insts) == 0 {\n")
-               fmt.Fprintf(buf, "\t\t\treturn nil, fmt.Errorf(\"program too short\")\n")
-               fmt.Fprintf(buf, "\t\t}\n")
-               fmt.Fprintf(buf, "\t\tif !insts[0].IsPushdata() {\n")
-               fmt.Fprintf(buf, "\t\t\treturn nil, fmt.Errorf(\"too few arguments\")\n")
-               fmt.Fprintf(buf, "\t\t}\n")
-               fmt.Fprintf(buf, "\t\tresult = append(result, insts[0].Data)\n")
-               fmt.Fprintf(buf, "\t\tinsts = insts[1:]\n")
-               fmt.Fprintf(buf, "\t}\n")
-               if contract.Recursive {
-                       // args... body DEPTH OVER 0 CHECKPREDICATE
-                       fmt.Fprintf(buf, "\tif len(insts) == 0 {\n")
-                       fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"program too short\")\n")
-                       fmt.Fprintf(buf, "\t}\n")
-                       fmt.Fprintf(buf, "\tif !insts[0].IsPushdata() {\n")
-                       fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"too few arguments\")\n")
-                       fmt.Fprintf(buf, "\t}\n")
-                       fmt.Fprintf(buf, "\tif !bytes.Equal(%s_body_bytes, insts[0].Data) {\n", contract.Name)
-                       fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"body bytes do not match %s\")\n", contract.Name)
-                       fmt.Fprintf(buf, "\t}\n")
-                       fmt.Fprintf(buf, "\tinsts = insts[1:]\n")
-               } // else args ... DEPTH body 0 CHECKPREDICATE
-               fmt.Fprintf(buf, "\tif len(insts) != 4 {\n")
-               fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"program too short\")\n")
-               fmt.Fprintf(buf, "\t}\n")
-               fmt.Fprintf(buf, "\tif insts[0].Op != vm.OP_DEPTH {\n")
-               fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"wrong program format\")\n")
-               fmt.Fprintf(buf, "\t}\n")
-               if contract.Recursive {
-                       fmt.Fprintf(buf, "\tif insts[1].Op != vm.OP_OVER {\n")
-                       fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"wrong program format\")\n")
-                       fmt.Fprintf(buf, "\t}\n")
-               } else {
-                       fmt.Fprintf(buf, "\tif !insts[1].IsPushdata() {\n")
-                       fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"wrong program format\")\n")
-                       fmt.Fprintf(buf, "\t}\n")
-                       fmt.Fprintf(buf, "\tif !bytes.Equal(%s_body_bytes, insts[1].Data) {\n", contract.Name)
-                       fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"body bytes do not match %s\")\n", contract.Name)
-                       fmt.Fprintf(buf, "\t}\n")
-               }
-               fmt.Fprintf(buf, "\tif !insts[2].IsPushdata() {\n")
-               fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"wrong program format\")\n")
-               fmt.Fprintf(buf, "\t}\n")
-               fmt.Fprintf(buf, "\tv, err := vm.AsInt64(insts[2].Data)\n")
-               fmt.Fprintf(buf, "\tif err != nil {\n")
-               fmt.Fprintf(buf, "\t\treturn nil, err\n")
-               fmt.Fprintf(buf, "\t}\n")
-               fmt.Fprintf(buf, "\tif v != 0 {\n")
-               fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"wrong program format\")\n")
-               fmt.Fprintf(buf, "\t}\n")
-               fmt.Fprintf(buf, "\tif insts[3].Op != vm.OP_CHECKPREDICATE {\n")
-               fmt.Fprintf(buf, "\t\treturn nil, fmt.Errorf(\"wrong program format\")\n")
-               fmt.Fprintf(buf, "\t}\n")
-               fmt.Fprintf(buf, "\treturn result, nil\n")
-               fmt.Fprintf(buf, "}\n\n")
-
-               // TODO(bobg): RedeemFoo_Bar functions for marshaling the args to
-               // the Bar clause of contract Foo.
-       }
-
-       fmt.Printf("import (\n")
-       for imp := range imports {
-               fmt.Printf("\t\"%s\"\n", imp)
-       }
-       fmt.Printf(")\n\n")
-
-       os.Stdout.Write(buf.Bytes())
-}
-
-func paramsStr(params []*compiler.Param) string {
-       var strs []string
-       for _, p := range params {
-               strs = append(strs, fmt.Sprintf("%s: %s", p.Name, p.Type))
-       }
-       return strings.Join(strs, ", ")
-}
-
-func asGoParams(params []*compiler.Param) (goParams string, imports []string) {
-       var strs []string
-       for _, p := range params {
-               var typ string
-               switch p.Type {
-               case "Amount":
-                       typ = "uint64"
-               case "Asset":
-                       typ = "bc.AssetId"
-                       imports = append(imports, "chain/protocol/bc")
-               case "Boolean":
-                       typ = "bool"
-               case "Hash":
-                       typ = "[]byte"
-               case "Integer":
-                       typ = "int64"
-               case "Program":
-                       typ = "[]byte"
-               case "PublicKey":
-                       typ = "ed25519.PublicKey"
-                       imports = append(imports, "chain/crypto/ed25519")
-               case "Signature":
-                       typ = "[]byte"
-               case "String":
-                       typ = "[]byte"
-               case "Time":
-                       typ = "time.Time"
-                       imports = append(imports, "time")
-               }
-               strs = append(strs, fmt.Sprintf("%s %s", p.Name, typ))
-       }
-       return strings.Join(strs, ", "), imports
-}
diff --git a/exp/ivy/compiler/compile.go b/exp/ivy/compiler/compile.go
deleted file mode 100644 (file)
index f55ff72..0000000
+++ /dev/null
@@ -1,756 +0,0 @@
-package compiler
-
-import (
-       "encoding/json"
-       "fmt"
-       "io"
-       "io/ioutil"
-
-       chainjson "github.com/bytom/encoding/json"
-       "github.com/bytom/errors"
-       "github.com/bytom/protocol/vm"
-       "github.com/bytom/protocol/vm/vmutil"
-)
-
-// ValueInfo describes how a blockchain value is used in a contract
-// clause.
-type ValueInfo struct {
-       // Name is the clause's name for this value.
-       Name string `json:"name"`
-
-       // Program is the program expression used to the lock the value, if
-       // the value is locked with "lock." If it's unlocked with "unlock"
-       // instead, this is empty.
-       Program string `json:"program,omitempty"`
-
-       // Asset is the expression describing the asset type the value must
-       // have, as it appears in a clause's "requires" section. If this is
-       // the contract value instead, this is empty.
-       Asset string `json:"asset,omitempty"`
-
-       // Amount is the expression describing the amount the value must
-       // have, as it appears in a clause's "requires" section. If this is
-       // the contract value instead, this is empty.
-       Amount string `json:"amount,omitempty"`
-}
-
-// ContractArg is an argument with which to instantiate a contract as
-// a program. Exactly one of B, I, and S should be supplied.
-type ContractArg struct {
-       B *bool               `json:"boolean,omitempty"`
-       I *int64              `json:"integer,omitempty"`
-       S *chainjson.HexBytes `json:"string,omitempty"`
-}
-
-// Compile parses a sequence of Ivy contracts from the supplied reader
-// and produces Contract objects containing the compiled bytecode and
-// other analysis. If argMap is non-nil, it maps contract names to
-// lists of arguments with which to instantiate them as programs, with
-// the results placed in the contract's Program field. A contract
-// named in argMap but not found in the input is silently ignored.
-func Compile(r io.Reader) ([]*Contract, error) {
-       inp, err := ioutil.ReadAll(r)
-       if err != nil {
-               return nil, errors.Wrap(err, "reading input")
-       }
-       contracts, err := parse(inp)
-       if err != nil {
-               return nil, errors.Wrap(err, "parse error")
-       }
-
-       globalEnv := newEnviron(nil)
-       for _, k := range keywords {
-               globalEnv.add(k, nilType, roleKeyword)
-       }
-       for _, b := range builtins {
-               globalEnv.add(b.name, nilType, roleBuiltin)
-       }
-
-       // All contracts must be checked for recursiveness before any are
-       // compiled.
-       for _, contract := range contracts {
-               contract.Recursive = checkRecursive(contract)
-       }
-
-       for _, contract := range contracts {
-               err = globalEnv.addContract(contract)
-               if err != nil {
-                       return nil, err
-               }
-       }
-
-       for _, contract := range contracts {
-               err = compileContract(contract, globalEnv)
-               if err != nil {
-                       return nil, errors.Wrap(err, "compiling contract")
-               }
-               for _, clause := range contract.Clauses {
-                       for _, stmt := range clause.statements {
-                               switch s := stmt.(type) {
-                               case *lockStatement:
-                                       valueInfo := ValueInfo{
-                                               Name:    s.locked.String(),
-                                               Program: s.program.String(),
-                                       }
-                                       if s.locked.String() != contract.Value {
-                                               for _, r := range clause.Reqs {
-                                                       if s.locked.String() == r.Name {
-                                                               valueInfo.Asset = r.assetExpr.String()
-                                                               valueInfo.Amount = r.amountExpr.String()
-                                                               break
-                                                       }
-                                               }
-                                       }
-                                       clause.Values = append(clause.Values, valueInfo)
-                               case *unlockStatement:
-                                       valueInfo := ValueInfo{Name: contract.Value}
-                                       clause.Values = append(clause.Values, valueInfo)
-                               }
-                       }
-               }
-       }
-
-       return contracts, nil
-}
-
-func Instantiate(body []byte, params []*Param, recursive bool, args []ContractArg) ([]byte, error) {
-       if len(args) != len(params) {
-               return nil, fmt.Errorf("got %d argument(s), want %d", len(args), len(params))
-       }
-
-       // typecheck args against param types
-       for i, param := range params {
-               arg := args[i]
-               switch param.Type {
-               case amountType, intType, timeType:
-                       if arg.I == nil {
-                               return nil, fmt.Errorf("type mismatch in arg %d (want integer)", i)
-                       }
-               case assetType, hashType, progType, pubkeyType, sigType, strType:
-                       if arg.S == nil {
-                               return nil, fmt.Errorf("type mismatch in arg %d (want string)", i)
-                       }
-               case boolType:
-                       if arg.B == nil {
-                               return nil, fmt.Errorf("type mismatch in arg %d (want boolean)", i)
-                       }
-               }
-       }
-
-       b := vmutil.NewBuilder()
-
-       for i := len(args) - 1; i >= 0; i-- {
-               a := args[i]
-               switch {
-               case a.B != nil:
-                       var n int64
-                       if *a.B {
-                               n = 1
-                       }
-                       b.AddInt64(n)
-               case a.I != nil:
-                       b.AddInt64(*a.I)
-               case a.S != nil:
-                       b.AddData(*a.S)
-               }
-       }
-
-       if recursive {
-               // <argN> <argN-1> ... <arg1> <body> DEPTH OVER 0 CHECKPREDICATE
-               b.AddData(body)
-               b.AddOp(vm.OP_DEPTH).AddOp(vm.OP_OVER)
-       } else {
-               // <argN> <argN-1> ... <arg1> DEPTH <body> 0 CHECKPREDICATE
-               b.AddOp(vm.OP_DEPTH)
-               b.AddData(body)
-       }
-       b.AddInt64(0)
-       b.AddOp(vm.OP_CHECKPREDICATE)
-       return b.Build()
-}
-
-func compileContract(contract *Contract, globalEnv *environ) error {
-       var err error
-
-       if len(contract.Clauses) == 0 {
-               return fmt.Errorf("empty contract")
-       }
-       env := newEnviron(globalEnv)
-       for _, p := range contract.Params {
-               err = env.add(p.Name, p.Type, roleContractParam)
-               if err != nil {
-                       return err
-               }
-       }
-       err = env.add(contract.Value, valueType, roleContractValue)
-       if err != nil {
-               return err
-       }
-       for _, c := range contract.Clauses {
-               err = env.add(c.Name, nilType, roleClause)
-               if err != nil {
-                       return err
-               }
-       }
-
-       err = prohibitValueParams(contract)
-       if err != nil {
-               return err
-       }
-       err = prohibitSigParams(contract)
-       if err != nil {
-               return err
-       }
-       err = requireAllParamsUsedInClauses(contract.Params, contract.Clauses)
-       if err != nil {
-               return err
-       }
-
-       var stk stack
-
-       if len(contract.Clauses) > 1 {
-               stk = stk.add("<clause selector>")
-       }
-
-       for i := len(contract.Params) - 1; i >= 0; i-- {
-               p := contract.Params[i]
-               stk = stk.add(p.Name)
-       }
-
-       if contract.Recursive {
-               stk = stk.add(contract.Name)
-       }
-
-       b := &builder{}
-
-       if len(contract.Clauses) == 1 {
-               err = compileClause(b, stk, contract, env, contract.Clauses[0])
-               if err != nil {
-                       return err
-               }
-       } else {
-               if len(contract.Params) > 0 {
-                       // A clause selector is at the bottom of the stack. Roll it to the
-                       // top.
-                       n := len(contract.Params)
-                       if contract.Recursive {
-                               n++
-                       }
-                       stk = b.addRoll(stk, n) // stack: [<clause params> <contract params> [<maybe contract body>] <clause selector>]
-               }
-
-               var stk2 stack
-
-               // clauses 2..N-1
-               for i := len(contract.Clauses) - 1; i >= 2; i-- {
-                       stk = b.addDup(stk)                                                   // stack: [... <clause selector> <clause selector>]
-                       stk = b.addInt64(stk, int64(i))                                       // stack: [... <clause selector> <clause selector> <i>]
-                       stk = b.addNumEqual(stk, fmt.Sprintf("(<clause selector> == %d)", i)) // stack: [... <clause selector> <i == clause selector>]
-                       stk = b.addJumpIf(stk, contract.Clauses[i].Name)                      // stack: [... <clause selector>]
-                       stk2 = stk                                                            // stack starts here for clauses 2 through N-1
-               }
-
-               // clause 1
-               stk = b.addJumpIf(stk, contract.Clauses[1].Name) // consumes the clause selector
-
-               // no jump needed for clause 0
-
-               for i, clause := range contract.Clauses {
-                       if i > 1 {
-                               // Clauses 0 and 1 have no clause selector on top of the
-                               // stack. Clauses 2 and later do.
-                               stk = stk2
-                       }
-
-                       b.addJumpTarget(stk, clause.Name)
-
-                       if i > 1 {
-                               stk = b.addDrop(stk)
-                       }
-
-                       err = compileClause(b, stk, contract, env, clause)
-                       if err != nil {
-                               return errors.Wrapf(err, "compiling clause \"%s\"", clause.Name)
-                       }
-                       b.forgetPendingVerify()
-                       if i < len(contract.Clauses)-1 {
-                               b.addJump(stk, "_end")
-                       }
-               }
-               b.addJumpTarget(stk, "_end")
-       }
-
-       opcodes := optimize(b.opcodes())
-       prog, err := vm.Assemble(opcodes)
-       if err != nil {
-               return err
-       }
-
-       contract.Body = prog
-       contract.Opcodes = opcodes
-
-       contract.Steps = b.steps()
-
-       return nil
-}
-
-func compileClause(b *builder, contractStk stack, contract *Contract, env *environ, clause *Clause) error {
-       var err error
-
-       // copy env to leave outerEnv unchanged
-       env = newEnviron(env)
-       for _, p := range clause.Params {
-               err = env.add(p.Name, p.Type, roleClauseParam)
-               if err != nil {
-                       return err
-               }
-       }
-       for _, req := range clause.Reqs {
-               err = env.add(req.Name, valueType, roleClauseValue)
-               if err != nil {
-                       return err
-               }
-               req.Asset = req.assetExpr.String()
-               req.Amount = req.amountExpr.String()
-       }
-
-       assignIndexes(clause)
-
-       var stk stack
-       for _, p := range clause.Params {
-               // NOTE: the order of clause params is not reversed, unlike
-               // contract params (and also unlike the arguments to Ivy
-               // function-calls).
-               stk = stk.add(p.Name)
-       }
-       stk = stk.addFromStack(contractStk)
-
-       // a count of the number of times each variable is referenced
-       counts := make(map[string]int)
-       for _, req := range clause.Reqs {
-               req.assetExpr.countVarRefs(counts)
-               req.amountExpr.countVarRefs(counts)
-       }
-       for _, s := range clause.statements {
-               s.countVarRefs(counts)
-       }
-
-       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 "before":
-                                               clause.MaxTimes = append(clause.MaxTimes, c.args[0].String())
-                                       case "after":
-                                               clause.MinTimes = append(clause.MinTimes, c.args[0].String())
-                                       }
-                               }
-                       }
-
-               case *lockStatement:
-                       // index
-                       stk = b.addInt64(stk, stmt.index)
-
-                       // refdatahash
-                       stk = b.addData(stk, nil)
-
-                       // TODO: permit more complex expressions for locked,
-                       // like "lock x+y with foo" (?)
-
-                       if stmt.locked.String() == contract.Value {
-                               stk = b.addAmount(stk)
-                               stk = b.addAsset(stk)
-                       } else {
-                               var req *ClauseReq
-                               for _, r := range clause.Reqs {
-                                       if stmt.locked.String() == r.Name {
-                                               req = r
-                                               break
-                                       }
-                               }
-                               if req == nil {
-                                       return fmt.Errorf("unknown value \"%s\" in lock statement in clause \"%s\"", stmt.locked, clause.Name)
-                               }
-
-                               // amount
-                               stk, err = compileExpr(b, stk, contract, clause, env, counts, req.amountExpr)
-                               if err != nil {
-                                       return errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
-                               }
-
-                               // asset
-                               stk, err = compileExpr(b, stk, contract, clause, env, counts, req.assetExpr)
-                               if err != nil {
-                                       return errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
-                               }
-                       }
-
-                       // version
-                       stk = b.addInt64(stk, 1)
-
-                       // prog
-                       stk, err = compileExpr(b, stk, contract, clause, env, counts, stmt.program)
-                       if err != nil {
-                               return errors.Wrapf(err, "in lock statement in clause \"%s\"", clause.Name)
-                       }
-
-                       stk = b.addCheckOutput(stk, fmt.Sprintf("checkOutput(%s, %s)", stmt.locked, stmt.program))
-                       stk = b.addVerify(stk)
-
-               case *unlockStatement:
-                       if len(clause.statements) == 1 {
-                               // This is the only statement in the clause, make sure TRUE is
-                               // on the stack.
-                               stk = b.addBoolean(stk, true)
-                       }
-               }
-       }
-
-       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 compileExpr(b *builder, stk stack, contract *Contract, clause *Clause, env *environ, counts map[string]int, expr expression) (stack, error) {
-       var err error
-
-       switch e := expr.(type) {
-       case *binaryExpr:
-               // Do typechecking after compiling subexpressions (because other
-               // compilation errors are more interesting than type mismatch
-               // errors).
-
-               stk, err = compileExpr(b, stk, contract, clause, env, counts, e.left)
-               if err != nil {
-                       return stk, errors.Wrapf(err, "in left operand of \"%s\" expression", e.op.op)
-               }
-               stk, err = compileExpr(b, stk, contract, clause, env, counts, e.right)
-               if err != nil {
-                       return stk, errors.Wrapf(err, "in right operand of \"%s\" expression", e.op.op)
-               }
-
-               lType := e.left.typ(env)
-               if e.op.left != "" && lType != e.op.left {
-                       return stk, fmt.Errorf("in \"%s\", left operand has type \"%s\", must be \"%s\"", e, lType, e.op.left)
-               }
-
-               rType := e.right.typ(env)
-               if e.op.right != "" && rType != e.op.right {
-                       return stk, fmt.Errorf("in \"%s\", right operand has type \"%s\", must be \"%s\"", e, rType, e.op.right)
-               }
-
-               switch e.op.op {
-               case "==", "!=":
-                       if lType != rType {
-                               // Maybe one is Hash and the other is (more-specific-Hash subtype).
-                               // TODO(bobg): generalize this mechanism
-                               if lType == hashType && isHashSubtype(rType) {
-                                       propagateType(contract, clause, env, rType, e.left)
-                               } else if rType == hashType && isHashSubtype(lType) {
-                                       propagateType(contract, clause, env, lType, e.right)
-                               } else {
-                                       return stk, fmt.Errorf("type mismatch in \"%s\": left operand has type \"%s\", right operand has type \"%s\"", e, lType, rType)
-                               }
-                       }
-                       if lType == "Boolean" {
-                               return stk, fmt.Errorf("in \"%s\": using \"%s\" on Boolean values not allowed", e, e.op.op)
-                       }
-               }
-
-               stk = b.addOps(stk.dropN(2), e.op.opcodes, e.String())
-
-       case *unaryExpr:
-               // Do typechecking after compiling subexpression (because other
-               // compilation errors are more interesting than type mismatch
-               // errors).
-
-               var err error
-               stk, err = compileExpr(b, stk, contract, clause, env, counts, e.expr)
-               if err != nil {
-                       return stk, errors.Wrapf(err, "in \"%s\" expression", e.op.op)
-               }
-
-               if e.op.operand != "" && e.expr.typ(env) != e.op.operand {
-                       return stk, fmt.Errorf("in \"%s\", operand has type \"%s\", must be \"%s\"", e, e.expr.typ(env), e.op.operand)
-               }
-               b.addOps(stk.drop(), e.op.opcodes, e.String())
-
-       case *callExpr:
-               bi := referencedBuiltin(e.fn)
-               if bi == nil {
-                       if v, ok := e.fn.(varRef); ok {
-                               if entry := env.lookup(string(v)); entry != nil && entry.t == contractType {
-                                       clause.Contracts = append(clause.Contracts, entry.c.Name)
-
-                                       partialName := fmt.Sprintf("%s(...)", v)
-                                       stk = b.addData(stk, nil)
-
-                                       if len(e.args) != len(entry.c.Params) {
-                                               return stk, fmt.Errorf("contract \"%s\" expects %d argument(s), got %d", entry.c.Name, len(entry.c.Params), len(e.args))
-                                       }
-
-                                       for i := len(e.args) - 1; i >= 0; i-- {
-                                               arg := e.args[i]
-                                               if entry.c.Params[i].Type != "" && arg.typ(env) != entry.c.Params[i].Type {
-                                                       return stk, fmt.Errorf("argument %d to contract \"%s\" has type \"%s\", must be \"%s\"", i, entry.c.Name, arg.typ(env), entry.c.Params[i].Type)
-                                               }
-                                               stk, err = compileExpr(b, stk, contract, clause, env, counts, arg)
-                                               if err != nil {
-                                                       return stk, err
-                                               }
-                                               stk = b.addCatPushdata(stk, partialName)
-                                       }
-
-                                       switch {
-                                       case entry.c == contract:
-                                               // Recursive call - cannot use entry.c.Body
-                                               // <argN> <argN-1> ... <arg1> <body> DEPTH OVER 0 CHECKPREDICATE
-                                               stk, err = compileRef(b, stk, counts, varRef(contract.Name))
-                                               if err != nil {
-                                                       return stk, errors.Wrap(err, "compiling contract call")
-                                               }
-                                               stk = b.addCatPushdata(stk, partialName)
-                                               stk = b.addData(stk, []byte{byte(vm.OP_DEPTH), byte(vm.OP_OVER)})
-                                               stk = b.addCat(stk, partialName)
-
-                                       case entry.c.Recursive:
-                                               // Non-recursive call to a (different) recursive contract
-                                               // <argN> <argN-1> ... <arg1> <body> DEPTH OVER 0 CHECKPREDICATE
-                                               if len(entry.c.Body) == 0 {
-                                                       // TODO(bobg): sort input contracts topologically to permit forward calling
-                                                       return stk, fmt.Errorf("contract \"%s\" not defined", entry.c.Name)
-                                               }
-                                               stk = b.addData(stk, entry.c.Body)
-                                               stk = b.addCatPushdata(stk, partialName)
-                                               stk = b.addData(stk, []byte{byte(vm.OP_DEPTH), byte(vm.OP_OVER)})
-                                               stk = b.addCat(stk, partialName)
-
-                                       default:
-                                               // Non-recursive call to non-recursive contract
-                                               // <argN> <argN-1> ... <arg1> DEPTH <body> 0 CHECKPREDICATE
-                                               stk = b.addData(stk, []byte{byte(vm.OP_DEPTH)})
-                                               stk = b.addCat(stk, partialName)
-                                               if len(entry.c.Body) == 0 {
-                                                       // TODO(bobg): sort input contracts topologically to permit forward calling
-                                                       return stk, fmt.Errorf("contract \"%s\" not defined", entry.c.Name)
-                                               }
-                                               stk = b.addData(stk, entry.c.Body)
-                                               stk = b.addCatPushdata(stk, partialName)
-                                       }
-                                       stk = b.addData(stk, vm.Int64Bytes(0))
-                                       stk = b.addCatPushdata(stk, partialName)
-                                       stk = b.addData(stk, []byte{byte(vm.OP_CHECKPREDICATE)})
-                                       stk = b.addCat(stk, e.String())
-
-                                       return stk, nil
-                               }
-                       }
-                       return stk, fmt.Errorf("unknown function \"%s\"", e.fn)
-               }
-
-               if len(e.args) != len(bi.args) {
-                       return stk, fmt.Errorf("wrong number of args for \"%s\": have %d, want %d", bi.name, len(e.args), len(bi.args))
-               }
-
-               // WARNING WARNING WOOP WOOP
-               // special-case hack
-               // WARNING WARNING WOOP WOOP
-               if bi.name == "checkTxMultiSig" {
-                       if _, ok := e.args[0].(listExpr); !ok {
-                               return stk, fmt.Errorf("checkTxMultiSig expects list literals, got %T for argument 0", e.args[0])
-                       }
-                       if _, ok := e.args[1].(listExpr); !ok {
-                               return stk, fmt.Errorf("checkTxMultiSig expects list literals, got %T for argument 1", e.args[1])
-                       }
-
-                       var k1, k2 int
-
-                       stk, k1, err = compileArg(b, stk, contract, clause, env, counts, e.args[1])
-                       if err != nil {
-                               return stk, err
-                       }
-
-                       // stack: [... sigM ... sig1 M]
-
-                       var altEntry string
-                       stk, altEntry = b.addToAltStack(stk) // stack: [... sigM ... sig1]
-                       stk = b.addTxSigHash(stk)            // stack: [... sigM ... sig1 txsighash]
-
-                       stk, k2, err = compileArg(b, stk, contract, clause, env, counts, e.args[0])
-                       if err != nil {
-                               return stk, err
-                       }
-
-                       // stack: [... sigM ... sig1 txsighash pubkeyN ... pubkey1 N]
-
-                       stk = b.addFromAltStack(stk, altEntry) // stack: [... sigM ... sig1 txsighash pubkeyN ... pubkey1 N M]
-                       stk = b.addSwap(stk)                   // stack: [... sigM ... sig1 txsighash pubkeyN ... pubkey1 M N]
-                       stk = b.addCheckMultisig(stk, k1+k2, e.String())
-
-                       return stk, nil
-               }
-
-               var k int
-
-               for i := len(e.args) - 1; i >= 0; i-- {
-                       a := e.args[i]
-                       var k2 int
-                       var err error
-                       stk, k2, err = compileArg(b, stk, contract, clause, env, counts, a)
-                       if err != nil {
-                               return stk, errors.Wrapf(err, "compiling argument %d in call expression", i)
-                       }
-                       k += k2
-               }
-
-               // Do typechecking after compiling subexpressions (because other
-               // compilation errors are more interesting than type mismatch
-               // errors).
-               for i, actual := range e.args {
-                       if bi.args[i] != "" && actual.typ(env) != bi.args[i] {
-                               return stk, fmt.Errorf("argument %d to \"%s\" has type \"%s\", must be \"%s\"", i, bi.name, actual.typ(env), bi.args[i])
-                       }
-               }
-
-               stk = b.addOps(stk.dropN(k), bi.opcodes, e.String())
-
-               // special-case reporting
-               switch bi.name {
-               case "sha3", "sha256":
-                       clause.HashCalls = append(clause.HashCalls, HashCall{bi.name, e.args[0].String(), string(e.args[0].typ(env))})
-               }
-
-       case varRef:
-               return compileRef(b, stk, counts, e)
-
-       case integerLiteral:
-               stk = b.addInt64(stk, int64(e))
-
-       case bytesLiteral:
-               stk = b.addData(stk, []byte(e))
-
-       case booleanLiteral:
-               stk = b.addBoolean(stk, bool(e))
-
-       case listExpr:
-               // Lists are excluded here because they disobey the invariant of
-               // this function: namely, that it increases the stack size by
-               // exactly one. (A list pushes its items and its length on the
-               // stack.) But they're OK as function-call arguments because the
-               // function (presumably) consumes all the stack items added.
-               return stk, fmt.Errorf("encountered list outside of function-call context")
-       }
-       return stk, nil
-}
-
-func compileArg(b *builder, stk stack, contract *Contract, clause *Clause, env *environ, counts map[string]int, expr expression) (stack, int, error) {
-       var n int
-       if list, ok := expr.(listExpr); ok {
-               for i := 0; i < len(list); i++ {
-                       elt := list[len(list)-i-1]
-                       var err error
-                       stk, err = compileExpr(b, stk, contract, clause, env, counts, elt)
-                       if err != nil {
-                               return stk, 0, err
-                       }
-                       n++
-               }
-               stk = b.addInt64(stk, int64(len(list)))
-               n++
-               return stk, n, nil
-       }
-       var err error
-       stk, err = compileExpr(b, stk, contract, clause, env, counts, expr)
-       return stk, 1, err
-}
-
-func compileRef(b *builder, stk stack, counts map[string]int, ref varRef) (stack, error) {
-       depth := stk.find(string(ref))
-       if depth < 0 {
-               return stk, fmt.Errorf("undefined reference: \"%s\"", ref)
-       }
-
-       var isFinal bool
-       if count, ok := counts[string(ref)]; ok && count > 0 {
-               count--
-               counts[string(ref)] = count
-               isFinal = count == 0
-       }
-
-       switch depth {
-       case 0:
-               if !isFinal {
-                       stk = b.addDup(stk)
-               }
-       case 1:
-               if isFinal {
-                       stk = b.addSwap(stk)
-               } else {
-                       stk = b.addOver(stk)
-               }
-       default:
-               if isFinal {
-                       stk = b.addRoll(stk, depth)
-               } else {
-                       stk = b.addPick(stk, depth)
-               }
-       }
-       return stk, nil
-}
-
-func (a *ContractArg) UnmarshalJSON(b []byte) error {
-       var m map[string]json.RawMessage
-       err := json.Unmarshal(b, &m)
-       if err != nil {
-               return err
-       }
-       if r, ok := m["boolean"]; ok {
-               var bval bool
-               err = json.Unmarshal(r, &bval)
-               if err != nil {
-                       return err
-               }
-               a.B = &bval
-               return nil
-       }
-       if r, ok := m["integer"]; ok {
-               var ival int64
-               err = json.Unmarshal(r, &ival)
-               if err != nil {
-                       return err
-               }
-               a.I = &ival
-               return nil
-       }
-       r, ok := m["string"]
-       if !ok {
-               return fmt.Errorf("contract arg must define one of boolean, integer, string")
-       }
-       var sval chainjson.HexBytes
-       err = json.Unmarshal(r, &sval)
-       if err != nil {
-               return err
-       }
-       a.S = &sval
-       return nil
-}
diff --git a/exp/ivy/compiler/compile_test.go b/exp/ivy/compiler/compile_test.go
deleted file mode 100644 (file)
index 6780df6..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-package compiler
-
-import (
-       "encoding/hex"
-       "encoding/json"
-       "strings"
-       "testing"
-
-       "github.com/bytom/exp/ivy/compiler/ivytest"
-)
-
-func TestCompile(t *testing.T) {
-       cases := []struct {
-               name     string
-               contract string
-               wantJSON string
-       }{
-               {
-                       "TrivialLock",
-                       ivytest.TrivialLock,
-                       `[{"name":"TrivialLock","clauses":[{"name":"trivialUnlock","values":[{"name":"locked"}]}],"value":"locked","body_bytecode":"51","body_opcodes":"TRUE","recursive":false}]`,
-               },
-               {
-                       "LockWithPublicKey",
-                       ivytest.LockWithPublicKey,
-                       `[{"name":"LockWithPublicKey","params":[{"name":"publicKey","declared_type":"PublicKey"}],"clauses":[{"name":"unlockWithSig","params":[{"name":"sig","declared_type":"Signature"}],"values":[{"name":"locked"}]}],"value":"locked","body_bytecode":"ae7cac","body_opcodes":"TXSIGHASH SWAP CHECKSIG","recursive":false}]`,
-               },
-               {
-                       "LockWithPublicKeyHash",
-                       ivytest.LockWithPKHash,
-                       `[{"name":"LockWithPublicKeyHash","params":[{"name":"pubKeyHash","declared_type":"Hash","inferred_type":"Sha3(PublicKey)"}],"clauses":[{"name":"spend","params":[{"name":"pubKey","declared_type":"PublicKey"},{"name":"sig","declared_type":"Signature"}],"hash_calls":[{"hash_type":"sha3","arg":"pubKey","arg_type":"PublicKey"}],"values":[{"name":"value"}]}],"value":"value","body_bytecode":"5279aa887cae7cac","body_opcodes":"2 PICK SHA3 EQUALVERIFY SWAP TXSIGHASH SWAP CHECKSIG","recursive":false}]`,
-               },
-               {
-                       "LockWith2of3Keys",
-                       ivytest.LockWith2of3Keys,
-                       `[{"name":"LockWith3Keys","params":[{"name":"pubkey1","declared_type":"PublicKey"},{"name":"pubkey2","declared_type":"PublicKey"},{"name":"pubkey3","declared_type":"PublicKey"}],"clauses":[{"name":"unlockWith2Sigs","params":[{"name":"sig1","declared_type":"Signature"},{"name":"sig2","declared_type":"Signature"}],"values":[{"name":"locked"}]}],"value":"locked","body_bytecode":"537a547a526bae71557a536c7cad","body_opcodes":"3 ROLL 4 ROLL 2 TOALTSTACK TXSIGHASH 2ROT 5 ROLL 3 FROMALTSTACK SWAP CHECKMULTISIG","recursive":false}]`,
-               },
-               {
-                       "LockToOutput",
-                       ivytest.LockToOutput,
-                       `[{"name":"LockToOutput","params":[{"name":"address","declared_type":"Program"}],"clauses":[{"name":"relock","values":[{"name":"locked","program":"address"}]}],"value":"locked","body_bytecode":"0000c3c251557ac1","body_opcodes":"0 0 AMOUNT ASSET 1 5 ROLL CHECKOUTPUT","recursive":false}]`,
-               },
-               {
-                       "TradeOffer",
-                       ivytest.TradeOffer,
-                       `[{"name":"TradeOffer","params":[{"name":"requestedAsset","declared_type":"Asset"},{"name":"requestedAmount","declared_type":"Amount"},{"name":"sellerProgram","declared_type":"Program"},{"name":"sellerKey","declared_type":"PublicKey"}],"clauses":[{"name":"trade","reqs":[{"name":"payment","asset":"requestedAsset","amount":"requestedAmount"}],"values":[{"name":"payment","program":"sellerProgram","asset":"requestedAsset","amount":"requestedAmount"},{"name":"offered"}]},{"name":"cancel","params":[{"name":"sellerSig","declared_type":"Signature"}],"values":[{"name":"offered","program":"sellerProgram"}]}],"value":"offered","body_bytecode":"547a641300000000007251557ac16323000000547a547aae7cac690000c3c251577ac1","body_opcodes":"4 ROLL JUMPIF:$cancel $trade 0 0 2SWAP 1 5 ROLL CHECKOUTPUT JUMP:$_end $cancel 4 ROLL 4 ROLL TXSIGHASH SWAP CHECKSIG VERIFY 0 0 AMOUNT ASSET 1 7 ROLL CHECKOUTPUT $_end","recursive":false}]`,
-               },
-               {
-                       "EscrowedTransfer",
-                       ivytest.EscrowedTransfer,
-                       `[{"name":"EscrowedTransfer","params":[{"name":"agent","declared_type":"PublicKey"},{"name":"sender","declared_type":"Program"},{"name":"recipient","declared_type":"Program"}],"clauses":[{"name":"approve","params":[{"name":"sig","declared_type":"Signature"}],"values":[{"name":"value","program":"recipient"}]},{"name":"reject","params":[{"name":"sig","declared_type":"Signature"}],"values":[{"name":"value","program":"sender"}]}],"value":"value","body_bytecode":"537a641b000000537a7cae7cac690000c3c251567ac1632a000000537a7cae7cac690000c3c251557ac1","body_opcodes":"3 ROLL JUMPIF:$reject $approve 3 ROLL SWAP TXSIGHASH SWAP CHECKSIG VERIFY 0 0 AMOUNT ASSET 1 6 ROLL CHECKOUTPUT JUMP:$_end $reject 3 ROLL SWAP TXSIGHASH SWAP CHECKSIG VERIFY 0 0 AMOUNT ASSET 1 5 ROLL CHECKOUTPUT $_end","recursive":false}]`,
-               },
-               {
-                       "RevealPreimage",
-                       ivytest.RevealPreimage,
-                       `[{"name":"RevealPreimage","params":[{"name":"hash","declared_type":"Hash","inferred_type":"Sha3(String)"}],"clauses":[{"name":"reveal","params":[{"name":"string","declared_type":"String"}],"hash_calls":[{"hash_type":"sha3","arg":"string","arg_type":"String"}],"values":[{"name":"value"}]}],"value":"value","body_bytecode":"7caa87","body_opcodes":"SWAP SHA3 EQUAL","recursive":false}]`,
-               },
-               {
-                       "PriceChanger",
-                       ivytest.PriceChanger,
-                       `[{"name":"PriceChanger","params":[{"name":"askAmount","declared_type":"Amount"},{"name":"askAsset","declared_type":"Asset"},{"name":"sellerKey","declared_type":"PublicKey"},{"name":"sellerProg","declared_type":"Program"}],"clauses":[{"name":"changePrice","params":[{"name":"newAmount","declared_type":"Amount"},{"name":"newAsset","declared_type":"Asset"},{"name":"sig","declared_type":"Signature"}],"values":[{"name":"offered","program":"PriceChanger(newAmount, newAsset, sellerKey, sellerProg)"}],"contracts":["PriceChanger"]},{"name":"redeem","reqs":[{"name":"payment","asset":"askAsset","amount":"askAmount"}],"values":[{"name":"payment","program":"sellerProg","asset":"askAsset","amount":"askAmount"},{"name":"offered"}]}],"value":"offered","body_bytecode":"557a6433000000557a5479ae7cac690000c3c251005a7a89597a89597a89597a89567a890274787e008901c07ec1633d0000000000537a547a51577ac1","body_opcodes":"5 ROLL JUMPIF:$redeem $changePrice 5 ROLL 4 PICK TXSIGHASH SWAP CHECKSIG VERIFY 0 0 AMOUNT ASSET 1 0 10 ROLL CATPUSHDATA 9 ROLL CATPUSHDATA 9 ROLL CATPUSHDATA 9 ROLL CATPUSHDATA 6 ROLL CATPUSHDATA 0x7478 CAT 0 CATPUSHDATA 192 CAT CHECKOUTPUT JUMP:$_end $redeem 0 0 3 ROLL 4 ROLL 1 7 ROLL CHECKOUTPUT $_end","recursive":true}]`,
-               },
-       }
-       for _, c := range cases {
-               t.Run(c.name, func(t *testing.T) {
-                       r := strings.NewReader(c.contract)
-                       got, err := Compile(r)
-                       if err != nil {
-                               t.Fatal(err)
-                       }
-                       gotJSON, _ := json.Marshal(got)
-                       if string(gotJSON) != c.wantJSON {
-                               t.Errorf("\ngot  %s\nwant %s", string(gotJSON), c.wantJSON)
-                       } else {
-                               for _, contract := range got {
-                                       t.Log(contract.Opcodes)
-                               }
-                       }
-               })
-       }
-}
-
-func mustDecodeHex(h string) []byte {
-       bits, err := hex.DecodeString(h)
-       if err != nil {
-               panic(err)
-       }
-       return bits
-}
diff --git a/exp/ivy/compiler/doc.go b/exp/ivy/compiler/doc.go
deleted file mode 100644 (file)
index 5a1736a..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
-Package ivy provides a compiler for Chain's Ivy contract language.
-
-A contract is a means to lock some payment in the output of a
-transaction. It contains a number of clauses, each describing a way to
-unlock, or redeem, the payment in a subsequent transaction.  By
-executing the statements in a clause, using contract arguments
-supplied by the payer and clause arguments supplied by the redeemer,
-nodes in a Chain network can determine whether a proposed spend is
-valid.
-
-The language definition is in flux, but here's what's implemented as
-of late May 2017.
-
-  program = contract*
-
-  contract = "contract" identifier "(" [params] ")" "locks" identifier "{" clause+ "}"
-
-    The identifier after "locks" is a name for the value locked by
-    the contract. It must be unlocked or re-locked (with "unlock"
-    or "lock") in every clause.
-
-  clause = "clause" identifier "(" [params] ")" ["requires" requirements] "{" statement+ "}"
-
-    The requirements are blockchain values that must be present in
-    the spending transaction in order to spend the value locked by
-    the earlier transaction. Each such value must be re-locked
-    (with "lock") in its clause.
-
-  statement = verify | unlock | lock
-
-  verify = "verify" expr
-
-    Verifies that boolean expression expr produces a true result.
-
-  unlock = "unlock" expr
-
-    Expr must evaluate to the contract value. This unlocks that
-    value for any use.
-
-  lock = "lock" expr "with" expr
-
-    The first expr must be a blockchain value (i.e., one named
-    with "locks" or "requires"). The second expr must be a
-    program. This unlocks expr and re-locks it with the new
-    program.
-
-  requirements = requirement | requirements "," requirement
-
-  requirement = identifier ":" expr "of" expr
-
-    The first expr must be an amount, the second must be an
-    asset. This denotes that the named value must have the given
-    quantity and asset type.
-
-  params = param | params "," param
-
-  param = idlist ":" identifier
-
-    The identifiers in idlist are individual parameter names. The
-    identifier after the colon is their type. Available types are:
-
-      Amount; Asset; Boolean; Hash; Integer; Program; PublicKey;
-      Signature; String; Time
-
-  idlist = identifier | idlist "," identifier
-
-  expr = unary_expr | binary_expr | call_expr | identifier | "(" expr ")" | literal
-
-  unary_expr = unary_op expr
-
-  binary_expr = expr binary_op expr
-
-  call_expr = expr "(" [args] ")"
-
-    If expr is the name of an Ivy contract, then calling it (with
-    the appropriate arguments) produces a program suitable for use
-    in "lock" statements.
-
-    Otherwise, expr should be one of these builtin functions:
-
-      sha3(x)
-        SHA3-256 hash of x.
-      sha256(x)
-        SHA-256 hash of x.
-      size(x)
-        Size in bytes of x.
-      abs(x)
-        Absolute value of x.
-      min(x, y)
-        The lesser of x and y.
-      max(x, y)
-        The greater of x and y.
-      checkTxSig(pubkey, signature)
-        Whether signature matches both the spending
-        transaction and pubkey.
-      concat(x, y)
-        The concatenation of x and y.
-      concatpush(x, y)
-        The concatenation of x with the bytecode sequence
-        needed to push y on the ChainVM stack.
-      before(x)
-        Whether the spending transaction is happening before
-        time x.
-      after(x)
-        Whether the spending transaction is happening after
-        time x.
-      checkTxMultiSig([pubkey1, pubkey2, ...], [sig1, sig2, ...])
-        Like checkTxSig, but for M-of-N signature checks.
-        Every sig must match both the spending transaction and
-        one of the pubkeys. There may be more pubkeys than
-        sigs, but they are only checked left-to-right so must
-        be supplied in the same order as the sigs. The square
-        brackets here are literal and must appear as shown.
-
-  unary_op = "-" | "~"
-
-  binary_op = ">" | "<" | ">=" | "<=" | "==" | "!=" | "^" | "|" |
-        "+" | "-" | "&" | "<<" | ">>" | "%" | "*" | "/"
-
-  args = expr | args "," expr
-
-  literal = int_literal | str_literal | hex_literal
-
-*/
-package compiler
diff --git a/exp/ivy/compiler/environ.go b/exp/ivy/compiler/environ.go
deleted file mode 100644 (file)
index 07c4645..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-package compiler
-
-import "fmt"
-
-// name-binding environment
-type environ struct {
-       entries map[string]*envEntry
-       parent  *environ
-}
-
-type envEntry struct {
-       t typeDesc
-       r role
-       c *Contract // if t == contractType
-}
-
-type role int
-
-const (
-       roleKeyword role = 1 + iota
-       roleBuiltin
-       roleContract
-       roleContractParam
-       roleContractValue
-       roleClause
-       roleClauseParam
-       roleClauseValue
-)
-
-var roleDesc = map[role]string{
-       roleKeyword:       "keyword",
-       roleBuiltin:       "built-in function",
-       roleContract:      "contract",
-       roleContractParam: "contract parameter",
-       roleContractValue: "contract value",
-       roleClause:        "clause",
-       roleClauseParam:   "clause parameter",
-       roleClauseValue:   "clause value",
-}
-
-func newEnviron(parent *environ) *environ {
-       return &environ{
-               entries: make(map[string]*envEntry),
-               parent:  parent,
-       }
-}
-
-func (e *environ) add(name string, t typeDesc, r role) error {
-       if entry := e.lookup(name); entry != nil {
-               return fmt.Errorf("%s \"%s\" conflicts with %s", roleDesc[r], name, roleDesc[entry.r])
-       }
-       e.entries[name] = &envEntry{t: t, r: r}
-       return nil
-}
-
-func (e *environ) addContract(contract *Contract) error {
-       if entry := e.lookup(contract.Name); entry != nil {
-               return fmt.Errorf("%s \"%s\" conflicts with %s", roleDesc[roleContract], contract.Name, roleDesc[entry.r])
-       }
-       e.entries[contract.Name] = &envEntry{t: contractType, r: roleContract, c: contract}
-       return nil
-}
-
-func (e environ) lookup(name string) *envEntry {
-       if res, ok := e.entries[name]; ok {
-               return res
-       }
-       if e.parent != nil {
-               return e.parent.lookup(name)
-       }
-       return nil
-}
diff --git a/exp/ivy/compiler/ivytest/ivytest.go b/exp/ivy/compiler/ivytest/ivytest.go
deleted file mode 100644 (file)
index 55888a1..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-package ivytest
-
-const TrivialLock = `
-contract TrivialLock() locks locked {
-  clause trivialUnlock() {
-    unlock locked
-  }
-}
-`
-
-const LockWithPublicKey = `
-contract LockWithPublicKey(publicKey: PublicKey) locks locked {
-  clause unlockWithSig(sig: Signature) {
-    verify checkTxSig(publicKey, sig)
-    unlock locked
-  }
-}
-`
-
-const LockWithPKHash = `
-contract LockWithPublicKeyHash(pubKeyHash: Hash) locks value {
-  clause spend(pubKey: PublicKey, sig: Signature) {
-    verify sha3(pubKey) == pubKeyHash
-    verify checkTxSig(pubKey, sig)
-    unlock value
-  }
-}
-`
-
-const LockWith2of3Keys = `
-contract LockWith3Keys(pubkey1, pubkey2, pubkey3: PublicKey) locks locked {
-  clause unlockWith2Sigs(sig1, sig2: Signature) {
-    verify checkTxMultiSig([pubkey1, pubkey2, pubkey3], [sig1, sig2])
-    unlock locked
-  }
-}
-`
-
-const LockToOutput = `
-contract LockToOutput(address: Program) locks locked {
-  clause relock() {
-    lock locked with address
-  }
-}
-`
-
-const TradeOffer = `
-contract TradeOffer(requestedAsset: Asset, requestedAmount: Amount, sellerProgram: Program, sellerKey: PublicKey) locks offered {
-  clause trade() requires payment: requestedAmount of requestedAsset {
-    lock payment with sellerProgram
-    unlock offered
-  }
-  clause cancel(sellerSig: Signature) {
-    verify checkTxSig(sellerKey, sellerSig)
-    lock offered with sellerProgram
-  }
-}
-`
-
-const EscrowedTransfer = `
-contract EscrowedTransfer(agent: PublicKey, sender: Program, recipient: Program) locks value {
-  clause approve(sig: Signature) {
-    verify checkTxSig(agent, sig)
-    lock value with recipient
-  }
-  clause reject(sig: Signature) {
-    verify checkTxSig(agent, sig)
-    lock value with sender
-  }
-}
-`
-
-const CollateralizedLoan = `
-contract CollateralizedLoan(balanceAsset: Asset, balanceAmount: Amount, deadline: Time, lender: Program, borrower: Program) locks collateral {
-  clause repay() requires payment: balanceAmount of balanceAsset {
-    lock payment with lender
-    lock collateral with borrower
-  }
-  clause default() {
-    verify after(deadline)
-    lock collateral with lender
-  }
-}
-`
-
-const RevealPreimage = `
-contract RevealPreimage(hash: Hash) locks value {
-  clause reveal(string: String) {
-    verify sha3(string) == hash
-    unlock value
-  }
-}
-`
-
-const PriceChanger = `
-contract PriceChanger(askAmount: Amount, askAsset: Asset, sellerKey: PublicKey, sellerProg: Program) locks offered {
-  clause changePrice(newAmount: Amount, newAsset: Asset, sig: Signature) {
-    verify checkTxSig(sellerKey, sig)
-    lock offered with PriceChanger(newAmount, newAsset, sellerKey, sellerProg)
-  }
-  clause redeem() requires payment: askAmount of askAsset {
-    lock payment with sellerProg
-    unlock offered
-  }
-}
-`
-
-const CallOptionWithSettlement = `
-contract CallOptionWithSettlement(strikePrice: Amount,
-                    strikeCurrency: Asset,
-                    sellerProgram: Program,
-                    sellerKey: PublicKey,
-                    buyerKey: PublicKey,
-                    deadline: Time) locks underlying {
-  clause exercise(buyerSig: Signature)
-                 requires payment: strikePrice of strikeCurrency {
-    verify before(deadline)
-    verify checkTxSig(buyerKey, buyerSig)
-    lock payment with sellerProgram
-    unlock underlying
-  }
-  clause expire() {
-    verify after(deadline)
-    lock underlying with sellerProgram
-  }
-  clause settle(sellerSig: Signature, buyerSig: Signature) {
-    verify checkTxSig(sellerKey, sellerSig)
-    verify checkTxSig(buyerKey, buyerSig)
-    unlock underlying
-  }
-}
-`
-
-const OneTwo = `
-contract Two(b, c: Program, expirationTime: Time) locks value {
-  clause redeem() {
-    verify before(expirationTime)
-    lock value with b
-  }
-  clause default() {
-    verify after(expirationTime)
-    lock value with c
-  }
-}
-contract One(a, b, c: Program, switchTime, expirationTime: Time) locks value {
-  clause redeem() {
-    verify before(switchTime)
-    lock value with a
-  }
-  clause switch() {
-    verify after(switchTime)
-    lock value with Two(b, c, expirationTime)
-  }
-}
-`
diff --git a/exp/ivy/compiler/optimize.go b/exp/ivy/compiler/optimize.go
deleted file mode 100644 (file)
index f05cac4..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-package compiler
-
-import "strings"
-
-var optimizations = []struct {
-       before, after string
-}{
-       {"0 ROLL", ""},
-       {"0 PICK", "DUP"},
-       {"1 ROLL", "SWAP"},
-       {"1 PICK", "OVER"},
-       {"2 ROLL", "ROT"},
-       {"TRUE VERIFY", ""},
-       {"SWAP SWAP", ""},
-       {"OVER OVER", "2DUP"},
-       {"SWAP OVER", "TUCK"},
-       {"DROP DROP", "2DROP"},
-       {"SWAP DROP", "NIP"},
-       {"5 ROLL 5 ROLL", "2ROT"},
-       {"3 PICK 3 PICK", "2OVER"},
-       {"3 ROLL 3 ROLL", "2SWAP"},
-       {"2 PICK 2 PICK 2 PICK", "3DUP"},
-       {"1 ADD", "1ADD"},
-       {"1 SUB", "1SUB"},
-       {"EQUAL VERIFY", "EQUALVERIFY"},
-       {"SWAP TXSIGHASH ROT", "TXSIGHASH SWAP"},
-       {"SWAP EQUAL", "EQUAL"},
-       {"SWAP EQUALVERIFY", "EQUALVERIFY"},
-       {"SWAP ADD", "ADD"},
-       {"SWAP BOOLAND", "BOOLAND"},
-       {"SWAP BOOLOR", "BOOLOR"},
-       {"SWAP MIN", "MIN"},
-       {"SWAP MAX", "MAX"},
-       {"DUP 2 PICK EQUAL", "2DUP EQUAL"},
-       {"DUP 2 PICK EQUALVERIFY", "2DUP EQUALVERIFY"},
-       {"DUP 2 PICK ADD", "2DUP ADD"},
-       {"DUP 2 PICK BOOLAND", "2DUP BOOLAND"},
-       {"DUP 2 PICK BOOLOR", "2DUP BOOLOR"},
-       {"DUP 2 PICK MIN", "2DUP MIN"},
-       {"DUP 2 PICK MAX", "2DUP MAX"},
-}
-
-func optimize(opcodes string) string {
-       opcodes = " " + opcodes + " "
-       looping := true
-       for looping {
-               looping = false
-               for _, o := range optimizations {
-                       before := " " + o.before + " "
-                       var after string
-                       if o.after == "" {
-                               after = " "
-                       } else {
-                               after = " " + o.after + " "
-                       }
-                       newOpcodes := strings.Replace(opcodes, before, after, -1)
-                       if newOpcodes != opcodes {
-                               looping = true
-                               opcodes = newOpcodes
-                       }
-               }
-       }
-       return strings.TrimSpace(opcodes)
-}
diff --git a/exp/ivy/compiler/parse.go b/exp/ivy/compiler/parse.go
deleted file mode 100644 (file)
index 61a4765..0000000
+++ /dev/null
@@ -1,563 +0,0 @@
-package compiler
-
-import (
-       "bytes"
-       "encoding/hex"
-       "fmt"
-       "strconv"
-       "unicode"
-)
-
-// We have some function naming conventions.
-//
-// For terminals:
-//   scanX     takes buf and position, returns new position (and maybe a value)
-//   peekX     takes *parser, returns bool or string
-//   consumeX  takes *parser and maybe a required literal, maybe returns value
-//             also updates the parser position
-//
-// For nonterminals:
-//   parseX    takes *parser, returns AST node, updates parser position
-
-type parser struct {
-       buf []byte
-       pos int
-}
-
-func (p *parser) errorf(format string, args ...interface{}) {
-       panic(parserErr{buf: p.buf, offset: p.pos, format: format, args: args})
-}
-
-// parse is the main entry point to the parser
-func parse(buf []byte) (contracts []*Contract, err error) {
-       defer func() {
-               if val := recover(); val != nil {
-                       if e, ok := val.(parserErr); ok {
-                               err = e
-                       } else {
-                               panic(val)
-                       }
-               }
-       }()
-       p := &parser{buf: buf}
-       contracts = parseContracts(p)
-       return
-}
-
-// parse functions
-
-func parseContracts(p *parser) []*Contract {
-       var result []*Contract
-       for peekKeyword(p) == "contract" {
-               contract := parseContract(p)
-               result = append(result, contract)
-       }
-       return result
-}
-
-// contract name(p1, p2: t1, p3: t2) locks value { ... }
-func parseContract(p *parser) *Contract {
-       consumeKeyword(p, "contract")
-       name := consumeIdentifier(p)
-       params := parseParams(p)
-       consumeKeyword(p, "locks")
-       value := consumeIdentifier(p)
-       consumeTok(p, "{")
-       clauses := parseClauses(p)
-       consumeTok(p, "}")
-       return &Contract{Name: name, Params: params, Clauses: clauses, Value: value}
-}
-
-// (p1, p2: t1, p3: t2)
-func parseParams(p *parser) []*Param {
-       var params []*Param
-       consumeTok(p, "(")
-       first := true
-       for !peekTok(p, ")") {
-               if first {
-                       first = false
-               } else {
-                       consumeTok(p, ",")
-               }
-               pt := parseParamsType(p)
-               params = append(params, pt...)
-       }
-       consumeTok(p, ")")
-       return params
-}
-
-func parseClauses(p *parser) []*Clause {
-       var clauses []*Clause
-       for !peekTok(p, "}") {
-               c := parseClause(p)
-               clauses = append(clauses, c)
-       }
-       return clauses
-}
-
-func parseParamsType(p *parser) []*Param {
-       firstName := consumeIdentifier(p)
-       params := []*Param{&Param{Name: firstName}}
-       for peekTok(p, ",") {
-               consumeTok(p, ",")
-               name := consumeIdentifier(p)
-               params = append(params, &Param{Name: name})
-       }
-       consumeTok(p, ":")
-       typ := consumeIdentifier(p)
-       for _, parm := range params {
-               if tdesc, ok := types[typ]; ok {
-                       parm.Type = tdesc
-               } else {
-                       p.errorf("unknown type %s", typ)
-               }
-       }
-       return params
-}
-
-func parseClause(p *parser) *Clause {
-       var c Clause
-       consumeKeyword(p, "clause")
-       c.Name = consumeIdentifier(p)
-       c.Params = parseParams(p)
-       if peekKeyword(p) == "requires" {
-               consumeKeyword(p, "requires")
-               c.Reqs = parseClauseRequirements(p)
-       }
-       consumeTok(p, "{")
-       c.statements = parseStatements(p)
-       consumeTok(p, "}")
-       return &c
-}
-
-func parseClauseRequirements(p *parser) []*ClauseReq {
-       var result []*ClauseReq
-       first := true
-       for {
-               switch {
-               case first:
-                       first = false
-               case peekTok(p, ","):
-                       consumeTok(p, ",")
-               default:
-                       return result
-               }
-               var req ClauseReq
-               req.Name = consumeIdentifier(p)
-               consumeTok(p, ":")
-               req.amountExpr = parseExpr(p)
-               consumeKeyword(p, "of")
-               req.assetExpr = parseExpr(p)
-               result = append(result, &req)
-       }
-}
-
-func parseStatements(p *parser) []statement {
-       var statements []statement
-       for !peekTok(p, "}") {
-               s := parseStatement(p)
-               statements = append(statements, s)
-       }
-       return statements
-}
-
-func parseStatement(p *parser) statement {
-       switch peekKeyword(p) {
-       case "verify":
-               return parseVerifyStmt(p)
-       case "lock":
-               return parseLockStmt(p)
-       case "unlock":
-               return parseUnlockStmt(p)
-       }
-       panic(parseErr(p.buf, p.pos, "unknown keyword \"%s\"", peekKeyword(p)))
-}
-
-func parseVerifyStmt(p *parser) *verifyStatement {
-       consumeKeyword(p, "verify")
-       expr := parseExpr(p)
-       return &verifyStatement{expr: expr}
-}
-
-func parseLockStmt(p *parser) *lockStatement {
-       consumeKeyword(p, "lock")
-       locked := parseExpr(p)
-       consumeKeyword(p, "with")
-       program := parseExpr(p)
-       return &lockStatement{locked: locked, program: program}
-}
-
-func parseUnlockStmt(p *parser) *unlockStatement {
-       consumeKeyword(p, "unlock")
-       expr := parseExpr(p)
-       return &unlockStatement{expr}
-}
-
-func parseExpr(p *parser) expression {
-       // Uses the precedence-climbing algorithm
-       // <https://en.wikipedia.org/wiki/Operator-precedence_parser#Precedence_climbing_method>
-       expr := parseUnaryExpr(p)
-       expr2, pos := parseExprCont(p, expr, 0)
-       if pos < 0 {
-               p.errorf("expected expression")
-       }
-       p.pos = pos
-       return expr2
-}
-
-func parseUnaryExpr(p *parser) expression {
-       op, pos := scanUnaryOp(p.buf, p.pos)
-       if pos < 0 {
-               return parseExpr2(p)
-       }
-       p.pos = pos
-       expr := parseUnaryExpr(p)
-       return &unaryExpr{op: op, expr: expr}
-}
-
-func parseExprCont(p *parser, lhs expression, minPrecedence int) (expression, int) {
-       for {
-               op, pos := scanBinaryOp(p.buf, p.pos)
-               if pos < 0 || op.precedence < minPrecedence {
-                       break
-               }
-               p.pos = pos
-
-               rhs := parseUnaryExpr(p)
-
-               for {
-                       op2, pos2 := scanBinaryOp(p.buf, p.pos)
-                       if pos2 < 0 || op2.precedence <= op.precedence {
-                               break
-                       }
-                       rhs, p.pos = parseExprCont(p, rhs, op2.precedence)
-                       if p.pos < 0 {
-                               return nil, -1 // or is this an error?
-                       }
-               }
-               lhs = &binaryExpr{left: lhs, right: rhs, op: op}
-       }
-       return lhs, p.pos
-}
-
-func parseExpr2(p *parser) expression {
-       if expr, pos := scanLiteralExpr(p.buf, p.pos); pos >= 0 {
-               p.pos = pos
-               return expr
-       }
-       return parseExpr3(p)
-}
-
-func parseExpr3(p *parser) expression {
-       e := parseExpr4(p)
-       if peekTok(p, "(") {
-               args := parseArgs(p)
-               return &callExpr{fn: e, args: args}
-       }
-       return e
-}
-
-func parseExpr4(p *parser) expression {
-       if peekTok(p, "(") {
-               consumeTok(p, "(")
-               e := parseExpr(p)
-               consumeTok(p, ")")
-               return e
-       }
-       if peekTok(p, "[") {
-               var elts []expression
-               consumeTok(p, "[")
-               first := true
-               for !peekTok(p, "]") {
-                       if first {
-                               first = false
-                       } else {
-                               consumeTok(p, ",")
-                       }
-                       e := parseExpr(p)
-                       elts = append(elts, e)
-               }
-               consumeTok(p, "]")
-               return listExpr(elts)
-       }
-       name := consumeIdentifier(p)
-       return varRef(name)
-}
-
-func parseArgs(p *parser) []expression {
-       var exprs []expression
-       consumeTok(p, "(")
-       first := true
-       for !peekTok(p, ")") {
-               if first {
-                       first = false
-               } else {
-                       consumeTok(p, ",")
-               }
-               e := parseExpr(p)
-               exprs = append(exprs, e)
-       }
-       consumeTok(p, ")")
-       return exprs
-}
-
-// peek functions
-
-func peekKeyword(p *parser) string {
-       name, _ := scanIdentifier(p.buf, p.pos)
-       return name
-}
-
-func peekTok(p *parser, token string) bool {
-       pos := scanTok(p.buf, p.pos, token)
-       return pos >= 0
-}
-
-// consume functions
-
-var keywords = []string{
-       "contract", "clause", "verify", "output", "return",
-       "locks", "requires", "of", "lock", "with", "unlock",
-}
-
-func consumeKeyword(p *parser, keyword string) {
-       pos := scanKeyword(p.buf, p.pos, keyword)
-       if pos < 0 {
-               p.errorf("expected keyword %s", keyword)
-       }
-       p.pos = pos
-}
-
-func consumeIdentifier(p *parser) string {
-       name, pos := scanIdentifier(p.buf, p.pos)
-       if pos < 0 {
-               p.errorf("expected identifier")
-       }
-       p.pos = pos
-       return name
-}
-
-func consumeTok(p *parser, token string) {
-       pos := scanTok(p.buf, p.pos, token)
-       if pos < 0 {
-               p.errorf("expected %s token", token)
-       }
-       p.pos = pos
-}
-
-// scan functions
-
-func scanUnaryOp(buf []byte, offset int) (*unaryOp, int) {
-       // Maximum munch. Make sure "-3" scans as ("-3"), not ("-", "3").
-       if _, pos := scanIntLiteral(buf, offset); pos >= 0 {
-               return nil, -1
-       }
-       for _, op := range unaryOps {
-               newOffset := scanTok(buf, offset, op.op)
-               if newOffset >= 0 {
-                       return &op, newOffset
-               }
-       }
-       return nil, -1
-}
-
-func scanBinaryOp(buf []byte, offset int) (*binaryOp, int) {
-       offset = skipWsAndComments(buf, offset)
-       var (
-               found     *binaryOp
-               newOffset = -1
-       )
-       for i, op := range binaryOps {
-               offset2 := scanTok(buf, offset, op.op)
-               if offset2 >= 0 {
-                       if found == nil || len(op.op) > len(found.op) {
-                               found = &binaryOps[i]
-                               newOffset = offset2
-                       }
-               }
-       }
-       return found, newOffset
-}
-
-// TODO(bobg): boolean literals?
-func scanLiteralExpr(buf []byte, offset int) (expression, int) {
-       offset = skipWsAndComments(buf, offset)
-       intliteral, newOffset := scanIntLiteral(buf, offset)
-       if newOffset >= 0 {
-               return intliteral, newOffset
-       }
-       strliteral, newOffset := scanStrLiteral(buf, offset)
-       if newOffset >= 0 {
-               return strliteral, newOffset
-       }
-       bytesliteral, newOffset := scanBytesLiteral(buf, offset) // 0x6c249a...
-       if newOffset >= 0 {
-               return bytesliteral, newOffset
-       }
-       return nil, -1
-}
-
-func scanIdentifier(buf []byte, offset int) (string, int) {
-       offset = skipWsAndComments(buf, offset)
-       i := offset
-       for ; i < len(buf) && isIDChar(buf[i], i == offset); i++ {
-       }
-       if i == offset {
-               return "", -1
-       }
-       return string(buf[offset:i]), i
-}
-
-func scanTok(buf []byte, offset int, s string) int {
-       offset = skipWsAndComments(buf, offset)
-       prefix := []byte(s)
-       if bytes.HasPrefix(buf[offset:], prefix) {
-               return offset + len(prefix)
-       }
-       return -1
-}
-
-func scanKeyword(buf []byte, offset int, keyword string) int {
-       id, newOffset := scanIdentifier(buf, offset)
-       if newOffset < 0 {
-               return -1
-       }
-       if id != keyword {
-               return -1
-       }
-       return newOffset
-}
-
-func scanIntLiteral(buf []byte, offset int) (integerLiteral, int) {
-       offset = skipWsAndComments(buf, offset)
-       start := offset
-       if offset < len(buf) && buf[offset] == '-' {
-               offset++
-       }
-       i := offset
-       for ; i < len(buf) && unicode.IsDigit(rune(buf[i])); i++ {
-       }
-       if i > offset {
-               n, err := strconv.ParseInt(string(buf[start:i]), 10, 64)
-               if err != nil {
-                       return 0, -1
-               }
-               return integerLiteral(n), i
-       }
-       return 0, -1
-}
-
-func scanStrLiteral(buf []byte, offset int) (bytesLiteral, int) {
-       offset = skipWsAndComments(buf, offset)
-       if offset >= len(buf) || buf[offset] != '\'' {
-               return bytesLiteral{}, -1
-       }
-       for i := offset + 1; i < len(buf); i++ {
-               if buf[i] == '\'' {
-                       return bytesLiteral(buf[offset : i+1]), i + 1
-               }
-               if buf[i] == '\\' {
-                       i++
-               }
-       }
-       panic(parseErr(buf, offset, "unterminated string literal"))
-}
-
-func scanBytesLiteral(buf []byte, offset int) (bytesLiteral, int) {
-       offset = skipWsAndComments(buf, offset)
-       if offset+4 >= len(buf) {
-               return nil, -1
-       }
-       if buf[offset] != '0' || (buf[offset+1] != 'x' && buf[offset+1] != 'X') {
-               return nil, -1
-       }
-       if !isHexDigit(buf[offset+2]) || !isHexDigit(buf[offset+3]) {
-               return nil, -1
-       }
-       i := offset + 4
-       for ; i < len(buf); i += 2 {
-               if i == len(buf)-1 {
-                       panic(parseErr(buf, offset, "odd number of digits in hex literal"))
-               }
-               if !isHexDigit(buf[i]) {
-                       break
-               }
-               if !isHexDigit(buf[i+1]) {
-                       panic(parseErr(buf, offset, "odd number of digits in hex literal"))
-               }
-       }
-       decoded := make([]byte, hex.DecodedLen(i-(offset+2)))
-       _, err := hex.Decode(decoded, buf[offset+2:i])
-       if err != nil {
-               return bytesLiteral{}, -1
-       }
-       return bytesLiteral(decoded), i
-}
-
-func skipWsAndComments(buf []byte, offset int) int {
-       var inComment bool
-       for ; offset < len(buf); offset++ {
-               c := buf[offset]
-               if inComment {
-                       if c == '\n' {
-                               inComment = false
-                       }
-               } else {
-                       if c == '/' && offset < len(buf)-1 && buf[offset+1] == '/' {
-                               inComment = true
-                               offset++ // skip two chars instead of one
-                       } else if !unicode.IsSpace(rune(c)) {
-                               break
-                       }
-               }
-       }
-       return offset
-}
-
-func isHexDigit(b byte) bool {
-       return (b >= '0' && b <= '9') || (b >= 'a' && b <= 'f') || (b >= 'A' && b <= 'F')
-}
-
-func isIDChar(c byte, initial bool) bool {
-       if c >= 'a' && c <= 'z' {
-               return true
-       }
-       if c >= 'A' && c <= 'Z' {
-               return true
-       }
-       if c == '_' {
-               return true
-       }
-       if initial {
-               return false
-       }
-       return unicode.IsDigit(rune(c))
-}
-
-type parserErr struct {
-       buf    []byte
-       offset int
-       format string
-       args   []interface{}
-}
-
-func parseErr(buf []byte, offset int, format string, args ...interface{}) error {
-       return parserErr{buf: buf, offset: offset, format: format, args: args}
-}
-
-func (p parserErr) Error() string {
-       // Lines start at 1, columns start at 0, like nature intended.
-       line := 1
-       col := 0
-       for i := 0; i < p.offset; i++ {
-               if p.buf[i] == '\n' {
-                       line++
-                       col = 0
-               } else {
-                       col++
-               }
-       }
-       args := []interface{}{line, col}
-       args = append(args, p.args...)
-       return fmt.Sprintf("line %d, col %d: "+p.format, args...)
-}
diff --git a/exp/ivy/compiler/stack.go b/exp/ivy/compiler/stack.go
deleted file mode 100644 (file)
index 1459f02..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-package compiler
-
-type (
-       stack struct {
-               *stackEntry
-       }
-       stackEntry struct {
-               str  string
-               prev *stackEntry
-       }
-)
-
-func (stk stack) isEmpty() bool {
-       return stk.stackEntry == nil
-}
-
-func (stk stack) top() string {
-       if stk.isEmpty() {
-               return ""
-       }
-       return stk.str
-}
-
-func (stk stack) add(str string) stack {
-       e := &stackEntry{
-               str:  str,
-               prev: stk.stackEntry,
-       }
-       return stack{e}
-}
-
-func (stk stack) addFromStack(other stack) stack {
-       if other.isEmpty() {
-               return stk
-       }
-       res := stk.addFromStack(other.drop())
-       return res.add(other.top())
-}
-
-func (stk stack) drop() stack {
-       if !stk.isEmpty() {
-               stk = stack{stk.prev}
-       }
-       return stk
-}
-
-func (stk stack) dropN(n int) stack {
-       for n > 0 {
-               stk = stk.drop()
-               n--
-       }
-       return stk
-}
-
-func (stk stack) find(str string) int {
-       if stk.isEmpty() {
-               return -1
-       }
-       if stk.str == str {
-               return 0
-       }
-       res := stk.drop().find(str)
-       if res < 0 {
-               return res
-       }
-       return res + 1
-}
-
-func (stk stack) roll(n int) stack {
-       var x func(stack, int) (stack, string)
-       x = func(stk stack, n int) (stack, string) {
-               if n == 0 {
-                       return stk.drop(), stk.top()
-               }
-               stk2, entry := x(stk.drop(), n-1)
-               return stk2.add(stk.top()), entry
-       }
-       stk, entry := x(stk, n)
-       return stk.add(entry)
-}
-
-func (stk stack) swap() stack {
-       a := stk.top()
-       stk = stk.drop()
-       b := stk.top()
-       stk = stk.drop()
-       return stk.add(a).add(b)
-}
-
-func (stk stack) dup() stack {
-       return stk.add(stk.top())
-}
-
-func (stk stack) over() stack {
-       t := stk.drop().top()
-       return stk.add(t)
-}
-
-func (stk stack) pick(n int) stack {
-       t := stk.dropN(n).top()
-       return stk.add(t)
-}
-
-func (stk stack) String() string {
-       if stk.stackEntry == nil {
-               return "[]"
-       }
-       var x func(stk stack) string
-       x = func(stk stack) string {
-               if stk.stackEntry == nil {
-                       return ""
-               }
-               return x(stk.drop()) + " " + stk.stackEntry.str
-       }
-       return "[..." + x(stk) + "]"
-}
diff --git a/exp/ivy/compiler/types.go b/exp/ivy/compiler/types.go
deleted file mode 100644 (file)
index 4fb4bff..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-package compiler
-
-type typeDesc string
-
-var (
-       amountType   = typeDesc("Amount")
-       assetType    = typeDesc("Asset")
-       boolType     = typeDesc("Boolean")
-       contractType = typeDesc("Contract")
-       hashType     = typeDesc("Hash")
-       intType      = typeDesc("Integer")
-       listType     = typeDesc("List")
-       nilType      = typeDesc("")
-       predType     = typeDesc("Predicate")
-       progType     = typeDesc("Program")
-       pubkeyType   = typeDesc("PublicKey")
-       sigType      = typeDesc("Signature")
-       strType      = typeDesc("String")
-       timeType     = typeDesc("Time")
-       valueType    = typeDesc("Value")
-
-       sha3StrType      = typeDesc("Sha3(String)")
-       sha3PubkeyType   = typeDesc("Sha3(PublicKey)")
-       sha256StrType    = typeDesc("Sha256(String)")
-       sha256PubkeyType = typeDesc("Sha256(PublicKey)")
-)
-
-var types = map[string]typeDesc{
-       string(amountType): amountType,
-       string(assetType):  assetType,
-       string(boolType):   boolType,
-       string(hashType):   hashType,
-       string(intType):    intType,
-       string(listType):   listType,
-       string(nilType):    nilType,
-       string(predType):   predType,
-       string(progType):   progType,
-       string(pubkeyType): pubkeyType,
-       string(sigType):    sigType,
-       string(strType):    strType,
-       string(timeType):   timeType,
-       string(valueType):  valueType,
-
-       string(sha3StrType):      sha3StrType,
-       string(sha3PubkeyType):   sha3PubkeyType,
-       string(sha256StrType):    sha256StrType,
-       string(sha256PubkeyType): sha256PubkeyType,
-}
-
-func isHashSubtype(t typeDesc) bool {
-       switch t {
-       case sha3StrType, sha3PubkeyType, sha256StrType, sha256PubkeyType:
-               return true
-       }
-       return false
-}
-
-func propagateType(contract *Contract, clause *Clause, env *environ, t typeDesc, e expression) {
-       v, ok := e.(varRef)
-       if !ok {
-               return
-       }
-       if entry := env.lookup(string(v)); entry != nil {
-               entry.t = t
-               for _, p := range contract.Params {
-                       if p.Name == string(v) {
-                               p.InferredType = t
-                               return
-                       }
-               }
-               for _, p := range clause.Params {
-                       if p.Name == string(v) {
-                               p.InferredType = t
-                               return
-                       }
-               }
-       }
-}