OSDN Git Service

add AST for if-else statement which contains lock or unlock statement (#32)
[bytom/equity.git] / compiler / ast.go
1 package compiler
2
3 import (
4         "encoding/hex"
5         "fmt"
6         "strconv"
7         "strings"
8
9         chainjson "github.com/bytom/encoding/json"
10 )
11
12 // Contract is a compiled Equity contract.
13 type Contract struct {
14         // Name is the contract name.
15         Name string `json:"name"`
16
17         // Params is the list of contract parameters.
18         Params []*Param `json:"params,omitempty"`
19
20         // Clauses is the list of contract clauses.
21         Clauses []*Clause `json:"clauses"`
22
23         // Value is the name of the value locked by the contract.
24         Value ValueInfo `json:"value"`
25
26         // Body is the optimized bytecode of the contract body. This is not
27         // a complete program!  Use instantiate to turn this (plus some
28         // arguments) into a program.
29         Body chainjson.HexBytes `json:"body_bytecode"`
30
31         // Opcodes is the human-readable string of opcodes corresponding to
32         // Body.
33         Opcodes string `json:"body_opcodes,omitempty"`
34
35         // Recursive tells whether this contract calls itself.  (This is
36         // used to select between two possible instantiation options.)
37         Recursive bool `json:"recursive"`
38
39         // Pre-optimized list of instruction steps, with stack snapshots.
40         Steps []Step `json:"-"`
41 }
42
43 // Param is a contract or clause parameter.
44 type Param struct {
45         // Name is the parameter name.
46         Name string `json:"name"`
47
48         // Type is the declared parameter type.
49         Type typeDesc `json:"type"`
50
51         // InferredType, if available, is a more-specific type than Type,
52         // inferred from the logic of the contract.
53         InferredType typeDesc `json:"inferred_type,omitempty"`
54 }
55
56 // Clause is a compiled contract clause.
57 type Clause struct {
58         // Name is the clause name.
59         Name string `json:"name"`
60
61         // Params is the list of clause parameters.
62         Params []*Param `json:"params,omitempty"`
63
64         statements []statement
65
66         // BlockHeight is the list of expressions passed to greater()/less() in this
67         // clause.
68         BlockHeight []string `json:"blockheight,omitempty"`
69
70         // HashCalls is the list of hash functions and their arguments used
71         // in this clause.
72         HashCalls []HashCall `json:"hash_calls,omitempty"`
73
74         // Values is the list of values unlocked or relocked in this clause.
75         Values []ValueInfo `json:"values"`
76
77         // Conditions is the list of condition for if-else statements which body contains
78         // the lock or unlock statement in this clause.
79         Conditions map[string]Condition `json:"conditions"`
80
81         // CondValues is the map of values unlocked or relocked in this clause's
82         // if-else statements which body contains the lock or unlock statement.
83         CondValues map[string][]ValueInfo `json:"cond_values"`
84
85         // Contracts is the list of contracts called by this clause.
86         Contracts []string `json:"contracts,omitempty"`
87 }
88
89 // ValueInfo describes how a blockchain value is used in a contract clause.
90 type ValueInfo struct {
91         // Name is the clause's name for this value.
92         Name string `json:"name"`
93
94         // Program is the program expression used to the lock the value, if
95         // the value is locked with "lock." If it's unlocked with "unlock"
96         // instead, this is empty.
97         Program string `json:"program,omitempty"`
98
99         // Asset is the expression describing the asset type the value must
100         // have, as it appears in a clause's "requires" section. If this is
101         // the contract value instead, this is empty.
102         Asset string `json:"asset,omitempty"`
103
104         // Amount is the expression describing the amount the value must
105         // have, as it appears in a clause's "requires" section. If this is
106         // the contract value instead, this is empty.
107         Amount string `json:"amount,omitempty"`
108
109         // Params is the list of parameters for amount expression. If the value
110         // of amount is a variable, this is empty.
111         Params []*Param `json:"params,omitempty"`
112 }
113
114 // HashCall describes a call to a hash function.
115 type HashCall struct {
116         // HashType is "sha3" or "sha256".
117         HashType string `json:"hash_type"`
118
119         // Arg is the expression passed to the hash function.
120         Arg string `json:"arg"`
121
122         // ArgType is the type of Arg.
123         ArgType string `json:"arg_type"`
124 }
125
126 // Condition describes a condition expression.
127 type Condition struct {
128         // Source is the string format of condition expression.
129         Source string `json:"source"`
130
131         // Params is the list of parameters for condition expression.
132         Params []*Param `json:"params,omitempty"`
133 }
134
135 // ContractArg is an argument with which to instantiate a contract as
136 // a program. Exactly one of B, I, and S should be supplied.
137 type ContractArg struct {
138         B *bool               `json:"boolean,omitempty"`
139         I *int64              `json:"integer,omitempty"`
140         S *chainjson.HexBytes `json:"string,omitempty"`
141 }
142
143 type statement interface {
144         countVarRefs(map[string]int)
145 }
146
147 type defineStatement struct {
148         variable *Param
149         expr     expression
150 }
151
152 func (s defineStatement) countVarRefs(counts map[string]int) {
153         s.expr.countVarRefs(counts)
154 }
155
156 type assignStatement struct {
157         variable *Param
158         expr     expression
159 }
160
161 func (s assignStatement) countVarRefs(counts map[string]int) {
162         s.expr.countVarRefs(counts)
163 }
164
165 // IfStatmentBody describes the content of if-else structure
166 type IfStatmentBody struct {
167         // if body statements
168         trueBody []statement
169
170         // else body statements
171         falseBody []statement
172 }
173
174 type ifStatement struct {
175         condition expression
176         body      *IfStatmentBody
177 }
178
179 func (s ifStatement) countVarRefs(counts map[string]int) {
180         s.condition.countVarRefs(counts)
181 }
182
183 type verifyStatement struct {
184         expr expression
185 }
186
187 func (s verifyStatement) countVarRefs(counts map[string]int) {
188         s.expr.countVarRefs(counts)
189 }
190
191 type lockStatement struct {
192         lockedAmount expression
193         lockedAsset  expression
194         program      expression
195
196         // Added as a decoration, used by CHECKOUTPUT
197         index int64
198 }
199
200 func (s lockStatement) countVarRefs(counts map[string]int) {
201         s.lockedAmount.countVarRefs(counts)
202         s.lockedAsset.countVarRefs(counts)
203         s.program.countVarRefs(counts)
204 }
205
206 type unlockStatement struct {
207         unlockedAmount expression
208         unlockedAsset  expression
209 }
210
211 func (s unlockStatement) countVarRefs(counts map[string]int) {
212         s.unlockedAmount.countVarRefs(counts)
213         s.unlockedAsset.countVarRefs(counts)
214 }
215
216 type expression interface {
217         String() string
218         typ(*environ) typeDesc
219         countVarRefs(map[string]int)
220 }
221
222 type binaryExpr struct {
223         left, right expression
224         op          *binaryOp
225 }
226
227 func (e binaryExpr) String() string {
228         return fmt.Sprintf("(%s %s %s)", e.left, e.op.op, e.right)
229 }
230
231 func (e binaryExpr) typ(*environ) typeDesc {
232         return e.op.result
233 }
234
235 func (e binaryExpr) countVarRefs(counts map[string]int) {
236         e.left.countVarRefs(counts)
237         e.right.countVarRefs(counts)
238 }
239
240 type unaryExpr struct {
241         op   *unaryOp
242         expr expression
243 }
244
245 func (e unaryExpr) String() string {
246         return fmt.Sprintf("%s%s", e.op.op, e.expr)
247 }
248
249 func (e unaryExpr) typ(*environ) typeDesc {
250         return e.op.result
251 }
252
253 func (e unaryExpr) countVarRefs(counts map[string]int) {
254         e.expr.countVarRefs(counts)
255 }
256
257 type callExpr struct {
258         fn   expression
259         args []expression
260 }
261
262 func (e callExpr) String() string {
263         var argStrs []string
264         for _, a := range e.args {
265                 argStrs = append(argStrs, a.String())
266         }
267         return fmt.Sprintf("%s(%s)", e.fn, strings.Join(argStrs, ", "))
268 }
269
270 func (e callExpr) typ(env *environ) typeDesc {
271         if b := referencedBuiltin(e.fn); b != nil {
272                 switch b.name {
273                 case "sha3":
274                         if len(e.args) == 1 {
275                                 switch e.args[0].typ(env) {
276                                 case strType:
277                                         return sha3StrType
278                                 case pubkeyType:
279                                         return sha3PubkeyType
280                                 }
281                         }
282
283                 case "sha256":
284                         if len(e.args) == 1 {
285                                 switch e.args[0].typ(env) {
286                                 case strType:
287                                         return sha256StrType
288                                 case pubkeyType:
289                                         return sha256PubkeyType
290                                 }
291                         }
292                 }
293
294                 return b.result
295         }
296         if e.fn.typ(env) == predType {
297                 return boolType
298         }
299         if e.fn.typ(env) == contractType {
300                 return progType
301         }
302         return nilType
303 }
304
305 func (e callExpr) countVarRefs(counts map[string]int) {
306         e.fn.countVarRefs(counts)
307         for _, a := range e.args {
308                 a.countVarRefs(counts)
309         }
310 }
311
312 type varRef string
313
314 func (v varRef) String() string {
315         return string(v)
316 }
317
318 func (v varRef) typ(env *environ) typeDesc {
319         if entry := env.lookup(string(v)); entry != nil {
320                 return entry.t
321         }
322         return nilType
323 }
324
325 func (v varRef) countVarRefs(counts map[string]int) {
326         counts[string(v)]++
327 }
328
329 type bytesLiteral []byte
330
331 func (e bytesLiteral) String() string {
332         return "0x" + hex.EncodeToString([]byte(e))
333 }
334
335 func (bytesLiteral) typ(*environ) typeDesc {
336         return "String"
337 }
338
339 func (bytesLiteral) countVarRefs(map[string]int) {}
340
341 type integerLiteral int64
342
343 func (e integerLiteral) String() string {
344         return strconv.FormatInt(int64(e), 10)
345 }
346
347 func (integerLiteral) typ(*environ) typeDesc {
348         return "Integer"
349 }
350
351 func (integerLiteral) countVarRefs(map[string]int) {}
352
353 type booleanLiteral bool
354
355 func (e booleanLiteral) String() string {
356         if e {
357                 return "true"
358         }
359         return "false"
360 }
361
362 func (booleanLiteral) typ(*environ) typeDesc {
363         return "Boolean"
364 }
365
366 func (booleanLiteral) countVarRefs(map[string]int) {}
367
368 type listExpr []expression
369
370 func (e listExpr) String() string {
371         var elts []string
372         for _, elt := range e {
373                 elts = append(elts, elt.String())
374         }
375         return fmt.Sprintf("[%s]", strings.Join(elts, ", "))
376 }
377
378 func (listExpr) typ(*environ) typeDesc {
379         return "List"
380 }
381
382 func (e listExpr) countVarRefs(counts map[string]int) {
383         for _, elt := range e {
384                 elt.countVarRefs(counts)
385         }
386 }