1mod constant;
2mod custom_type;
3mod expression;
4mod external_type;
5mod function;
6mod id;
7mod pattern;
8mod reference;
9mod step;
10mod type_scheme;
11
12use crate::plan::SourceContext;
13use ecow::EcoString;
14
15pub(crate) use constant::{
16 ConstantBitArrayFunctionInstantiation, ConstantBitArrayListInstantiation,
17 ConstantBitArrayReference, ConstantBitArraySegment, ConstantBitArrayValue,
18 ConstantBoolFunctionInstantiation, ConstantBoolListInstantiation, ConstantBoolReference,
19 ConstantCustomFunctionInstantiation, ConstantCustomListInstantiation, ConstantCustomReference,
20 ConstantExternalFunctionInstantiation, ConstantExternalListInstantiation,
21 ConstantFloatFunctionInstantiation, ConstantFloatListInstantiation, ConstantFloatReference,
22 ConstantFloatValue, ConstantFunctionFunctionInstantiation, ConstantFunctionInstantiation,
23 ConstantFunctionListInstantiation, ConstantGenericFunctionInstantiation,
24 ConstantGenericListInstantiation, ConstantInstantiation, ConstantIntFunctionInstantiation,
25 ConstantIntListInstantiation, ConstantIntReference, ConstantIntValue,
26 ConstantListConstructionError, ConstantListFunctionInstantiation, ConstantListInstantiation,
27 ConstantListListInstantiation, ConstantNilFunctionInstantiation, ConstantNilListInstantiation,
28 ConstantNilReference, ConstantParameterListListInstantiation,
29 ConstantStringFunctionInstantiation, ConstantStringListInstantiation, ConstantStringReference,
30 ConstantStringValue, ConstantTemplateSignature, ConstantTemplates,
31 ConstantTupleFunctionInstantiation, ConstantTupleListInstantiation, ConstantTupleReference,
32 ConstantUtfCodepointFunctionInstantiation, ConstantUtfCodepointListInstantiation,
33 ConstantValue,
34};
35pub use constant::{ConstantTemplate, ConstantTemplateId};
36pub(crate) use custom_type::{CustomConstructor, CustomConstructorField};
37pub use custom_type::{
38 CustomConstructorDefinition, CustomFieldDefinition, CustomTypeDefinition,
39 CustomTypeParameterId, CustomTypePublicity, CustomTypeTemplate,
40};
41pub(crate) use external_type::ExternalValueShape;
42pub use external_type::{ExternalType, ExternalTypeDefinition, ExternalTypeName};
43
44#[cfg(test)]
45pub(crate) use expression::TypedFunctionExpr;
46pub(crate) use expression::custom_constructor_expr;
47pub(crate) use expression::{
48 BitArrayBitsSize, BitArrayEvaluatedSize, BitArrayExprKind, BitArrayFunctionExprKind,
49 BitArraySegment, BoolCaseBranches, BoolExprKind, BoolFunctionExprKind, CallArgStorage,
50 CaptureArg, CustomBoolCaseBranches, CustomCaseBranches, CustomConstruction, CustomExprKind,
51 CustomFieldAccess, CustomFunctionExprKind, CustomLocalExpr, Endianness, ExprKind,
52 ExternalExprKind, ExternalFunctionExprKind, FloatBitSize, FloatCaseBranches, FloatExprKind,
53 FloatFunctionExprKind, FunctionExprKind, FunctionFunctionExprKind, GenericExpr,
54 GenericExprKind, GenericFunctionExpr, GenericFunctionExprKind, IntCaseBranches, IntExprKind,
55 IntFunctionExprKind, ListElements, ListFunctionExprKind, NilExprKind, NilFunctionExprKind,
56 PanicExpr, PanicExprKind, PotentiallyUninhabitedCallArg, StringCaseBranches, StringEncoding,
57 StringExprKind, StringFunctionExprKind, TupleExprKind, TupleFunctionExprKind,
58 TypedFunctionExprKind, UtfCodepointExprKind, UtfCodepointFunctionExprKind,
59};
60pub use expression::{
61 BitArrayExpr, BitArrayFunctionExpr, BoolExpr, BoolFunctionExpr, CallArg, CustomExpr,
62 CustomFunctionExpr, Expr, ExternalExpr, ExternalFunctionExpr, FloatExpr, FloatFunctionExpr,
63 FunctionExpr, FunctionFunctionExpr, IntExpr, IntFunctionExpr, ListFunctionExpr, NilExpr,
64 NilFunctionExpr, StringExpr, StringFunctionExpr, TupleExpr, TupleFunctionExpr,
65 UtfCodepointExpr, UtfCodepointFunctionExpr,
66};
67pub(crate) use expression::{
68 BitArrayListExpr, BitArrayListItem, BoolListCaseBranches, BoolListExpr, BoolListItem,
69 CustomListExpr, CustomListItem, ExternalListExpr, ExternalListItem, FloatListExpr,
70 FloatListItem, FunctionListExpr, FunctionListItem, GenericListExpr, GenericListItem,
71 IntListExpr, IntListItem, ListCaseBranches, ListExpr, ListItem, ListListExpr, ListListItem,
72 ListLocalExpr, ListSpreadConstructionError, ListSpreadElements, NilListExpr, NilListItem,
73 ParameterListListExpr, ParameterListListItem, StoredListExpr, StringListExpr, StringListItem,
74 TupleListExpr, TupleListItem, TypedListExpr, TypedListExprKind, TypedListReturnKind,
75 UtfCodepointListExpr, UtfCodepointListItem,
76};
77pub(crate) use function::{
78 BitArrayFunctionReturn, BitArrayReturn, BoolFunctionReturn, BoolReturn, CapturePosition,
79 CustomFunctionReturn, CustomReturn, ExternalFunctionReturn, ExternalReturn,
80 FloatFunctionReturn, FloatReturn, FunctionFunctionReturn, GenericFunctionReturn,
81 GenericListReturn, GenericReturn, IntFunctionReturn, IntReturn, ListFunctionReturn,
82 NilFunctionReturn, NilReturn, ParamLocal, ParamSlot, ParameterListListReturn, ReturnBody,
83 ReturnBodyKind, ReturnExprKind, StringFunctionReturn, StringReturn, TupleFunctionReturn,
84 TupleReturn, UtfCodepointFunctionReturn, UtfCodepointReturn,
85};
86#[cfg(test)]
87pub(crate) use function::{
88 BitArrayListReturn, BoolListReturn, CustomListReturn, FloatListReturn, FunctionListReturn,
89 IntListReturn, ListListReturn, ListReturn, NilListReturn, StringListReturn, TupleListReturn,
90 UtfCodepointListReturn,
91};
92pub use function::{FunctionTemplate, Param, ParamBinding, ReturnExpr};
93#[cfg(test)]
94pub(crate) use id::{
95 BitArrayFunctionFunctionId, BitArrayFunctionId, BoolFunctionFunctionId, BoolFunctionId,
96 CustomFunctionFunctionId, CustomFunctionId, FloatFunctionFunctionId, FloatFunctionId,
97 FunctionFunctionFunctionId, FunctionFunctionId, IntFunctionFunctionId, IntFunctionId,
98 ListFunctionFunctionId, ListFunctionId, NilFunctionFunctionId, NilFunctionId,
99 RuntimeFunctionId, StringFunctionFunctionId, StringFunctionId, TupleFunctionFunctionId,
100 TupleFunctionId, UtfCodepointFunctionFunctionId, UtfCodepointFunctionId,
101};
102pub use id::{
103 BitArrayFunctionLocalId, BitArrayListFunctionLocalId, BitArrayListLocalId, BitArrayLocalId,
104 BoolFunctionLocalId, BoolListFunctionLocalId, BoolListLocalId, BoolLocalId,
105 CustomFunctionLocalId, CustomListFunctionLocalId, CustomListLocalId, CustomLocalId,
106 ExternalFunctionLocalId, ExternalListFunctionLocalId, ExternalListLocalId, ExternalLocalId,
107 FloatFunctionLocalId, FloatListFunctionLocalId, FloatListLocalId, FloatLocalId,
108 FunctionFunctionLocalId, FunctionListFunctionLocalId, FunctionListLocalId,
109 FunctionReturnFamily, FunctionTemplateId, GenericFunctionLocalId, GenericListFunctionLocalId,
110 GenericListLocalId, GenericLocal, GenericLocalId, IntFunctionLocalId, IntListFunctionLocalId,
111 IntListLocalId, IntLocalId, ListFunctionLocal, ListListFunctionLocalId, ListListLocalId,
112 ListLocal, LocalId, ModuleId, NilFunctionLocalId, NilListFunctionLocalId, NilListLocalId,
113 NilLocalId, StringFunctionLocalId, StringListFunctionLocalId, StringListLocalId, StringLocalId,
114 TupleFunctionLocalId, TupleListFunctionLocalId, TupleListLocalId, TupleLocalId,
115 UtfCodepointFunctionLocalId, UtfCodepointListFunctionLocalId, UtfCodepointListLocalId,
116 UtfCodepointLocalId,
117};
118pub(crate) use id::{
119 CustomFunctionLocal, CustomLocal, ExternalFunctionLocal, ExternalLocal, FunctionFunctionLocal,
120 GenericFunctionLocal,
121};
122pub(crate) use pattern::{
123 BitArrayBindingPattern, BitArrayPattern, BitArrayPatternSegment, BitArrayPatternSize,
124 BitArrayPatternSizeExpr, BitArrayPatternValue, BitArrayStringPattern, CustomBindingPattern,
125 CustomPattern, PatternBinding, Signedness, TotalBindingPattern, TotalBindingPatternKind,
126};
127pub(crate) use reference::{
128 BitArrayFunctionReference, BoolFunctionReference, CustomFunctionReference,
129 ExternalFunctionReference, FloatFunctionReference, FunctionFunctionReference,
130 FunctionReference, GenericFunctionReference, IntFunctionReference, ListFunctionReference,
131 NilFunctionReference, StringFunctionReference, TupleFunctionReference, TypedFunctionReference,
132 UtfCodepointFunctionReference,
133};
134pub use step::Step;
135pub(crate) use step::{
136 AssertBinding, AssertPattern, AssertSubject, Echo, EchoSubject, ListAssertPattern,
137 ListAssertTail, StepKind, StringAssertBinding,
138};
139pub use type_scheme::TypeScheme;
140#[cfg(test)]
141pub(crate) use type_scheme::monomorphic_function_instantiation;
142pub(crate) use type_scheme::{FunctionInstantiation, FunctionTemplateSignature, TypeSubstitution};
143
144#[derive(Debug, PartialEq)]
145pub struct ModulePlan {
146 root: ModuleId,
147 entry: FunctionTemplateId,
148 modules: Vec<PlannedModule>,
149}
150
151pub(crate) struct LibraryModulePlan {
152 root: ModuleId,
153 modules: Vec<PlannedModule>,
154}
155
156#[derive(Clone)]
157pub(crate) struct LibraryEntry {
158 template: FunctionTemplateId,
159 return_: LibraryValueType,
160 input_variants: Box<[super::StandardVariant]>,
161 input_lists: Box<[LibraryValueType]>,
162}
163
164#[derive(Clone)]
165pub(crate) enum LibraryValueType {
166 Int,
167 Float,
168 String,
169 BitArray,
170 UtfCodepoint,
171 Custom(super::CustomType),
172 Bool,
173 Nil,
174 Tuple(Vec<super::ValueType>),
175 List(Box<LibraryValueType>),
176}
177
178impl LibraryValueType {
179 pub(crate) fn value_type(&self) -> super::ValueType {
180 use super::ValueType;
181 match self {
182 Self::Int => ValueType::Int,
183 Self::Float => ValueType::Float,
184 Self::String => ValueType::String,
185 Self::BitArray => ValueType::BitArray,
186 Self::UtfCodepoint => ValueType::UtfCodepoint,
187 Self::Custom(type_) => ValueType::Custom(type_.clone()),
188 Self::Bool => ValueType::Bool,
189 Self::Nil => ValueType::Nil,
190 Self::Tuple(elements) => ValueType::Tuple(elements.clone()),
191 Self::List(item) => ValueType::List(Box::new(item.value_type())),
192 }
193 }
194}
195
196impl LibraryEntry {
197 pub(crate) fn new(
198 template: FunctionTemplateId,
199 return_: LibraryValueType,
200 input_variants: Vec<super::StandardVariant>,
201 input_lists: Vec<LibraryValueType>,
202 ) -> Self {
203 Self {
204 template,
205 return_,
206 input_variants: input_variants.into_boxed_slice(),
207 input_lists: input_lists.into_boxed_slice(),
208 }
209 }
210
211 pub(crate) fn return_(&self) -> &LibraryValueType {
212 &self.return_
213 }
214
215 pub(crate) fn into_parts(
216 self,
217 ) -> (
218 FunctionTemplateId,
219 LibraryValueType,
220 Box<[super::StandardVariant]>,
221 Box<[LibraryValueType]>,
222 ) {
223 (
224 self.template,
225 self.return_,
226 self.input_variants,
227 self.input_lists,
228 )
229 }
230}
231
232#[derive(Debug, PartialEq)]
233pub struct PlannedModule {
234 id: ModuleId,
235 package: EcoString,
236 module: EcoString,
237 source_context: Option<SourceContext>,
238 custom_types: Vec<CustomTypeDefinition>,
239 constants: ConstantTemplates,
240 functions: Vec<FunctionTemplate>,
241 anonymous_functions: Vec<FunctionTemplate>,
242}
243
244pub(crate) struct ModulePlanParts {
245 pub(crate) root: ModuleId,
246 pub(crate) entry: FunctionTemplateId,
247 pub(crate) modules: Vec<PlannedModule>,
248}
249
250pub(crate) struct LibraryModulePlanParts {
251 pub(crate) root: ModuleId,
252 pub(crate) modules: Vec<PlannedModule>,
253}
254
255pub(crate) struct PlannedModuleParts {
256 pub(crate) module: EcoString,
257 pub(crate) source_context: Option<SourceContext>,
258 pub(crate) custom_types: Vec<CustomTypeDefinition>,
259 pub(crate) constants: ConstantTemplates,
260 pub(crate) functions: Vec<FunctionTemplate>,
261 pub(crate) anonymous_functions: Vec<FunctionTemplate>,
262}
263
264impl ModulePlan {
265 #[cfg(test)]
266 pub(crate) fn new(
267 module: EcoString,
268 main: FunctionTemplate,
269 functions: Vec<FunctionTemplate>,
270 ) -> Self {
271 let root = ModuleId::root();
272 let entry = main.id();
273 let mut named_functions = Vec::with_capacity(functions.len() + 1);
274 named_functions.push(main);
275 named_functions.extend(functions);
276 Self {
277 root,
278 entry,
279 modules: vec![PlannedModule {
280 id: root,
281 package: "geam".into(),
282 module,
283 source_context: None,
284 custom_types: Vec::new(),
285 constants: ConstantTemplates::empty(),
286 functions: named_functions,
287 anonymous_functions: Vec::new(),
288 }],
289 }
290 }
291
292 pub(crate) fn from_modules(
293 root: ModuleId,
294 entry: FunctionTemplateId,
295 modules: Vec<PlannedModule>,
296 ) -> Self {
297 Self {
298 root,
299 entry,
300 modules,
301 }
302 }
303
304 #[cfg(test)]
305 pub(crate) fn with_anonymous_functions(
306 mut self,
307 anonymous_functions: Vec<FunctionTemplate>,
308 ) -> Self {
309 self.root_module_mut().anonymous_functions = anonymous_functions;
310 self
311 }
312
313 #[cfg(test)]
314 pub(crate) fn with_custom_types(mut self, custom_types: Vec<CustomTypeDefinition>) -> Self {
315 self.root_module_mut().custom_types = custom_types;
316 self
317 }
318
319 #[cfg(test)]
320 pub(crate) fn with_constants(mut self, constants: ConstantTemplates) -> Self {
321 self.root_module_mut().constants = constants;
322 self
323 }
324
325 #[cfg(test)]
326 pub(crate) fn with_source_context(mut self, source_context: SourceContext) -> Self {
327 self.root_module_mut().source_context = Some(source_context);
328 self
329 }
330
331 pub fn root(&self) -> ModuleId {
332 self.root
333 }
334
335 pub fn entry(&self) -> FunctionTemplateId {
336 self.entry
337 }
338
339 pub fn modules(&self) -> &[PlannedModule] {
340 &self.modules
341 }
342
343 pub fn module(&self) -> &EcoString {
344 self.root_module().module()
345 }
346
347 pub fn source_context(&self) -> Option<&SourceContext> {
348 self.root_module().source_context()
349 }
350
351 pub fn custom_types(&self) -> &[CustomTypeDefinition] {
352 self.root_module().custom_types()
353 }
354
355 pub fn constants(&self) -> &[ConstantTemplate] {
356 self.root_module().constants()
357 }
358
359 pub fn main_function(&self) -> &FunctionTemplate {
360 &self.root_module().functions[self.entry.index()]
361 }
362
363 pub fn functions(&self) -> &[FunctionTemplate] {
364 &self.root_module().functions[1..]
365 }
366
367 #[cfg(test)]
368 pub(crate) fn anonymous_functions(&self) -> &[FunctionTemplate] {
369 &self.root_module().anonymous_functions
370 }
371
372 pub(crate) fn into_parts(self) -> ModulePlanParts {
373 ModulePlanParts {
374 root: self.root,
375 entry: self.entry,
376 modules: self.modules,
377 }
378 }
379
380 fn root_module(&self) -> &PlannedModule {
381 &self.modules[self.root.index()]
382 }
383
384 #[cfg(test)]
385 fn root_module_mut(&mut self) -> &mut PlannedModule {
386 &mut self.modules[self.root.index()]
387 }
388}
389
390impl LibraryModulePlan {
391 pub(crate) fn from_modules(root: ModuleId, modules: Vec<PlannedModule>) -> Self {
392 Self { root, modules }
393 }
394
395 pub(crate) fn functions(&self) -> &[FunctionTemplate] {
396 &self.modules[self.root.index()].functions
397 }
398
399 pub(crate) fn custom_type(
400 &self,
401 name: &super::CustomTypeName,
402 ) -> Option<&CustomTypeDefinition> {
403 self.modules
404 .iter()
405 .flat_map(PlannedModule::custom_types)
406 .find(|definition| definition.name() == name)
407 }
408
409 pub(crate) fn into_parts(self) -> LibraryModulePlanParts {
410 LibraryModulePlanParts {
411 root: self.root,
412 modules: self.modules,
413 }
414 }
415}
416
417impl PlannedModule {
418 pub(crate) fn new(id: ModuleId, package: EcoString, parts: PlannedModuleParts) -> Self {
419 let PlannedModuleParts {
420 module,
421 source_context,
422 custom_types,
423 constants,
424 functions,
425 anonymous_functions,
426 } = parts;
427 Self {
428 id,
429 package,
430 module,
431 source_context,
432 custom_types,
433 constants,
434 functions,
435 anonymous_functions,
436 }
437 }
438
439 pub fn id(&self) -> ModuleId {
440 self.id
441 }
442
443 pub fn package(&self) -> &EcoString {
444 &self.package
445 }
446
447 pub fn module(&self) -> &EcoString {
448 &self.module
449 }
450
451 pub fn source_context(&self) -> Option<&SourceContext> {
452 self.source_context.as_ref()
453 }
454
455 pub fn custom_types(&self) -> &[CustomTypeDefinition] {
456 &self.custom_types
457 }
458
459 pub fn constants(&self) -> &[ConstantTemplate] {
460 self.constants.headers()
461 }
462
463 pub fn functions(&self) -> &[FunctionTemplate] {
464 &self.functions
465 }
466
467 pub(crate) fn into_parts(self) -> PlannedModuleParts {
468 PlannedModuleParts {
469 module: self.module,
470 source_context: self.source_context,
471 custom_types: self.custom_types,
472 constants: self.constants,
473 functions: self.functions,
474 anonymous_functions: self.anonymous_functions,
475 }
476 }
477}
478
479#[cfg(test)]
480mod tests {
481 use super::ModulePlan;
482 use crate::plan::{
483 ConstantTemplate, ConstantTemplateId, ConstantTemplateSignature, ConstantTemplates,
484 ConstantValue, FunctionTemplate, FunctionTemplateId, IntExpr, IntFunctionId, ReturnExpr,
485 SourceContext, TypeScheme,
486 };
487 use num_bigint::BigInt;
488
489 #[test]
490 fn module_plan_accessors() {
491 let main = function(0, "main", 1);
492 let helper = function(1, "helper", 2);
493 let anonymous = function(2, "<anonymous:0>", 3);
494 let signature =
495 ConstantTemplateSignature::int(ConstantTemplateId::new(0), 0, TypeScheme::new(0));
496 let constant = ConstantTemplate::new(signature, "answer".into());
497 let plan = ModulePlan::new("main".into(), main, vec![helper])
498 .with_anonymous_functions(vec![anonymous])
499 .with_constants(ConstantTemplates::from_entries(vec![(
500 constant.clone(),
501 ConstantValue::int(BigInt::from(42)),
502 )]));
503
504 assert_eq!(plan.module(), "main");
505 assert_eq!(plan.modules()[0].package(), "geam");
506 assert_eq!(plan.main_function().name(), "main");
507 assert_eq!(plan.functions().len(), 1);
508 assert_eq!(plan.functions()[0].name(), "helper");
509 assert_eq!(plan.anonymous_functions().len(), 1);
510 assert_eq!(plan.anonymous_functions()[0].name(), "<anonymous:0>");
511 assert_eq!(plan.constants(), &[constant]);
512 assert_eq!(plan.constants()[0].scheme().parameters(), &[]);
513 assert_eq!(plan.source_context(), None);
514 }
515
516 #[test]
517 fn module_plan_debug_surface_contains_only_canonical_plan() {
518 let plan = ModulePlan::new("main".into(), function(0, "main", 1), Vec::new())
519 .with_source_context(SourceContext::new("main.gleam", "pub fn main() { panic }"));
520 let debug = format!("{plan:?}");
521
522 assert_eq!(
523 debug,
524 format!(
525 "ModulePlan {{ root: {:?}, entry: {:?}, modules: {:?} }}",
526 plan.root, plan.entry, plan.modules,
527 ),
528 );
529 }
530
531 #[test]
532 fn module_plan_equality_includes_source_context() {
533 let new_plan = || ModulePlan::new("main".into(), function(0, "main", 1), Vec::new());
534
535 assert_eq!(
536 new_plan().with_source_context(SourceContext::new("main.gleam", "pub fn main() { 1 }")),
537 new_plan().with_source_context(SourceContext::new("main.gleam", "pub fn main() { 1 }")),
538 );
539 assert_ne!(
540 new_plan(),
541 new_plan().with_source_context(SourceContext::new("main.gleam", "pub fn main() { 1 }")),
542 );
543 assert_ne!(
544 new_plan().with_source_context(SourceContext::new("main.gleam", "pub fn main() { 1 }")),
545 new_plan()
546 .with_source_context(SourceContext::new("other.gleam", "pub fn main() { 1 }")),
547 );
548 assert_ne!(
549 new_plan().with_source_context(SourceContext::new("main.gleam", "pub fn main() { 1 }")),
550 new_plan().with_source_context(SourceContext::new("main.gleam", "pub fn main() { 2 }")),
551 );
552 assert_ne!(
553 ModulePlan::new("left".into(), function(0, "main", 1), Vec::new()),
554 ModulePlan::new("right".into(), function(0, "main", 1), Vec::new()),
555 );
556 assert_ne!(
557 ModulePlan::new("main".into(), function(0, "main", 1), Vec::new()),
558 ModulePlan::new("main".into(), function(0, "main", 2), Vec::new()),
559 );
560 assert_ne!(
561 ModulePlan::new("main".into(), function(0, "main", 1), Vec::new()),
562 ModulePlan::new(
563 "main".into(),
564 function(0, "main", 1),
565 vec![function(1, "helper", 2)],
566 ),
567 );
568 assert_ne!(
569 ModulePlan::new("main".into(), function(0, "main", 1), Vec::new()),
570 ModulePlan::new("main".into(), function(0, "main", 1), Vec::new())
571 .with_anonymous_functions(vec![function(1, "<anonymous:0>", 2)]),
572 );
573 }
574
575 fn function(id: usize, name: &str, value: i64) -> FunctionTemplate {
576 FunctionTemplate::new(
577 FunctionTemplateId::new(id),
578 name.into(),
579 Vec::new(),
580 Vec::new(),
581 ReturnExpr::int(IntFunctionId(id), IntExpr::value(BigInt::from(value))),
582 )
583 }
584}