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