From a29a7f9463cb92ca80375e857787cb85e28bcf76 Mon Sep 17 00:00:00 2001 From: Andrew Segavac Date: Sun, 22 Aug 2021 15:54:48 -0600 Subject: [PATCH] added type alias resolution to rust version --- src/hir/body.rs | 0 src/hir/errors.rs | 31 ----- src/hir/types.rs | 157 --------------------- src/main.rs | 4 + src/type_alias_resolution.rs | 257 +++++++++++++++++++++++++++++++++++ src/type_checker.rs | 74 ---------- 6 files changed, 261 insertions(+), 262 deletions(-) delete mode 100644 src/hir/body.rs delete mode 100644 src/hir/errors.rs delete mode 100644 src/hir/types.rs create mode 100644 src/type_alias_resolution.rs delete mode 100644 src/type_checker.rs diff --git a/src/hir/body.rs b/src/hir/body.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/hir/errors.rs b/src/hir/errors.rs deleted file mode 100644 index fe72650..0000000 --- a/src/hir/errors.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::error::Error; -use std::fmt; - - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum ErrorLabel { - Primary, - Secondary, -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct ErrorPart { - pub message: String, - pub label_type: ErrorLabel, - pub start: i64 - pub end: i64 -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct CompilerError { - pub message: String, - pub parts: Vec, -} - - - -impl fmt::Display for CompilerError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, self.message) - } -} diff --git a/src/hir/types.rs b/src/hir/types.rs deleted file mode 100644 index 2045750..0000000 --- a/src/hir/types.rs +++ /dev/null @@ -1,157 +0,0 @@ -use inkwell::values::{BasicValueEnum, FunctionValue, IntValue}; -use inkwell::context::Context; -use crate::ast; -use crate::hir:errors; - - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Signedness { - Signed, - Unsigned, -} - - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum IntBitness { - X8, - X16, - X32, - X64, - X128, -} - - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum FloatBitness { - X32, - X64, - X128, -} - - -#[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct IntTypeDef { - pub signedness: Signedness, - pub bitness: IntBitness, -} - - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct FloatTypeDef { - pub bitness: FloatBitness, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub struct FunctionTypeDef { - pub arguments: Vec, - pub return_type: Type, -} - - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -pub enum Type { - Bool, - Int(IntTypeDef), - Float(FloatTypeDef), - Function(FunctionTypeDef), - // String(StringTypeDef), - // Struct(StructTypeDef), - // Trait(TraitTypeDef), - // Void, - // Never, -} - -impl Type { - /// Construct an inkwell value for this type. Will eventually take in a list of types for - /// generic params. - pub fn construct(&self, context: Context) -> BasicValueEnum { - match self { - Bool => context.bool_type(), - Int(type_def) => { - // Signed + Unsigned use the same size, builder operations determine signedness - match type_def.bitness { - X8 => context.i8_type(), - X16 => context.i16_type(), - X32 => context.i32_type(), - X64 => context.i64_type(), - X128 => context.i128_type(), - } - }, - Float(type_def) => { - match type_def.bitness { - X32 => context.f32_type(), - X64 => context.f64_type(), - X128 => context.f128_type(), - } - }, - Function(type_def) => { - let return_type = type_def.return_type.construct(context); - let mut args = Vec::new(); - for arg in &type_def.arguments { - args.push(arg.construct(context)); - } - return_type.fn_type(&args, false) - }, - } - } -} - - -/// Used for places where type info may or may not be solved. -#[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub enum SpecifiedType { - Unknown, - Type(Type), -} - -/// Used by HIR in any place that needs a type. Allows `Unknown` types for places that haven't -/// been solved yet, and will verify/solve types via the `Compare` method. This will also -/// eventually contain info from escape analysis for if it will need to be created on the stack. -#[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct TypeLocation { - pub specified_type: SpecifiedType, - // pub type_parameters: Vec, // will be used for generics - pub span: ast::Span, -} - -impl TypeLocation { - // Checks if the types are valid to be used this way, returns true - // if we updated an unknown. - pub fn compare(&mut self, other: &mut Self) -> Result { - match self.specified_type { - SpecifiedType::Unknown => match other.specified_type { - SpecifiedType::Unknown => false, - SpecifiedType::Type(ty) => { - self.specified_type = ty; - true - }, - }, - SpecifiedType::Type(ty) => match other.specified_type { - SpecifiedType::Unknown => { - other.specified_type = ty; - true - }, - SpecifiedType::Type(other_ty) => { - if ty == other_ty { - false - } else { - Err(errors::CompilerError{ - message: "types do not match", - parts: vec![errors::ErrorPart{ - message: format!("type {} must match", self.specified_type), - label_type: errors::ErrorLabel::Primary, - start: self.span.left, - end: self.span.right, - }, errors::ErrorPart{ - message: format!("type {}", other.specified_type), - label_type: errors::ErrorLabel::Primary, - start: other.span.left, - end: other.span.right, - }], - }) - } - } - } - } - } -} diff --git a/src/main.rs b/src/main.rs index 054d59c..82d4876 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ // mod types; mod ast; +mod type_alias_resolution; #[macro_use] extern crate lalrpop_util; lalrpop_mod!(pub grammar); // synthesized by LALRPOP @@ -41,6 +42,9 @@ fn main() { let unknown_id_gen = ast::IdGenerator::new(); let module_ast = grammar::ModuleParser::new().parse(&unknown_id_gen, &contents).unwrap(); //TODO: convert to error println!("ast: {:#?}", &module_ast); + let alias_resolver = type_alias_resolution::TypeAliasResolver{}; + let resolved_ast = alias_resolver.with_module(&module_ast); + println!("ast: {:#?}", &resolved_ast); // let context = Context::create(); diff --git a/src/type_alias_resolution.rs b/src/type_alias_resolution.rs new file mode 100644 index 0000000..a40a80a --- /dev/null +++ b/src/type_alias_resolution.rs @@ -0,0 +1,257 @@ +use crate::ast; + + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct Context { + pub type_aliases: Vec, +} + +fn resolve_type(ctx: &Context, type_: &ast::NamedTypeUsage) -> ast::TypeUsage { + let mut changed = true; + let mut result = ast::TypeUsage::Named(type_.clone()); + while changed { + changed = false; + let current = &result.clone(); + match current { + ast::TypeUsage::Named(named) => { + for alias in ctx.type_aliases.iter() { + if named.name.name.value == alias.name.name.value { + changed = true; + result = alias.replaces.clone(); + } + } + }, + _ => break, + } + } + return result; +} + +fn process_type(ctx: &Context, type_: &ast::TypeUsage) -> ast::TypeUsage { + match type_ { + ast::TypeUsage::Named(named) => { + return resolve_type(ctx, named); + }, + ast::TypeUsage::Function(function) => { + return ast::TypeUsage::Function(ast::FunctionTypeUsage{ + arguments: function.arguments.iter().map(|a|{process_type(ctx, &a.clone())}).collect(), + return_type: Box::new(process_type(ctx, &function.return_type.clone())), + }); + }, + ast::TypeUsage::Unknown(unknown) => { + return ast::TypeUsage::Unknown(unknown.clone()); + }, + } +} + +pub struct TypeAliasResolver {} + +impl TypeAliasResolver { + pub fn with_module(self: &Self, module: &ast::Module) -> ast::Module { + let mut ctx = Context{ + type_aliases: vec!(), + }; + for item in module.items.iter() { + match item { + ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Alias(alias)) => { + ctx.type_aliases.push(alias.clone()); + }, + _ => {}, + } + } + + return ast::Module{ + items: module.items.iter().map(|item|{ + match item { + ast::ModuleItem::Function(function) => { + ast::ModuleItem::Function(self.with_function(&ctx, function)) + }, + ast::ModuleItem::TypeDeclaration(type_declaration) => { + ast::ModuleItem::TypeDeclaration(self.with_type_declaration(&ctx, type_declaration)) + }, + ast::ModuleItem::Impl(impl_) => { + ast::ModuleItem::Impl(self.with_impl(&ctx, impl_)) + }, + } + }).collect() + }; + } + + fn with_function(self: &Self, ctx: &Context, function: &ast::Function) -> ast::Function { + return ast::Function{ + declaration: ast::FunctionDeclaration{ + name: function.declaration.name.clone(), + arguments: function.declaration.arguments.iter().map(|arg| { + ast::VariableDeclaration{name: arg.name.clone(), type_: process_type(ctx, &arg.type_)} + }).collect(), + return_type: process_type(ctx, &function.declaration.return_type), + }, + block: self.with_block(ctx, &function.block), + }; + } + + fn with_type_declaration(self: &Self, ctx: &Context, type_declaration: &ast::TypeDeclaration) -> ast::TypeDeclaration { + match type_declaration { + ast::TypeDeclaration::Struct(struct_) => { + return ast::TypeDeclaration::Struct(self.with_struct_declaration(ctx, struct_)); + }, + ast::TypeDeclaration::Primitive(primitive) => { + return ast::TypeDeclaration::Primitive(primitive.clone()); + }, + ast::TypeDeclaration::Alias(alias) => { + return ast::TypeDeclaration::Alias(alias.clone()); + }, + } + } + + fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> ast::StructTypeDeclaration { + return ast::StructTypeDeclaration{ + name: struct_.name.clone(), + fields: struct_.fields.iter().map(|field|{ + ast::StructField{ + name: field.name.clone(), + type_: process_type(ctx, &field.type_), + } + }).collect(), + }; + } + + fn with_impl(self: &Self, ctx: &Context, impl_: &ast::Impl) -> ast::Impl { + let mut impl_ctx = ctx.clone(); + impl_ctx.type_aliases.push(ast::AliasTypeDeclaration{ + name: ast::Identifier{ + name: ast::Spanned{ + span: ast::Span{left: 0, right: 0}, //todo: figure out a sane value for these + value: "Self".to_string(), + } + }, + replaces: ast::TypeUsage::Named(ast::NamedTypeUsage{name: impl_.struct_name.clone()}) + }); + return ast::Impl{ + struct_name: impl_.struct_name.clone(), + functions: impl_.functions.iter().map(|f|{ + self.with_function(&impl_ctx, f) + }).collect(), + }; + } + + fn with_block(self: &Self, ctx: &Context, block: &ast::Block) -> ast::Block { + return ast::Block{ + statements: block.statements.iter().map(|s| { + self.with_statement(ctx, s) + }).collect(), + type_: process_type(ctx, &block.type_), + }; + } + + fn with_statement(self: &Self, ctx: &Context, statement: &ast::Statement) -> ast::Statement { + match statement { + ast::Statement::Return(return_statement) => { + return ast::Statement::Return(self.with_return_statement(ctx, return_statement)); + }, + ast::Statement::Let(let_statement) => { + return ast::Statement::Let(self.with_let_statement(ctx, let_statement)); + }, + ast::Statement::Assignment(assignment_statement) => { + return ast::Statement::Assignment(self.with_assignment_statement(ctx, assignment_statement)); + }, + ast::Statement::Expression(expression) => { + return ast::Statement::Expression(self.with_expression(ctx, expression)); + }, + } + } + + fn with_return_statement(self: &Self, ctx: &Context, statement: &ast::ReturnStatement) -> ast::ReturnStatement { + return ast::ReturnStatement{ + source: self.with_expression(ctx, &statement.source), + }; + } + + fn with_let_statement(self: &Self, ctx: &Context, statement: &ast::LetStatement) -> ast::LetStatement { + return ast::LetStatement{ + variable_name: statement.variable_name.clone(), + expression: self.with_expression(ctx, &statement.expression), + type_: process_type(ctx, &statement.type_), + }; + } + + fn with_assignment_statement(self: &Self, ctx: &Context, statement: &ast::AssignmentStatement) -> ast::AssignmentStatement { + return ast::AssignmentStatement{ + source: match &statement.source { + ast::AssignmentTarget::Variable(variable) => { + ast::AssignmentTarget::Variable(ast::VariableUsage{ + name: variable.name.clone(), + type_: process_type(ctx, &variable.type_), + }) + }, + ast::AssignmentTarget::StructAttr(struct_attr) => { + ast::AssignmentTarget::StructAttr(ast::StructGetter{ + source: self.with_expression(ctx, &struct_attr.source), + attribute: struct_attr.attribute.clone(), + type_: process_type(ctx, &struct_attr.type_) + }) + }, + }, + expression: self.with_expression(ctx, &statement.expression), + } + } + + fn with_expression(self: &Self, ctx: &Context, expression: &ast::Expression) -> ast::Expression { + return ast::Expression{ + subexpression: Box::new(match &*expression.subexpression { + ast::Subexpression::LiteralInt(literal_int) => { + ast::Subexpression::LiteralInt(ast::LiteralInt{ + value: literal_int.value.clone(), + type_: process_type(ctx, &literal_int.type_), + }) + }, + ast::Subexpression::LiteralFloat(literal_float) => { + ast::Subexpression::LiteralFloat(ast::LiteralFloat{ + value: literal_float.value.clone(), + type_: process_type(ctx, &literal_float.type_), + }) + }, + ast::Subexpression::LiteralStruct(literal_struct) => { + ast::Subexpression::LiteralStruct(ast::LiteralStruct{ + name: literal_struct.name.clone(), + fields: literal_struct.fields.iter().map(|field|{ + (field.0.clone(), self.with_expression(ctx, &field.1)) + }).collect(), + type_: process_type(ctx, &literal_struct.type_), + }) + }, + ast::Subexpression::FunctionCall(function_call) => { + ast::Subexpression::FunctionCall(ast::FunctionCall{ + source: self.with_expression(ctx, &function_call.source), + arguments: function_call.arguments.iter().map(|arg| {self.with_expression(ctx, arg)}).collect(), + type_: process_type(ctx, &function_call.type_) + }) + }, + ast::Subexpression::VariableUsage(variable_usage) => { + ast::Subexpression::VariableUsage(ast::VariableUsage{ + name: variable_usage.name.clone(), + type_: process_type(ctx, &variable_usage.type_) + }) + }, + ast::Subexpression::StructGetter(struct_getter) => { + ast::Subexpression::StructGetter(ast::StructGetter{ + source: self.with_expression(ctx, &struct_getter.source), + attribute: struct_getter.attribute.clone(), + type_: process_type(ctx, &struct_getter.type_), + }) + }, + ast::Subexpression::Block(block) => { + ast::Subexpression::Block(self.with_block(ctx, &block)) + }, + ast::Subexpression::Op(op) => { + ast::Subexpression::Op(ast::Operation{ + left: self.with_expression(ctx, &op.left), + op: op.op.clone(), + right: self.with_expression(ctx, &op.right), + }) + }, + }), + type_: process_type(ctx, &expression.type_), + } + } +} diff --git a/src/type_checker.rs b/src/type_checker.rs deleted file mode 100644 index 4079127..0000000 --- a/src/type_checker.rs +++ /dev/null @@ -1,74 +0,0 @@ -use std::collections::HashMap; -use crate::types; -use crate::ast; - - - -pub struct TypeChecker {} - - -impl TypeChecker { - pub fn check_module(&self, types_defs: HashMap, module: &mut ast::Module) -> Result { - let mut update = false; - for function in module.functions { - let update_here = self.check_function(&mut function)?; - if update_here { - update = true; - } - } - return update; - } - - pub fn check_function(&self, function: &mut ast::Function) -> Result { - let mut update = false; - for argument in function.arguments { - let update_here = self.check_variable_declaration(argument)?; - if update_here { - update = true; - } - } - let update_here = self.check_variable_declaration(function.return_type)?; - if update_here { - update = true; - } - let update_here = self.check_block(function.block)?; - return update; - } - - pub fn check_variable_declaration(&self, declaration: &mut ast::Spanned) -> Result { - return self.check_type_usage(&self, declaration.value.type_usage)?; - } - - pub fn check_type_usage(&self, usage: &mut ast::Spanned) { - match usage.value.identifier.value.name { - "Int8" => { - let def = IntTypeDef{ - signedness: types::Signedness::Signed, - bitness: types::IntBitness::X8, - } - usage.ty = types::SpecifiedType::Type(types::Type::Int(def)) - }, - "Int16" => { - let def = IntTypeDef{ - signedness: types::Signedness::Signed, - bitness: types::IntBitness::X16, - } - usage.ty = types::SpecifiedType::Type(types::Type::Int(def)) - }, - "Int32" => { - let def = IntTypeDef{ - signedness: types::Signedness::Signed, - bitness: types::IntBitness::X32, - } - usage.ty = types::SpecifiedType::Type(types::Type::Int(def)) - }, - "Int64" => { - let def = IntTypeDef{ - signedness: types::Signedness::Signed, - bitness: types::IntBitness::X32, - } - usage.ty = types::SpecifiedType::Type(types::Type::Int(def)) - }, - } - } -}