package solidity-common

  1. Overview
  2. Docs

Source file solidity_ast.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
(**************************************************************************)
(*                                                                        *)
(*  Copyright (c) 2021 OCamlPro & Origin Labs                             *)
(*                                                                        *)
(*  All rights reserved.                                                  *)
(*  This file is distributed under the terms of the GNU Lesser General    *)
(*  Public License version 2.1, with the special exception on linking     *)
(*  described in the LICENSE.md file in the root directory.               *)
(*                                                                        *)
(*                                                                        *)
(**************************************************************************)

open Solidity_common

type ident = Ident.t node

type longident = relative LongIdent.t node

type program = {
  program_modules : module_ list;
  program_modules_by_id : module_ IdentMap.t;
  program_modules_by_file : module_ StringMap.t;
}

and module_ = {
  module_file : string; (* *absolute* path *)
  module_id : Ident.t; (* the module id: @n *)
  module_units : module_units;
}

and module_units = (source_unit node) list

and source_unit =
  | Pragma of (Ident.t * string)
  | Import of import_directive
  | GlobalTypeDefinition of type_definition
  | GlobalFunctionDefinition of function_definition
  | GlobalVariableDefinition of state_variable_definition
  | ContractDefinition of contract_definition

and import_directive = {
  import_from : string;
  import_symbols : import_symbols;
}

and import_symbols =
  | ImportAll of ident option
  | ImportIdents of (ident * ident option) list

and contract_definition = {
  contract_name : ident;
  contract_kind : contract_kind;
  contract_abstract : bool;
  contract_inheritance : inheritance_specifier list;
  contract_parts : (contract_part node) list;
}

and inheritance_specifier = longident * expression list

and contract_part =
  | TypeDefinition of type_definition
  | StateVariableDeclaration of state_variable_definition
  | FunctionDefinition of function_definition
  | ModifierDefinition of modifier_definition
  | EventDefinition of event_definition
  | UsingForDeclaration of longident * type_ option

and type_definition =
  | EnumDefinition of enum_definition
  | StructDefinition of struct_definition

and enum_definition = ident * ident list

and struct_definition = ident * field_definition list

and field_definition = type_ * ident

and state_variable_definition = {
  var_name : ident;
  var_type : type_;
  var_visibility : visibility; (* def: internal *)
  var_mutability : var_mutability; (* def: mutable *)
  var_override : longident list option;
  var_init : expression option;
}

and function_definition = {
  fun_name : ident;
  fun_params : param list;
  fun_returns : return list;
  fun_modifiers : (longident * expression list option) list;
  fun_visibility : visibility; (* def: public (external in interface) *)
  fun_mutability : fun_mutability; (* ctor: public/forbidden ? *)
  fun_override : longident list option; (* fallback/receive: external *)
  fun_virtual : bool;                   (* but public if missing...  *)
  fun_body : block option;        (* mutability : nonpayable by default *)
}

and modifier_definition = {
  mod_name : ident;
  mod_params : param list;
  mod_override : longident list option;
  mod_virtual : bool;
  mod_body : block option;
}

and event_definition = {
  event_name : ident;
  event_params : (type_ * bool * ident option) list; (* indexed *)
  event_anonymous : bool;
}

and param = type_ * storage_location option * ident option

and return = type_ * storage_location option * ident option

and type_ =
  | ElementaryType of elementary_type
  | Array of type_ * expression option
  | Mapping of type_ * type_
  | FunctionType of function_type
  | UserDefinedType of longident

and elementary_type =
  | TypeBool
  | TypeInt of int
  | TypeUint of int
  | TypeFixed of int * int
  | TypeUfixed of int * int
  | TypeAddress of bool (* false = address, true = address payable *)
  | TypeBytes of int option (* None = bytes, Some (N) = bytesN *)
  | TypeString

and function_type = {
  fun_type_params : param list;
  fun_type_returns : (type_ * storage_location option) list; (* ident forbid *)
  fun_type_visibility : visibility; (* def: internal *) (* only intern/extern *)
  fun_type_mutability : fun_mutability; (* def: non-payable *)
}

and statement = raw_statement node

and raw_statement =
  | Block of block
  | VariableDefinition of variable_definition
  | ExpressionStatement of expression
  | IfStatement of expression * statement * statement option
  | WhileStatement of expression * statement
  | DoWhileStatement of statement * expression
  | ForStatement of statement option * expression option *
                    expression option * statement
  | TryStatement of expression * return list * block * catch_clause list
  | Emit of expression * function_call_arguments
  | Return of expression option
  | Continue
  | Break
  | PlaceholderStatement

and expression = raw_expression node

and raw_expression =
  | BooleanLiteral of bool
  | NumberLiteral of Q.t * number_unit * int option (* hex size / use type *)
  | StringLiteral of string
  | AddressLiteral of string
  | IdentifierExpression of ident
  | ImmediateArray of expression list
  | ArrayAccess of expression * expression option
  | ArraySlice of expression * expression option * expression option
  | TupleExpression of expression option list

  | PrefixExpression of unary_operator * expression
  | SuffixExpression of expression * unary_operator
  | CompareExpression of expression * compare_operator * expression
  | BinaryExpression of expression * binary_operator * expression
  | AssignExpression of expression * expression
  | AssignBinaryExpression of expression * binary_operator * expression

  | IfExpression of expression * expression * expression
  | FieldExpression of expression * ident
  | FunctionCallExpression of expression * function_call_arguments
  | CallOptions of expression * (ident * expression) list
  | NewExpression of type_
  | TypeExpression of type_

and block = statement list

and catch_clause = ident option * param list * block

and variable_definition =
  | VarInfer of ident option list * expression
  | VarType of (type_ * storage_location option * ident) option list *
               expression option

and function_call_arguments =
  | ExpressionList of expression list
  | NameValueList of (ident * expression) list

and contract_kind =
  | Contract
  | Library
  | Interface

and storage_location =
  | Memory
  | Storage
  | Calldata

and var_mutability =
  | MMutable
  | MConstant
  | MImmutable

and fun_mutability =
  | MPure
  | MView
  | MPayable
  | MNonPayable

and visibility =
  | VInternal
  | VExternal (* not for variables *)
  | VPublic
  | VPrivate

and number_unit =
  | Unit
  | Wei
  | Kwei (* Babbage *)
  | Mwei (* Lovelace *)
  | Gwei (* Shannon *)
  | Twei (* Szabo *)
  | Pwei (* Finney *)
  | Ether
  | Hours
  | Minutes
  | Seconds
  | Days
  | Weeks
  | Years

and unary_operator =
  | UPlus
  | UMinus
  | UNot
  | ULNot
  | UInc
  | UDec
  | UDelete

and binary_operator =
  | BPlus
  | BMinus
  | BDiv
  | BMod
  | BTimes
  | BExp
  | BLShift
  | BRShift
  | BAnd
  | BOr
  | BXor
  | BLAnd
  | BLOr

and compare_operator =
  | CEq
  | CNeq
  | CLt
  | CGt
  | CLeq
  | CGeq


let is_contract = function
  | Contract -> true
  | Library | Interface -> false

let is_library = function
  | Library -> true
  | Contract | Interface -> false

let is_interface = function
  | Interface -> true
  | Contract | Library -> false


let is_mutable = function
  | MMutable -> true
  | MConstant | MImmutable -> false

let is_constant = function
  | MConstant -> true
  | MMutable | MImmutable -> false

let is_immutable = function
  | MImmutable -> true
  | MConstant | MMutable -> false


let is_payable = function
  | MPayable -> true
  | MNonPayable | MView | MPure -> false

let is_nonpayable = function
  | MNonPayable -> true
  | MPayable | MView | MPure -> false


let is_external = function
  | VExternal -> true
  | VInternal | VPublic | VPrivate -> false

let is_internal = function
  | VInternal -> true
  | VExternal | VPublic | VPrivate -> false

let is_private = function
  | VPrivate -> true
  | VExternal | VInternal | VPublic -> false

let is_public = function
  | VPublic -> true
  | VExternal | VInternal | VPrivate -> false

let is_inheritable = function
  | VPublic | VExternal | VInternal -> true
  | VPrivate -> false



let same_mutability m1 m2 =
  match m1, m2 with
  | MPure, MPure -> true
  | MView, MView -> true
  | MPayable, MPayable -> true
  | MNonPayable, MNonPayable -> true
  | _ -> false

(* for the purpose of overriding *)
let convertible_mutability ~from ~to_ =
  match from, to_ with
  | MNonPayable, (MView | MPure | MNonPayable) -> true
  | MNonPayable, MPayable -> false
  | MView, (MPure | MView) -> true
  | MView, (MPayable | MNonPayable) -> false
  | MPure, MPure -> true
  | MPure, (MView | MPayable | MNonPayable) -> false
  | MPayable, MPayable -> true
  | MPayable, (MPure | MView | MNonPayable) -> false



let same_visibility v1 v2 =
  match v1, v2 with
  | VExternal, VExternal -> true
  | VInternal, VInternal -> true
  | VPublic, VPublic -> true
  | VPrivate, VPrivate -> true
  | _ -> false

(* for the purpose of overriding *)
let convertible_visibility ~from ~to_ =
  match from, to_ with
  | VExternal, (VPublic | VExternal) -> true
  | VExternal, (VInternal | VPrivate) -> false
  | VPublic, VPublic -> true
  | VPublic, (VExternal | VInternal | VPrivate) -> false
  | VInternal, VInternal -> true
  | VInternal, (VExternal | VPublic | VPrivate) -> false
  | VPrivate, VPrivate -> true
  | VPrivate, (VExternal | VPublic | VInternal) -> false



let unit_factor unit =
  let z =
    match unit with
    | Unit     -> Z.one
    | Wei      -> Z.one
    | Kwei     -> ExtZ._10_3
    | Mwei     -> ExtZ._10_6
    | Gwei     -> ExtZ._10_9
    | Twei     -> ExtZ._10_12
    | Pwei     -> ExtZ._10_15
    | Ether    -> ExtZ._10_18
    | Hours    -> ExtZ._3600
    | Minutes  -> ExtZ._60
    | Seconds  -> Z.one
    | Days     -> ExtZ._24x3600
    | Weeks    -> ExtZ._7x24x3600
    | Years    -> ExtZ._365x24x3600
  in
  Q.of_bigint z

let apply_unit q unit =
  match unit with
  | Unit | Wei | Seconds -> q
  | _ -> Q.mul q (unit_factor unit)

let apply_unop op q =
  match op with
  | UPlus ->
      Some (q)
  | UMinus ->
      Some (Q.neg q)
  | UNot ->
      if ExtQ.is_int q then
        Some (Q.of_bigint (Z.lognot (Q.num q)))
      else
        None
  | ULNot
  | UInc | UDec
  | UDelete ->
      None

let apply_binop q1 op q2 =
  match op with
  | BPlus ->
      Some (Q.add q1 q2)
  | BMinus ->
      Some (Q.sub q1 q2)
  | BTimes ->
      Some (Q.mul q1 q2)
  | BDiv ->
      Some (Q.div q1 q2)
  | BMod ->
(* TODO: Solidity allows this on fractions *)
      if ExtQ.is_int q1 && ExtQ.is_int q2 then
        Some (Q.of_bigint (snd (Z.ediv_rem (Q.num q1) (Q.num q2))))
      else
        None
  | BExp ->
      if ExtQ.is_int q2 then
        let e = Z.to_int (Q.num q2) in (* Warning: may overflow *)
        let n = Z.pow (Q.num q1) e in
        let d = Z.pow (Q.den q1) e in
        Some (Q.make n d)
      else
        None
  | BAnd ->
      if ExtQ.is_int q1 && ExtQ.is_int q2 then
        Some (Q.of_bigint (Z.logand (Q.num q1) (Q.num q2)))
      else
        None
  | BOr ->
      if ExtQ.is_int q1 && ExtQ.is_int q2 then
        Some (Q.of_bigint (Z.logor (Q.num q1) (Q.num q2)))
      else
        None
  | BXor ->
      if ExtQ.is_int q1 && ExtQ.is_int q2 then
        Some (Q.of_bigint (Z.logxor (Q.num q1) (Q.num q2)))
      else
        None
  | BLShift ->
      if ExtQ.is_int q1 && ExtQ.is_int q2 && ExtQ.is_pos q2 then
        Some (Q.of_bigint (Z.shift_left (Q.num q1) (Q.to_int q2)))
      else
        None
  | BRShift ->
      if ExtQ.is_int q1 && ExtQ.is_int q2 && ExtQ.is_pos q2 then
        Some (Q.of_bigint (Z.shift_right (Q.num q1) (Q.to_int q2)))
      else
        None
  | BLAnd | BLOr ->
      None