Skip to main content

geam_core/plan/
module.rs

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}