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
151#[derive(Debug, PartialEq)]
152pub struct PlannedModule {
153    id: ModuleId,
154    package: EcoString,
155    module: EcoString,
156    source_context: Option<SourceContext>,
157    custom_types: Vec<CustomTypeDefinition>,
158    constants: ConstantTemplates,
159    functions: Vec<FunctionTemplate>,
160    anonymous_functions: Vec<FunctionTemplate>,
161}
162
163pub(crate) struct ModulePlanParts {
164    pub(crate) root: ModuleId,
165    pub(crate) entry: FunctionTemplateId,
166    pub(crate) modules: Vec<PlannedModule>,
167}
168
169pub(crate) struct PlannedModuleParts {
170    pub(crate) module: EcoString,
171    pub(crate) source_context: Option<SourceContext>,
172    pub(crate) custom_types: Vec<CustomTypeDefinition>,
173    pub(crate) constants: ConstantTemplates,
174    pub(crate) functions: Vec<FunctionTemplate>,
175    pub(crate) anonymous_functions: Vec<FunctionTemplate>,
176}
177
178impl ModulePlan {
179    #[cfg(test)]
180    pub(crate) fn new(
181        module: EcoString,
182        main: FunctionTemplate,
183        functions: Vec<FunctionTemplate>,
184    ) -> Self {
185        let root = ModuleId::root();
186        let entry = main.id();
187        let mut named_functions = Vec::with_capacity(functions.len() + 1);
188        named_functions.push(main);
189        named_functions.extend(functions);
190        Self {
191            root,
192            entry,
193            modules: vec![PlannedModule {
194                id: root,
195                package: "geam".into(),
196                module,
197                source_context: None,
198                custom_types: Vec::new(),
199                constants: ConstantTemplates::empty(),
200                functions: named_functions,
201                anonymous_functions: Vec::new(),
202            }],
203        }
204    }
205
206    pub(crate) fn from_modules(
207        root: ModuleId,
208        entry: FunctionTemplateId,
209        modules: Vec<PlannedModule>,
210    ) -> Self {
211        Self {
212            root,
213            entry,
214            modules,
215        }
216    }
217
218    #[cfg(test)]
219    pub(crate) fn with_anonymous_functions(
220        mut self,
221        anonymous_functions: Vec<FunctionTemplate>,
222    ) -> Self {
223        self.root_module_mut().anonymous_functions = anonymous_functions;
224        self
225    }
226
227    #[cfg(test)]
228    pub(crate) fn with_custom_types(mut self, custom_types: Vec<CustomTypeDefinition>) -> Self {
229        self.root_module_mut().custom_types = custom_types;
230        self
231    }
232
233    #[cfg(test)]
234    pub(crate) fn with_constants(mut self, constants: ConstantTemplates) -> Self {
235        self.root_module_mut().constants = constants;
236        self
237    }
238
239    #[cfg(test)]
240    pub(crate) fn with_source_context(mut self, source_context: SourceContext) -> Self {
241        self.root_module_mut().source_context = Some(source_context);
242        self
243    }
244
245    pub fn root(&self) -> ModuleId {
246        self.root
247    }
248
249    pub fn entry(&self) -> FunctionTemplateId {
250        self.entry
251    }
252
253    pub fn modules(&self) -> &[PlannedModule] {
254        &self.modules
255    }
256
257    pub fn module(&self) -> &EcoString {
258        self.root_module().module()
259    }
260
261    pub fn source_context(&self) -> Option<&SourceContext> {
262        self.root_module().source_context()
263    }
264
265    pub fn custom_types(&self) -> &[CustomTypeDefinition] {
266        self.root_module().custom_types()
267    }
268
269    pub fn constants(&self) -> &[ConstantTemplate] {
270        self.root_module().constants()
271    }
272
273    pub fn main_function(&self) -> &FunctionTemplate {
274        &self.root_module().functions[self.entry.index()]
275    }
276
277    pub fn functions(&self) -> &[FunctionTemplate] {
278        &self.root_module().functions[1..]
279    }
280
281    #[cfg(test)]
282    pub(crate) fn anonymous_functions(&self) -> &[FunctionTemplate] {
283        &self.root_module().anonymous_functions
284    }
285
286    pub(crate) fn into_parts(self) -> ModulePlanParts {
287        ModulePlanParts {
288            root: self.root,
289            entry: self.entry,
290            modules: self.modules,
291        }
292    }
293
294    fn root_module(&self) -> &PlannedModule {
295        &self.modules[self.root.index()]
296    }
297
298    #[cfg(test)]
299    fn root_module_mut(&mut self) -> &mut PlannedModule {
300        &mut self.modules[self.root.index()]
301    }
302}
303
304impl PlannedModule {
305    pub(crate) fn new(id: ModuleId, package: EcoString, parts: PlannedModuleParts) -> Self {
306        let PlannedModuleParts {
307            module,
308            source_context,
309            custom_types,
310            constants,
311            functions,
312            anonymous_functions,
313        } = parts;
314        Self {
315            id,
316            package,
317            module,
318            source_context,
319            custom_types,
320            constants,
321            functions,
322            anonymous_functions,
323        }
324    }
325
326    pub fn id(&self) -> ModuleId {
327        self.id
328    }
329
330    pub fn package(&self) -> &EcoString {
331        &self.package
332    }
333
334    pub fn module(&self) -> &EcoString {
335        &self.module
336    }
337
338    pub fn source_context(&self) -> Option<&SourceContext> {
339        self.source_context.as_ref()
340    }
341
342    pub fn custom_types(&self) -> &[CustomTypeDefinition] {
343        &self.custom_types
344    }
345
346    pub fn constants(&self) -> &[ConstantTemplate] {
347        self.constants.headers()
348    }
349
350    pub fn functions(&self) -> &[FunctionTemplate] {
351        &self.functions
352    }
353
354    pub(crate) fn into_parts(self) -> PlannedModuleParts {
355        PlannedModuleParts {
356            module: self.module,
357            source_context: self.source_context,
358            custom_types: self.custom_types,
359            constants: self.constants,
360            functions: self.functions,
361            anonymous_functions: self.anonymous_functions,
362        }
363    }
364}
365
366#[cfg(test)]
367mod tests {
368    use super::ModulePlan;
369    use crate::plan::{
370        ConstantTemplate, ConstantTemplateId, ConstantTemplateSignature, ConstantTemplates,
371        ConstantValue, FunctionTemplate, FunctionTemplateId, IntExpr, IntFunctionId, ReturnExpr,
372        SourceContext, TypeScheme,
373    };
374    use num_bigint::BigInt;
375
376    #[test]
377    fn module_plan_accessors() {
378        let main = function(0, "main", 1);
379        let helper = function(1, "helper", 2);
380        let anonymous = function(2, "<anonymous:0>", 3);
381        let signature =
382            ConstantTemplateSignature::int(ConstantTemplateId::new(0), 0, TypeScheme::new(0));
383        let constant = ConstantTemplate::new(signature, "answer".into());
384        let plan = ModulePlan::new("main".into(), main, vec![helper])
385            .with_anonymous_functions(vec![anonymous])
386            .with_constants(ConstantTemplates::from_entries(vec![(
387                constant.clone(),
388                ConstantValue::int(BigInt::from(42)),
389            )]));
390
391        assert_eq!(plan.module(), "main");
392        assert_eq!(plan.modules()[0].package(), "geam");
393        assert_eq!(plan.main_function().name(), "main");
394        assert_eq!(plan.functions().len(), 1);
395        assert_eq!(plan.functions()[0].name(), "helper");
396        assert_eq!(plan.anonymous_functions().len(), 1);
397        assert_eq!(plan.anonymous_functions()[0].name(), "<anonymous:0>");
398        assert_eq!(plan.constants(), &[constant]);
399        assert_eq!(plan.constants()[0].scheme().parameters(), &[]);
400        assert_eq!(plan.source_context(), None);
401    }
402
403    #[test]
404    fn module_plan_debug_surface_contains_only_canonical_plan() {
405        let plan = ModulePlan::new("main".into(), function(0, "main", 1), Vec::new())
406            .with_source_context(SourceContext::new("main.gleam", "pub fn main() { panic }"));
407        let debug = format!("{plan:?}");
408
409        assert_eq!(
410            debug,
411            format!(
412                "ModulePlan {{ root: {:?}, entry: {:?}, modules: {:?} }}",
413                plan.root, plan.entry, plan.modules,
414            ),
415        );
416    }
417
418    #[test]
419    fn module_plan_equality_includes_source_context() {
420        let new_plan = || ModulePlan::new("main".into(), function(0, "main", 1), Vec::new());
421
422        assert_eq!(
423            new_plan().with_source_context(SourceContext::new("main.gleam", "pub fn main() { 1 }")),
424            new_plan().with_source_context(SourceContext::new("main.gleam", "pub fn main() { 1 }")),
425        );
426        assert_ne!(
427            new_plan(),
428            new_plan().with_source_context(SourceContext::new("main.gleam", "pub fn main() { 1 }")),
429        );
430        assert_ne!(
431            new_plan().with_source_context(SourceContext::new("main.gleam", "pub fn main() { 1 }")),
432            new_plan()
433                .with_source_context(SourceContext::new("other.gleam", "pub fn main() { 1 }")),
434        );
435        assert_ne!(
436            new_plan().with_source_context(SourceContext::new("main.gleam", "pub fn main() { 1 }")),
437            new_plan().with_source_context(SourceContext::new("main.gleam", "pub fn main() { 2 }")),
438        );
439        assert_ne!(
440            ModulePlan::new("left".into(), function(0, "main", 1), Vec::new()),
441            ModulePlan::new("right".into(), function(0, "main", 1), Vec::new()),
442        );
443        assert_ne!(
444            ModulePlan::new("main".into(), function(0, "main", 1), Vec::new()),
445            ModulePlan::new("main".into(), function(0, "main", 2), Vec::new()),
446        );
447        assert_ne!(
448            ModulePlan::new("main".into(), function(0, "main", 1), Vec::new()),
449            ModulePlan::new(
450                "main".into(),
451                function(0, "main", 1),
452                vec![function(1, "helper", 2)],
453            ),
454        );
455        assert_ne!(
456            ModulePlan::new("main".into(), function(0, "main", 1), Vec::new()),
457            ModulePlan::new("main".into(), function(0, "main", 1), Vec::new())
458                .with_anonymous_functions(vec![function(1, "<anonymous:0>", 2)]),
459        );
460    }
461
462    fn function(id: usize, name: &str, value: i64) -> FunctionTemplate {
463        FunctionTemplate::new(
464            FunctionTemplateId::new(id),
465            name.into(),
466            Vec::new(),
467            Vec::new(),
468            ReturnExpr::int(IntFunctionId(id), IntExpr::value(BigInt::from(value))),
469        )
470    }
471}