1pub(crate) mod constant;
2mod explain;
3pub(crate) mod function;
4pub(crate) mod graph;
5pub(crate) mod host;
6mod lowering;
7pub(crate) mod runtime;
8pub(crate) mod type_;
9
10use self::constant::ProfiledConstantTable;
11#[cfg(test)]
12use self::constant::{ConstantId, ConstantValue};
13#[cfg(test)]
14use self::function::ExecutableFunction;
15#[cfg(test)]
16use self::function::{
17 BitArrayFunctionFunctionId, BitArrayFunctionId, BitArrayListFunctionId, BoolFunctionFunctionId,
18 BoolFunctionId, BoolListFunctionId, CustomFunctionFunctionId, CustomFunctionId,
19 CustomListFunctionId, ExecutionBitArrayFunctionBody, ExecutionBitArrayFunctionFunctionBody,
20 ExecutionBoolFunctionBody, ExecutionBoolFunctionFunctionBody,
21 ExecutionCoreListFunctionFunctionBody, ExecutionCustomFunctionBody,
22 ExecutionCustomFunctionFunctionBody, ExecutionFloatFunctionFunctionBody,
23 ExecutionFunctionFunctionFunctionBody, ExecutionGenericFunctionFunctionBody,
24 ExecutionIntFunctionBody, ExecutionIntFunctionFunctionBody, ExecutionNeverFunctionFunctionBody,
25 ExecutionNilFunctionBody, ExecutionNilFunctionFunctionBody,
26 ExecutionStringFunctionFunctionBody, ExecutionTupleFunctionBody,
27 ExecutionTupleFunctionFunctionBody, ExecutionUtfCodepointFunctionFunctionBody,
28 FloatFunctionFunctionId, FloatListFunctionId, FunctionFunctionFunctionId,
29 FunctionListFunctionId, GenericFunctionFunctionId, IntFunctionFunctionId, IntFunctionId,
30 IntListFunctionId, ListListFunctionId, NeverFunctionFunctionId, NilFunctionFunctionId,
31 NilFunctionId, NilListFunctionId, ParameterListFunctionId, ParameterListListFunctionId,
32 ProfiledListFunctionFunctionId, StringFunctionFunctionId, StringListFunctionId,
33 TupleFunctionFunctionId, TupleFunctionId, TupleListFunctionId, UtfCodepointFunctionFunctionId,
34 UtfCodepointListFunctionId,
35};
36use self::function::{
37 ExecutionGraphProfile, ExecutionProfile, FunctionLabelSource, FunctionTables,
38 ProfiledRuntimeFunctionId,
39};
40#[cfg(test)]
41use self::type_::{
42 CustomConstructorId, CustomConstructorRefinement, CustomTypeId, CustomValueShape,
43 CustomValueShapeId, FunctionListTypeId, FunctionType, ListListTypeId, ListStorageTypeId,
44 ListTypeId, TupleListTypeId, ValueShapeId, ValueType,
45};
46use self::type_::{CustomTypeTable, ExternalTypeTable, ListTypeTable, ValueShapeTable};
47use crate::host::HostProfile;
48use crate::plan::{HostedModulePlan, ModuleId, ModulePlan, SourceContext};
49use ecow::EcoString;
50pub use explain::ExecutionPlanExplanation;
51pub use host::{HostSpecializationError, HostSpecializationErrorReason};
52use std::convert::Infallible;
53
54pub struct ExecutionPlan {
55 program: ExecutionProgram<Infallible>,
56}
57
58pub(crate) struct LibraryFunctionEntry<Function> {
59 function: Function,
60 inputs: LibraryInputConstructions,
61}
62
63pub(crate) struct LibraryInputConstructions {
64 variants: Box<[[type_::CustomConstructorId; 2]]>,
65 lists: LibraryListConstructions,
66}
67
68#[derive(Default)]
69pub(crate) struct LibraryListConstructions {
70 pub(crate) ints: Vec<type_::IntListTypeId>,
71 pub(crate) floats: Vec<type_::FloatListTypeId>,
72 pub(crate) strings: Vec<type_::StringListTypeId>,
73 pub(crate) bit_arrays: Vec<type_::BitArrayListTypeId>,
74 pub(crate) utf_codepoints: Vec<type_::UtfCodepointListTypeId>,
75 pub(crate) customs: Vec<type_::CustomListTypeId>,
76 pub(crate) bools: Vec<type_::BoolListTypeId>,
77 pub(crate) nils: Vec<type_::NilListTypeId>,
78 pub(crate) tuples: Vec<type_::TupleListTypeId>,
79 pub(crate) lists: Vec<type_::ListListTypeId>,
80}
81
82pub(crate) struct LibraryFunctionEntries {
83 pub(crate) ints: Box<[LibraryFunctionEntry<function::IntFunctionId>]>,
84 pub(crate) floats: Box<[LibraryFunctionEntry<function::FloatFunctionId>]>,
85 pub(crate) strings: Box<[LibraryFunctionEntry<function::StringFunctionId>]>,
86 pub(crate) bit_arrays: Box<[LibraryFunctionEntry<function::BitArrayFunctionId>]>,
87 pub(crate) utf_codepoints: Box<[LibraryFunctionEntry<function::UtfCodepointFunctionId>]>,
88 pub(crate) customs: Box<[LibraryFunctionEntry<function::CustomFunctionId>]>,
89 pub(crate) bools: Box<[LibraryFunctionEntry<function::BoolFunctionId>]>,
90 pub(crate) nils: Box<[LibraryFunctionEntry<function::NilFunctionId>]>,
91 pub(crate) tuples: Box<[LibraryFunctionEntry<function::TupleFunctionId>]>,
92 pub(crate) lists: Box<[LibraryFunctionEntry<function::ProfiledListFunctionId<Infallible>>]>,
93}
94
95impl<Function> LibraryFunctionEntry<Function> {
96 pub(in crate::plan::execution) fn new(
97 function: Function,
98 inputs: LibraryInputConstructions,
99 ) -> Self {
100 Self { function, inputs }
101 }
102
103 pub(crate) fn function(&self) -> &Function {
104 &self.function
105 }
106
107 pub(crate) fn inputs(&self) -> &LibraryInputConstructions {
108 &self.inputs
109 }
110}
111
112impl LibraryInputConstructions {
113 pub(in crate::plan::execution) fn new(
114 variants: Vec<[type_::CustomConstructorId; 2]>,
115 lists: LibraryListConstructions,
116 ) -> Self {
117 Self {
118 variants: variants.into_boxed_slice(),
119 lists,
120 }
121 }
122
123 pub(crate) fn variants(&self) -> &[[type_::CustomConstructorId; 2]] {
124 &self.variants
125 }
126
127 pub(crate) fn lists(&self) -> &LibraryListConstructions {
128 &self.lists
129 }
130}
131
132pub struct HostedExecution<Profile: HostProfile> {
133 program: ExecutionProgram<host::HostedExecutionProfile>,
134 host_functions: host::HostFunctionTables<Profile>,
135 external_stores: Profile::ExternalStores,
136}
137
138pub(crate) struct ExecutionProgram<Profile: ExecutionProfile> {
139 common: ExecutionProgramCommon<Profile::Graph>,
140 functions: FunctionTables<Profile>,
141}
142
143struct ExecutionProgramCommon<Graph: ExecutionGraphProfile> {
144 root: ModuleId,
145 modules: Box<[ExecutionModuleContext]>,
146 main: ProfiledRuntimeFunctionId<Graph>,
147 constants: ProfiledConstantTable<Graph>,
148 list_types: ListTypeTable,
149 custom_types: CustomTypeTable,
150 external_types: ExternalTypeTable,
151 value_shapes: ValueShapeTable,
152}
153
154struct ExecutionModuleContext {
155 module: EcoString,
156 source_context: Option<SourceContext>,
157}
158
159impl ExecutionModuleContext {
160 fn new(module: EcoString, source_context: Option<SourceContext>) -> Self {
161 Self {
162 module,
163 source_context,
164 }
165 }
166}
167
168impl explain::Explain for ExecutionPlan {
169 fn write_explanation(&self, context: &mut explain::ExplainContext<'_, '_>) {
170 context.push_str("module ");
171 context.push_str(self.module());
172 context.push_str("\nmain ");
173 self.program
174 .common
175 .main
176 .function_label()
177 .write(context.output());
178 context.push('\n');
179 context.write(&self.program.functions);
180 context.write(&self.program.common.constants);
181 }
182}
183
184impl<Profile: HostProfile> explain::Explain for HostedExecution<Profile> {
185 fn write_explanation(&self, context: &mut explain::ExplainContext<'_, '_>) {
186 context.push_str("module ");
187 context.push_str(&self.program.common.modules[self.program.common.root.index()].module);
188 context.push_str("\nmain ");
189 self.program
190 .common
191 .main
192 .function_label()
193 .write(context.output());
194 context.push('\n');
195 context.write(&function::HostedFunctionTablesExplanation::new(
196 &self.program.functions,
197 &self.host_functions,
198 ));
199 context.write(&self.program.common.constants);
200 }
201}
202
203impl ExecutionPlan {
204 pub fn from_module_plan(module_plan: ModulePlan) -> Self {
205 Self {
206 program: lowering::lower(module_plan),
207 }
208 }
209
210 pub(crate) fn from_library_plan(
211 module_plan: crate::plan::LibraryModulePlan,
212 first: crate::plan::LibraryEntry,
213 remaining: Vec<crate::plan::LibraryEntry>,
214 ) -> (Self, LibraryFunctionEntries) {
215 let (program, entries) = lowering::lower_library(module_plan, first, remaining);
216 (Self { program }, entries)
217 }
218
219 pub fn module(&self) -> &EcoString {
220 &self.program.common.modules[self.program.common.root.index()].module
221 }
222
223 pub fn source_context(&self) -> Option<&SourceContext> {
224 self.program.common.modules[self.program.common.root.index()]
225 .source_context
226 .as_ref()
227 }
228
229 pub fn explain(&self) -> ExecutionPlanExplanation<'_> {
230 ExecutionPlanExplanation::new(self)
231 }
232}
233
234impl<Profile: HostProfile> HostedExecution<Profile> {
235 pub fn try_from_module_plan(
239 module_plan: HostedModulePlan<Profile>,
240 ) -> Result<Self, HostSpecializationError> {
241 let (program, host_functions) = lowering::lower_hosted(module_plan)?;
242 Ok(Self {
243 program,
244 host_functions,
245 external_stores: Profile::ExternalStores::default(),
246 })
247 }
248
249 pub(crate) fn try_from_library_plan(
250 module_plan: crate::plan::HostedLibraryModulePlan<Profile>,
251 first: crate::plan::LibraryEntry,
252 remaining: Vec<crate::plan::LibraryEntry>,
253 ) -> Result<(Self, LibraryFunctionEntries), HostSpecializationError> {
254 let (program, host_functions, entries) =
255 lowering::lower_hosted_library(module_plan, first, remaining)?;
256 Ok((
257 Self {
258 program,
259 host_functions,
260 external_stores: Profile::ExternalStores::default(),
261 },
262 entries,
263 ))
264 }
265
266 pub fn run_main(
267 &self,
268 state: &mut Profile::RunState,
269 echo: &mut dyn crate::EchoSink,
270 ) -> Result<crate::Value, crate::ExecutionError> {
271 crate::runtime::run_hosted_main(self, state, echo)
272 }
273
274 pub fn explain(&self) -> ExecutionPlanExplanation<'_> {
275 ExecutionPlanExplanation::new_hosted(self)
276 }
277
278 pub(crate) fn host_value_function<Body>(
279 &self,
280 id: &host::HostFunctionId<Body>,
281 ) -> &host::HostedValueFunction<Profile>
282 where
283 Body: function::ExecutionFunctionBody,
284 {
285 self.host_functions.value(id)
286 }
287
288 pub(crate) fn host_never_function(
289 &self,
290 id: host::HostNeverFunctionId,
291 ) -> &host::HostedNeverFunction<Profile> {
292 self.host_functions.never(id)
293 }
294
295 pub(crate) fn external_stores(&self) -> &Profile::ExternalStores {
296 &self.external_stores
297 }
298}
299
300#[cfg(test)]
301impl ExecutionPlan {
302 pub(crate) fn main_runtime(&self) -> self::function::RuntimeFunctionId {
303 self.program.common.main.runtime_id()
304 }
305
306 pub(crate) fn constant<Return: ConstantValue>(
307 &self,
308 id: ConstantId<Return>,
309 ) -> &self::constant::ProfiledConstantProgram<Return, Infallible> {
310 self.program.common.constants.get(id)
311 }
312
313 pub(crate) fn list_value_type(&self, id: ListTypeId) -> crate::plan::ValueType {
314 self.program.common.list_types.list_value_type(
315 id,
316 &self.program.common.custom_types,
317 &self.program.common.external_types,
318 )
319 }
320
321 #[cfg(test)]
322 pub(crate) fn list_storage_type(&self, id: ListTypeId) -> ListStorageTypeId {
323 self.program.common.list_types.storage_type(id)
324 }
325
326 pub(crate) fn tuple_list_item_type(&self, id: TupleListTypeId) -> Vec<crate::plan::ValueType> {
327 self.program.common.list_types.tuple_item_type(
328 id,
329 &self.program.common.custom_types,
330 &self.program.common.external_types,
331 )
332 }
333
334 pub(crate) fn nested_list_item_type(&self, id: ListListTypeId) -> crate::plan::ValueType {
335 self.program.common.list_types.nested_list_item_type(
336 id,
337 &self.program.common.custom_types,
338 &self.program.common.external_types,
339 )
340 }
341
342 pub(crate) fn function_list_item_type(
343 &self,
344 id: FunctionListTypeId,
345 ) -> crate::plan::FunctionType {
346 self.program.common.list_types.function_item_type(
347 id,
348 &self.program.common.custom_types,
349 &self.program.common.external_types,
350 )
351 }
352
353 pub(crate) fn function_type(&self, type_: &FunctionType) -> crate::plan::FunctionType {
354 self.program.common.list_types.function_type(
355 type_,
356 &self.program.common.custom_types,
357 &self.program.common.external_types,
358 )
359 }
360
361 pub(crate) fn custom_value_type(&self, id: CustomTypeId) -> crate::plan::CustomType {
362 self.program.common.custom_types.value_type(id)
363 }
364
365 #[cfg(test)]
366 pub(crate) fn custom_shape_refinement(
367 &self,
368 shape: &CustomValueShape,
369 ) -> CustomConstructorRefinement {
370 self.program
371 .common
372 .value_shapes
373 .custom(shape.shape_id())
374 .constructor()
375 }
376
377 #[cfg(test)]
378 pub(crate) fn custom_shape_value_type(
379 &self,
380 shape: &CustomValueShape,
381 ) -> crate::plan::CustomType {
382 self.custom_shape_type(shape.shape_id())
383 }
384
385 #[cfg(test)]
386 fn custom_shape_type(&self, id: CustomValueShapeId) -> crate::plan::CustomType {
387 let shape = self.program.common.value_shapes.custom(id);
388 let nominal = self.program.common.custom_types.value_type(shape.type_id());
389 crate::plan::CustomType::new(
390 nominal.type_name().clone(),
391 shape
392 .arguments()
393 .iter()
394 .map(|argument| {
395 self.program.common.list_types.value_type(
396 self.program.common.value_shapes.value_type(*argument),
397 &self.program.common.custom_types,
398 &self.program.common.external_types,
399 )
400 })
401 .collect(),
402 )
403 }
404
405 pub(crate) fn shape_value_type(&self, id: ValueShapeId) -> ValueType {
406 self.program.common.value_shapes.value_type(id).clone()
407 }
408
409 pub(crate) fn custom_constructor(
410 &self,
411 id: CustomConstructorId,
412 ) -> &type_::CustomConstructorDescriptor {
413 self.program.common.custom_types.constructor(id)
414 }
415
416 #[cfg(test)]
417 pub(crate) fn custom_constructor_id(
418 &self,
419 type_index: usize,
420 constructor_index: usize,
421 ) -> CustomConstructorId {
422 self.program
423 .common
424 .custom_types
425 .constructor_id(type_index, constructor_index)
426 }
427
428 pub(crate) fn int_function(
429 &self,
430 id: IntFunctionId,
431 ) -> &ExecutableFunction<ExecutionIntFunctionBody<Infallible>> {
432 self.program.functions.int_function(id)
433 }
434
435 pub(crate) fn bit_array_function(
436 &self,
437 id: BitArrayFunctionId,
438 ) -> &ExecutableFunction<ExecutionBitArrayFunctionBody<Infallible>> {
439 self.program.functions.bit_array_function(id)
440 }
441
442 pub(crate) fn custom_function(
443 &self,
444 id: CustomFunctionId,
445 ) -> &ExecutableFunction<ExecutionCustomFunctionBody<Infallible>> {
446 self.program.functions.custom_function(id)
447 }
448
449 #[cfg(test)]
450 pub(crate) fn custom_function_id(&self, index: usize) -> CustomFunctionId {
451 self.program.functions.custom_function_id(index)
452 }
453
454 pub(crate) fn bool_function(
455 &self,
456 id: BoolFunctionId,
457 ) -> &ExecutableFunction<ExecutionBoolFunctionBody<Infallible>> {
458 self.program.functions.bool_function(id)
459 }
460
461 pub(crate) fn nil_function(
462 &self,
463 id: NilFunctionId,
464 ) -> &ExecutableFunction<ExecutionNilFunctionBody<Infallible>> {
465 self.program.functions.nil_function(id)
466 }
467
468 pub(crate) fn tuple_function(
469 &self,
470 id: TupleFunctionId,
471 ) -> &ExecutableFunction<ExecutionTupleFunctionBody<Infallible>> {
472 self.program.functions.tuple_function(id)
473 }
474
475 #[cfg(test)]
476 pub(crate) fn parameter_list_function_id(&self, index: usize) -> ParameterListFunctionId {
477 self.program.functions.parameter_list_function_id(index)
478 }
479
480 #[cfg(test)]
481 pub(crate) fn parameter_list_list_function_id(
482 &self,
483 index: usize,
484 ) -> ParameterListListFunctionId {
485 self.program
486 .functions
487 .parameter_list_list_function_id(index)
488 }
489
490 #[cfg(test)]
491 pub(crate) fn int_list_function_id(&self, index: usize) -> IntListFunctionId {
492 self.program.functions.int_list_function_id(index)
493 }
494
495 #[cfg(test)]
496 pub(crate) fn string_list_function_id(&self, index: usize) -> StringListFunctionId {
497 self.program.functions.string_list_function_id(index)
498 }
499
500 #[cfg(test)]
501 pub(crate) fn bit_array_list_function_id(&self, index: usize) -> BitArrayListFunctionId {
502 self.program.functions.bit_array_list_function_id(index)
503 }
504
505 #[cfg(test)]
506 pub(crate) fn utf_codepoint_list_function_id(
507 &self,
508 index: usize,
509 ) -> UtfCodepointListFunctionId {
510 self.program.functions.utf_codepoint_list_function_id(index)
511 }
512
513 #[cfg(test)]
514 pub(crate) fn custom_list_function_id(&self, index: usize) -> CustomListFunctionId {
515 self.program.functions.custom_list_function_id(index)
516 }
517
518 #[cfg(test)]
519 pub(crate) fn float_list_function_id(&self, index: usize) -> FloatListFunctionId {
520 self.program.functions.float_list_function_id(index)
521 }
522
523 #[cfg(test)]
524 pub(crate) fn bool_list_function_id(&self, index: usize) -> BoolListFunctionId {
525 self.program.functions.bool_list_function_id(index)
526 }
527
528 #[cfg(test)]
529 pub(crate) fn nil_list_function_id(&self, index: usize) -> NilListFunctionId {
530 self.program.functions.nil_list_function_id(index)
531 }
532
533 #[cfg(test)]
534 pub(crate) fn tuple_list_function_id(&self, index: usize) -> TupleListFunctionId {
535 self.program.functions.tuple_list_function_id(index)
536 }
537
538 #[cfg(test)]
539 pub(crate) fn list_list_function_id(&self, index: usize) -> ListListFunctionId {
540 self.program.functions.list_list_function_id(index)
541 }
542
543 #[cfg(test)]
544 pub(crate) fn function_list_function_id(&self, index: usize) -> FunctionListFunctionId {
545 self.program.functions.function_list_function_id(index)
546 }
547
548 pub(crate) fn int_function_function(
549 &self,
550 id: IntFunctionFunctionId,
551 ) -> &ExecutableFunction<ExecutionIntFunctionFunctionBody<Infallible>> {
552 self.program.functions.int_function_function(id)
553 }
554
555 pub(crate) fn float_function_function(
556 &self,
557 id: FloatFunctionFunctionId,
558 ) -> &ExecutableFunction<ExecutionFloatFunctionFunctionBody<Infallible>> {
559 self.program.functions.float_function_function(id)
560 }
561
562 pub(crate) fn string_function_function(
563 &self,
564 id: StringFunctionFunctionId,
565 ) -> &ExecutableFunction<ExecutionStringFunctionFunctionBody<Infallible>> {
566 self.program.functions.string_function_function(id)
567 }
568
569 pub(crate) fn bit_array_function_function(
570 &self,
571 id: BitArrayFunctionFunctionId,
572 ) -> &ExecutableFunction<ExecutionBitArrayFunctionFunctionBody<Infallible>> {
573 self.program.functions.bit_array_function_function(id)
574 }
575
576 pub(crate) fn utf_codepoint_function_function(
577 &self,
578 id: UtfCodepointFunctionFunctionId,
579 ) -> &ExecutableFunction<ExecutionUtfCodepointFunctionFunctionBody<Infallible>> {
580 self.program.functions.utf_codepoint_function_function(id)
581 }
582
583 pub(crate) fn custom_function_function(
584 &self,
585 id: &CustomFunctionFunctionId,
586 ) -> &ExecutableFunction<ExecutionCustomFunctionFunctionBody<Infallible>> {
587 self.program.functions.custom_function_function(id)
588 }
589
590 pub(crate) fn generic_function_function(
591 &self,
592 id: &GenericFunctionFunctionId,
593 ) -> &ExecutableFunction<ExecutionGenericFunctionFunctionBody<Infallible>> {
594 self.program.functions.generic_function_function(id)
595 }
596
597 pub(crate) fn never_function_function(
598 &self,
599 id: &NeverFunctionFunctionId,
600 ) -> &ExecutableFunction<ExecutionNeverFunctionFunctionBody<Infallible>> {
601 self.program.functions.never_function_function(id)
602 }
603
604 pub(crate) fn bool_function_function(
605 &self,
606 id: BoolFunctionFunctionId,
607 ) -> &ExecutableFunction<ExecutionBoolFunctionFunctionBody<Infallible>> {
608 self.program.functions.bool_function_function(id)
609 }
610
611 pub(crate) fn nil_function_function(
612 &self,
613 id: NilFunctionFunctionId,
614 ) -> &ExecutableFunction<ExecutionNilFunctionFunctionBody<Infallible>> {
615 self.program.functions.nil_function_function(id)
616 }
617
618 pub(crate) fn tuple_function_function(
619 &self,
620 id: TupleFunctionFunctionId,
621 ) -> &ExecutableFunction<ExecutionTupleFunctionFunctionBody<Infallible>> {
622 self.program.functions.tuple_function_function(id)
623 }
624
625 pub(crate) fn core_list_function_function(
626 &self,
627 id: &ProfiledListFunctionFunctionId<Infallible>,
628 ) -> &ExecutableFunction<ExecutionCoreListFunctionFunctionBody<Infallible>> {
629 self.program.functions.core_list_function_function(id)
630 }
631
632 pub(crate) fn function_function_function(
633 &self,
634 id: &FunctionFunctionFunctionId,
635 ) -> &ExecutableFunction<ExecutionFunctionFunctionFunctionBody<Infallible>> {
636 self.program.functions.function_function_function(id)
637 }
638
639 #[cfg(test)]
640 pub(crate) fn function_function_function_id(&self, index: usize) -> FunctionFunctionFunctionId {
641 self.program.functions.function_function_function_id(index)
642 }
643}
644
645#[cfg(test)]
646mod tests {
647 use super::HostedExecution;
648 use crate::plan::execution::explain;
649 use crate::plan::execution::function::IntFunctionId;
650 use crate::{
651 HostModule, HostProviderSet, ModuleSource, PackageSource, compile_typed_host_program,
652 compile_typed_module, plan_host_program, plan_module,
653 };
654 use num_bigint::BigInt;
655 use std::convert::Infallible;
656
657 #[test]
658 fn plain_execution_program_keeps_host_targets_uninhabited() {
659 let typed = compile_typed_module("main", "main.gleam", "pub fn main() { 1 }")
660 .expect("source should compile");
661 let plan = plan_module(typed).expect("source should plan");
662 let execution = super::ExecutionPlan::from_module_plan(plan);
663 let function: &super::ExecutableFunction<
664 super::function::ExecutionIntFunctionBody<Infallible>,
665 > = execution.program.functions.int_function(IntFunctionId(0));
666
667 assert_eq!(function.body().block_graph().blocks().len(), 1);
668 }
669
670 #[test]
671 fn exposes_the_root_module_and_source_context() {
672 let source = "pub fn main() { 1 }";
673 let typed =
674 compile_typed_module("sample", "sample.gleam", source).expect("source should compile");
675 let context = crate::SourceContext::new("sample.gleam", source);
676 let module =
677 crate::plan_module_with_source(typed, context.clone()).expect("source should plan");
678 let execution = super::ExecutionPlan::from_module_plan(module);
679
680 assert_eq!(execution.module(), "sample");
681 assert_eq!(execution.source_context(), Some(&context));
682 }
683
684 #[test]
685 fn writes_the_complete_execution_plan() {
686 let source = "pub fn main() { 1 }";
687 let expected = concat!(
688 "module main\n",
689 "main int#0\n",
690 "\n",
691 "function int#0\n",
692 " entry b0 params=[] captures=[]\n",
693 " block b0 params=[]\n",
694 " %int#0:shape#0(Int) = int.value 1\n",
695 " return %int#0\n",
696 );
697
698 explain::assert_rendered(source, expected, |plan, output| {
699 let mut context = explain::ExplainContext::new(plan, output);
700 context.write(plan);
701 });
702 }
703
704 #[test]
705 fn writes_the_complete_hosted_execution_plan() {
706 let math = HostModule::new("host_support", "host/math")
707 .expect("host module should be valid")
708 .with_function("add", <BigInt as std::ops::Add>::add)
709 .expect("host function should be valid");
710 let hosts = HostProviderSet::new([math]).expect("host modules should be unique");
711 let source = "import host/math\npub fn main() { math.add(1, 2) }";
712 let typed = compile_typed_host_program(
713 "application",
714 "main",
715 [PackageSource::new(
716 "application",
717 ["host_support"],
718 [ModuleSource::new("main", "main.gleam", source)],
719 )],
720 hosts,
721 )
722 .expect("host source should compile");
723 let plan = plan_host_program(typed).expect("host source should plan");
724 let execution =
725 HostedExecution::try_from_module_plan(plan).expect("hosted execution should seal");
726 let expected = concat!(
727 "module main\n",
728 "main int#0\n",
729 "\nfunction int#0\n",
730 " entry b0 params=[] captures=[]\n",
731 " block b0 params=[]\n",
732 " %int#0:shape#0(Int) = int.value 1\n",
733 " %int#1:shape#0(Int) = int.value 2\n",
734 " tail int#1 args=[%int#0, %int#1]\n",
735 "\nfunction int#1\n",
736 " host host_support::host/math.add signature=fn(Int, Int) -> Int\n",
737 );
738
739 assert_eq!(execution.explain().to_string(), expected);
740 }
741}