diff --git a/src/ast.rs b/src/ast.rs index 3db5fcb..3913a25 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -6,7 +6,9 @@ pub struct IdGenerator { impl IdGenerator { pub fn new() -> Self { - IdGenerator{counter: RefCell::new(0)} + IdGenerator { + counter: RefCell::new(0), + } } pub fn next(&self) -> String { @@ -16,32 +18,31 @@ impl IdGenerator { } pub fn new_unit() -> TypeUsage { - TypeUsage::Named(NamedTypeUsage{ - name: Identifier{ - name: Spanned{ - span: Span{left: 0, right: 0}, //todo: figure out a sane value for these + TypeUsage::Named(NamedTypeUsage { + name: Identifier { + name: Spanned { + span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these value: "unit".to_string(), - } - } + }, + }, }) } pub fn new_never() -> TypeUsage { - TypeUsage::Named(NamedTypeUsage{ - name: Identifier{ - name: Spanned{ - span: Span{left: 0, right: 0}, //todo: figure out a sane value for these + TypeUsage::Named(NamedTypeUsage { + name: Identifier { + name: Spanned { + span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these value: "!".to_string(), - } - } + }, + }, }) } - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Span { pub left: usize, - pub right: usize + pub right: usize, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -50,7 +51,6 @@ pub struct Spanned { pub value: T, } - #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FunctionTypeUsage { pub arguments: Vec, @@ -76,31 +76,33 @@ pub enum TypeUsage { impl TypeUsage { pub fn new_unknown(id_gen: &IdGenerator) -> TypeUsage { - return TypeUsage::Unknown(UnknownTypeUsage{ + return TypeUsage::Unknown(UnknownTypeUsage { name: id_gen.next(), }); } pub fn new_named(identifier: Identifier) -> TypeUsage { - return TypeUsage::Named(NamedTypeUsage{ + return TypeUsage::Named(NamedTypeUsage { name: identifier.clone(), }); } pub fn new_builtin(name: String) -> TypeUsage { - TypeUsage::Named(NamedTypeUsage{ - name: Identifier{ - name: Spanned{ - span: Span{left: 0, right: 0}, //todo: figure out a sane value for these + TypeUsage::Named(NamedTypeUsage { + name: Identifier { + name: Spanned { + span: Span { left: 0, right: 0 }, //todo: figure out a sane value for these value: name, - } - } + }, + }, }) } pub fn new_function(arg_count: usize, id_gen: &IdGenerator) -> TypeUsage { - return TypeUsage::Function(FunctionTypeUsage{ - arguments: (0..arg_count).map(|_| TypeUsage::new_unknown(&id_gen)).collect(), + return TypeUsage::Function(FunctionTypeUsage { + arguments: (0..arg_count) + .map(|_| TypeUsage::new_unknown(&id_gen)) + .collect(), return_type: Box::new(TypeUsage::new_unknown(&id_gen)), }); } diff --git a/src/compiler.rs b/src/compiler.rs index 1c14e82..56ab103 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,10 +1,10 @@ -use std::collections::HashMap; -use std::mem; -use std::convert::TryInto; use inkwell::builder::Builder; use inkwell::context::Context; use inkwell::module::Module; use inkwell::values::{BasicValueEnum, FunctionValue, IntValue}; +use std::collections::HashMap; +use std::convert::TryInto; +use std::mem; use crate::ast; @@ -17,28 +17,39 @@ pub struct ModuleCodeGen<'ctx> { scope: Scope<'ctx>, } - impl<'ctx> ModuleCodeGen<'ctx> { pub fn new(context: &'ctx Context, name: String) -> Self { - return ModuleCodeGen{ + return ModuleCodeGen { context: context, module: context.create_module(&name), builder: context.create_builder(), scope: Scope::new(), - } + }; } pub fn gen_literal_int(&mut self, literal_int: &ast::LiteralInt) -> IntValue<'ctx> { - self.context.i64_type().const_int(unsafe { mem::transmute::(literal_int.value) }, true) + self.context.i64_type().const_int( + unsafe { mem::transmute::(literal_int.value) }, + true, + ) } - pub fn gen_op_expression(&mut self, scope: &Scope<'ctx>, operation: &ast::Operation) -> IntValue<'ctx> { + pub fn gen_op_expression( + &mut self, + scope: &Scope<'ctx>, + operation: &ast::Operation, + ) -> IntValue<'ctx> { let lhs_result = self.gen_expression(scope, &operation.left); let rhs_result = self.gen_expression(scope, &operation.right); self.gen_op_int(&lhs_result, &rhs_result, &operation.op) } - pub fn gen_op_int(&mut self, lhs: &IntValue<'ctx>, rhs: &IntValue<'ctx>, op: &ast::Operator) -> IntValue<'ctx> { + pub fn gen_op_int( + &mut self, + lhs: &IntValue<'ctx>, + rhs: &IntValue<'ctx>, + op: &ast::Operator, + ) -> IntValue<'ctx> { match *op { ast::Operator::Plus => self.builder.build_int_add(*lhs, *rhs, "add"), ast::Operator::Minus => self.builder.build_int_sub(*lhs, *rhs, "sub"), @@ -47,28 +58,40 @@ impl<'ctx> ModuleCodeGen<'ctx> { } } - pub fn gen_expression(&mut self, scope: &Scope<'ctx>, expression: &Box) -> IntValue<'ctx> { + pub fn gen_expression( + &mut self, + scope: &Scope<'ctx>, + expression: &Box, + ) -> IntValue<'ctx> { match &**expression { ast::Expression::LiteralInt(literal_int) => self.gen_literal_int(&literal_int), - ast::Expression::Identifier(identifier) => { - match scope[&identifier.name] { - BasicValueEnum::IntValue(value) => value, - _ => panic!("function returned type other than int, no types yet"), - } + ast::Expression::Identifier(identifier) => match scope[&identifier.name] { + BasicValueEnum::IntValue(value) => value, + _ => panic!("function returned type other than int, no types yet"), }, - ast::Expression::FunctionCall(function_call) => self.gen_function_call(scope, &function_call), + ast::Expression::FunctionCall(function_call) => { + self.gen_function_call(scope, &function_call) + } ast::Expression::Op(operation) => self.gen_op_expression(scope, &operation), } } - pub fn gen_function_call(&mut self, scope: &Scope<'ctx>, function_call: &ast::FunctionCall) -> IntValue<'ctx> { + pub fn gen_function_call( + &mut self, + scope: &Scope<'ctx>, + function_call: &ast::FunctionCall, + ) -> IntValue<'ctx> { let fn_value = self.module.get_function(&function_call.name.name).unwrap(); let mut arguments = Vec::new(); for expression in (&function_call.arguments).into_iter() { - arguments.push(BasicValueEnum::IntValue(self.gen_expression(scope, &expression))); + arguments.push(BasicValueEnum::IntValue( + self.gen_expression(scope, &expression), + )); } - let result = self.builder.build_call(fn_value, &arguments, &function_call.name.name) + let result = self + .builder + .build_call(fn_value, &arguments, &function_call.name.name) .try_as_basic_value() .left() .unwrap(); @@ -100,7 +123,10 @@ impl<'ctx> ModuleCodeGen<'ctx> { let mut scope = self.scope.clone(); for (i, param) in (&function.arguments).into_iter().enumerate() { - scope.insert(param.name.name.to_string(), fn_value.get_nth_param(i.try_into().unwrap()).unwrap()); + scope.insert( + param.name.name.to_string(), + fn_value.get_nth_param(i.try_into().unwrap()).unwrap(), + ); } let body = &function.block; let return_value = self.gen_expression(&scope, &body.expression); diff --git a/src/main.rs b/src/main.rs index e3948be..5d61767 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,8 @@ mod ast; mod type_alias_resolution; mod type_checking; -#[macro_use] extern crate lalrpop_util; +#[macro_use] +extern crate lalrpop_util; lalrpop_mod!(pub grammar); // synthesized by LALRPOP @@ -11,42 +12,54 @@ use std::io::Write; // mod compiler; // use inkwell::context::Context; extern crate clap; -use clap::{Arg, App}; - +use clap::{App, Arg}; fn main() { let matches = App::new("Boring Language Compiler") - .version("0.0.1") - .author("Andrew Segavac") - .about("Compiles boring language files to LLVM IR.") - .arg(Arg::with_name("OUTPUT") - .short("o") - .long("out") - .value_name("OUTOUT") - .help("Sets an output file") - .takes_value(true)) - .arg(Arg::with_name("INPUT") - .help("Sets the input file") - .required(true) - .index(1)) - .arg(Arg::with_name("v") - .short("v") - .multiple(true) - .help("Sets the level of verbosity")) - .get_matches(); + .version("0.0.1") + .author("Andrew Segavac") + .about("Compiles boring language files to LLVM IR.") + .arg( + Arg::with_name("OUTPUT") + .short("o") + .long("out") + .value_name("OUTOUT") + .help("Sets an output file") + .takes_value(true), + ) + .arg( + Arg::with_name("INPUT") + .help("Sets the input file") + .required(true) + .index(1), + ) + .arg( + Arg::with_name("v") + .short("v") + .multiple(true) + .help("Sets the level of verbosity"), + ) + .get_matches(); let input = matches.value_of("INPUT").unwrap(); - let default_output = input.rsplitn(2, ".").collect::>().last().unwrap().clone(); + let default_output = input + .rsplitn(2, ".") + .collect::>() + .last() + .unwrap() + .clone(); let output = matches.value_of("OUTPUT").unwrap_or(default_output); let contents = fs::read_to_string(input).expect("input file not found"); let unknown_id_gen = ast::IdGenerator::new(); - let module_ast = grammar::ModuleParser::new().parse(&unknown_id_gen, &contents).unwrap(); //TODO: convert to error + 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 alias_resolver = type_alias_resolution::TypeAliasResolver {}; let resolved_ast = alias_resolver.with_module(&module_ast); println!("resolved ast: {:#?}", &resolved_ast); - let type_checker = type_checking::TypeChecker{}; + let type_checker = type_checking::TypeChecker {}; let (checked_ast, subst) = type_checker.with_module(&resolved_ast); println!("checked ast: {:#?}", &checked_ast); println!("substitutions: {:#?}", &subst); @@ -59,37 +72,70 @@ fn main() { // f.write_all(code_gen.dump().as_bytes()).expect("Unable to write data"); } - #[test] fn grammar() { let id_gen = ast::IdGenerator::new(); - assert!(grammar::LiteralIntParser::new().parse(&id_gen, "22").is_ok()); - assert!(grammar::IdentifierParser::new().parse(&id_gen, "foo").is_ok()); - assert!(grammar::LiteralIntParser::new().parse(&id_gen, "2a").is_err()); + assert!(grammar::LiteralIntParser::new() + .parse(&id_gen, "22") + .is_ok()); + assert!(grammar::IdentifierParser::new() + .parse(&id_gen, "foo") + .is_ok()); + assert!(grammar::LiteralIntParser::new() + .parse(&id_gen, "2a") + .is_err()); assert!(grammar::TermParser::new().parse(&id_gen, "22").is_ok()); assert!(grammar::TermParser::new().parse(&id_gen, "foo").is_ok()); - assert!(grammar::ExpressionParser::new().parse(&id_gen, "22 * foo").is_ok()); - assert!(grammar::ExpressionParser::new().parse(&id_gen, "22 * 33").is_ok()); - assert!(grammar::ExpressionParser::new().parse(&id_gen, "(22 * 33) + 24").is_ok()); + assert!(grammar::ExpressionParser::new() + .parse(&id_gen, "22 * foo") + .is_ok()); + assert!(grammar::ExpressionParser::new() + .parse(&id_gen, "22 * 33") + .is_ok()); + assert!(grammar::ExpressionParser::new() + .parse(&id_gen, "(22 * 33) + 24") + .is_ok()); - assert!(grammar::BlockParser::new().parse(&id_gen, "{ (22 * 33) + 24 }").is_ok()); - assert!(grammar::BlockParser::new().parse(&id_gen, "{ (22 * 33) + 24; 25 }").is_ok()); + assert!(grammar::BlockParser::new() + .parse(&id_gen, "{ (22 * 33) + 24 }") + .is_ok()); + assert!(grammar::BlockParser::new() + .parse(&id_gen, "{ (22 * 33) + 24; 25 }") + .is_ok()); // assert!(grammar::BlockParser::new().parse("{ (22 * 33) + 24\n 24 }").is_ok()); assert!(grammar::BlockParser::new().parse(&id_gen, "{ }").is_ok()); - assert!(grammar::VariableDeclarationParser::new().parse(&id_gen, "foo: Int32").is_ok()); - assert!(grammar::VariableDeclarationParser::new().parse(&id_gen, "foo").is_err()); - assert!(grammar::VariableDeclarationParser::new().parse(&id_gen, "1234").is_err()); + assert!(grammar::VariableDeclarationParser::new() + .parse(&id_gen, "foo: Int32") + .is_ok()); + assert!(grammar::VariableDeclarationParser::new() + .parse(&id_gen, "foo") + .is_err()); + assert!(grammar::VariableDeclarationParser::new() + .parse(&id_gen, "1234") + .is_err()); - assert!(grammar::FunctionParser::new().parse(&id_gen, "fn add(a: Int32, b: Int32): Int32 { a + b }").is_ok()); - assert!(grammar::FunctionParser::new().parse(&id_gen, "fn random_dice_roll(): Int32 { 4 }").is_ok()); - assert!(grammar::FunctionParser::new().parse(&id_gen, "fn add(a: Int32, b: Int32): Int32 { a + }").is_err()); - assert!(grammar::FunctionParser::new().parse(&id_gen, "fn add(a: Int32, b: Int32): Int32").is_err()); + assert!(grammar::FunctionParser::new() + .parse(&id_gen, "fn add(a: Int32, b: Int32): Int32 { a + b }") + .is_ok()); + assert!(grammar::FunctionParser::new() + .parse(&id_gen, "fn random_dice_roll(): Int32 { 4 }") + .is_ok()); + assert!(grammar::FunctionParser::new() + .parse(&id_gen, "fn add(a: Int32, b: Int32): Int32 { a + }") + .is_err()); + assert!(grammar::FunctionParser::new() + .parse(&id_gen, "fn add(a: Int32, b: Int32): Int32") + .is_err()); - assert!(grammar::FunctionCallParser::new().parse(&id_gen, "foo(1, 2)").is_ok()); + assert!(grammar::FunctionCallParser::new() + .parse(&id_gen, "foo(1, 2)") + .is_ok()); - assert!(grammar::ModuleParser::new().parse(&id_gen, "fn add(a: Int32, b: Int32): Int32 { a + b }").is_ok()); + assert!(grammar::ModuleParser::new() + .parse(&id_gen, "fn add(a: Int32, b: Int32): Int32 { a + b }") + .is_ok()); assert!(grammar::ModuleParser::new().parse(&id_gen, "fn add(a: Int32, b: Int32): Int32 { a + b } fn subtract(a: Int32, b: Int32): Int32 { a - b }").is_ok()); } diff --git a/src/type_alias_resolution.rs b/src/type_alias_resolution.rs index 9e46052..ecb3588 100644 --- a/src/type_alias_resolution.rs +++ b/src/type_alias_resolution.rs @@ -1,6 +1,5 @@ use crate::ast; - #[derive(Debug, Clone, PartialEq, Eq, Hash)] struct Context { pub type_aliases: Vec, @@ -20,7 +19,7 @@ fn resolve_type(ctx: &Context, type_: &ast::NamedTypeUsage) -> ast::TypeUsage { result = alias.replaces.clone(); } } - }, + } _ => break, } } @@ -31,16 +30,20 @@ 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 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()); - }, + } } } @@ -48,98 +51,124 @@ pub struct TypeAliasResolver {} impl TypeAliasResolver { pub fn with_module(self: &Self, module: &ast::Module) -> ast::Module { - let mut ctx = Context{ - type_aliases: vec!(), + 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 { + 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::TypeDeclaration( + self.with_type_declaration(&ctx, type_declaration), + ) + } ast::ModuleItem::Impl(impl_) => { ast::ModuleItem::Impl(self.with_impl(&ctx, impl_)) - }, - } - }).collect() + } + }) + .collect(), }; } fn with_function(self: &Self, ctx: &Context, function: &ast::Function) -> ast::Function { - return ast::Function{ - declaration: ast::FunctionDeclaration{ + 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(), + 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 { + 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{ + 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{ + fields: struct_ + .fields + .iter() + .map(|field| ast::StructField { name: field.name.clone(), type_: process_type(ctx, &field.type_), - } - }).collect(), + }) + .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(), - } + 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()}) + replaces: ast::TypeUsage::Named(ast::NamedTypeUsage { + name: impl_.struct_name.clone(), + }), }); - return ast::Impl{ + return ast::Impl { struct_name: impl_.struct_name.clone(), - functions: impl_.functions.iter().map(|f|{ - self.with_function(&impl_ctx, f) - }).collect(), + 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(), + return ast::Block { + statements: block + .statements + .iter() + .map(|s| self.with_statement(ctx, s)) + .collect(), type_: process_type(ctx, &block.type_), }; } @@ -148,115 +177,142 @@ impl TypeAliasResolver { 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)); - }, + 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{ + 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{ + 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{ + 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{ + 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{ + 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_) + 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{ + 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{ + 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{ + ast::Subexpression::LiteralFloat(ast::LiteralFloat { value: literal_float.value.clone(), type_: process_type(ctx, &literal_float.type_), }) - }, + } ast::Subexpression::LiteralStruct(literal_struct) => { - let result = resolve_type(ctx, &ast::NamedTypeUsage{name: literal_struct.name.clone()}); + let result = resolve_type( + ctx, + &ast::NamedTypeUsage { + name: literal_struct.name.clone(), + }, + ); let new_name = match &result { - ast::TypeUsage::Named(named) => { named.name.clone() }, + ast::TypeUsage::Named(named) => named.name.clone(), _ => panic!("LiteralStruct resolved to non-named-type"), }; - ast::Subexpression::LiteralStruct(ast::LiteralStruct{ + ast::Subexpression::LiteralStruct(ast::LiteralStruct { name: new_name.clone(), - fields: literal_struct.fields.iter().map(|field|{ - (field.0.clone(), self.with_expression(ctx, &field.1)) - }).collect(), + 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{ + 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_) + 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{ + ast::Subexpression::VariableUsage(ast::VariableUsage { name: variable_usage.name.clone(), - type_: process_type(ctx, &variable_usage.type_) + type_: process_type(ctx, &variable_usage.type_), }) - }, + } ast::Subexpression::StructGetter(struct_getter) => { - ast::Subexpression::StructGetter(ast::StructGetter{ + 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), - }) - }, + } + 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_checking.rs b/src/type_checking.rs index e07446a..abd58b2 100644 --- a/src/type_checking.rs +++ b/src/type_checking.rs @@ -1,6 +1,5 @@ -use std::collections::HashMap; use crate::ast; - +use std::collections::HashMap; pub type SubstitutionMap = HashMap; @@ -10,7 +9,6 @@ pub enum NamedEntity { Variable(ast::TypeUsage), } - #[derive(Debug, Clone, PartialEq, Eq)] struct Context { pub current_function_return: Option, @@ -20,23 +18,121 @@ struct Context { fn create_builtins() -> HashMap { let mut result = HashMap::new(); - result.insert("i8".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "i8".to_string()}))); - result.insert("i16".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "i16".to_string()}))); - result.insert("i32".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "i32".to_string()}))); - result.insert("i64".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "i64".to_string()}))); - result.insert("isize".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "isize".to_string()}))); + result.insert( + "i8".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "i8".to_string(), + }, + )), + ); + result.insert( + "i16".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "i16".to_string(), + }, + )), + ); + result.insert( + "i32".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "i32".to_string(), + }, + )), + ); + result.insert( + "i64".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "i64".to_string(), + }, + )), + ); + result.insert( + "isize".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "isize".to_string(), + }, + )), + ); - result.insert("u8".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "u8".to_string()}))); - result.insert("u16".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "u16".to_string()}))); - result.insert("u32".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "u32".to_string()}))); - result.insert("u64".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "u64".to_string()}))); - result.insert("usize".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "usize".to_string()}))); + result.insert( + "u8".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "u8".to_string(), + }, + )), + ); + result.insert( + "u16".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "u16".to_string(), + }, + )), + ); + result.insert( + "u32".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "u32".to_string(), + }, + )), + ); + result.insert( + "u64".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "u64".to_string(), + }, + )), + ); + result.insert( + "usize".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "usize".to_string(), + }, + )), + ); - result.insert("f32".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "f32".to_string()}))); - result.insert("f64".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "f64".to_string()}))); + result.insert( + "f32".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "f32".to_string(), + }, + )), + ); + result.insert( + "f64".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "f64".to_string(), + }, + )), + ); - result.insert("!".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "!".to_string()}))); - result.insert("unit".to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive(ast::PrimitiveTypeDeclaration{name: "!".to_string()}))); + result.insert( + "!".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "!".to_string(), + }, + )), + ); + result.insert( + "unit".to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Primitive( + ast::PrimitiveTypeDeclaration { + name: "!".to_string(), + }, + )), + ); return result; } @@ -44,13 +140,17 @@ fn create_builtins() -> HashMap { impl Context { fn add_variable(&self, name: String, type_usage: &ast::TypeUsage) -> Context { let mut ctx = self.clone(); - ctx.environment.insert(name.to_string(), NamedEntity::Variable(type_usage.clone())); + ctx.environment + .insert(name.to_string(), NamedEntity::Variable(type_usage.clone())); return ctx; } fn add_type(&self, name: String, type_decl: &ast::TypeDeclaration) -> Context { let mut ctx = self.clone(); - ctx.environment.insert(name.to_string(), NamedEntity::TypeDeclaration(type_decl.clone())); + ctx.environment.insert( + name.to_string(), + NamedEntity::TypeDeclaration(type_decl.clone()), + ); return ctx; } @@ -61,7 +161,8 @@ impl Context { } } -fn type_exists(ctx: &Context, type_: &ast::TypeUsage) { // TODO: error handling +fn type_exists(ctx: &Context, type_: &ast::TypeUsage) { + // TODO: error handling match type_ { ast::TypeUsage::Named(named) => { if !ctx.environment.contains_key(&named.name.name.value) { @@ -70,13 +171,13 @@ fn type_exists(ctx: &Context, type_: &ast::TypeUsage) { // TODO: error handling match ctx.environment[&named.name.name.value] { NamedEntity::TypeDeclaration(_) => { // is a type - }, + } _ => { panic!("unknown type") - }, + } } - }, - ast::TypeUsage::Unknown(unknown) => {}, // do nothing + } + ast::TypeUsage::Unknown(unknown) => {} // do nothing ast::TypeUsage::Function(function) => { for arg in function.arguments.iter() { type_exists(ctx, arg); @@ -86,38 +187,47 @@ fn type_exists(ctx: &Context, type_: &ast::TypeUsage) { // TODO: error handling } } -fn apply_substitution(ctx: &Context, substitution: &SubstitutionMap, type_: &ast::TypeUsage) -> ast::TypeUsage { - +fn apply_substitution( + ctx: &Context, + substitution: &SubstitutionMap, + type_: &ast::TypeUsage, +) -> ast::TypeUsage { let result = match type_ { - ast::TypeUsage::Named(named) => { - ast::TypeUsage::Named(named.clone()) - }, + ast::TypeUsage::Named(named) => ast::TypeUsage::Named(named.clone()), ast::TypeUsage::Unknown(unknown) => { if substitution.contains_key(&unknown.name) { substitution[&unknown.name].clone() } else { ast::TypeUsage::Unknown(unknown.clone()) } - }, - ast::TypeUsage::Function(function) => { - ast::TypeUsage::Function(ast::FunctionTypeUsage{ - arguments: function.arguments.iter().map(|arg| { - apply_substitution(ctx, substitution, arg) - }).collect(), - return_type: Box::new(apply_substitution(ctx, substitution, &function.return_type)), - }) } + ast::TypeUsage::Function(function) => ast::TypeUsage::Function(ast::FunctionTypeUsage { + arguments: function + .arguments + .iter() + .map(|arg| apply_substitution(ctx, substitution, arg)) + .collect(), + return_type: Box::new(apply_substitution(ctx, substitution, &function.return_type)), + }), }; type_exists(ctx, &result); return result; } -fn compose_substitutions(ctx: &Context, s1: &SubstitutionMap, s2: &SubstitutionMap) -> SubstitutionMap { +fn compose_substitutions( + ctx: &Context, + s1: &SubstitutionMap, + s2: &SubstitutionMap, +) -> SubstitutionMap { let mut result = SubstitutionMap::new(); for k in s2.keys() { result.insert(k.to_string(), apply_substitution(ctx, s1, &s2[k])); } - return s1.into_iter().map(|(k, v)| (k.clone(), v.clone())).chain(result).collect(); + return s1 + .into_iter() + .map(|(k, v)| (k.clone(), v.clone())) + .chain(result) + .collect(); } fn unify(ctx: &Context, t1: &ast::TypeUsage, t2: &ast::TypeUsage) -> SubstitutionMap { @@ -129,20 +239,20 @@ fn unify(ctx: &Context, t1: &ast::TypeUsage, t2: &ast::TypeUsage) -> Substitutio if named1.name.name.value == named2.name.name.value { return SubstitutionMap::new(); } - }, - _ => {}, + } + _ => {} } match t1 { ast::TypeUsage::Unknown(unknown) => { return var_bind(&unknown.name, t2); - }, - _ => {}, + } + _ => {} } match t2 { ast::TypeUsage::Unknown(unknown) => { return var_bind(&unknown.name, t1); - }, - _ => {}, + } + _ => {} } match (t1, t2) { (ast::TypeUsage::Function(f1), ast::TypeUsage::Function(f2)) => { @@ -151,11 +261,19 @@ fn unify(ctx: &Context, t1: &ast::TypeUsage, t2: &ast::TypeUsage) -> Substitutio panic!("Argument lengths don't match"); } for (i, _) in f1.arguments.iter().enumerate() { - result = compose_substitutions(ctx, &result, &unify(ctx, &apply_substitution(ctx, &result, &f1.arguments[i]), &apply_substitution(ctx, &result, &f2.arguments[i]))); + result = compose_substitutions( + ctx, + &result, + &unify( + ctx, + &apply_substitution(ctx, &result, &f1.arguments[i]), + &apply_substitution(ctx, &result, &f2.arguments[i]), + ), + ); } return result; - }, - _ => {}, + } + _ => {} } println!("problem:\n{:?}\n{:?}", t1, t2); panic!("Mismatched unification types"); @@ -167,7 +285,7 @@ fn var_bind(name: &str, t: &ast::TypeUsage) -> SubstitutionMap { if name == unknown.name { return SubstitutionMap::new(); } - }, + } _ => {} } if contains(t, name) { @@ -180,12 +298,8 @@ fn var_bind(name: &str, t: &ast::TypeUsage) -> SubstitutionMap { fn contains(t: &ast::TypeUsage, name: &str) -> bool { match t { - ast::TypeUsage::Named(_) => { - return false - }, - ast::TypeUsage::Unknown(unknown) => { - unknown.name == name - }, + ast::TypeUsage::Named(_) => return false, + ast::TypeUsage::Unknown(unknown) => unknown.name == name, ast::TypeUsage::Function(f) => { if contains(&*f.return_type, name) { return true; @@ -196,16 +310,15 @@ fn contains(t: &ast::TypeUsage, name: &str) -> bool { } } return false; - }, + } } } - pub struct TypeChecker {} impl TypeChecker { pub fn with_module(self: &Self, module: &ast::Module) -> (ast::Module, SubstitutionMap) { - let mut ctx = Context{ + let mut ctx = Context { environment: create_builtins(), impls: HashMap::new(), current_function_return: None, @@ -214,127 +327,210 @@ impl TypeChecker { for item in module.items.iter() { match item { ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Struct(struct_)) => { - ctx.environment.insert(struct_.name.name.value.to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(struct_.clone()))); - }, + ctx.environment.insert( + struct_.name.name.value.to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(struct_.clone())), + ); + } ast::ModuleItem::TypeDeclaration(ast::TypeDeclaration::Alias(alias)) => { - ctx.environment.insert(alias.name.name.value.to_string(), NamedEntity::TypeDeclaration(ast::TypeDeclaration::Alias(alias.clone()))); - }, + ctx.environment.insert( + alias.name.name.value.to_string(), + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Alias(alias.clone())), + ); + } ast::ModuleItem::Function(function) => { - let function_type = ast::FunctionTypeUsage{ - arguments: function.declaration.arguments.iter().map(|arg|{arg.type_.clone()}).collect(), + let function_type = ast::FunctionTypeUsage { + arguments: function + .declaration + .arguments + .iter() + .map(|arg| arg.type_.clone()) + .collect(), return_type: Box::new(function.declaration.return_type.clone()), }; - ctx.environment.insert(function.declaration.name.name.value.to_string(), NamedEntity::Variable(ast::TypeUsage::Function(function_type))); - }, + ctx.environment.insert( + function.declaration.name.name.value.to_string(), + NamedEntity::Variable(ast::TypeUsage::Function(function_type)), + ); + } ast::ModuleItem::Impl(impl_) => { - ctx.impls.insert(impl_.struct_name.name.value.to_string(), impl_.clone()); - }, - _ => {}, + ctx.impls + .insert(impl_.struct_name.name.value.to_string(), impl_.clone()); + } + _ => {} } } let mut subst = SubstitutionMap::new(); - let result = ast::Module{ - items: module.items.iter().map(|item|{ - match item { + let result = ast::Module { + items: module + .items + .iter() + .map(|item| match item { ast::ModuleItem::Function(function) => { let (func, fn_subst) = self.with_function(&ctx, &subst, function); subst = compose_substitutions(&ctx, &subst, &fn_subst); ast::ModuleItem::Function(func) - }, + } ast::ModuleItem::TypeDeclaration(type_declaration) => { - let (ty_decl, ty_subst) = self.with_type_declaration(&ctx, type_declaration); + let (ty_decl, ty_subst) = + self.with_type_declaration(&ctx, type_declaration); subst = compose_substitutions(&ctx, &subst, &ty_subst); ast::ModuleItem::TypeDeclaration(ty_decl) - }, + } ast::ModuleItem::Impl(impl_) => { let (impl_result, impl_subst) = self.with_impl(&ctx, &subst, impl_); subst = compose_substitutions(&ctx, &subst, &impl_subst); ast::ModuleItem::Impl(impl_result) - }, - } - }).collect() + } + }) + .collect(), }; return (result, subst); } - fn with_function(self: &Self, ctx: &Context, incoming_substitutions: &SubstitutionMap, function: &ast::Function) -> (ast::Function, SubstitutionMap) { + fn with_function( + self: &Self, + ctx: &Context, + incoming_substitutions: &SubstitutionMap, + function: &ast::Function, + ) -> (ast::Function, SubstitutionMap) { // add args to env - let mut function_ctx = ctx.set_current_function_return(&function.declaration.return_type.clone()); + let mut function_ctx = + ctx.set_current_function_return(&function.declaration.return_type.clone()); for arg in function.declaration.arguments.iter() { type_exists(ctx, &arg.type_); - function_ctx = function_ctx.add_variable(arg.name.name.value.to_string(), &arg.type_.clone()); + function_ctx = + function_ctx.add_variable(arg.name.name.value.to_string(), &arg.type_.clone()); } type_exists(ctx, &function.declaration.return_type); - let (block, substitution) = self.with_block(&function_ctx, incoming_substitutions, &function.block); - let mut substitution = compose_substitutions(&function_ctx, incoming_substitutions, &substitution); + let (block, substitution) = + self.with_block(&function_ctx, incoming_substitutions, &function.block); + let mut substitution = + compose_substitutions(&function_ctx, incoming_substitutions, &substitution); match &block.type_ { ast::TypeUsage::Named(named) => { if named.name.name.value != "!" { - substitution = compose_substitutions(&function_ctx, &substitution, &unify(&function_ctx, &function.declaration.return_type, &block.type_)); + substitution = compose_substitutions( + &function_ctx, + &substitution, + &unify( + &function_ctx, + &function.declaration.return_type, + &block.type_, + ), + ); } - }, + } _ => { - substitution = compose_substitutions(&function_ctx, &substitution, &unify(&function_ctx, &function.declaration.return_type, &block.type_)); + substitution = compose_substitutions( + &function_ctx, + &substitution, + &unify( + &function_ctx, + &function.declaration.return_type, + &block.type_, + ), + ); } } - - return (ast::Function{ - declaration: ast::FunctionDeclaration{ - name: function.declaration.name.clone(), - arguments: function.declaration.arguments.iter().map(|arg| { - arg.clone() - }).collect(), - return_type: function.declaration.return_type.clone(), + return ( + ast::Function { + declaration: ast::FunctionDeclaration { + name: function.declaration.name.clone(), + arguments: function + .declaration + .arguments + .iter() + .map(|arg| arg.clone()) + .collect(), + return_type: function.declaration.return_type.clone(), + }, + block: block, }, - block: block, - }, substitution); + substitution, + ); } - fn with_type_declaration(self: &Self, ctx: &Context, type_declaration: &ast::TypeDeclaration) -> (ast::TypeDeclaration, SubstitutionMap) { + fn with_type_declaration( + self: &Self, + ctx: &Context, + type_declaration: &ast::TypeDeclaration, + ) -> (ast::TypeDeclaration, SubstitutionMap) { match type_declaration { ast::TypeDeclaration::Struct(struct_) => { let result = self.with_struct_declaration(ctx, struct_); return (ast::TypeDeclaration::Struct(result), SubstitutionMap::new()); - }, + } ast::TypeDeclaration::Primitive(primitive) => { - return (ast::TypeDeclaration::Primitive(primitive.clone()), SubstitutionMap::new()); - }, + return ( + ast::TypeDeclaration::Primitive(primitive.clone()), + SubstitutionMap::new(), + ); + } ast::TypeDeclaration::Alias(alias) => { - return (ast::TypeDeclaration::Alias(alias.clone()), SubstitutionMap::new()); - }, + return ( + ast::TypeDeclaration::Alias(alias.clone()), + SubstitutionMap::new(), + ); + } } } - fn with_struct_declaration(self: &Self, ctx: &Context, struct_: &ast::StructTypeDeclaration) -> ast::StructTypeDeclaration { - return ast::StructTypeDeclaration{ + 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|{ - type_exists(ctx, &field.type_); - ast::StructField{ - name: field.name.clone(), - type_: field.type_.clone(), - } - }).collect(), + fields: struct_ + .fields + .iter() + .map(|field| { + type_exists(ctx, &field.type_); + ast::StructField { + name: field.name.clone(), + type_: field.type_.clone(), + } + }) + .collect(), }; } - fn with_impl(self: &Self, ctx: &Context, incoming_substitutions: &SubstitutionMap, impl_: &ast::Impl) -> (ast::Impl, SubstitutionMap) { + fn with_impl( + self: &Self, + ctx: &Context, + incoming_substitutions: &SubstitutionMap, + impl_: &ast::Impl, + ) -> (ast::Impl, SubstitutionMap) { let mut substitutions = incoming_substitutions.clone(); type_exists(ctx, &ast::TypeUsage::new_named(impl_.struct_name.clone())); - return (ast::Impl{ - struct_name: impl_.struct_name.clone(), - functions: impl_.functions.iter().map(|f|{ - let (result, function_subs) = self.with_function(&ctx, &substitutions, f); - substitutions = compose_substitutions(ctx, &substitutions, &function_subs); - result - }).collect(), - }, substitutions); + return ( + ast::Impl { + struct_name: impl_.struct_name.clone(), + functions: impl_ + .functions + .iter() + .map(|f| { + let (result, function_subs) = self.with_function(&ctx, &substitutions, f); + substitutions = compose_substitutions(ctx, &substitutions, &function_subs); + result + }) + .collect(), + }, + substitutions, + ); } - fn with_block(self: &Self, ctx: &Context, incoming_substitutions: &SubstitutionMap, block: &ast::Block) -> (ast::Block, SubstitutionMap) { + fn with_block( + self: &Self, + ctx: &Context, + incoming_substitutions: &SubstitutionMap, + block: &ast::Block, + ) -> (ast::Block, SubstitutionMap) { let mut substitutions = incoming_substitutions.clone(); let mut block_ctx = ctx.clone(); // if return it's always never @@ -344,23 +540,37 @@ impl TypeChecker { match statement { ast::Statement::Return(_) => { has_return = true; - }, + } _ => {} } } - let statements = block.statements.iter().map(|s| { - let (statement_ctx, result, statement_substitutions) = self.with_statement(&block_ctx, &substitutions, s); - block_ctx = statement_ctx; - substitutions = compose_substitutions(&block_ctx, &substitutions, &statement_substitutions); - result - }).collect(); + let statements = block + .statements + .iter() + .map(|s| { + let (statement_ctx, result, statement_substitutions) = + self.with_statement(&block_ctx, &substitutions, s); + block_ctx = statement_ctx; + substitutions = + compose_substitutions(&block_ctx, &substitutions, &statement_substitutions); + result + }) + .collect(); if !has_return { match block.statements.last().unwrap() { ast::Statement::Expression(expr) => { - substitutions = compose_substitutions(&block_ctx, &substitutions, &unify(&block_ctx, &block.type_, &expr.type_)); - }, + substitutions = compose_substitutions( + &block_ctx, + &substitutions, + &unify(&block_ctx, &block.type_, &expr.type_), + ); + } _ => { - substitutions = compose_substitutions(&block_ctx, &substitutions, &unify(&block_ctx, &block.type_, &ast::new_unit())); + substitutions = compose_substitutions( + &block_ctx, + &substitutions, + &unify(&block_ctx, &block.type_, &ast::new_unit()), + ); } } } @@ -369,39 +579,55 @@ impl TypeChecker { } else { apply_substitution(&block_ctx, &substitutions, &block.type_) }; - let block_result = ast::Block{ + let block_result = ast::Block { statements: statements, type_: result_type, }; return (block_result, substitutions); } - fn with_statement(self: &Self, ctx: &Context, incoming_substitutions: &SubstitutionMap, statement: &ast::Statement) -> (Context, ast::Statement, SubstitutionMap) { + fn with_statement( + self: &Self, + ctx: &Context, + incoming_substitutions: &SubstitutionMap, + statement: &ast::Statement, + ) -> (Context, ast::Statement, SubstitutionMap) { match statement { ast::Statement::Return(return_statement) => { - let (result, subst) = self.with_return_statement(ctx, incoming_substitutions, return_statement); + let (result, subst) = + self.with_return_statement(ctx, incoming_substitutions, return_statement); let subst = compose_substitutions(ctx, &incoming_substitutions, &subst); return (ctx.clone(), ast::Statement::Return(result), subst); - }, + } ast::Statement::Let(let_statement) => { - let (let_ctx, result, subst) = self.with_let_statement(ctx, incoming_substitutions, let_statement); + let (let_ctx, result, subst) = + self.with_let_statement(ctx, incoming_substitutions, let_statement); let subst = compose_substitutions(ctx, &incoming_substitutions, &subst); return (let_ctx, ast::Statement::Let(result), subst); - }, + } ast::Statement::Assignment(assignment_statement) => { - let (result, subst) = self.with_assignment_statement(ctx, incoming_substitutions, assignment_statement); + let (result, subst) = self.with_assignment_statement( + ctx, + incoming_substitutions, + assignment_statement, + ); let subst = compose_substitutions(ctx, &incoming_substitutions, &subst); return (ctx.clone(), ast::Statement::Assignment(result), subst); - }, + } ast::Statement::Expression(expression) => { let (result, subst) = self.with_expression(ctx, incoming_substitutions, expression); let subst = compose_substitutions(ctx, &incoming_substitutions, &subst); return (ctx.clone(), ast::Statement::Expression(result), subst); - }, + } } } - fn with_return_statement(self: &Self, ctx: &Context, incoming_substitutions: &SubstitutionMap, statement: &ast::ReturnStatement) -> (ast::ReturnStatement, SubstitutionMap) { + fn with_return_statement( + self: &Self, + ctx: &Context, + incoming_substitutions: &SubstitutionMap, + statement: &ast::ReturnStatement, + ) -> (ast::ReturnStatement, SubstitutionMap) { let (result, subst) = self.with_expression(ctx, incoming_substitutions, &statement.source); let mut substitution = compose_substitutions(ctx, &incoming_substitutions, &subst); let mut is_never = false; @@ -410,220 +636,361 @@ impl TypeChecker { if named.name.name.value == "!" { is_never = true; } - }, - _ => {}, + } + _ => {} } if !is_never { - substitution = compose_substitutions(ctx, &subst, &unify(ctx, &ctx.current_function_return.as_ref().unwrap(), &result.type_)); + substitution = compose_substitutions( + ctx, + &subst, + &unify( + ctx, + &ctx.current_function_return.as_ref().unwrap(), + &result.type_, + ), + ); } - return (ast::ReturnStatement{ - source: result, - }, substitution); + return (ast::ReturnStatement { source: result }, substitution); } - fn with_let_statement(self: &Self, ctx: &Context, incoming_substitutions: &SubstitutionMap, statement: &ast::LetStatement) -> (Context, ast::LetStatement, SubstitutionMap) { - let (result, subst) = self.with_expression(ctx, incoming_substitutions, &statement.expression); + fn with_let_statement( + self: &Self, + ctx: &Context, + incoming_substitutions: &SubstitutionMap, + statement: &ast::LetStatement, + ) -> (Context, ast::LetStatement, SubstitutionMap) { + let (result, subst) = + self.with_expression(ctx, incoming_substitutions, &statement.expression); let let_ctx = ctx.add_variable(statement.variable_name.name.value.clone(), &result.type_); - let substitution = compose_substitutions(ctx, &subst, &unify(ctx, &statement.type_, &result.type_)); - return (let_ctx, ast::LetStatement{ - variable_name: statement.variable_name.clone(), - expression: result, - type_: apply_substitution(ctx, &substitution, &statement.type_), - }, substitution); + let substitution = + compose_substitutions(ctx, &subst, &unify(ctx, &statement.type_, &result.type_)); + return ( + let_ctx, + ast::LetStatement { + variable_name: statement.variable_name.clone(), + expression: result, + type_: apply_substitution(ctx, &substitution, &statement.type_), + }, + substitution, + ); } - fn with_assignment_statement(self: &Self, ctx: &Context, incoming_substitutions: &SubstitutionMap, statement: &ast::AssignmentStatement) -> (ast::AssignmentStatement, SubstitutionMap) { - let (expr, subst) = self.with_expression(ctx, incoming_substitutions, &statement.expression); + fn with_assignment_statement( + self: &Self, + ctx: &Context, + incoming_substitutions: &SubstitutionMap, + statement: &ast::AssignmentStatement, + ) -> (ast::AssignmentStatement, SubstitutionMap) { + let (expr, subst) = + self.with_expression(ctx, incoming_substitutions, &statement.expression); let mut substitution = compose_substitutions(ctx, &incoming_substitutions, &subst); - let result_as = ast::AssignmentStatement{ + let result_as = ast::AssignmentStatement { source: match &statement.source { ast::AssignmentTarget::Variable(variable) => { - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable.type_, &expr.type_)); - ast::AssignmentTarget::Variable(ast::VariableUsage{ + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &variable.type_, &expr.type_), + ); + ast::AssignmentTarget::Variable(ast::VariableUsage { name: variable.name.clone(), type_: apply_substitution(ctx, &substitution, &variable.type_), }) - }, + } ast::AssignmentTarget::StructAttr(struct_attr) => { - let (source, subst) = self.with_expression(ctx, &substitution, &struct_attr.source); + let (source, subst) = + self.with_expression(ctx, &substitution, &struct_attr.source); let mut subst = subst.clone(); match &source.type_ { ast::TypeUsage::Named(named) => { match &ctx.environment[&named.name.name.value] { - NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(type_declaration)) => { + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct( + type_declaration, + )) => { let mut found = false; for field in type_declaration.fields.iter() { - if field.name.name.value == struct_attr.attribute.name.value { + if field.name.name.value == struct_attr.attribute.name.value + { found = true; - subst = compose_substitutions(ctx, &subst, &unify(ctx, &struct_attr.type_, &field.type_)); + subst = compose_substitutions( + ctx, + &subst, + &unify(ctx, &struct_attr.type_, &field.type_), + ); } } if !found { panic!("unknown field name") } - - }, - _ => panic!("struct getter being used on non-struct") + } + _ => panic!("struct getter being used on non-struct"), } - }, + } ast::TypeUsage::Function(_) => { panic!("function used with attr") - }, + } _ => {} // skip unifying if struct type is unknown1 } - let substitution = compose_substitutions(ctx, &compose_substitutions(ctx, &substitution, &subst), &unify(ctx, &struct_attr.type_, &expr.type_)); - ast::AssignmentTarget::StructAttr(ast::StructGetter{ + let substitution = compose_substitutions( + ctx, + &compose_substitutions(ctx, &substitution, &subst), + &unify(ctx, &struct_attr.type_, &expr.type_), + ); + ast::AssignmentTarget::StructAttr(ast::StructGetter { source: source, attribute: struct_attr.attribute.clone(), type_: apply_substitution(ctx, &substitution, &struct_attr.type_), }) - }, + } }, expression: expr, }; return (result_as, substitution); } - fn with_expression(self: &Self, ctx: &Context, incoming_substitutions: &SubstitutionMap, expression: &ast::Expression) -> (ast::Expression, SubstitutionMap) { + fn with_expression( + self: &Self, + ctx: &Context, + incoming_substitutions: &SubstitutionMap, + expression: &ast::Expression, + ) -> (ast::Expression, SubstitutionMap) { let mut substitution = incoming_substitutions.clone(); let subexpression = Box::new(match &*expression.subexpression { ast::Subexpression::LiteralInt(literal_int) => { - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &expression.type_, &literal_int.type_)); - ast::Subexpression::LiteralInt(ast::LiteralInt{ + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &expression.type_, &literal_int.type_), + ); + ast::Subexpression::LiteralInt(ast::LiteralInt { value: literal_int.value.clone(), type_: apply_substitution(ctx, &substitution, &literal_int.type_), }) - }, + } ast::Subexpression::LiteralFloat(literal_float) => { - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &expression.type_, &literal_float.type_)); - ast::Subexpression::LiteralFloat(ast::LiteralFloat{ + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &expression.type_, &literal_float.type_), + ); + ast::Subexpression::LiteralFloat(ast::LiteralFloat { value: literal_float.value.clone(), type_: apply_substitution(ctx, &substitution, &literal_float.type_), }) - }, + } ast::Subexpression::LiteralStruct(literal_struct) => { - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &expression.type_, &literal_struct.type_)); + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &expression.type_, &literal_struct.type_), + ); let type_declaration = match &ctx.environment[&literal_struct.name.name.value] { - NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(type_declaration)) => { - type_declaration - }, - _ => {panic!("literal struct used with non struct name")} + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct( + type_declaration, + )) => type_declaration, + _ => { + panic!("literal struct used with non struct name") + } }; if type_declaration.fields.len() != literal_struct.fields.len() { panic!("literal type declaration has mismatched fields"); } - ast::Subexpression::LiteralStruct(ast::LiteralStruct{ + ast::Subexpression::LiteralStruct(ast::LiteralStruct { name: literal_struct.name.clone(), - fields: type_declaration.fields.iter().map(|type_field|{ - let mut found = false; - let mut field_expression: Option = None; - for field in literal_struct.fields.iter() { - if type_field.name.name.value == field.0.name.value { - found = true; - let (result, subst) = self.with_expression(ctx, &substitution, &field.1); - substitution = compose_substitutions(ctx, &substitution, &subst); - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &type_field.type_, &result.type_)); - field_expression = Some(result); + fields: type_declaration + .fields + .iter() + .map(|type_field| { + let mut found = false; + let mut field_expression: Option = None; + for field in literal_struct.fields.iter() { + if type_field.name.name.value == field.0.name.value { + found = true; + let (result, subst) = + self.with_expression(ctx, &substitution, &field.1); + substitution = + compose_substitutions(ctx, &substitution, &subst); + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &type_field.type_, &result.type_), + ); + field_expression = Some(result); + } } - } - if !found { - panic!("missing field: {}", &type_field.name.name.value); - } - (type_field.name.clone(), field_expression.unwrap()) - }).collect(), + if !found { + panic!("missing field: {}", &type_field.name.name.value); + } + (type_field.name.clone(), field_expression.unwrap()) + }) + .collect(), type_: apply_substitution(ctx, &substitution, &literal_struct.type_), }) - }, + } ast::Subexpression::FunctionCall(function_call) => { - let (source, subst) = self.with_expression(ctx, &substitution, &function_call.source); + let (source, subst) = + self.with_expression(ctx, &substitution, &function_call.source); substitution = compose_substitutions(ctx, &substitution, &subst); match &source.type_ { ast::TypeUsage::Function(fn_type) => { - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &function_call.type_, &*fn_type.return_type)); + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &function_call.type_, &*fn_type.return_type), + ); if function_call.arguments.len() != fn_type.arguments.len() { panic!("mismatched function argument count"); } - }, + } ast::TypeUsage::Named(_) => panic!("FunctionCall doesn't have function type."), - _ => {}, + _ => {} } - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &expression.type_, &function_call.type_)); - ast::Subexpression::FunctionCall(ast::FunctionCall{ + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &expression.type_, &function_call.type_), + ); + ast::Subexpression::FunctionCall(ast::FunctionCall { source: source.clone(), - arguments: function_call.arguments.iter().enumerate().map(|(i, arg)| { - let (result, subst) = self.with_expression(ctx, &substitution, arg); - substitution = compose_substitutions(ctx, &substitution, &subst); + arguments: function_call + .arguments + .iter() + .enumerate() + .map(|(i, arg)| { + let (result, subst) = self.with_expression(ctx, &substitution, arg); + substitution = compose_substitutions(ctx, &substitution, &subst); - match &source.type_ { - ast::TypeUsage::Function(fn_type) => { - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &fn_type.arguments[i], &result.type_)); - }, - ast::TypeUsage::Named(_) => panic!("FunctionCall doesn't have function type."), - _ => {}, - } - result - }).collect(), + match &source.type_ { + ast::TypeUsage::Function(fn_type) => { + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &fn_type.arguments[i], &result.type_), + ); + } + ast::TypeUsage::Named(_) => { + panic!("FunctionCall doesn't have function type.") + } + _ => {} + } + result + }) + .collect(), type_: apply_substitution(ctx, &substitution, &function_call.type_), }) - }, + } ast::Subexpression::VariableUsage(variable_usage) => { match &ctx.environment[&variable_usage.name.name.value] { NamedEntity::TypeDeclaration(_) => { panic!("Using types not yet supported"); - }, + } NamedEntity::Variable(variable) => { - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &variable_usage.type_, &variable)); - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &expression.type_, &variable_usage.type_)); - }, + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &variable_usage.type_, &variable), + ); + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &expression.type_, &variable_usage.type_), + ); + } } - ast::Subexpression::VariableUsage(ast::VariableUsage{ + ast::Subexpression::VariableUsage(ast::VariableUsage { name: variable_usage.name.clone(), type_: apply_substitution(ctx, &substitution, &variable_usage.type_), }) - }, + } ast::Subexpression::StructGetter(struct_getter) => { - let (source, subst) = self.with_expression(ctx, &substitution, &struct_getter.source); + let (source, subst) = + self.with_expression(ctx, &substitution, &struct_getter.source); substitution = compose_substitutions(ctx, &substitution, &subst); match &source.type_ { ast::TypeUsage::Named(named) => { match &ctx.environment[&named.name.name.value] { - NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct(type_declaration)) => { + NamedEntity::TypeDeclaration(ast::TypeDeclaration::Struct( + type_declaration, + )) => { let mut found = false; for field in type_declaration.fields.iter() { if field.name.name.value == struct_getter.attribute.name.value { found = true; - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &struct_getter.type_, &field.type_)); + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &struct_getter.type_, &field.type_), + ); } } if !found { - for method in ctx.impls[&type_declaration.name.name.value].functions.iter() { - if method.declaration.name.name.value == struct_getter.attribute.name.value { - let mut function_type = ast::FunctionTypeUsage{ - arguments: method.declaration.arguments.iter().map(|arg|{arg.type_.clone()}).collect(), - return_type: Box::new(method.declaration.return_type.clone()), + for method in ctx.impls[&type_declaration.name.name.value] + .functions + .iter() + { + if method.declaration.name.name.value + == struct_getter.attribute.name.value + { + let mut function_type = ast::FunctionTypeUsage { + arguments: method + .declaration + .arguments + .iter() + .map(|arg| arg.type_.clone()) + .collect(), + return_type: Box::new( + method.declaration.return_type.clone(), + ), }; // if the name of the type of the first argument == the class, remove the first arg if function_type.arguments.len() > 0 { match &function_type.arguments[0] { ast::TypeUsage::Named(named) => { - if named.name.name.value == type_declaration.name.name.value { - function_type = ast::FunctionTypeUsage{ - arguments: method.declaration.arguments[1..method.declaration.arguments.len()].iter().map(|arg|{arg.type_.clone()}).collect(), - return_type: Box::new(method.declaration.return_type.clone()), - }; + if named.name.name.value + == type_declaration.name.name.value + { + function_type = + ast::FunctionTypeUsage { + arguments: method + .declaration + .arguments + [1..method + .declaration + .arguments + .len()] + .iter() + .map(|arg| { + arg.type_.clone() + }) + .collect(), + return_type: Box::new( + method + .declaration + .return_type + .clone(), + ), + }; } - }, - _ => {}, + } + _ => {} }; } println!("found: {:?}", &function_type); - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &struct_getter.type_, &ast::TypeUsage::Function(function_type))); + substitution = compose_substitutions( + ctx, + &substitution, + &unify( + ctx, + &struct_getter.type_, + &ast::TypeUsage::Function(function_type), + ), + ); found = true; } } @@ -631,47 +998,62 @@ impl TypeChecker { if !found { panic!("unknown field name") } - - }, - _ => panic!("struct getter being used on non-struct") + } + _ => panic!("struct getter being used on non-struct"), } - }, + } ast::TypeUsage::Function(_) => { panic!("function used with attr") - }, + } _ => {} // skip unifying if struct type is unknown1 } - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &expression.type_, &struct_getter.type_)); + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &expression.type_, &struct_getter.type_), + ); - ast::Subexpression::StructGetter(ast::StructGetter{ + ast::Subexpression::StructGetter(ast::StructGetter { source: source, attribute: struct_getter.attribute.clone(), type_: apply_substitution(ctx, &substitution, &struct_getter.type_), }) - }, + } ast::Subexpression::Block(block) => { let (result, subst) = self.with_block(ctx, &substitution, &block); substitution = compose_substitutions(ctx, &substitution, &subst); - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &expression.type_, &result.type_)); + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &expression.type_, &result.type_), + ); ast::Subexpression::Block(result) - }, + } ast::Subexpression::Op(op) => { let (expr_left, subst_left) = self.with_expression(ctx, &substitution, &op.left); let (expr_right, subst_right) = self.with_expression(ctx, &substitution, &op.right); substitution = compose_substitutions(ctx, &substitution, &subst_left); substitution = compose_substitutions(ctx, &substitution, &subst_right); - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &expression.type_, &expr_left.type_)); - substitution = compose_substitutions(ctx, &substitution, &unify(ctx, &expression.type_, &expr_right.type_)); - ast::Subexpression::Op(ast::Operation{ + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &expression.type_, &expr_left.type_), + ); + substitution = compose_substitutions( + ctx, + &substitution, + &unify(ctx, &expression.type_, &expr_right.type_), + ); + ast::Subexpression::Op(ast::Operation { left: expr_left, op: op.op.clone(), right: expr_right, }) - }, + } }); - let expr = ast::Expression{ + let expr = ast::Expression { subexpression: subexpression, type_: apply_substitution(ctx, &substitution, &expression.type_), }; diff --git a/src/types.rs b/src/types.rs index 7d8a947..9748860 100644 --- a/src/types.rs +++ b/src/types.rs @@ -4,7 +4,6 @@ pub enum Signedness { Unsigned, } - #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum IntBitness { X8, @@ -14,7 +13,6 @@ pub enum IntBitness { X128, } - #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub enum FloatBitness { X32, @@ -22,14 +20,12 @@ pub enum FloatBitness { X128, } - #[derive(Clone, Eq, PartialEq, Hash)] pub struct IntTypeDef { pub signedness: Signedness, pub bitness: IntBitness, } - #[derive(Clone, PartialEq, Eq, Hash)] pub struct FloatTypeDef { pub bitness: FloatBitness, @@ -41,7 +37,6 @@ pub struct FunctionTypeDef { pub return_type: Box, } - #[derive(Clone, PartialEq, Eq, Hash)] pub enum Type { Bool, @@ -55,7 +50,6 @@ pub enum Type { // Never, } - /// Used for places where type info may or may not be solved. #[derive(Clone, Eq, PartialEq, Hash)] pub enum SpecifiedType {