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