diff --git a/crates/cli/src/commands.rs b/crates/cli/src/commands.rs index eccd7c4..f92086b 100644 --- a/crates/cli/src/commands.rs +++ b/crates/cli/src/commands.rs @@ -40,7 +40,7 @@ impl CompiledModule { let ast = compiler_core::target::select_module(ast, target)?; let resolved = compiler_core::resolve::resolve(ast.clone())?; let typed = compiler_core::types::check(resolved.clone())?; - let ir = compiler_core::ir::lower(typed.clone())?; + let ir = typed.clone().lower()?; let wasm = ir.emit_wasm_with_options(target.into())?; Ok(Self { ast, resolved, typed, ir, wasm }) } diff --git a/crates/core/src/ir.rs b/crates/core/src/ir.rs index 56b9ef0..3c01fb2 100644 --- a/crates/core/src/ir.rs +++ b/crates/core/src/ir.rs @@ -18,6 +18,7 @@ use crate::{ }; pub use bit_slices::{BitArrayLiteral, BitArraySegment, BitSegmentOption, BitSegmentType, BitStringPatternSegment}; +pub use lowerer::lower; pub use lowerer::{FunctionContext, Lowerer}; pub use specialization::{DependencySpecialization, DependencySpecializationKey}; @@ -126,7 +127,7 @@ impl Module { let mut boundary_calls = self .functions .iter() - .filter_map(import_boundary_debug_line) + .filter_map(Function::import_boundary_debug_line) .collect::>(); if !boundary_calls.is_empty() { boundary_calls.sort(); @@ -142,20 +143,6 @@ impl Module { } } -// TODO: make an instance method on Function -fn import_boundary_debug_line(function: &Function) -> Option { - match &function.abi.boundary { - CallBoundary::HostImport { module, name } => { - Some(format!("host-import wrapper={} abi={module}.{name}", function.name)) - } - CallBoundary::ModuleImport { module, name } => Some(format!( - "dependency-interface wrapper={} abi={module}.{name}", - function.name - )), - CallBoundary::Internal | CallBoundary::ModuleExport => None, - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ConstantId(pub u32); @@ -165,6 +152,12 @@ pub struct ModuleIdentity { pub module: String, } +impl ModuleIdentity { + fn linked_source_name(&self, member: &str) -> String { + backend_key(self.package.as_str(), self.module.as_str(), member) + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct LinkedName { pub source_name: String, @@ -212,26 +205,6 @@ pub struct DeclarationMetadata { pub span: Span, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct TypeMetadata { - pub name: String, - pub parameters: Vec, - pub opaque: bool, - pub constructors: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ConstructorMetadata { - pub name: String, - pub fields: Vec, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct FieldMetadata { - pub name: Option, - pub type_: Type, -} - impl From<&ast::Declaration> for DeclarationMetadata { fn from(declaration: &ast::Declaration) -> Self { match declaration { @@ -244,37 +217,37 @@ impl From<&ast::Declaration> for DeclarationMetadata { ast::Declaration::Function(function) => Self { name: Some(function.name.text.clone()), kind: DeclarationKind::Function, - visibility: visibility(function.public), + visibility: Visibility::from_public(function.public), span: function.span, }, ast::Declaration::Constant(constant) => Self { name: Some(constant.name.text.clone()), kind: DeclarationKind::Constant, - visibility: visibility(constant.public), + visibility: Visibility::from_public(constant.public), span: constant.span, }, ast::Declaration::ExternalFunction(function) => Self { name: Some(function.name.text.clone()), kind: DeclarationKind::ExternalFunction, - visibility: visibility(function.public), + visibility: Visibility::from_public(function.public), span: function.span, }, ast::Declaration::ExternalType(type_) => Self { name: Some(type_.name.text.clone()), kind: DeclarationKind::ExternalType, - visibility: visibility(type_.public), + visibility: Visibility::from_public(type_.public), span: type_.span, }, ast::Declaration::TypeAlias(alias) => Self { name: Some(alias.name.text.clone()), kind: DeclarationKind::TypeAlias, - visibility: visibility(alias.public), + visibility: Visibility::from_public(alias.public), span: alias.span, }, ast::Declaration::TypeDefinition(type_) => Self { name: Some(type_.name.text.clone()), kind: DeclarationKind::TypeDefinition, - visibility: visibility(type_.public), + visibility: Visibility::from_public(type_.public), span: type_.span, }, ast::Declaration::Attribute(attribute) => Self { @@ -300,6 +273,26 @@ impl From<&ast::Declaration> for DeclarationMetadata { } } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TypeMetadata { + pub name: String, + pub parameters: Vec, + pub opaque: bool, + pub constructors: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ConstructorMetadata { + pub name: String, + pub fields: Vec, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FieldMetadata { + pub name: Option, + pub type_: Type, +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum DeclarationKind { Import, @@ -320,6 +313,12 @@ pub enum Visibility { Private, } +impl Visibility { + fn from_public(public: bool) -> Self { + if public { Self::Public } else { Self::Private } + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct Constant { pub id: ConstantId, @@ -331,7 +330,7 @@ pub struct Constant { #[derive(Debug, Clone, PartialEq, Eq)] pub enum ConstantValue { - Literal(Literal), + Literal(IrLiteral), Raw(String), } @@ -467,6 +466,38 @@ pub struct Function { pub span: Span, } +impl Function { + fn import_boundary_debug_line(&self) -> Option { + match &self.abi.boundary { + CallBoundary::HostImport { module, name } => { + Some(format!("host-import wrapper={} abi={module}.{name}", self.name)) + } + CallBoundary::ModuleImport { module, name } => Some(format!( + "dependency-interface wrapper={} abi={module}.{name}", + self.name + )), + CallBoundary::Internal | CallBoundary::ModuleExport => None, + } + } + + fn substitute_types(&mut self, substitutions: &HashMap) { + self.closure_captures = self + .closure_captures + .iter() + .map(|type_| type_.substitute(substitutions)) + .collect(); + for param in &mut self.params { + param.substitute_type(substitutions); + } + for local in &mut self.locals { + local.substitute_type(substitutions); + } + self.return_type = self.return_type.substitute(substitutions); + self.abi.substitute_types(substitutions); + self.body.substitute_types(substitutions); + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct CallAbi { pub params: Vec, @@ -474,6 +505,17 @@ pub struct CallAbi { pub boundary: CallBoundary, } +impl CallAbi { + fn substitute_types(&mut self, substitutions: &HashMap) { + for param in &mut self.params { + param.substitute_type(substitutions); + } + if let Some(return_) = &mut self.return_ { + return_.substitute_type(substitutions); + } + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct AbiValue { pub type_: Type, @@ -486,6 +528,13 @@ impl From<&Type> for AbiValue { } } +impl AbiValue { + fn substitute_type(&mut self, substitutions: &HashMap) { + self.type_ = self.type_.substitute(substitutions); + self.representation = RepresentationType::from(&self.type_); + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub enum CallBoundary { Internal, @@ -502,6 +551,12 @@ pub struct Local { pub span: Span, } +impl Local { + fn substitute_type(&mut self, substitutions: &HashMap) { + self.type_ = self.type_.substitute(substitutions); + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct Block { pub instructions: Vec, @@ -532,6 +587,10 @@ impl Block { .any(|instruction| predicate(instruction.expression())) || predicate(&self.result) } + + fn substitute_types(&mut self, substitutions: &HashMap) { + substitute_block_types(self, substitutions); + } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -689,7 +748,7 @@ impl<'a> Iterator for ExpressionChildren<'a> { #[derive(Debug, Clone, PartialEq, Eq)] pub enum ExpressionKind { - Literal(Literal), + Literal(IrLiteral), LocalGet(LocalId), DirectCall(DirectCall), IndirectCall(IndirectCall), @@ -753,6 +812,28 @@ pub struct DirectCall { pub abi: CallAbi, } +impl DirectCall { + fn abi_rename_key(&self) -> Option { + let return_type = self.abi.return_.as_ref()?.type_.clone(); + let params = self + .abi + .params + .iter() + .map(|param| param.type_.clone()) + .collect::>(); + Some(call_rename_key(&self.function, ¶ms, &return_type)) + } + + fn expression_rename_key(&self, return_type: &Type) -> String { + let params = self + .arguments + .iter() + .map(|argument| argument.value.type_.clone()) + .collect::>(); + call_rename_key(&self.function, ¶ms, return_type) + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct IndirectCall { pub callee: Box, @@ -854,9 +935,7 @@ pub enum MemoryOperation { } #[derive(Debug, Clone, PartialEq, Eq)] -// TODO: this (and some other types) collide with ast types need to -// be renamed to avoid confusion. Maybe `IrLiteral`? -pub struct Literal { +pub struct IrLiteral { pub kind: LiteralKind, pub source: String, } @@ -929,7 +1008,7 @@ pub enum IrPattern { pattern: Box, local: LocalId, }, - Literal(Literal), + Literal(IrLiteral), Tuple(Vec), List { elements: Vec, @@ -949,10 +1028,6 @@ pub struct ConstructorPatternArgument { pub span: Span, } -pub fn lower(module: TypedModule) -> Result { - lowerer::lower(module) -} - pub fn lower_project(project: TypedProject) -> Result { let mut modules = Vec::new(); let mut diagnostics = unsupported_dependency_member_diagnostics(&project); @@ -1292,7 +1367,7 @@ fn global_backend_renames(modules: &[Module], specializations: &[DependencySpeci BackendName::function(identity.package.as_str(), module_name.clone(), function.name.as_str()) }; let generated_name = render_backend_name(&backend); - let source_name = linked_source_name(identity, function.name.as_str()); + let source_name = identity.linked_source_name(function.name.as_str()); let kind = if function.name.starts_with("__") || matches!( function.abi.boundary, @@ -1324,7 +1399,7 @@ fn global_backend_renames(modules: &[Module], specializations: &[DependencySpeci for constant in &module.constants { let backend = BackendName::constant(identity.package.as_str(), module_name.clone(), constant.name.as_str()); let generated_name = render_backend_name(&backend); - let source_name = linked_source_name(identity, constant.name.as_str()); + let source_name = identity.linked_source_name(constant.name.as_str()); renames.insert( backend_key( identity.package.as_str(), @@ -1346,7 +1421,7 @@ fn global_backend_renames(modules: &[Module], specializations: &[DependencySpeci { let backend = BackendName::constructor(identity.package.as_str(), module_name.clone(), name.as_str()); let generated_name = render_backend_name(&backend); - let source_name = linked_source_name(identity, name.as_str()); + let source_name = identity.linked_source_name(name.as_str()); renames.insert( backend_key(identity.package.as_str(), identity.module.as_str(), name.as_str()), generated_name.clone(), @@ -1361,7 +1436,7 @@ fn global_backend_renames(modules: &[Module], specializations: &[DependencySpeci } } let mut sorted_specializations = specializations.iter().collect::>(); - sorted_specializations.sort_by_key(|specialization| specialization_sort_key(&specialization.key)); + sorted_specializations.sort_by_key(|specialization| specialization.key.source_name()); let mut generated_by_owner = HashMap::<(&str, &str), u32>::new(); for specialization in sorted_specializations { let module_name = ModuleName::from_path(&specialization.key.module); @@ -1380,7 +1455,7 @@ fn global_backend_renames(modules: &[Module], specializations: &[DependencySpeci let generated_name = render_backend_name(&backend); dependency_specialization_names.push((specialization.key.clone(), generated_name.clone())); linked_names.push(LinkedName { - source_name: dep_specialization_source_name(&specialization.key), + source_name: specialization.key.source_name(), generated_name, kind: LinkedNameKind::Function, span: specialization.source_span, @@ -1398,26 +1473,17 @@ fn backend_key(package: &str, module: &str, member: &str) -> String { format!("{package}:{module}.{member}") } -// TODO: instance method on ModuleIdentity -fn linked_source_name(identity: &ModuleIdentity, member: &str) -> String { - backend_key(identity.package.as_str(), identity.module.as_str(), member) -} - -// TODO: instance method on DependencySpecializationKey -fn dep_specialization_source_name(key: &DependencySpecializationKey) -> String { - format!( - "{}:{}.{}/{}->{}", - key.package, - key.module, - key.function, - key.params.iter().map(Type::display).collect::>().join(","), - key.return_type.display() - ) -} - -// TODO: this is useless -fn specialization_sort_key(key: &DependencySpecializationKey) -> String { - dep_specialization_source_name(key) +impl DependencySpecializationKey { + fn source_name(&self) -> String { + format!( + "{}:{}.{}/{}->{}", + self.package, + self.module, + self.function, + self.params.iter().map(Type::display).collect::>().join(","), + self.return_type.display() + ) + } } fn generated_name_collision_diagnostics(linked_names: &[LinkedName]) -> Diagnostics { @@ -1462,7 +1528,6 @@ struct ModuleBackendRenames { calls: HashMap, } -// TODO: instance method on Module fn mod_backend_renames(module: &Module, plan: &BackendRenamePlan) -> ModuleBackendRenames { let mut names = HashMap::new(); let mut calls = HashMap::new(); @@ -1604,28 +1669,6 @@ fn call_rename_key(source_name: &str, params: &[Type], return_type: &Type) -> St ) } -// TODO: instance method on DirectCall -fn direct_call_rename_key(call: &DirectCall) -> Option { - let return_type = call.abi.return_.as_ref()?.type_.clone(); - let params = call - .abi - .params - .iter() - .map(|param| param.type_.clone()) - .collect::>(); - Some(call_rename_key(&call.function, ¶ms, &return_type)) -} - -// TODO: instance method on DirectCall -fn direct_call_expr_rename_key(call: &DirectCall, return_type: &Type) -> String { - let params = call - .arguments - .iter() - .map(|argument| argument.value.type_.clone()) - .collect::>(); - call_rename_key(&call.function, ¶ms, return_type) -} - fn unique_call_rename(source_name: &str, calls: &HashMap) -> Option { let prefix = format!("{source_name}("); let mut matches = calls @@ -1637,7 +1680,6 @@ fn unique_call_rename(source_name: &str, calls: &HashMap) -> Opt (matches.len() == 1).then(|| matches.remove(0)) } -// TODO: instance method on Module fn add_dep_specialization_funcs( module: &mut Module, specializations: &[DependencySpecialization], plan: &BackendRenamePlan, ) { @@ -1766,7 +1808,6 @@ fn dep_specialization_helper_renames(function: &Function, specialization_backend .collect() } -// TODO: instance method on Block fn collect_function_value_names(block: &Block, names: &mut HashSet) { for instruction in &block.instructions { collect_function_value_names_in_expr(instruction.expression(), names); @@ -1774,7 +1815,6 @@ fn collect_function_value_names(block: &Block, names: &mut HashSet) { collect_function_value_names_in_expr(&block.result, names); } -// TODO: instance method on Expression fn collect_function_value_names_in_expr(expr: &Expression, names: &mut HashSet) { match &expr.kind { ExpressionKind::FunctionValue(function) => { @@ -1788,53 +1828,24 @@ fn collect_function_value_names_in_expr(expr: &Expression, names: &mut HashSet) { - function.closure_captures = function - .closure_captures - .iter() - .map(|type_| type_.substitute(substitutions)) - .collect(); - for param in &mut function.params { - substitute_local_type(param, substitutions); - } - for local in &mut function.locals { - substitute_local_type(local, substitutions); - } - function.return_type = function.return_type.substitute(substitutions); - substitute_call_abi_types(&mut function.abi, substitutions); - substitute_block_types(&mut function.body, substitutions); + function.substitute_types(substitutions); } -// TODO: instance method on Local fn substitute_local_type(local: &mut Local, substitutions: &HashMap) { - local.type_ = local.type_.substitute(substitutions); + local.substitute_type(substitutions); } -// TODO: instance method on CallAbi fn substitute_call_abi_types(abi: &mut CallAbi, substitutions: &HashMap) { - for param in &mut abi.params { - substitute_abi_value_type(param, substitutions); - } - if let Some(return_) = &mut abi.return_ { - substitute_abi_value_type(return_, substitutions); - } -} - -// TODO: instance method on AbiValue -fn substitute_abi_value_type(value: &mut AbiValue, substitutions: &HashMap) { - value.type_ = value.type_.substitute(substitutions); - value.representation = RepresentationType::from(&value.type_); + abi.substitute_types(substitutions); } -// TODO: instance method on Block fn substitute_block_types(block: &mut Block, substitutions: &HashMap) { for instruction in &mut block.instructions { match instruction { @@ -1847,7 +1858,6 @@ fn substitute_block_types(block: &mut Block, substitutions: &HashMap) { expression.type_ = expression.type_.substitute(substitutions); match &mut expression.kind { @@ -1984,8 +1994,6 @@ fn rewrite_mod_backend_names(module: &mut Module, renames: &ModuleBackendRenames } } -// TODO: all rewrite_* functions can be instance methods on the first arg type - fn rewrite_reference(reference: &mut Reference, renames: &HashMap) { rewrite_name(&mut reference.name, renames); match &mut reference.target { @@ -2056,12 +2064,12 @@ fn rewrite_expr(expr: &mut Expression, renames: &ModuleBackendRenames) { let expression_type = expr.type_.clone(); match &mut expr.kind { ExpressionKind::DirectCall(call) => { - let expression_key = direct_call_expr_rename_key(call, &expression_type); + let expression_key = call.expression_rename_key(&expression_type); if let Some(name) = renames .calls .get(&expression_key) .cloned() - .or_else(|| direct_call_rename_key(call).and_then(|key| renames.calls.get(&key).cloned())) + .or_else(|| call.abi_rename_key().and_then(|key| renames.calls.get(&key).cloned())) .or_else(|| unique_call_rename(&call.function, &renames.calls)) { call.function = name; @@ -2316,7 +2324,7 @@ fn integer_expr(source: &str, span: Span) -> Option { Some(Expression { type_: Type::Int, span, - kind: ExpressionKind::Literal(Literal { kind: LiteralKind::Int, source: source.into() }), + kind: ExpressionKind::Literal(IrLiteral { kind: LiteralKind::Int, source: source.into() }), }) } @@ -2335,7 +2343,7 @@ fn abi_return(type_: &Type) -> Option { fn raw_metadata(raw: &ast::RawSyntax, kind: DeclarationKind, keyword: &str) -> DeclarationMetadata { let source = &raw.source; - let visibility = visibility(source.trim_start().starts_with("pub ")); + let visibility = Visibility::from_public(source.trim_start().starts_with("pub ")); DeclarationMetadata { name: declaration_name(source, keyword), kind, visibility, span: raw.span } } @@ -2349,11 +2357,6 @@ fn declaration_name(source: &str, keyword: &str) -> Option { .map(str::to_string) } -// TODO: instance method on Visibility -fn visibility(public: bool) -> Visibility { - if public { Visibility::Public } else { Visibility::Private } -} - #[cfg(test)] mod tests { use std::fs; @@ -2865,7 +2868,7 @@ pub fn main(input: String) -> String { result: Box::new(Expression { type_: Type::Nil, span, - kind: ExpressionKind::Literal(Literal { kind: LiteralKind::Nil, source: "Nil".into() }), + kind: ExpressionKind::Literal(IrLiteral { kind: LiteralKind::Nil, source: "Nil".into() }), }), span, }, @@ -2888,7 +2891,7 @@ pub fn main(input: String) -> String { result: Box::new(Expression { type_: Type::Nil, span, - kind: ExpressionKind::Literal(Literal { kind: LiteralKind::Nil, source: "Nil".into() }), + kind: ExpressionKind::Literal(IrLiteral { kind: LiteralKind::Nil, source: "Nil".into() }), }), span, }, diff --git a/crates/core/src/ir/lowerer.rs b/crates/core/src/ir/lowerer.rs index c7a2d48..0005a77 100644 --- a/crates/core/src/ir/lowerer.rs +++ b/crates/core/src/ir/lowerer.rs @@ -233,7 +233,7 @@ impl Lowerer { } if matches!( constant.value, - ConstantValue::Literal(Literal { kind: LiteralKind::String, .. }) + ConstantValue::Literal(IrLiteral { kind: LiteralKind::String, .. }) ) { init.steps .push(InitStep::StaticData { name: constant.name.clone(), span: constant.span }); @@ -594,7 +594,7 @@ impl Lowerer { ast::Expression::Literal(literal) => Some(Expression { type_: Type::from(&literal.kind), span: literal.span, - kind: ExpressionKind::Literal(Literal { kind: literal.kind.clone(), source: literal.source.clone() }), + kind: ExpressionKind::Literal(IrLiteral { kind: literal.kind.clone(), source: literal.source.clone() }), }), ast::Expression::Variable(name) => { if let Some(local) = context.lookup(&name.text) { @@ -1407,23 +1407,23 @@ impl Lowerer { context.bind(name.text.clone(), local.id); Some(IrPattern::Binding(local.id)) } - Pattern::Integer(literal) => Some(IrPattern::Literal(Literal { + Pattern::Integer(literal) => Some(IrPattern::Literal(IrLiteral { kind: LiteralKind::Int, source: literal.source.clone(), })), - Pattern::Float(literal) => Some(IrPattern::Literal(Literal { + Pattern::Float(literal) => Some(IrPattern::Literal(IrLiteral { kind: LiteralKind::Float, source: literal.source.clone(), })), - Pattern::String(literal) => Some(IrPattern::Literal(Literal { + Pattern::String(literal) => Some(IrPattern::Literal(IrLiteral { kind: LiteralKind::String, source: literal.source.clone(), })), - Pattern::Bool(literal) => Some(IrPattern::Literal(Literal { + Pattern::Bool(literal) => Some(IrPattern::Literal(IrLiteral { kind: LiteralKind::Bool, source: literal.source.clone(), })), - Pattern::Nil(literal) => Some(IrPattern::Literal(Literal { + Pattern::Nil(literal) => Some(IrPattern::Literal(IrLiteral { kind: LiteralKind::Nil, source: literal.source.clone(), })), @@ -1525,7 +1525,7 @@ impl Lowerer { Expression { type_: Type::Nil, span, - kind: ExpressionKind::Literal(Literal { kind: LiteralKind::Nil, source: "Nil".into() }), + kind: ExpressionKind::Literal(IrLiteral { kind: LiteralKind::Nil, source: "Nil".into() }), } } @@ -1775,7 +1775,7 @@ impl Lowerer { fn ast_constant_value(&self, expression: &ast::Expression) -> ConstantValue { match expression { ast::Expression::Literal(literal) => { - ConstantValue::Literal(Literal { kind: literal.kind.clone(), source: literal.source.clone() }) + ConstantValue::Literal(IrLiteral { kind: literal.kind.clone(), source: literal.source.clone() }) } _ => ConstantValue::Raw(format!("{expression:?}")), } diff --git a/crates/core/src/ir/snapshots/compiler_core__ir__lowerer__tests__core_control_flow_ir.snap b/crates/core/src/ir/snapshots/compiler_core__ir__lowerer__tests__core_control_flow_ir.snap index abf3b36..2584f6c 100644 --- a/crates/core/src/ir/snapshots/compiler_core__ir__lowerer__tests__core_control_flow_ir.snap +++ b/crates/core/src/ir/snapshots/compiler_core__ir__lowerer__tests__core_control_flow_ir.snap @@ -1,6 +1,6 @@ --- source: crates/core/src/ir/lowerer.rs -assertion_line: 2956 +assertion_line: 2620 expression: module --- Module { @@ -539,7 +539,7 @@ Module { end: 114, }, kind: Literal( - Literal { + IrLiteral { kind: Int, source: "1", }, @@ -582,7 +582,7 @@ Module { end: 114, }, kind: Literal( - Literal { + IrLiteral { kind: Int, source: "1", }, diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 39546fa..412efff 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -74,8 +74,7 @@ pub fn compile_source_with_options(source: SourceFile, options: CompileOptions) let ast = target::select_module(ast, options.target)?; let resolved = resolve::resolve(ast)?; let typed = types::check(resolved)?; - let ir = ir::lower(typed)?; - + let ir = typed.lower()?; Ok(CompileOutput { wasm: ir.emit_wasm_with_options(options.target.into())? }) } diff --git a/crates/core/src/types.rs b/crates/core/src/types.rs index a83df7a..d7c02f9 100644 --- a/crates/core/src/types.rs +++ b/crates/core/src/types.rs @@ -18,6 +18,7 @@ use crate::{ ConstraintGenerationError, ConstraintGenerator, Environment, Field, InferenceVariable, Scheme, Substitutions, TypeTerm, UnificationError, Unifier, }, + ir::{self, Module}, labels::{ArgumentLabelError, FunctionLabelMap, call_argument_order, function_label_map, use_callback_placement}, loader::registry::TypeInterfaceRegistry, project::{GleamToml, PackageGraph, PackageNode, Project}, @@ -340,6 +341,12 @@ pub struct TypedModule { pub module_name: Option, } +impl TypedModule { + pub fn lower(self) -> Result { + ir::lower(self) + } +} + #[derive(Debug, Clone, PartialEq, Eq)] pub struct TypedProject { pub package_name: String, diff --git a/crates/core/src/wasm/codegen.rs b/crates/core/src/wasm/codegen.rs index 91d9de4..4ba495f 100644 --- a/crates/core/src/wasm/codegen.rs +++ b/crates/core/src/wasm/codegen.rs @@ -1055,7 +1055,7 @@ impl<'a> StructuredEmitter<'a> { } } - fn literal(&mut self, literal: &ir::Literal, span: Span, out: &mut Vec) -> StructuredResult<()> { + fn literal(&mut self, literal: &ir::IrLiteral, span: Span, out: &mut Vec) -> StructuredResult<()> { match literal.kind { LiteralKind::Int => { let value = literal @@ -2286,7 +2286,7 @@ impl<'a> StructuredEmitter<'a> { } fn pattern_literal_test( - &mut self, subject: &PatternSubject<'_>, literal: &ir::Literal, out: &mut Vec, + &mut self, subject: &PatternSubject<'_>, literal: &ir::IrLiteral, out: &mut Vec, ) -> StructuredResult<()> { if subject.path.is_empty() { self.expression(subject.root, out)?; @@ -2902,7 +2902,7 @@ impl<'a> StructuredEmitter<'a> { } fn constant(&mut self, constant: &ir::Constant) -> StructuredResult<()> { - if let ir::ConstantValue::Literal(ir::Literal { kind: LiteralKind::String, source }) = &constant.value { + if let ir::ConstantValue::Literal(ir::IrLiteral { kind: LiteralKind::String, source }) = &constant.value { let string = source.trim_matches('"'); self.push_static(runtime::string_object(self.config, self.next_static_offset, string)); } @@ -3040,7 +3040,7 @@ fn invariant_diagnostics(module: &ir::Module, message: &str) -> Diagnostics { ] } -fn literal_parse_diagnostic(literal: &ir::Literal, span: Span, expected: &'static str) -> StructuredError { +fn literal_parse_diagnostic(literal: &ir::IrLiteral, span: Span, expected: &'static str) -> StructuredError { let kind = match literal.kind { LiteralKind::Int => "int", LiteralKind::Float => "float", @@ -3060,7 +3060,7 @@ fn literal_parse_diagnostic(literal: &ir::Literal, span: Span, expected: &'stati ]) } -fn literal_type(literal: &ir::Literal) -> Type { +fn literal_type(literal: &ir::IrLiteral) -> Type { match literal.kind { LiteralKind::Int => Type::Int, LiteralKind::Float => Type::Float, diff --git a/crates/core/src/wasm/tests.rs b/crates/core/src/wasm/tests.rs index e74a6df..59a95c1 100644 --- a/crates/core/src/wasm/tests.rs +++ b/crates/core/src/wasm/tests.rs @@ -13,7 +13,7 @@ fn lower_ir(source: &str) -> ir::Module { let ast = ast::build(&cst).expect("build ast"); let resolved = resolve::resolve(ast).expect("resolve names"); let typed = types::check(resolved).expect("type check source"); - ir::lower(typed).expect("lower source") + typed.lower().expect("lower source") } fn compile_wasm(source: &str) -> WasmModule { @@ -39,7 +39,7 @@ fn int_expr(source: &str, span: Span) -> ir::Expression { ir::Expression { type_: Type::Int, span, - kind: ExpressionKind::Literal(ir::Literal { kind: LiteralKind::Int, source: source.into() }), + kind: ExpressionKind::Literal(ir::IrLiteral { kind: LiteralKind::Int, source: source.into() }), } } @@ -565,7 +565,7 @@ fn literal_parse_failures_report_source_spanned_diagnostics() { let result = ir::Expression { type_: Type::Int, span, - kind: ExpressionKind::Literal(ir::Literal { kind: LiteralKind::Int, source: "nope".into() }), + kind: ExpressionKind::Literal(ir::IrLiteral { kind: LiteralKind::Int, source: "nope".into() }), }; let function = exported_function_with_body("bad", &Type::Int, result, span); assert_emit_wasm_error(&ir_module(vec![function], span), "invalid int literal", span); @@ -577,7 +577,7 @@ fn static_value_parse_failures_report_source_spanned_diagnostics() { let bad_field = ir::Expression::new( Type::Int, span, - ExpressionKind::Literal(ir::Literal { kind: LiteralKind::Int, source: "nope".into() }), + ExpressionKind::Literal(ir::IrLiteral { kind: LiteralKind::Int, source: "nope".into() }), ); let result = ir::Expression::new( Type::Tuple(vec![Type::Int]), @@ -1363,7 +1363,7 @@ fn generic_expr(span: Span) -> ir::Expression { ir::Expression { type_: Type::Generic("a".into()), span, - kind: ExpressionKind::Literal(ir::Literal { kind: LiteralKind::Int, source: "1".into() }), + kind: ExpressionKind::Literal(ir::IrLiteral { kind: LiteralKind::Int, source: "1".into() }), } } @@ -1389,7 +1389,7 @@ fn residual_generic_debug_reports_source_spanned_diagnostic() { ir::Expression { type_: Type::Int, span, - kind: ExpressionKind::Literal(ir::Literal { kind: LiteralKind::Int, source: "0".into() }), + kind: ExpressionKind::Literal(ir::IrLiteral { kind: LiteralKind::Int, source: "0".into() }), }, span, ); diff --git a/docs/book/src/chapter_9/pass_pipeline_invariants.md b/docs/book/src/chapter_9/pass_pipeline_invariants.md index 6367e01..da5a4de 100644 --- a/docs/book/src/chapter_9/pass_pipeline_invariants.md +++ b/docs/book/src/chapter_9/pass_pipeline_invariants.md @@ -12,13 +12,13 @@ is neither pure analysis nor a normal program transformation.[^llvm-passes] Regulus is small, but the same categories already fit: -| Regulus work | Category | -| --------------- | ------------------------------------ | -| Name resolution | analysis over AST | -| Type checking | analysis plus checked annotations | -| Lowering | transformation from typed AST to IR | -| WAT emission | artifact-producing backend pass | -| Debug dumps | utility output | +| Regulus work | Category | +| --------------- | ----------------------------------- | +| Name resolution | analysis over AST | +| Type checking | analysis plus checked annotations | +| Lowering | transformation from typed AST to IR | +| WAT emission | artifact-producing backend pass | +| Debug dumps | utility output | ## Invariants @@ -114,7 +114,7 @@ let cst = parse::parse(source)?; let ast = ast::build(&cst)?; let resolved = resolve::resolve(ast)?; let typed = types::check(resolved)?; -let ir = ir::lower(typed)?; +let ir = typed.lower()?; let wasm = wasm::emit(&ir)?; ```