OSDN Git Service

versoin1.1.9 (#594)
[bytom/vapor.git] / equity / compiler / builder.go
1 package compiler
2
3 import (
4         "fmt"
5         "strconv"
6         "strings"
7 )
8
9 type builder struct {
10         items         []*builderItem
11         pendingVerify *builderItem
12 }
13
14 type builderItem struct {
15         opcodes string
16         stk     stack
17 }
18
19 func (b *builder) add(opcodes string, newstack stack) stack {
20         if b.pendingVerify != nil {
21                 b.items = append(b.items, b.pendingVerify)
22                 b.pendingVerify = nil
23         }
24         item := &builderItem{opcodes: opcodes, stk: newstack}
25         if opcodes == "VERIFY" {
26                 b.pendingVerify = item
27         } else {
28                 b.items = append(b.items, item)
29         }
30         return newstack
31 }
32
33 func (b *builder) addRoll(stk stack, n int) stack {
34         b.addInt64(stk, int64(n))
35         return b.add("ROLL", stk.roll(n))
36 }
37
38 func (b *builder) addDup(stk stack) stack {
39         return b.add("DUP", stk.dup())
40 }
41
42 func (b *builder) addInt64(stk stack, n int64) stack {
43         s := strconv.FormatInt(n, 10)
44         return b.add(s, stk.add(s))
45 }
46
47 func (b *builder) addNot(stk stack, desc string) stack {
48         return b.add("NOT", stk.drop().add(desc))
49 }
50
51 func (b *builder) addEqual(stk stack, desc string) stack {
52         return b.add("EQUAL", stk.dropN(2).add(desc))
53 }
54
55 func (b *builder) addNumEqual(stk stack, desc string) stack {
56         return b.add("NUMEQUAL", stk.dropN(2).add(desc))
57 }
58
59 func (b *builder) addJumpIf(stk stack, label string) stack {
60         return b.add(fmt.Sprintf("JUMPIF:$%s", label), stk.drop())
61 }
62
63 func (b *builder) addJumpTarget(stk stack, label string) stack {
64         return b.add("$"+label, stk)
65 }
66
67 func (b *builder) addDrop(stk stack) stack {
68         return b.add("DROP", stk.drop())
69 }
70
71 func (b *builder) forgetPendingVerify() {
72         b.pendingVerify = nil
73 }
74
75 func (b *builder) addJump(stk stack, label string) stack {
76         return b.add(fmt.Sprintf("JUMP:$%s", label), stk)
77 }
78
79 func (b *builder) addVerify(stk stack) stack {
80         return b.add("VERIFY", stk.drop())
81 }
82
83 func (b *builder) addData(stk stack, data []byte) stack {
84         var s string
85         switch len(data) {
86         case 0:
87                 s = "0"
88         case 1:
89                 s = strconv.FormatInt(int64(data[0]), 10)
90         default:
91                 s = fmt.Sprintf("0x%x", data)
92         }
93         return b.add(s, stk.add(s))
94 }
95
96 func (b *builder) addAmount(stk stack, desc string) stack {
97         return b.add("AMOUNT", stk.add(desc))
98 }
99
100 func (b *builder) addAsset(stk stack, desc string) stack {
101         return b.add("ASSET", stk.add(desc))
102 }
103
104 func (b *builder) addCheckOutput(stk stack, desc string) stack {
105         return b.add("CHECKOUTPUT", stk.dropN(5).add(desc))
106 }
107
108 func (b *builder) addBoolean(stk stack, val bool) stack {
109         if val {
110                 return b.add("TRUE", stk.add("true"))
111         }
112         return b.add("FALSE", stk.add("false"))
113 }
114
115 func (b *builder) addOps(stk stack, ops string, desc string) stack {
116         return b.add(ops, stk.add(desc))
117 }
118
119 func (b *builder) addToAltStack(stk stack) (stack, string) {
120         t := stk.top()
121         return b.add("TOALTSTACK", stk.drop()), t
122 }
123
124 func (b *builder) addTxSigHash(stk stack) stack {
125         return b.add("TXSIGHASH", stk.add("<txsighash>"))
126 }
127
128 func (b *builder) addFromAltStack(stk stack, alt string) stack {
129         return b.add("FROMALTSTACK", stk.add(alt))
130 }
131
132 func (b *builder) addSwap(stk stack) stack {
133         return b.add("SWAP", stk.swap())
134 }
135
136 func (b *builder) addCheckMultisig(stk stack, n int, desc string) stack {
137         return b.add("CHECKMULTISIG", stk.dropN(n).add(desc))
138 }
139
140 func (b *builder) addOver(stk stack) stack {
141         return b.add("OVER", stk.over())
142 }
143
144 func (b *builder) addPick(stk stack, n int) stack {
145         b.addInt64(stk, int64(n))
146         return b.add("PICK", stk.pick(n))
147 }
148
149 func (b *builder) addCatPushdata(stk stack, desc string) stack {
150         return b.add("CATPUSHDATA", stk.dropN(2).add(desc))
151 }
152
153 func (b *builder) addCat(stk stack, desc string) stack {
154         return b.add("CAT", stk.dropN(2).add(desc))
155 }
156
157 func (b *builder) addNop(stk stack) stack {
158         return b.add("NOP", stk)
159 }
160
161 func (b *builder) opcodes() string {
162         var ops []string
163         for _, item := range b.items {
164                 ops = append(ops, item.opcodes)
165         }
166         return strings.Join(ops, " ")
167 }
168
169 // This is for producing listings like:
170 // 5                 |  [... <clause selector> borrower lender deadline balanceAmount balanceAsset 5]
171 // ROLL              |  [... borrower lender deadline balanceAmount balanceAsset <clause selector>]
172 // JUMPIF:$default   |  [... borrower lender deadline balanceAmount balanceAsset]
173 // $repay            |  [... borrower lender deadline balanceAmount balanceAsset]
174 // 0                 |  [... borrower lender deadline balanceAmount balanceAsset 0]
175 // 0                 |  [... borrower lender deadline balanceAmount balanceAsset 0 0]
176 // 3                 |  [... borrower lender deadline balanceAmount balanceAsset 0 0 3]
177 // ROLL              |  [... borrower lender deadline balanceAsset 0 0 balanceAmount]
178 // 3                 |  [... borrower lender deadline balanceAsset 0 0 balanceAmount 3]
179 // ROLL              |  [... borrower lender deadline 0 0 balanceAmount balanceAsset]
180 // 1                 |  [... borrower lender deadline 0 0 balanceAmount balanceAsset 1]
181 // 6                 |  [... borrower lender deadline 0 0 balanceAmount balanceAsset 1 6]
182 // ROLL              |  [... borrower deadline 0 0 balanceAmount balanceAsset 1 lender]
183 // CHECKOUTPUT       |  [... borrower deadline checkOutput(payment, lender)]
184 // VERIFY            |  [... borrower deadline]
185 // 1                 |  [... borrower deadline 1]
186 // 0                 |  [... borrower deadline 1 0]
187 // AMOUNT            |  [... borrower deadline 1 0 <amount>]
188 // ASSET             |  [... borrower deadline 1 0 <amount> <asset>]
189 // 1                 |  [... borrower deadline 1 0 <amount> <asset> 1]
190 // 6                 |  [... borrower deadline 1 0 <amount> <asset> 1 6]
191 // ROLL              |  [... deadline 1 0 <amount> <asset> 1 borrower]
192 // CHECKOUTPUT       |  [... deadline checkOutput(collateral, borrower)]
193 // JUMP:$_end        |  [... borrower lender deadline balanceAmount balanceAsset]
194 // $default          |  [... borrower lender deadline balanceAmount balanceAsset]
195 // 2                 |  [... borrower lender deadline balanceAmount balanceAsset 2]
196 // ROLL              |  [... borrower lender balanceAmount balanceAsset deadline]
197 // MINTIME LESSTHAN  |  [... borrower lender balanceAmount balanceAsset after(deadline)]
198 // VERIFY            |  [... borrower lender balanceAmount balanceAsset]
199 // 0                 |  [... borrower lender balanceAmount balanceAsset 0]
200 // 0                 |  [... borrower lender balanceAmount balanceAsset 0 0]
201 // AMOUNT            |  [... borrower lender balanceAmount balanceAsset 0 0 <amount>]
202 // ASSET             |  [... borrower lender balanceAmount balanceAsset 0 0 <amount> <asset>]
203 // 1                 |  [... borrower lender balanceAmount balanceAsset 0 0 <amount> <asset> 1]
204 // 7                 |  [... borrower lender balanceAmount balanceAsset 0 0 <amount> <asset> 1 7]
205 // ROLL              |  [... borrower balanceAmount balanceAsset 0 0 <amount> <asset> 1 lender]
206 // CHECKOUTPUT       |  [... borrower balanceAmount balanceAsset checkOutput(collateral, lender)]
207 // $_end             |  [... borrower lender deadline balanceAmount balanceAsset]
208
209 type (
210         Step struct {
211                 Opcodes string `json:"opcodes"`
212                 Stack   string `json:"stack"`
213         }
214 )
215
216 func (b *builder) steps() []Step {
217         var result []Step
218         for _, item := range b.items {
219                 result = append(result, Step{item.opcodes, item.stk.String()})
220         }
221         return result
222 }