1pub(crate) mod compile;
2pub mod const_eval;
3mod convert;
4mod function;
5mod lexical_map;
6mod purity;
7pub mod storage;
8mod types;
9
10use std::{
11 collections::HashMap,
12 hash::{DefaultHasher, Hasher},
13};
14
15use sway_error::error::CompileError;
16use sway_features::ExperimentalFeatures;
17use sway_ir::{Context, Function, Kind, Module};
18use sway_types::{span::Span, Ident};
19
20pub(crate) use purity::{check_function_purity, PurityEnv};
21
22use crate::{
23 engine_threading::HashWithEngines,
24 language::ty,
25 metadata::MetadataManager,
26 types::{LogId, MessageId},
27 Engines, TypeId,
28};
29
30type FnKey = u64;
31
32#[derive(Default)]
36pub(crate) struct CompiledFunctionCache {
37 recreated_fns: HashMap<FnKey, Function>,
38}
39
40impl CompiledFunctionCache {
41 #[allow(clippy::too_many_arguments)]
42 fn ty_function_decl_to_unique_function(
43 &mut self,
44 engines: &Engines,
45 context: &mut Context,
46 module: Module,
47 md_mgr: &mut MetadataManager,
48 decl: &ty::TyFunctionDecl,
49 logged_types_map: &HashMap<TypeId, LogId>,
50 messages_types_map: &HashMap<TypeId, MessageId>,
51 ) -> Result<Function, CompileError> {
52 let mut hasher = DefaultHasher::default();
70 decl.hash(&mut hasher, engines);
71 let fn_key = hasher.finish();
72
73 let (fn_key, item) = (Some(fn_key), self.recreated_fns.get(&fn_key).copied());
74 let new_callee = match item {
75 Some(func) => func,
76 None => {
77 let callee_fn_decl = ty::TyFunctionDecl {
78 type_parameters: Vec::new(),
79 name: Ident::new(Span::from_string(format!(
80 "{}_{}",
81 decl.name,
82 context.get_unique_id()
83 ))),
84 parameters: decl.parameters.clone(),
85 ..decl.clone()
86 };
87 let is_entry = false;
90 let is_original_entry = callee_fn_decl.is_main() || callee_fn_decl.is_test();
91 let new_func = compile::compile_function(
92 engines,
93 context,
94 md_mgr,
95 module,
96 &callee_fn_decl,
97 &decl.name,
98 logged_types_map,
99 messages_types_map,
100 is_entry,
101 is_original_entry,
102 None,
103 self,
104 )
105 .map_err(|mut x| x.pop().unwrap())?
106 .unwrap();
107
108 if let Some(fn_key) = fn_key {
109 self.recreated_fns.insert(fn_key, new_func);
110 }
111
112 new_func
113 }
114 };
115
116 Ok(new_callee)
117 }
118}
119
120pub fn compile_program<'eng>(
121 program: &ty::TyProgram,
122 include_tests: bool,
123 engines: &'eng Engines,
124 experimental: ExperimentalFeatures,
125) -> Result<Context<'eng>, Vec<CompileError>> {
126 let declaration_engine = engines.de();
127
128 let test_fns = match include_tests {
129 true => program.test_fns(declaration_engine).collect(),
130 false => vec![],
131 };
132
133 let ty::TyProgram {
134 kind,
135 namespace,
136 logged_types,
137 messages_types,
138 declarations,
139 ..
140 } = program;
141
142 let logged_types = logged_types
143 .iter()
144 .map(|(log_id, type_id)| (*type_id, *log_id))
145 .collect();
146
147 let messages_types = messages_types
148 .iter()
149 .map(|(message_id, type_id)| (*type_id, *message_id))
150 .collect();
151
152 let mut ctx = Context::new(engines.se(), experimental);
153 ctx.program_kind = match kind {
154 ty::TyProgramKind::Script { .. } => Kind::Script,
155 ty::TyProgramKind::Predicate { .. } => Kind::Predicate,
156 ty::TyProgramKind::Contract { .. } => Kind::Contract,
157 ty::TyProgramKind::Library { .. } => Kind::Library,
158 };
159
160 let mut cache = CompiledFunctionCache::default();
161
162 match kind {
163 ty::TyProgramKind::Script { entry_function, .. } => compile::compile_script(
166 engines,
167 &mut ctx,
168 entry_function,
169 namespace.root_ref(),
170 &logged_types,
171 &messages_types,
172 &test_fns,
173 &mut cache,
174 ),
175 ty::TyProgramKind::Predicate { entry_function, .. } => compile::compile_predicate(
176 engines,
177 &mut ctx,
178 entry_function,
179 namespace.root_ref(),
180 &logged_types,
181 &messages_types,
182 &test_fns,
183 &mut cache,
184 ),
185 ty::TyProgramKind::Contract {
186 entry_function,
187 abi_entries,
188 } => compile::compile_contract(
189 &mut ctx,
190 entry_function.as_ref(),
191 abi_entries,
192 namespace.root_ref(),
193 declarations,
194 &logged_types,
195 &messages_types,
196 &test_fns,
197 engines,
198 &mut cache,
199 ),
200 ty::TyProgramKind::Library { .. } => compile::compile_library(
201 engines,
202 &mut ctx,
203 namespace.root_ref(),
204 &logged_types,
205 &messages_types,
206 &test_fns,
207 &mut cache,
208 ),
209 }?;
210
211 ctx.verify().map_err(|ir_error: sway_ir::IrError| {
212 vec![CompileError::InternalOwned(
213 ir_error.to_string(),
214 Span::dummy(),
215 )]
216 })
217}