1use sway_features::ExperimentalFeatures;
4use sway_types::SourceEngine;
5
6use crate::{context::Context, error::IrError, Backtrace};
7
8pub fn parse<'eng>(
11 input: &str,
12 source_engine: &'eng SourceEngine,
13 experimental: ExperimentalFeatures,
14 backtrace: Backtrace,
15) -> Result<Context<'eng>, IrError> {
16 let irmod = ir_builder::parser::ir_descrs(input).map_err(|err| {
17 let found = if input.len() - err.location.offset <= 20 {
18 &input[err.location.offset..]
19 } else {
20 &input[err.location.offset..][..20]
21 };
22 IrError::ParseFailure(err.to_string(), found.into())
23 })?;
24 let ir = ir_builder::build_context(irmod, source_engine, experimental, backtrace)?;
25 ir.verify()?;
26 Ok(ir)
27}
28
29mod ir_builder {
32 use slotmap::KeyData;
33 use std::convert::TryFrom;
34 use sway_features::ExperimentalFeatures;
35 use sway_types::{ident::Ident, span::Span, u256::U256, SourceEngine};
36
37 type MdIdxRef = u64;
38
39 peg::parser! {
40 pub(in crate::parser) grammar parser() for str {
41 pub(in crate::parser) rule ir_descrs() -> IrAstModule
42 = _ sop:script_or_predicate() eoi() {
43 sop
44 }
45 / _ c:contract() eoi() {
46 c
47 }
48
49 rule script_or_predicate() -> IrAstModule
50 = kind:module_kind() "{" _ configs:init_config()* _ global_vars:global_var()* _ fn_decls:fn_decl()* "}" _
51 metadata:metadata_decls() {
52 IrAstModule {
53 kind,
54 configs,
55 global_vars,
56 storage_keys: vec![],
57 fn_decls,
58 metadata
59 }
60 }
61
62 rule module_kind() -> Kind
63 = "script" _ { Kind::Script }
64 / "predicate" _ { Kind::Predicate }
65
66 rule contract() -> IrAstModule
67 = "contract" _ "{" _
68 configs:init_config()* _ global_vars:global_var()* _ storage_keys:storage_key()* _ fn_decls:fn_decl()* "}" _
69 metadata:metadata_decls() {
70 IrAstModule {
71 kind: crate::module::Kind::Contract,
72 configs,
73 global_vars,
74 storage_keys,
75 fn_decls,
76 metadata
77 }
78 }
79
80 rule global_var() -> IrAstGlobalVar
81 = "global" _ m:("mut" _)? name:path() _ ":" _ ty:ast_ty() init:global_init()? {
82 IrAstGlobalVar {
83 name,
84 ty,
85 init,
86 mutable: m.is_some(),
87 }
88 }
89
90 rule global_init() -> IrAstOperation
91 = "=" _ cv:op_const() {
92 cv
93 }
94
95 rule config_encoded_bytes() -> Vec<u8>
96 = "0x" s:$(hex_digit()*) _ {
97 hex_string_to_vec(s)
98 }
99
100 rule init_config() -> IrAstConfig
101 = value_name:value_assign() "config" _ val_ty:ast_ty() _ "," _ decode_fn:id() _ "," _ encoded_bytes:config_encoded_bytes()
102 metadata:comma_metadata_idx()? {
103 IrAstConfig {
104 value_name,
105 ty: val_ty,
106 encoded_bytes,
107 decode_fn,
108 metadata,
109 }
110 }
111
112 rule storage_key() -> IrAstStorageKey
113 = "storage_key" _ namespaces:path() "." fields:field_access() _ "=" _ slot:constant() _ offset:storage_key_offset()? _ field_id:storage_key_field_id()? {
114 IrAstStorageKey {
115 namespaces,
116 fields,
117 slot,
118 offset,
119 field_id,
120 }
121 }
122
123 rule storage_key_offset() -> IrAstConst
124 = ":" _ offset:constant() {
125 offset
126 }
127
128 rule storage_key_field_id() -> IrAstConst
129 = ":" _ field_id:constant() {
130 field_id
131 }
132
133 rule fn_decl() -> IrAstFnDecl
134 = is_public:is_public() _ is_original_entry:is_original_entry() _ is_entry:is_entry() _ is_fallback:is_fallback() _ "fn" _
135 name:id() _ selector:selector_id()? _ "(" _
136 args:(block_arg() ** comma()) ")" _ "->" _ ret_type:ast_ty()
137 metadata:comma_metadata_idx()? "{" _
138 locals:fn_local()*
139 blocks:block_decl()*
140 "}" _ {
141 let is_original_entry = is_original_entry || (is_entry && !name.starts_with("__entry"));
146 IrAstFnDecl {
147 name,
148 args,
149 ret_type,
150 is_public,
151 metadata,
152 locals,
153 blocks,
154 selector,
155 is_entry,
156 is_original_entry,
157 is_fallback,
158 }
159 }
160
161 rule is_public() -> bool
162 = "pub" _ { true }
163 / "" _ { false }
164
165 rule is_entry() -> bool
166 = "entry" _ { true }
167 / "" _ { false }
168
169 rule is_original_entry() -> bool
170 = "entry_orig" _ { true }
171 / "" _ { false }
172
173 rule is_fallback() -> bool
174 = "fallback" _ { true }
175 / "" _ { false }
176
177 rule selector_id() -> [u8; 4]
178 = "<" _ s:$(['0'..='9' | 'a'..='f' | 'A'..='F']*<8>) _ ">" _ {
179 string_to_hex::<4>(s)
180 }
181
182 rule block_arg() -> (IrAstTy, String, Option<MdIdxRef>)
183 = name:id() mdi:metadata_idx()? ":" _ ty:ast_ty() {
184 (ty, name, mdi)
185 }
186
187 rule fn_local() -> (IrAstTy, String, Option<IrAstOperation>, bool)
188 = "local" _ m:("mut" _)? ty:ast_ty() name:id() init:fn_local_init()? {
189 (ty, name, init, m.is_some())
190 }
191
192 rule fn_local_init() -> IrAstOperation
193 = "=" _ cv:op_const() {
194 cv
195 }
196
197 rule block_decl() -> IrAstBlock
198 = label:id() "(" _ args:(block_arg() ** comma()) ")" _
199 ":" _ instructions: instr_decl()* {
200 IrAstBlock {
201 label,
202 args,
203 instructions
204 }
205 }
206
207 rule instr_decl() -> IrAstInstruction
208 = value_name:value_assign()? op:operation() metadata:comma_metadata_idx()? {
209 IrAstInstruction {
210 value_name,
211 op,
212 metadata,
213 }
214 }
215
216 rule value_assign() -> String
217 = name:id() "=" _ {
218 name
219 }
220
221 rule metadata_idx() -> MdIdxRef
222 = "!" idx:decimal() {
223 idx
224 }
225
226 rule comma_metadata_idx() -> MdIdxRef
227 = "," _ mdi:metadata_idx() {
228 mdi
229 }
230
231 rule unary_op_kind() -> UnaryOpKind
232 = "not" _ { UnaryOpKind::Not }
233
234 rule binary_op_kind() -> BinaryOpKind
235 = "add" _ { BinaryOpKind::Add }
236 / "sub" _ { BinaryOpKind::Sub }
237 / "mul" _ { BinaryOpKind::Mul }
238 / "div" _ { BinaryOpKind::Div }
239 / "and" _ { BinaryOpKind::And }
240 / "or" _ { BinaryOpKind::Or }
241 / "xor" _ { BinaryOpKind::Xor }
242 / "mod" _ { BinaryOpKind::Mod }
243 / "rsh" _ { BinaryOpKind::Rsh }
244 / "lsh" _ { BinaryOpKind::Lsh }
245
246 rule operation() -> IrAstOperation
247 = op_asm()
248 / op_wide_unary()
249 / op_wide_binary()
250 / op_wide_cmp()
251 / op_retd()
252 / op_branch()
253 / op_bitcast()
254 / op_unary()
255 / op_binary()
256 / op_call()
257 / op_cast_ptr()
258 / op_cbr()
259 / op_cmp()
260 / op_const()
261 / op_contract_call()
262 / op_get_elem_ptr()
263 / op_get_local()
264 / op_get_global()
265 / op_get_config()
266 / op_get_storage_key()
267 / op_gtf()
268 / op_int_to_ptr()
269 / op_load()
270 / op_log()
271 / op_mem_copy_bytes()
272 / op_mem_copy_val()
273 / op_mem_clear_val()
274 / op_nop()
275 / op_ptr_to_int()
276 / op_read_register()
277 / op_ret()
278 / op_revert()
279 / op_jmp_mem()
280 / op_smo()
281 / op_state_load_quad_word()
282 / op_state_load_word()
283 / op_state_store_quad_word()
284 / op_state_store_word()
285 / op_store()
286 / op_alloc()
287
288 rule op_asm() -> IrAstOperation
289 = "asm" _ "(" _ args:(asm_arg() ** comma()) ")" _ ret:asm_ret() meta_idx:comma_metadata_idx()? "{" _
290 ops:asm_op()*
291 "}" _ {
292 IrAstOperation::Asm(
293 args,
294 ret.0,
295 ret.1,
296 ops,
297 meta_idx
298 )
299 }
300
301 rule op_bitcast() -> IrAstOperation
302 = "bitcast" _ val:id() "to" _ ty:ast_ty() {
303 IrAstOperation::BitCast(val, ty)
304 }
305
306 rule op_unary() -> IrAstOperation
307 = op: unary_op_kind() arg1:id() {
308 IrAstOperation::UnaryOp(op, arg1)
309 }
310
311 rule op_wide_modular_operation() -> IrAstOperation
312 = "wide" _ op:binary_op_kind() arg1:id() comma() arg2:id() comma() arg3:id() "to" _ result:id() {
313 IrAstOperation::WideModularOp(op, arg1, arg2, arg3, result)
314 }
315
316 rule op_wide_unary() -> IrAstOperation
317 = "wide" _ op:unary_op_kind() arg:id() "to" _ result:id() {
318 IrAstOperation::WideUnaryOp(op, arg, result)
319 }
320
321 rule op_wide_binary() -> IrAstOperation
322 = "wide" _ op:binary_op_kind() arg1:id() comma() arg2:id() "to" _ result:id() {
323 IrAstOperation::WideBinaryOp(op, arg1, arg2, result)
324 }
325
326 rule op_wide_cmp() -> IrAstOperation
327 = "wide" _ "cmp" _ op:cmp_pred() arg1:id() arg2:id() {
328 IrAstOperation::WideCmp(op, arg1, arg2)
329 }
330
331 rule op_retd() -> IrAstOperation
332 = "retd" _ arg1:id() _ arg2:id() {
333 IrAstOperation::Retd(arg1, arg2)
334 }
335
336 rule op_binary() -> IrAstOperation
337 = op: binary_op_kind() arg1:id() comma() arg2:id() {
338 IrAstOperation::BinaryOp(op, arg1, arg2)
339 }
340
341 rule op_branch() -> IrAstOperation
342 = "br" _ to_block:id() "(" _ args:(id() ** comma()) ")" _ {
343 IrAstOperation::Br(to_block, args)
344 }
345
346 rule op_call() -> IrAstOperation
347 = "call" _ callee:id() "(" _ args:(id() ** comma()) ")" _ {
348 IrAstOperation::Call(callee, args)
349 }
350
351 rule op_cast_ptr() -> IrAstOperation
352 = "cast_ptr" _ val:id() "to" _ ty:ast_ty() {
353 IrAstOperation::CastPtr(val, ty)
354 }
355
356 rule op_cbr() -> IrAstOperation
357 = "cbr" _ cond:id() comma() tblock:id()
358 "(" _ targs:(id() ** comma()) ")" _
359 comma() fblock:id() "(" _ fargs:(id() ** comma()) ")" _ {
360 IrAstOperation::Cbr(cond, tblock, targs, fblock, fargs)
361 }
362
363 rule op_cmp() -> IrAstOperation
364 = "cmp" _ p:cmp_pred() l:id() r:id() {
365 IrAstOperation::Cmp(p, l, r)
366 }
367
368 rule op_const() -> IrAstOperation
369 = "const" _ val_ty:ast_ty() cv:constant() {
370 IrAstOperation::Const(val_ty, cv)
371 }
372
373 rule op_contract_call() -> IrAstOperation
374 = "contract_call" _
375 ty:ast_ty() _ name:id() _
376 params:id() comma() coins:id() comma() asset_id:id() comma() gas:id() _ {
377 IrAstOperation::ContractCall(ty, name, params, coins, asset_id, gas)
378 }
379
380 rule op_get_elem_ptr() -> IrAstOperation
381 = "get_elem_ptr" _ base:id() comma() ty:ast_ty() comma() idcs:(id() ++ comma()) {
382 IrAstOperation::GetElemPtr(base, ty, idcs)
383 }
384
385 rule op_get_local() -> IrAstOperation
386 = "get_local" _ ast_ty() comma() name:id() {
387 IrAstOperation::GetLocal(name)
388 }
389
390 rule op_get_global() -> IrAstOperation
391 = "get_global" _ ast_ty() comma() name:path() {
392 IrAstOperation::GetGlobal(name)
393 }
394
395 rule op_get_config() -> IrAstOperation
396 = "get_config" _ ast_ty() comma() name:id() {
397 IrAstOperation::GetConfig(name)
398 }
399
400 rule op_get_storage_key() -> IrAstOperation
401 = "get_storage_key" _ ast_ty() comma() namespaces:path() "." fields:field_access() {
402 IrAstOperation::GetStorageKey(format!("{}.{}", namespaces.join("::"), fields.join(".")))
403 }
404
405 rule op_gtf() -> IrAstOperation
406 = "gtf" _ index:id() comma() tx_field_id:decimal() {
407 IrAstOperation::Gtf(index, tx_field_id)
408 }
409
410 rule op_int_to_ptr() -> IrAstOperation
411 = "int_to_ptr" _ val:id() "to" _ ty:ast_ty() {
412 IrAstOperation::IntToPtr(val, ty)
413 }
414
415 rule op_alloc() -> IrAstOperation
416 = "alloc" _ ty:ast_ty() "x" _ count:id() {
417 IrAstOperation::Alloc(ty, count)
418 }
419
420 rule op_load() -> IrAstOperation
421 = "load" _ src:id() {
422 IrAstOperation::Load(src)
423 }
424
425 rule log_event_data() -> LogEventData
426 = _ "log_data" _ "(" _
427 "version" _ ":" _ version:decimal() comma()
428 "is_event" _ ":" _ is_event:bool_lit() comma()
429 "is_indexed" _ ":" _ is_indexed:bool_lit() comma()
430 "event_type_size" _ ":" _ event_type_size:decimal() comma()
431 "num_elements" _ ":" _ num_elements:decimal()
432 _ ")" {
433 LogEventData::new(
434 u8::try_from(version).expect("log event data version must fit in u8"),
435 is_event,
436 is_indexed,
437 u8::try_from(event_type_size)
438 .expect("log event data size must fit in u8"),
439 u16::try_from(num_elements)
440 .expect("log event data count must fit in u16"),
441 )
442 }
443
444 rule op_log() -> IrAstOperation
445 = "log" _ log_ty:ast_ty() log_val:id() comma() log_id:id() log_data:log_event_data()? _ {
446 IrAstOperation::Log(log_ty, log_val, log_id, log_data)
447 }
448
449 rule op_mem_copy_bytes() -> IrAstOperation
450 = "mem_copy_bytes" _ dst_name:id() comma() src_name:id() comma() len:decimal() {
451 IrAstOperation::MemCopyBytes(dst_name, src_name, len)
452 }
453
454 rule op_mem_copy_val() -> IrAstOperation
455 = "mem_copy_val" _ dst_name:id() comma() src_name:id() {
456 IrAstOperation::MemCopyVal(dst_name, src_name)
457 }
458
459 rule op_mem_clear_val() -> IrAstOperation
460 = "mem_clear_val" _ dst_name:id() {
461 IrAstOperation::MemClearVal(dst_name)
462 }
463
464 rule op_nop() -> IrAstOperation
465 = "nop" _ {
466 IrAstOperation::Nop
467 }
468
469 rule op_ptr_to_int() -> IrAstOperation
470 = "ptr_to_int" _ val:id() "to" _ ty:ast_ty() {
471 IrAstOperation::PtrToInt(val, ty)
472 }
473
474 rule op_read_register() -> IrAstOperation
475 = "read_register" _ r:reg_name() {
476 IrAstOperation::ReadRegister(r)
477 }
478
479 rule op_ret() -> IrAstOperation
480 = "ret" _ ty:ast_ty() vn:id() {
481 IrAstOperation::Ret(ty, vn)
482 }
483
484 rule op_revert() -> IrAstOperation
485 = "revert" _ vn:id() {
486 IrAstOperation::Revert(vn)
487 }
488
489 rule op_jmp_mem() -> IrAstOperation
490 = "jmp_mem" _ {
491 IrAstOperation::JmpMem
492 }
493
494 rule op_smo() -> IrAstOperation
495 = "smo" _
496 recipient_and_message:id() comma() message_size:id() comma() output_index:id() comma() coins:id() _ {
497 IrAstOperation::Smo(recipient_and_message, message_size, output_index, coins)
498 }
499
500 rule op_state_clear() -> IrAstOperation
501 = "state_clear" _ "key" _ key:id() comma() number_of_slots:id() {
502 IrAstOperation::StateClear(key, number_of_slots)
503 }
504
505 rule op_state_load_quad_word() -> IrAstOperation
506 = "state_load_quad_word" _ dst:id() comma() "key" _ key:id() comma() number_of_slots:id() {
507 IrAstOperation::StateLoadQuadWord(dst, key, number_of_slots)
508 }
509
510 rule op_state_load_word() -> IrAstOperation
511 = "state_load_word" _ "key" _ key:id() {
512 IrAstOperation::StateLoadWord(key)
513 }
514
515 rule op_state_store_quad_word() -> IrAstOperation
516 = "state_store_quad_word" _ src:id() comma() "key" _ key:id() comma() number_of_slots:id() {
517 IrAstOperation::StateStoreQuadWord(src, key, number_of_slots)
518 }
519
520 rule op_state_store_word() -> IrAstOperation
521 = "state_store_word" _ src:id() comma() "key" _ key:id() {
522 IrAstOperation::StateStoreWord(src, key)
523 }
524
525 rule op_store() -> IrAstOperation
526 = "store" _ val:id() "to" _ dst:id() {
527 IrAstOperation::Store(val, dst)
528 }
529
530 rule cmp_pred() -> Predicate
531 = "eq" _ { Predicate::Equal }
532 / "gt" _ { Predicate::GreaterThan }
533 / "lt" _ { Predicate::LessThan }
534
535 rule reg_name() -> String
536 = r:$("of" / "pc" / "ssp" / "sp" / "fp" / "hp" / "err" / "ggas" / "cgas" / "bal" / "is" / "ret" / "retl" / "flag") _ {
537 r.to_string()
538 }
539
540 rule asm_arg() -> (Ident, Option<IrAstAsmArgInit>)
541 = name:id_id() init:asm_arg_init()? {
542 (name, init)
543 }
544
545 rule asm_arg_init() -> IrAstAsmArgInit
546 = ":" _ imm:constant() {
547 IrAstAsmArgInit::Imm(imm)
548 }
549 / ":" _ var:id() {
550 IrAstAsmArgInit::Var(var)
551 }
552
553 rule asm_ret() -> (IrAstTy, Option<Ident>)
554 = "->" _ ty:ast_ty() ret:id_id()? {
555 (ty, ret)
556 }
557
558 rule asm_op() -> IrAstAsmOp
559 = name:id_id() args:asm_op_arg()* imm:asm_op_arg_imm()? meta_idx:comma_metadata_idx()? {
560 IrAstAsmOp {
561 name,
562 args,
563 imm,
564 meta_idx
565 }
566 }
567
568 rule asm_op_arg() -> Ident
569 = !asm_op_arg_imm() arg:id_id() {
570 arg
571 }
572
573 rule asm_op_arg_imm() -> Ident
574 = imm:$("i" d:decimal()) {
575 Ident::new(Span::new(imm.into(), 0, imm.len(), None).unwrap())
576 }
577
578 rule constant() -> IrAstConst
579 = value:constant_value() meta_idx:metadata_idx()? {
580 IrAstConst {
581 value,
582 meta_idx
583 }
584 }
585
586 rule constant_value() -> IrAstConstValue
587 = "()" _ { IrAstConstValue::Unit }
588 / "true" _ { IrAstConstValue::Bool(true) }
589 / "false" _ { IrAstConstValue::Bool(false) }
590 / "0x" s:$(hex_digit()*<64>) _ {
591 IrAstConstValue::Hex256(string_to_hex::<32>(s))
592 }
593 / n:decimal() { IrAstConstValue::Number(n) }
594 / string_const()
595 / array_const()
596 / struct_const()
597
598 rule string_const() -> IrAstConstValue
599 = ['"'] chs:str_char()* ['"'] _ {
600 IrAstConstValue::String(chs)
601 }
602
603 rule str_char() -> u8
604 = c:$([' ' | '!' | '#'..='[' | ']'..='~']) {
606 *c.as_bytes().first().unwrap()
607 }
608 / "\\x" h:hex_digit() l:hex_digit() {
609 (h << 4) | l
610 }
611
612 rule hex_digit() -> u8
619 = d:$(['0'..='9']) {
620 d.as_bytes().first().unwrap() - b'0'
621 }
622 / d:$(['a'..='f' | 'A'..='F']) {
623 (d.as_bytes().first().unwrap() | 0x20) - b'a' + 10
624 }
625
626 rule array_const() -> IrAstConstValue
627 = "[" _ els:(field_or_element_const() ++ comma()) "]" _ {
628 let el_ty = els[0].0.clone();
629 let els = els.into_iter().map(|(_, cv)| cv).collect::<Vec<_>>();
630 IrAstConstValue::Array(el_ty, els)
631 }
632
633 rule struct_const() -> IrAstConstValue
634 = "{" _ flds:(field_or_element_const() ** comma()) "}" _ {
635 IrAstConstValue::Struct(flds)
636 }
637
638 rule field_or_element_const() -> (IrAstTy, IrAstConst)
639 = ty:ast_ty() cv:constant() {
640 (ty, cv)
641 }
642 / ty:ast_ty() "undef" _ {
643 (ty.clone(), IrAstConst { value: IrAstConstValue::Undef, meta_idx: None })
644 }
645
646 rule ast_ty() -> IrAstTy
647 = ("unit" / "()") _ { IrAstTy::Unit }
648 / "bool" _ { IrAstTy::Bool }
649 / "u8" _ { IrAstTy::U8 }
650 / "u64" _ { IrAstTy::U64 }
651 / "u256" _ { IrAstTy::U256 }
652 / "b256" _ { IrAstTy::B256 }
653 / "slice" _ { IrAstTy::Slice }
654 / "__slice" _ "[" _ ty:ast_ty() "]" _ { IrAstTy::TypedSlice(Box::new(ty)) }
655 / "string" _ "<" _ sz:decimal() ">" _ { IrAstTy::String(sz) }
656 / array_ty()
657 / struct_ty()
658 / union_ty()
659 / "__ptr" _ ty:ast_ty() _ { IrAstTy::TypedPtr(Box::new(ty)) }
660 / "ptr" _ { IrAstTy::Ptr }
661 / "never" _ { IrAstTy::Never }
662
663 rule array_ty() -> IrAstTy
664 = "[" _ ty:ast_ty() ";" _ c:decimal() "]" _ {
665 IrAstTy::Array(Box::new(ty), c)
666 }
667
668 rule union_ty() -> IrAstTy
669 = "(" _ tys:(ast_ty() ++ ("|" _)) ")" _ {
670 IrAstTy::Union(tys)
671 }
672
673 rule struct_ty() -> IrAstTy
674 = "{" _ tys:(ast_ty() ** comma()) "}" _ {
675 IrAstTy::Struct(tys)
676 }
677
678 rule id() -> String
679 = !(ast_ty() (" " "\n")) id:$(id_char0() id_char()*) _ {
680 id.to_owned()
681 }
682
683 rule id_id() -> Ident
684 = !(ast_ty() (" " "\n")) id:$(id_char0() id_char()*) _ {
685 Ident::new(Span::new(id.into(), 0, id.len(), None).unwrap())
686 }
687
688 rule path() -> Vec<String>
689 = (id() ** "::")
690
691 rule field_access() -> Vec<String>
692 = (id() ** ".")
693
694 rule metadata_decls() -> Vec<(MdIdxRef, IrMetadatum)>
707 = ds:(metadata_decl() ** nl()) _ {
708 ds
709 }
710
711 rule metadata_decl() -> (MdIdxRef, IrMetadatum)
712 = idx:metadata_idx() "=" _ item:metadata_item() {
713 (idx, item)
714 }
715
716 rule metadata_item() -> IrMetadatum
719 = i:dec_digits() __ {
720 IrMetadatum::Integer(i)
721 }
722 / "!" idx:dec_digits() __ {
723 IrMetadatum::Index(idx)
724 }
725 / ['"'] s:$(([^ '"' | '\\'] / ['\\'] ['\\' | '"' ])+) ['"'] __ {
726 IrMetadatum::String(s.to_owned().replace("\\\\", "\\"))
728 }
729 / tag:$(id_char0() id_char()*) __ els:metadata_item()* {
730 IrMetadatum::Struct(tag.to_owned(), els)
731 }
732 / "(" _ els:metadata_idx()*<2,> ")" __ {
733 IrMetadatum::List(els)
735 }
736
737 rule id_char0()
738 = quiet!{ ['A'..='Z' | 'a'..='z' | '_'] }
739
740 rule id_char()
741 = quiet!{ id_char0() / ['0'..='9'] }
742
743 rule decimal() -> u64
744 = d:dec_digits() _ {
745 d
746 }
747
748 rule bool_lit() -> bool
749 = "true" _ { true }
750 / "false" _ { false }
751
752 rule dec_digits() -> u64
755 = ds:$("0" / ['1'..='9'] ['0'..='9']*) {
756 ds.parse::<u64>().unwrap()
757 }
758
759 rule comma()
760 = quiet!{ "," _ }
761
762 rule _()
763 = quiet!{ (space() / nl() / comment())* }
764
765 rule __()
766 = quiet!{ (space() / comment())* }
767
768 rule space()
769 = [' ' | '\t']
770
771 rule nl()
772 = ['\n' | '\r']
773
774 rule comment()
775 = "//" (!nl() [_])* nl()
776
777 rule eoi()
778 = ![_] / expected!("end of input")
779 }
780 }
781
782 use crate::{
785 asm::{AsmArg, AsmInstruction},
786 block::Block,
787 constant::{ConstantContent, ConstantValue},
788 context::Context,
789 error::IrError,
790 function::Function,
791 instruction::{InstOp, Predicate, Register},
792 irtype::Type,
793 metadata::{MetadataIndex, Metadatum},
794 module::{Kind, Module},
795 value::Value,
796 variable::LocalVar,
797 Backtrace, BinaryOpKind, BlockArgument, ConfigContent, Constant, GlobalVar, Instruction,
798 LogEventData, StorageKey, UnaryOpKind, B256,
799 };
800
801 #[derive(Debug)]
802 pub(super) struct IrAstModule {
803 kind: Kind,
804 configs: Vec<IrAstConfig>,
805 global_vars: Vec<IrAstGlobalVar>,
806 storage_keys: Vec<IrAstStorageKey>,
807 fn_decls: Vec<IrAstFnDecl>,
808 metadata: Vec<(MdIdxRef, IrMetadatum)>,
809 }
810
811 #[derive(Debug)]
812 pub(super) struct IrAstGlobalVar {
813 name: Vec<String>,
814 ty: IrAstTy,
815 init: Option<IrAstOperation>,
816 mutable: bool,
817 }
818
819 #[derive(Debug)]
820 pub(super) struct IrAstStorageKey {
821 namespaces: Vec<String>,
822 fields: Vec<String>,
823 slot: IrAstConst,
824 offset: Option<IrAstConst>,
825 field_id: Option<IrAstConst>,
826 }
827
828 #[derive(Debug)]
829 struct IrAstFnDecl {
830 name: String,
831 args: Vec<(IrAstTy, String, Option<MdIdxRef>)>,
832 ret_type: IrAstTy,
833 is_public: bool,
834 metadata: Option<MdIdxRef>,
835 locals: Vec<(IrAstTy, String, Option<IrAstOperation>, bool)>,
836 blocks: Vec<IrAstBlock>,
837 selector: Option<[u8; 4]>,
838 is_entry: bool,
839 is_original_entry: bool,
840 is_fallback: bool,
841 }
842
843 #[derive(Debug)]
844 struct IrAstBlock {
845 label: String,
846 args: Vec<(IrAstTy, String, Option<MdIdxRef>)>,
847 instructions: Vec<IrAstInstruction>,
848 }
849
850 #[derive(Debug)]
851 struct IrAstInstruction {
852 value_name: Option<String>,
853 op: IrAstOperation,
854 metadata: Option<MdIdxRef>,
855 }
856
857 #[derive(Debug)]
858 enum IrAstOperation {
859 Asm(
860 Vec<(Ident, Option<IrAstAsmArgInit>)>,
861 IrAstTy,
862 Option<Ident>,
863 Vec<IrAstAsmOp>,
864 Option<MdIdxRef>,
865 ),
866 BitCast(String, IrAstTy),
867 UnaryOp(UnaryOpKind, String),
868 BinaryOp(BinaryOpKind, String, String),
869 Br(String, Vec<String>),
870 Call(String, Vec<String>),
871 CastPtr(String, IrAstTy),
872 Cbr(String, String, Vec<String>, String, Vec<String>),
873 Cmp(Predicate, String, String),
874 Const(IrAstTy, IrAstConst),
875 ContractCall(IrAstTy, String, String, String, String, String),
876 GetElemPtr(String, IrAstTy, Vec<String>),
877 GetLocal(String),
878 GetGlobal(Vec<String>),
879 GetConfig(String),
880 GetStorageKey(String),
881 Gtf(String, u64),
882 IntToPtr(String, IrAstTy),
883 Load(String),
884 Log(IrAstTy, String, String, Option<LogEventData>),
885 MemCopyBytes(String, String, u64),
886 MemCopyVal(String, String),
887 MemClearVal(String),
888 Nop,
889 PtrToInt(String, IrAstTy),
890 ReadRegister(String),
891 Ret(IrAstTy, String),
892 Revert(String),
893 JmpMem,
894 Smo(String, String, String, String),
895 StateClear(String, String),
896 StateLoadQuadWord(String, String, String),
897 StateLoadWord(String),
898 StateStoreQuadWord(String, String, String),
899 StateStoreWord(String, String),
900 Store(String, String),
901 WideUnaryOp(UnaryOpKind, String, String),
902 WideBinaryOp(BinaryOpKind, String, String, String),
903 WideCmp(Predicate, String, String),
904 WideModularOp(BinaryOpKind, String, String, String, String),
905 Retd(String, String),
906 Alloc(IrAstTy, String),
907 }
908
909 #[derive(Debug)]
910 struct IrAstConfig {
911 value_name: String,
912 ty: IrAstTy,
913 encoded_bytes: Vec<u8>,
914 decode_fn: String,
915 metadata: Option<MdIdxRef>,
916 }
917
918 #[derive(Debug)]
919 struct IrAstConst {
920 value: IrAstConstValue,
921 meta_idx: Option<MdIdxRef>,
922 }
923
924 #[derive(Debug)]
925 enum IrAstConstValue {
926 Undef,
927 Unit,
928 Bool(bool),
929 Hex256([u8; 32]),
930 Number(u64),
931 String(Vec<u8>),
932 Array(IrAstTy, Vec<IrAstConst>),
933 Struct(Vec<(IrAstTy, IrAstConst)>),
934 }
935
936 #[derive(Debug)]
937 enum IrAstAsmArgInit {
938 Var(String),
939 Imm(IrAstConst),
940 }
941
942 #[derive(Debug)]
943 struct IrAstAsmOp {
944 name: Ident,
945 args: Vec<Ident>,
946 imm: Option<Ident>,
947 meta_idx: Option<MdIdxRef>,
948 }
949
950 impl IrAstConstValue {
951 fn as_constant_value(&self, context: &mut Context, val_ty: IrAstTy) -> ConstantValue {
952 match self {
953 IrAstConstValue::Undef => ConstantValue::Undef,
954 IrAstConstValue::Unit => ConstantValue::Unit,
955 IrAstConstValue::Bool(b) => ConstantValue::Bool(*b),
956 IrAstConstValue::Hex256(bs) => match val_ty {
957 IrAstTy::U256 => {
958 let value = U256::from_be_bytes(bs);
959 ConstantValue::U256(value)
960 }
961 IrAstTy::B256 => {
962 let value = B256::from_be_bytes(bs);
963 ConstantValue::B256(value)
964 }
965 _ => unreachable!("invalid type for hex number"),
966 },
967 IrAstConstValue::Number(n) => ConstantValue::Uint(*n),
968 IrAstConstValue::String(bs) => ConstantValue::String(bs.clone()),
969 IrAstConstValue::Array(el_ty, els) => {
970 let els: Vec<_> = els
971 .iter()
972 .map(|cv| {
973 cv.value
974 .as_constant(context, el_ty.clone())
975 .get_content(context)
976 .clone()
977 })
978 .collect();
979 ConstantValue::Array(els)
980 }
981 IrAstConstValue::Struct(flds) => {
982 let fields: Vec<_> = flds
983 .iter()
984 .map(|(ty, cv)| {
985 cv.value
986 .as_constant(context, ty.clone())
987 .get_content(context)
988 .clone()
989 })
990 .collect::<Vec<_>>();
991 ConstantValue::Struct(fields)
992 }
993 }
994 }
995
996 fn as_constant(&self, context: &mut Context, val_ty: IrAstTy) -> Constant {
997 let value = self.as_constant_value(context, val_ty.clone());
998 let constant = ConstantContent {
999 ty: val_ty.to_ir_type(context),
1000 value,
1001 };
1002 Constant::unique(context, constant)
1003 }
1004
1005 fn as_value(&self, context: &mut Context, val_ty: IrAstTy) -> Value {
1006 match self {
1007 IrAstConstValue::Undef => unreachable!("Can't convert 'undef' to a value."),
1008 IrAstConstValue::Unit => ConstantContent::get_unit(context),
1009 IrAstConstValue::Bool(b) => ConstantContent::get_bool(context, *b),
1010 IrAstConstValue::Hex256(bs) => match val_ty {
1011 IrAstTy::U256 => {
1012 let n = U256::from_be_bytes(bs);
1013 ConstantContent::get_uint256(context, n)
1014 }
1015 IrAstTy::B256 => ConstantContent::get_b256(context, *bs),
1016 _ => unreachable!("invalid type for hex number"),
1017 },
1018 IrAstConstValue::Number(n) => match val_ty {
1019 IrAstTy::U8 => ConstantContent::get_uint(context, 8, *n),
1020 IrAstTy::U64 => ConstantContent::get_uint(context, 64, *n),
1021 _ => unreachable!(),
1022 },
1023 IrAstConstValue::String(s) => ConstantContent::get_string(context, s.clone()),
1024 IrAstConstValue::Array(..) => {
1025 let array_const = self.as_constant(context, val_ty);
1026 ConstantContent::get_array(context, array_const.get_content(context).clone())
1027 }
1028 IrAstConstValue::Struct(_) => {
1029 let struct_const = self.as_constant(context, val_ty);
1030 ConstantContent::get_struct(context, struct_const.get_content(context).clone())
1031 }
1032 }
1033 }
1034 }
1035
1036 #[derive(Clone, Debug)]
1037 enum IrAstTy {
1038 Unit,
1039 Bool,
1040 U8,
1041 U64,
1042 U256,
1043 B256,
1044 Slice,
1045 TypedSlice(Box<IrAstTy>),
1046 String(u64),
1047 Array(Box<IrAstTy>, u64),
1048 Union(Vec<IrAstTy>),
1049 Struct(Vec<IrAstTy>),
1050 TypedPtr(Box<IrAstTy>),
1051 Ptr,
1052 Never,
1053 }
1054
1055 impl IrAstTy {
1056 fn to_ir_type(&self, context: &mut Context) -> Type {
1057 match self {
1058 IrAstTy::Unit => Type::get_unit(context),
1059 IrAstTy::Bool => Type::get_bool(context),
1060 IrAstTy::U8 => Type::get_uint8(context),
1061 IrAstTy::U64 => Type::get_uint64(context),
1062 IrAstTy::U256 => Type::get_uint256(context),
1063 IrAstTy::B256 => Type::get_b256(context),
1064 IrAstTy::Slice => Type::get_slice(context),
1065 IrAstTy::TypedSlice(el_ty) => {
1066 let inner_ty = el_ty.to_ir_type(context);
1067 Type::get_typed_slice(context, inner_ty)
1068 }
1069 IrAstTy::String(n) => Type::new_string_array(context, *n),
1070 IrAstTy::Array(el_ty, count) => {
1071 let el_ty = el_ty.to_ir_type(context);
1072 Type::new_array(context, el_ty, *count)
1073 }
1074 IrAstTy::Union(tys) => {
1075 let tys = tys.iter().map(|ty| ty.to_ir_type(context)).collect();
1076 Type::new_union(context, tys)
1077 }
1078 IrAstTy::Struct(tys) => {
1079 let tys = tys.iter().map(|ty| ty.to_ir_type(context)).collect();
1080 Type::new_struct(context, tys)
1081 }
1082 IrAstTy::TypedPtr(ty) => {
1083 let inner_ty = ty.to_ir_type(context);
1084 Type::new_typed_pointer(context, inner_ty)
1085 }
1086 IrAstTy::Ptr => Type::get_ptr(context),
1087 IrAstTy::Never => Type::get_never(context),
1088 }
1089 }
1090 }
1091
1092 #[derive(Debug)]
1093 enum IrMetadatum {
1094 Integer(u64),
1096 Index(MdIdxRef),
1098 String(String),
1100 Struct(String, Vec<IrMetadatum>),
1102 List(Vec<MdIdxRef>),
1104 }
1105
1106 use std::{
1109 cell::Cell,
1110 collections::{BTreeMap, HashMap},
1111 iter::FromIterator,
1112 };
1113
1114 pub(super) fn build_context(
1115 ir_ast_mod: IrAstModule,
1116 source_engine: &SourceEngine,
1117 experimental: ExperimentalFeatures,
1118 backtrace: Backtrace,
1119 ) -> Result<Context, IrError> {
1120 let mut ctx = Context::new(source_engine, experimental, backtrace);
1121 let md_map = build_metadata_map(&mut ctx, ir_ast_mod.metadata);
1122 let module = Module::new(&mut ctx, ir_ast_mod.kind);
1123 let mut builder = IrBuilder {
1124 module,
1125 configs_map: build_configs_map(&mut ctx, &module, ir_ast_mod.configs, &md_map),
1126 globals_map: build_global_vars_map(&mut ctx, &module, ir_ast_mod.global_vars),
1127 storage_keys_map: build_storage_keys_map(&mut ctx, &module, ir_ast_mod.storage_keys),
1128 md_map,
1129 unresolved_calls: Vec::new(),
1130 };
1131
1132 for fn_decl in ir_ast_mod.fn_decls {
1133 builder.add_fn_decl(&mut ctx, fn_decl)?;
1134 }
1135
1136 builder.resolve_calls(&mut ctx)?;
1137
1138 Ok(ctx)
1139 }
1140
1141 struct IrBuilder {
1142 module: Module,
1143 configs_map: BTreeMap<String, String>,
1144 globals_map: BTreeMap<Vec<String>, GlobalVar>,
1145 storage_keys_map: BTreeMap<String, StorageKey>,
1146 md_map: HashMap<MdIdxRef, MetadataIndex>,
1147 unresolved_calls: Vec<PendingCall>,
1148 }
1149
1150 struct PendingCall {
1151 call_val: Value,
1152 callee: String,
1153 }
1154
1155 impl IrBuilder {
1156 fn add_fn_decl(
1157 &mut self,
1158 context: &mut Context,
1159 fn_decl: IrAstFnDecl,
1160 ) -> Result<(), IrError> {
1161 let convert_md_idx = |opt_md_idx: &Option<MdIdxRef>| {
1162 opt_md_idx.and_then(|mdi| self.md_map.get(&mdi).copied())
1163 };
1164 let args: Vec<(String, Type, Option<MetadataIndex>)> = fn_decl
1165 .args
1166 .iter()
1167 .map(|(ty, name, md_idx)| {
1168 (name.into(), ty.to_ir_type(context), convert_md_idx(md_idx))
1169 })
1170 .collect();
1171 let ret_type = fn_decl.ret_type.to_ir_type(context);
1172 let func = Function::new(
1173 context,
1174 self.module,
1175 fn_decl.name.clone(),
1176 fn_decl.name,
1177 args,
1178 ret_type,
1179 fn_decl.selector,
1180 fn_decl.is_public,
1181 fn_decl.is_entry,
1182 fn_decl.is_original_entry,
1183 fn_decl.is_fallback,
1184 convert_md_idx(&fn_decl.metadata),
1185 );
1186
1187 let mut arg_map = HashMap::default();
1188 let mut local_map = HashMap::<String, LocalVar>::new();
1189 for (ty, name, initializer, mutable) in fn_decl.locals {
1190 let initializer = initializer.map(|const_init| {
1191 if let IrAstOperation::Const(val_ty, val) = const_init {
1192 val.value.as_constant(context, val_ty)
1193 } else {
1194 unreachable!("BUG! Initializer must be a const value.");
1195 }
1196 });
1197 let ty = ty.to_ir_type(context);
1198 local_map.insert(
1199 name.clone(),
1200 func.new_local_var(context, name, ty, initializer, mutable)?,
1201 );
1202 }
1203
1204 let named_blocks =
1206 HashMap::from_iter(fn_decl.blocks.iter().scan(true, |is_entry, block| {
1207 Some((
1208 block.label.clone(),
1209 if *is_entry {
1210 *is_entry = false;
1211 func.get_entry_block(context)
1212 } else {
1213 let irblock = func.create_block(context, Some(block.label.clone()));
1214 for (idx, (arg_ty, _, md)) in block.args.iter().enumerate() {
1215 let ty = arg_ty.to_ir_type(context);
1216 let arg = Value::new_argument(
1217 context,
1218 BlockArgument {
1219 block: irblock,
1220 idx,
1221 ty,
1222 is_immutable: false,
1224 },
1225 )
1226 .add_metadatum(context, convert_md_idx(md));
1227 irblock.add_arg(context, arg);
1228 }
1229 irblock
1230 },
1231 ))
1232 }));
1233
1234 for block in fn_decl.blocks {
1235 for (idx, arg) in block.args.iter().enumerate() {
1236 arg_map.insert(
1237 arg.1.clone(),
1238 named_blocks[&block.label].get_arg(context, idx).unwrap(),
1239 );
1240 }
1241 self.add_block_instructions(
1242 context,
1243 block,
1244 &named_blocks,
1245 &local_map,
1246 &mut arg_map,
1247 );
1248 }
1249 Ok(())
1250 }
1251
1252 fn add_block_instructions(
1253 &mut self,
1254 context: &mut Context,
1255 ir_block: IrAstBlock,
1256 named_blocks: &HashMap<String, Block>,
1257 local_map: &HashMap<String, LocalVar>,
1258 val_map: &mut HashMap<String, Value>,
1259 ) {
1260 let block = named_blocks.get(&ir_block.label).unwrap();
1261 for ins in ir_block.instructions {
1262 let opt_metadata = ins.metadata.and_then(|mdi| self.md_map.get(&mdi)).copied();
1263 let ins_val = match ins.op {
1264 IrAstOperation::Asm(args, return_type, return_name, ops, meta_idx) => {
1265 let args = args
1266 .into_iter()
1267 .map(|(name, opt_init)| AsmArg {
1268 name,
1269 initializer: opt_init.map(|init| match init {
1270 IrAstAsmArgInit::Var(var) => {
1271 val_map.get(&var).cloned().unwrap()
1272 }
1273 IrAstAsmArgInit::Imm(cv) => {
1274 cv.value.as_value(context, IrAstTy::U64).add_metadatum(
1275 context,
1276 self.md_map.get(cv.meta_idx.as_ref().unwrap()).copied(),
1277 )
1278 }
1279 }),
1280 })
1281 .collect();
1282 let body = ops
1283 .into_iter()
1284 .map(
1285 |IrAstAsmOp {
1286 name,
1287 args,
1288 imm,
1289 meta_idx,
1290 }| AsmInstruction {
1291 op_name: name,
1292 args,
1293 immediate: imm,
1294 metadata: meta_idx
1295 .as_ref()
1296 .and_then(|meta_idx| self.md_map.get(meta_idx).copied()),
1297 },
1298 )
1299 .collect();
1300 let md_idx = meta_idx.and_then(|mdi| self.md_map.get(&mdi)).copied();
1301 let return_type = return_type.to_ir_type(context);
1302 block
1303 .append(context)
1304 .asm_block(args, body, return_type, return_name)
1305 .add_metadatum(context, md_idx)
1306 }
1307 IrAstOperation::BitCast(val, ty) => {
1308 let to_ty = ty.to_ir_type(context);
1309 block
1310 .append(context)
1311 .bitcast(*val_map.get(&val).unwrap(), to_ty)
1312 .add_metadatum(context, opt_metadata)
1313 }
1314 IrAstOperation::Alloc(ty, name) => {
1315 let ir_ty = ty.to_ir_type(context);
1316 block
1317 .append(context)
1318 .alloc(ir_ty, *val_map.get(&name).unwrap())
1319 .add_metadatum(context, opt_metadata)
1320 }
1321 IrAstOperation::UnaryOp(op, arg) => block
1322 .append(context)
1323 .unary_op(op, *val_map.get(&arg).unwrap())
1324 .add_metadatum(context, opt_metadata),
1325 IrAstOperation::WideUnaryOp(op, arg, result) => block
1327 .append(context)
1328 .wide_unary_op(
1329 op,
1330 *val_map.get(&arg).unwrap(),
1331 *val_map.get(&result).unwrap(),
1332 )
1333 .add_metadatum(context, opt_metadata),
1334 IrAstOperation::WideBinaryOp(op, arg1, arg2, result) => block
1335 .append(context)
1336 .wide_binary_op(
1337 op,
1338 *val_map.get(&arg1).unwrap(),
1339 *val_map.get(&arg2).unwrap(),
1340 *val_map.get(&result).unwrap(),
1341 )
1342 .add_metadatum(context, opt_metadata),
1343 IrAstOperation::WideModularOp(op, arg1, arg2, arg3, result) => block
1344 .append(context)
1345 .wide_modular_op(
1346 op,
1347 *val_map.get(&result).unwrap(),
1348 *val_map.get(&arg1).unwrap(),
1349 *val_map.get(&arg2).unwrap(),
1350 *val_map.get(&arg3).unwrap(),
1351 )
1352 .add_metadatum(context, opt_metadata),
1353 IrAstOperation::WideCmp(op, arg1, arg2) => block
1354 .append(context)
1355 .wide_cmp_op(
1356 op,
1357 *val_map.get(&arg1).unwrap(),
1358 *val_map.get(&arg2).unwrap(),
1359 )
1360 .add_metadatum(context, opt_metadata),
1361 IrAstOperation::Retd(ret_ptr, ret_len) => block
1362 .append(context)
1363 .retd(
1364 *val_map.get(&ret_ptr).unwrap(),
1365 *val_map.get(&ret_len).unwrap(),
1366 )
1367 .add_metadatum(context, opt_metadata),
1368 IrAstOperation::BinaryOp(op, arg1, arg2) => block
1369 .append(context)
1370 .binary_op(
1371 op,
1372 *val_map.get(&arg1).unwrap(),
1373 *val_map.get(&arg2).unwrap(),
1374 )
1375 .add_metadatum(context, opt_metadata),
1376 IrAstOperation::Br(to_block_name, args) => {
1377 let to_block = named_blocks.get(&to_block_name).unwrap();
1378 block
1379 .append(context)
1380 .branch(
1381 *to_block,
1382 args.iter().map(|arg| *val_map.get(arg).unwrap()).collect(),
1383 )
1384 .add_metadatum(context, opt_metadata)
1385 }
1386 IrAstOperation::Call(callee, args) => {
1387 let dummy_func = block.get_function(context);
1393 let call_val = block
1394 .append(context)
1395 .call(
1396 dummy_func,
1397 &args
1398 .iter()
1399 .map(|arg_name| val_map.get(arg_name).unwrap())
1400 .cloned()
1401 .collect::<Vec<Value>>(),
1402 )
1403 .add_metadatum(context, opt_metadata);
1404 self.unresolved_calls.push(PendingCall { call_val, callee });
1405 call_val
1406 }
1407 IrAstOperation::CastPtr(val, ty) => {
1408 let ir_ty = ty.to_ir_type(context);
1409 block
1410 .append(context)
1411 .cast_ptr(*val_map.get(&val).unwrap(), ir_ty)
1412 .add_metadatum(context, opt_metadata)
1413 }
1414 IrAstOperation::Cbr(
1415 cond_val_name,
1416 true_block_name,
1417 true_args,
1418 false_block_name,
1419 false_args,
1420 ) => block
1421 .append(context)
1422 .conditional_branch(
1423 *val_map.get(&cond_val_name).unwrap(),
1424 *named_blocks.get(&true_block_name).unwrap(),
1425 *named_blocks.get(&false_block_name).unwrap(),
1426 true_args
1427 .iter()
1428 .map(|arg| *val_map.get(arg).unwrap())
1429 .collect(),
1430 false_args
1431 .iter()
1432 .map(|arg| *val_map.get(arg).unwrap())
1433 .collect(),
1434 )
1435 .add_metadatum(context, opt_metadata),
1436 IrAstOperation::Cmp(pred, lhs, rhs) => block
1437 .append(context)
1438 .cmp(
1439 pred,
1440 *val_map.get(&lhs).unwrap(),
1441 *val_map.get(&rhs).unwrap(),
1442 )
1443 .add_metadatum(context, opt_metadata),
1444 IrAstOperation::Const(ty, val) => val
1445 .value
1446 .as_value(context, ty)
1447 .add_metadatum(context, opt_metadata),
1448 IrAstOperation::ContractCall(
1449 return_type,
1450 name,
1451 params,
1452 coins,
1453 asset_id,
1454 gas,
1455 ) => {
1456 let ir_ty = return_type.to_ir_type(context);
1457 block
1458 .append(context)
1459 .contract_call(
1460 ir_ty,
1461 Some(name),
1462 *val_map.get(¶ms).unwrap(),
1463 *val_map.get(&coins).unwrap(),
1464 *val_map.get(&asset_id).unwrap(),
1465 *val_map.get(&gas).unwrap(),
1466 )
1467 .add_metadatum(context, opt_metadata)
1468 }
1469 IrAstOperation::GetElemPtr(base, elem_ty, idcs) => {
1470 let ir_elem_ty = elem_ty
1471 .to_ir_type(context)
1472 .get_pointee_type(context)
1473 .unwrap();
1474 block
1475 .append(context)
1476 .get_elem_ptr(
1477 *val_map.get(&base).unwrap(),
1478 ir_elem_ty,
1479 idcs.iter().map(|idx| *val_map.get(idx).unwrap()).collect(),
1480 )
1481 .add_metadatum(context, opt_metadata)
1482 }
1483 IrAstOperation::GetLocal(local_name) => block
1484 .append(context)
1485 .get_local(*local_map.get(&local_name).unwrap())
1486 .add_metadatum(context, opt_metadata),
1487 IrAstOperation::GetGlobal(global_name) => block
1488 .append(context)
1489 .get_global(*self.globals_map.get(&global_name).unwrap())
1490 .add_metadatum(context, opt_metadata),
1491 IrAstOperation::GetConfig(name) => block
1492 .append(context)
1493 .get_config(self.module, name)
1494 .add_metadatum(context, opt_metadata),
1495 IrAstOperation::GetStorageKey(path) => block
1496 .append(context)
1497 .get_storage_key(*self.storage_keys_map.get(&path).unwrap())
1498 .add_metadatum(context, opt_metadata),
1499 IrAstOperation::Gtf(index, tx_field_id) => block
1500 .append(context)
1501 .gtf(*val_map.get(&index).unwrap(), tx_field_id)
1502 .add_metadatum(context, opt_metadata),
1503 IrAstOperation::IntToPtr(val, ty) => {
1504 let to_ty = ty.to_ir_type(context);
1505 block
1506 .append(context)
1507 .int_to_ptr(*val_map.get(&val).unwrap(), to_ty)
1508 .add_metadatum(context, opt_metadata)
1509 }
1510 IrAstOperation::Load(src_name) => block
1511 .append(context)
1512 .load(*val_map.get(&src_name).unwrap())
1513 .add_metadatum(context, opt_metadata),
1514 IrAstOperation::Log(log_ty, log_val, log_id, log_data) => {
1515 let log_ty = log_ty.to_ir_type(context);
1516 block
1517 .append(context)
1518 .log(
1519 *val_map.get(&log_val).unwrap(),
1520 log_ty,
1521 *val_map.get(&log_id).unwrap(),
1522 log_data,
1523 )
1524 .add_metadatum(context, opt_metadata)
1525 }
1526 IrAstOperation::MemCopyBytes(dst_name, src_name, len) => block
1527 .append(context)
1528 .mem_copy_bytes(
1529 *val_map.get(&dst_name).unwrap(),
1530 *val_map.get(&src_name).unwrap(),
1531 len,
1532 )
1533 .add_metadatum(context, opt_metadata),
1534 IrAstOperation::MemCopyVal(dst_name, src_name) => block
1535 .append(context)
1536 .mem_copy_val(
1537 *val_map.get(&dst_name).unwrap(),
1538 *val_map.get(&src_name).unwrap(),
1539 )
1540 .add_metadatum(context, opt_metadata),
1541 IrAstOperation::MemClearVal(dst_name) => block
1542 .append(context)
1543 .mem_clear_val(*val_map.get(&dst_name).unwrap())
1544 .add_metadatum(context, opt_metadata),
1545 IrAstOperation::Nop => block.append(context).nop(),
1546 IrAstOperation::PtrToInt(val, ty) => {
1547 let to_ty = ty.to_ir_type(context);
1548 block
1549 .append(context)
1550 .ptr_to_int(*val_map.get(&val).unwrap(), to_ty)
1551 .add_metadatum(context, opt_metadata)
1552 }
1553 IrAstOperation::ReadRegister(reg_name) => block
1554 .append(context)
1555 .read_register(match reg_name.as_str() {
1556 "of" => Register::Of,
1557 "pc" => Register::Pc,
1558 "ssp" => Register::Ssp,
1559 "sp" => Register::Sp,
1560 "fp" => Register::Fp,
1561 "hp" => Register::Hp,
1562 "err" => Register::Error,
1563 "ggas" => Register::Ggas,
1564 "cgas" => Register::Cgas,
1565 "bal" => Register::Bal,
1566 "is" => Register::Is,
1567 "ret" => Register::Ret,
1568 "retl" => Register::Retl,
1569 "flag" => Register::Flag,
1570 _ => unreachable!("Guaranteed by grammar."),
1571 })
1572 .add_metadatum(context, opt_metadata),
1573 IrAstOperation::Ret(ty, ret_val_name) => {
1574 let ty = ty.to_ir_type(context);
1575 block
1576 .append(context)
1577 .ret(*val_map.get(&ret_val_name).unwrap(), ty)
1578 .add_metadatum(context, opt_metadata)
1579 }
1580 IrAstOperation::Revert(ret_val_name) => block
1581 .append(context)
1582 .revert(*val_map.get(&ret_val_name).unwrap())
1583 .add_metadatum(context, opt_metadata),
1584 IrAstOperation::JmpMem => block
1585 .append(context)
1586 .jmp_mem()
1587 .add_metadatum(context, opt_metadata),
1588 IrAstOperation::Smo(recipient, message, message_size, coins) => block
1589 .append(context)
1590 .smo(
1591 *val_map.get(&recipient).unwrap(),
1592 *val_map.get(&message).unwrap(),
1593 *val_map.get(&message_size).unwrap(),
1594 *val_map.get(&coins).unwrap(),
1595 )
1596 .add_metadatum(context, opt_metadata),
1597 IrAstOperation::StateClear(key, number_of_slots) => block
1598 .append(context)
1599 .state_clear(
1600 *val_map.get(&key).unwrap(),
1601 *val_map.get(&number_of_slots).unwrap(),
1602 )
1603 .add_metadatum(context, opt_metadata),
1604 IrAstOperation::StateLoadQuadWord(dst, key, number_of_slots) => block
1605 .append(context)
1606 .state_load_quad_word(
1607 *val_map.get(&dst).unwrap(),
1608 *val_map.get(&key).unwrap(),
1609 *val_map.get(&number_of_slots).unwrap(),
1610 )
1611 .add_metadatum(context, opt_metadata),
1612 IrAstOperation::StateLoadWord(key) => block
1613 .append(context)
1614 .state_load_word(*val_map.get(&key).unwrap())
1615 .add_metadatum(context, opt_metadata),
1616 IrAstOperation::StateStoreQuadWord(src, key, number_of_slots) => block
1617 .append(context)
1618 .state_store_quad_word(
1619 *val_map.get(&src).unwrap(),
1620 *val_map.get(&key).unwrap(),
1621 *val_map.get(&number_of_slots).unwrap(),
1622 )
1623 .add_metadatum(context, opt_metadata),
1624 IrAstOperation::StateStoreWord(src, key) => block
1625 .append(context)
1626 .state_store_word(*val_map.get(&src).unwrap(), *val_map.get(&key).unwrap())
1627 .add_metadatum(context, opt_metadata),
1628 IrAstOperation::Store(stored_val_name, dst_val_name) => {
1629 let dst_val_ptr = *val_map.get(&dst_val_name).unwrap();
1630 let stored_val = *val_map.get(&stored_val_name).unwrap();
1631
1632 block
1633 .append(context)
1634 .store(dst_val_ptr, stored_val)
1635 .add_metadatum(context, opt_metadata)
1636 }
1637 };
1638 ins.value_name.map(|vn| val_map.insert(vn, ins_val));
1639 }
1640 }
1641
1642 fn resolve_calls(self, context: &mut Context) -> Result<(), IrError> {
1643 for (configurable_name, fn_name) in self.configs_map {
1644 let f = self
1645 .module
1646 .function_iter(context)
1647 .find(|x| x.get_name(context) == fn_name)
1648 .unwrap();
1649
1650 if let Some(ConfigContent::V1 { decode_fn, .. }) = context
1651 .modules
1652 .get_mut(self.module.0)
1653 .unwrap()
1654 .configs
1655 .get_mut(&configurable_name)
1656 {
1657 decode_fn.replace(f);
1658 }
1659 }
1660
1661 for pending_call in self.unresolved_calls {
1667 let call_func = context
1668 .functions
1669 .iter()
1670 .find_map(|(idx, content)| {
1671 if content.name == pending_call.callee {
1672 Some(Function(idx))
1673 } else {
1674 None
1675 }
1676 })
1677 .unwrap();
1678
1679 if let Some(Instruction {
1680 op: InstOp::Call(dummy_func, _args),
1681 ..
1682 }) = pending_call.call_val.get_instruction_mut(context)
1683 {
1684 *dummy_func = call_func;
1685 }
1686 }
1687 Ok(())
1688 }
1689 }
1690
1691 fn build_global_vars_map(
1692 context: &mut Context,
1693 module: &Module,
1694 global_vars: Vec<IrAstGlobalVar>,
1695 ) -> BTreeMap<Vec<String>, GlobalVar> {
1696 global_vars
1697 .into_iter()
1698 .map(|global_var_node| {
1699 let ty = global_var_node.ty.to_ir_type(context);
1700 let init = global_var_node.init.map(|init| match init {
1701 IrAstOperation::Const(ty, val) => val.value.as_constant(context, ty),
1702 _ => unreachable!("Global const initializer must be a const value."),
1703 });
1704 let global_var = GlobalVar::new(context, ty, init, global_var_node.mutable);
1705 module.add_global_variable(context, global_var_node.name.clone(), global_var);
1706 (global_var_node.name, global_var)
1707 })
1708 .collect()
1709 }
1710
1711 fn build_storage_keys_map(
1712 context: &mut Context,
1713 module: &Module,
1714 storage_keys: Vec<IrAstStorageKey>,
1715 ) -> BTreeMap<String, StorageKey> {
1716 storage_keys
1717 .into_iter()
1718 .map(|storage_key_node| {
1719 let path = format!(
1720 "{}.{}",
1721 storage_key_node.namespaces.join("::"),
1722 storage_key_node.fields.join("."),
1723 );
1724 let slot = match storage_key_node.slot.value {
1725 IrAstConstValue::Hex256(val) => val,
1726 _ => panic!("Storage key slot must be a hex string representing b256."),
1727 };
1728 let offset = match storage_key_node.offset {
1729 Some(IrAstConst {
1730 value: IrAstConstValue::Number(n),
1731 ..
1732 }) => n,
1733 None => 0,
1734 _ => panic!("Storage key offset must be a u64 constant."),
1735 };
1736 let field_id = match storage_key_node.field_id {
1737 Some(IrAstConst {
1738 value: IrAstConstValue::Hex256(val),
1739 ..
1740 }) => val,
1741 None => slot,
1743 _ => panic!("Storage key field id must be a hex string representing b256."),
1744 };
1745 let storage_key = StorageKey::new(context, slot, offset, field_id);
1746 module.add_storage_key(context, path.clone(), storage_key);
1747 (path, storage_key)
1748 })
1749 .collect()
1750 }
1751
1752 fn build_configs_map(
1753 context: &mut Context,
1754 module: &Module,
1755 configs: Vec<IrAstConfig>,
1756 md_map: &HashMap<MdIdxRef, MetadataIndex>,
1757 ) -> BTreeMap<String, String> {
1758 configs
1759 .into_iter()
1760 .map(|config| {
1761 let opt_metadata = config
1762 .metadata
1763 .map(|mdi| md_map.get(&mdi).unwrap())
1764 .copied();
1765
1766 let ty = config.ty.to_ir_type(context);
1767
1768 let config_val = ConfigContent::V1 {
1769 name: config.value_name.clone(),
1770 ty,
1771 ptr_ty: Type::new_typed_pointer(context, ty),
1772 encoded_bytes: config.encoded_bytes,
1773 decode_fn: Cell::new(Function(KeyData::default().into())),
1775 opt_metadata,
1776 };
1777
1778 module.add_config(context, config.value_name.clone(), config_val.clone());
1779
1780 (config.value_name.clone(), config.decode_fn.clone())
1781 })
1782 .collect()
1783 }
1784
1785 fn build_metadata_map(
1788 context: &mut Context,
1789 ir_metadata: Vec<(MdIdxRef, IrMetadatum)>,
1790 ) -> HashMap<MdIdxRef, MetadataIndex> {
1791 fn convert_md(md: IrMetadatum, md_map: &mut HashMap<MdIdxRef, MetadataIndex>) -> Metadatum {
1792 match md {
1793 IrMetadatum::Integer(i) => Metadatum::Integer(i),
1794 IrMetadatum::Index(idx) => Metadatum::Index(
1795 md_map
1796 .get(&idx)
1797 .copied()
1798 .expect("Metadatum index not found in map."),
1799 ),
1800 IrMetadatum::String(s) => Metadatum::String(s),
1801 IrMetadatum::Struct(tag, els) => Metadatum::Struct(
1802 tag,
1803 els.into_iter()
1804 .map(|el_md| convert_md(el_md, md_map))
1805 .collect(),
1806 ),
1807 IrMetadatum::List(idcs) => Metadatum::List(
1808 idcs.into_iter()
1809 .map(|idx| {
1810 md_map
1811 .get(&idx)
1812 .copied()
1813 .expect("Metadatum index not found in map.")
1814 })
1815 .collect(),
1816 ),
1817 }
1818 }
1819
1820 let mut md_map = HashMap::new();
1821
1822 for (ir_idx, ir_md) in ir_metadata {
1823 let md = convert_md(ir_md, &mut md_map);
1824 let md_idx = MetadataIndex(context.metadata.insert(md));
1825 md_map.insert(ir_idx, md_idx);
1826 }
1827 md_map
1828 }
1829
1830 fn string_to_hex<const N: usize>(s: &str) -> [u8; N] {
1831 let mut bytes: [u8; N] = [0; N];
1832 let mut cur_byte: u8 = 0;
1833 for (idx, ch) in s.chars().enumerate() {
1834 cur_byte = (cur_byte << 4) | ch.to_digit(16).unwrap() as u8;
1835 if idx % 2 == 1 {
1836 bytes[idx / 2] = cur_byte;
1837 cur_byte = 0;
1838 }
1839 }
1840 bytes
1841 }
1842
1843 fn hex_string_to_vec(s: &str) -> Vec<u8> {
1844 let mut bytes = vec![];
1845 let mut cur_byte: u8 = 0;
1846 for (idx, ch) in s.chars().enumerate() {
1847 cur_byte = (cur_byte << 4) | ch.to_digit(16).unwrap() as u8;
1848 if idx % 2 == 1 {
1849 bytes.push(cur_byte);
1850 cur_byte = 0;
1851 }
1852 }
1853 bytes
1854 }
1855}
1856
1857