Compare commits

...

16 Commits

19 changed files with 787 additions and 262 deletions

View File

@ -59,11 +59,11 @@ Currently missing big features (TODOs) are:
- ~~Intrinsic functions~~ (DONE)
- ~~Ability to specify types in literals and variable definitions~~ (DONE)
- ~~Debug Information~~ (DONE)
- ~~Fix struct initialization (wrong order and missing fields allowed now)~~
- ~~Not-Unary~~
- ~~Importing types from other modules~~
- ~~Importable binops?~~
- Associated functions (for e.g. sizeof)
- ~~Fix struct initialization (wrong order and missing fields allowed now)~~ (DONE)
- ~~Not-Unary~~ (DONE)
- ~~Importing types from other modules~~ (DONE)
- ~~Importable binops?~~ (DONE)
- ~~Associated functions (for e.g. sizeof)~~ (DONE)
Big features that I want later but are not necessary:
- ~~User-defined binary operations~~ (DONE)

View File

@ -0,0 +1,28 @@
import std::print;
import std::from_str;
import std::String;
struct Otus {
field: u32,
}
impl Otus {
fn test(&self) -> u32 {
*self.field
}
}
impl i32 {
fn test(self) -> u32 {
43
}
}
fn main() -> u32 {
let otus = Otus { field: 17 };
print(from_str("otus: ") + Otus::test(&otus) as u64);
print(from_str("i32: ") + i32::test(54) as u64);
print(from_str("sizeof i32: ") + i32::sizeof());
return i32::sizeof() as u32;
}

View File

@ -40,6 +40,7 @@ pub enum TypeKind {
Custom(String),
Borrow(Box<TypeKind>, bool),
Ptr(Box<TypeKind>),
Unknown,
}
#[derive(Debug, Clone)]
@ -90,6 +91,7 @@ pub enum ExpressionKind {
Accessed(Box<Expression>, String),
Binop(BinaryOperator, Box<Expression>, Box<Expression>),
FunctionCall(Box<FunctionCallExpression>),
AssociatedFunctionCall(Type, Box<FunctionCallExpression>),
BlockExpr(Box<Block>),
IfExpr(Box<IfExpression>),
StructExpression(StructExpression),
@ -170,12 +172,21 @@ pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub To
#[derive(Debug, Clone)]
pub struct FunctionSignature {
pub name: String,
pub args: Vec<(String, Type)>,
pub self_kind: SelfKind,
pub params: Vec<(String, Type)>,
pub return_type: Option<Type>,
#[allow(dead_code)]
pub range: TokenRange,
}
#[derive(Debug, Clone)]
pub enum SelfKind {
Owned(TypeKind),
Borrow(TypeKind),
MutBorrow(TypeKind),
None,
}
#[derive(Debug, Clone, Copy)]
pub enum ReturnType {
Soft,
@ -236,6 +247,7 @@ pub enum TopLevelStatement {
FunctionDefinition(FunctionDefinition),
TypeDefinition(TypeDefinition),
BinopDefinition(BinopDefinition),
AssociatedFunction(Type, Vec<FunctionDefinition>),
}
#[derive(Debug)]

View File

@ -167,6 +167,18 @@ fn specific_int_lit(value: u128, stream: &mut TokenStream) -> Result<Expression,
))
}
#[derive(Debug)]
pub struct AssociatedFunctionCall(Type, FunctionCallExpression);
impl Parse for AssociatedFunctionCall {
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
let ty = stream.parse()?;
stream.expect(Token::Colon)?;
stream.expect(Token::Colon)?;
Ok(AssociatedFunctionCall(ty, stream.parse()?))
}
}
#[derive(Debug)]
pub struct PrimaryExpression(Expression);
@ -200,6 +212,11 @@ impl Parse for PrimaryExpression {
Kind::UnaryOperation(unary, Box::new(stream.parse()?)),
stream.get_range().unwrap(),
)
} else if let Ok(assoc_function) = stream.parse::<AssociatedFunctionCall>() {
Expression(
Kind::AssociatedFunctionCall(assoc_function.0, Box::new(assoc_function.1)),
stream.get_range().unwrap(),
)
} else if let Some(token) = stream.peek() {
match &token {
Token::Identifier(v) => {
@ -579,18 +596,58 @@ impl Parse for FunctionParam {
}
}
#[derive(Debug)]
pub struct SelfParam(SelfKind);
pub enum SelfParamKind {
Owned,
Borrow,
BorrowMut,
}
impl Parse for SelfParam {
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
let kind = if let Some(Token::Et) = stream.peek() {
stream.next();
if let Some(Token::MutKeyword) = stream.peek() {
stream.next();
SelfParamKind::BorrowMut
} else {
SelfParamKind::Borrow
}
} else {
SelfParamKind::Owned
};
let Some(Token::Identifier(name)) = stream.next() else {
return Err(stream.expected_err("parameter name")?);
};
if name == "self" {
match kind {
SelfParamKind::BorrowMut => Ok(SelfParam(SelfKind::MutBorrow(TypeKind::Unknown))),
SelfParamKind::Borrow => Ok(SelfParam(SelfKind::Borrow(TypeKind::Unknown))),
SelfParamKind::Owned => Ok(SelfParam(SelfKind::Owned(TypeKind::Unknown))),
}
} else {
Err(stream.expected_err("self parameter")?)
}
}
}
impl Parse for FunctionSignature {
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
if let Some(Token::Identifier(name)) = stream.next() {
stream.expect(Token::ParenOpen)?;
let mut args = Vec::new();
let mut params = Vec::new();
let self_kind = stream.parse::<SelfParam>().map(|s| s.0).unwrap_or(SelfKind::None);
if let Ok(param) = stream.parse::<FunctionParam>() {
args.push((param.0, param.1));
params.push((param.0, param.1));
while let Some(Token::Comma) = stream.peek() {
stream.next();
let param = stream.parse::<FunctionParam>()?;
args.push((param.0, param.1));
params.push((param.0, param.1));
}
}
@ -603,7 +660,8 @@ impl Parse for FunctionSignature {
Ok(FunctionSignature {
name,
args,
params,
self_kind,
return_type,
range: stream.get_range().unwrap(),
})
@ -874,7 +932,14 @@ impl Parse for TopLevelStatement {
range,
})
}
Some(Token::Impl) => Stmt::BinopDefinition(stream.parse()?),
Some(Token::Impl) => match stream.peek2() {
Some(Token::Binop) => Stmt::BinopDefinition(stream.parse()?),
Some(_) => {
let AssociatedFunctionBlock(ty, functions) = stream.parse::<AssociatedFunctionBlock>()?;
Stmt::AssociatedFunction(ty, functions)
}
_ => Err(stream.expecting_err("binop or associated function block")?)?,
},
_ => Err(stream.expecting_err("import or fn")?)?,
})
}
@ -917,3 +982,28 @@ impl Parse for BinopDefinition {
})
}
}
#[derive(Debug)]
pub struct AssociatedFunctionBlock(Type, Vec<FunctionDefinition>);
impl Parse for AssociatedFunctionBlock {
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
stream.expect(Token::Impl)?;
let ty = stream.parse::<Type>()?;
stream.expect(Token::BraceOpen)?;
let mut functions = Vec::new();
while let Some(Token::FnKeyword) = stream.peek() {
let mut fun: FunctionDefinition = stream.parse()?;
fun.0.self_kind = match fun.0.self_kind {
SelfKind::Owned(_) => SelfKind::Owned(ty.0.clone()),
SelfKind::Borrow(_) => SelfKind::Borrow(ty.0.clone()),
SelfKind::MutBorrow(_) => SelfKind::MutBorrow(ty.0.clone()),
SelfKind::None => SelfKind::None,
};
functions.push(fun);
}
stream.expect(Token::BraceClose)?;
Ok(AssociatedFunctionBlock(ty, functions))
}
}

View File

@ -21,6 +21,7 @@ impl mir::Context {
impl ast::Module {
pub fn process(self, module_id: SourceModuleId) -> mir::Module {
let mut imports = Vec::new();
let mut associated_functions = Vec::new();
let mut functions = Vec::new();
let mut typedefs = Vec::new();
let mut binops = Vec::new();
@ -31,29 +32,7 @@ impl ast::Module {
Import(import) => {
imports.push(mir::Import(import.0.clone(), import.1.as_meta(module_id)));
}
FunctionDefinition(ast::FunctionDefinition(signature, is_pub, block, range)) => {
let def = mir::FunctionDefinition {
name: signature.name.clone(),
is_pub: *is_pub,
is_imported: false,
return_type: signature
.return_type
.clone()
.map(|r| r.0.into_mir(module_id))
.unwrap_or(mir::TypeKind::Void),
parameters: signature
.args
.iter()
.cloned()
.map(|p| (p.0, p.1 .0.into_mir(module_id)))
.collect(),
kind: mir::FunctionDefinitionKind::Local(
block.into_mir(module_id),
(*range).as_meta(module_id),
),
};
functions.push(def);
}
FunctionDefinition(function_def) => functions.push(function_def.into_mir(module_id)),
ExternFunction(signature) => {
let def = mir::FunctionDefinition {
name: signature.name.clone(),
@ -65,7 +44,7 @@ impl ast::Module {
.map(|r| r.0.into_mir(module_id))
.unwrap_or(mir::TypeKind::Void),
parameters: signature
.args
.params
.iter()
.cloned()
.map(|p| (p.0, p.1 .0.into_mir(module_id)))
@ -120,6 +99,11 @@ impl ast::Module {
exported: false,
});
}
AssociatedFunction(ty, function_definition) => {
for function_def in function_definition {
associated_functions.push((ty.0.into_mir(module_id), function_def.into_mir(module_id)));
}
}
}
}
@ -128,6 +112,7 @@ impl ast::Module {
module_id: module_id,
binop_defs: binops,
imports,
associated_functions,
functions,
path: self.path.clone(),
is_main: self.is_main,
@ -137,6 +122,46 @@ impl ast::Module {
}
}
impl ast::FunctionDefinition {
pub fn into_mir(&self, module_id: SourceModuleId) -> mir::FunctionDefinition {
let &ast::FunctionDefinition(signature, is_pub, block, range) = &self;
let mut params = Vec::new();
match &signature.self_kind {
ast::SelfKind::Borrow(type_kind) => params.push((
"self".to_owned(),
mir::TypeKind::Borrow(Box::new(type_kind.into_mir(module_id)), false),
)),
ast::SelfKind::MutBorrow(type_kind) => params.push((
"self".to_owned(),
mir::TypeKind::Borrow(Box::new(type_kind.into_mir(module_id)), true),
)),
ast::SelfKind::Owned(type_kind) => params.push(("self".to_owned(), type_kind.into_mir(module_id))),
ast::SelfKind::None => {}
}
params.extend(
signature
.params
.iter()
.cloned()
.map(|p| (p.0, p.1 .0.into_mir(module_id))),
);
mir::FunctionDefinition {
name: signature.name.clone(),
is_pub: *is_pub,
is_imported: false,
return_type: signature
.return_type
.clone()
.map(|r| r.0.into_mir(module_id))
.unwrap_or(mir::TypeKind::Void),
parameters: params,
kind: mir::FunctionDefinitionKind::Local(block.into_mir(module_id), (range).as_meta(module_id)),
}
}
}
impl ast::Block {
pub fn into_mir(&self, module_id: SourceModuleId) -> mir::Block {
let mut mir_statements = Vec::new();
@ -388,6 +413,15 @@ impl ast::Expression {
.map(|e| e.process(module_id))
.collect(),
),
ast::ExpressionKind::AssociatedFunctionCall(ty, fn_call_expr) => mir::ExprKind::AssociatedFunctionCall(
ty.0.into_mir(module_id),
mir::FunctionCall {
name: fn_call_expr.0.clone(),
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
parameters: fn_call_expr.1.iter().map(|e| e.process(module_id)).collect(),
meta: fn_call_expr.2.as_meta(module_id),
},
),
};
mir::Expression(kind, self.1.as_meta(module_id))
@ -474,6 +508,7 @@ impl ast::TypeKind {
ast::TypeKind::F128 => mir::TypeKind::F128,
ast::TypeKind::F128PPC => mir::TypeKind::F128PPC,
ast::TypeKind::Char => mir::TypeKind::Char,
ast::TypeKind::Unknown => mir::TypeKind::Vague(mir::VagueType::Unknown),
}
}
}

View File

@ -5,9 +5,9 @@ use reid_lib::{
Block,
};
use crate::mir::{
self, CustomTypeKey, FunctionCall, FunctionDefinitionKind, IfExpression, SourceModuleId, TypeKind, WhileStatement,
};
use mir::{CustomTypeKey, FunctionCall, FunctionDefinitionKind, IfExpression, TypeKind, WhileStatement};
use crate::mir;
#[derive(Debug)]
pub struct Allocator {
@ -16,17 +16,10 @@ pub struct Allocator {
pub struct AllocatorScope<'ctx, 'a> {
pub(super) block: &'a mut Block<'ctx>,
pub(super) module_id: SourceModuleId,
pub(super) type_values: &'a HashMap<CustomTypeKey, TypeValue>,
}
impl Allocator {
pub fn empty() -> Allocator {
Allocator {
allocations: Vec::new(),
}
}
pub fn from(
func: &FunctionDefinitionKind,
params: &Vec<(String, TypeKind)>,
@ -100,7 +93,7 @@ impl mir::Statement {
let mut allocated = Vec::new();
match &self.0 {
crate::mir::StmtKind::Let(named_variable_ref, _, expression) => {
mir::StmtKind::Let(named_variable_ref, _, expression) => {
allocated.extend(expression.allocate(scope));
let allocation = scope
.block
@ -115,15 +108,15 @@ impl mir::Statement {
allocation,
));
}
crate::mir::StmtKind::Set(lhs, rhs) => {
mir::StmtKind::Set(lhs, rhs) => {
allocated.extend(lhs.allocate(scope));
allocated.extend(rhs.allocate(scope));
}
crate::mir::StmtKind::Import(_) => {}
crate::mir::StmtKind::Expression(expression) => {
mir::StmtKind::Import(_) => {}
mir::StmtKind::Expression(expression) => {
allocated.extend(expression.allocate(scope));
}
crate::mir::StmtKind::While(WhileStatement { condition, block, .. }) => {
mir::StmtKind::While(WhileStatement { condition, block, .. }) => {
allocated.extend(condition.allocate(scope));
allocated.extend(block.allocate(scope));
}
@ -138,49 +131,54 @@ impl mir::Expression {
let mut allocated = Vec::new();
match &self.0 {
crate::mir::ExprKind::Variable(_) => {}
crate::mir::ExprKind::Indexed(expr, _, idx) => {
mir::ExprKind::Variable(_) => {}
mir::ExprKind::Indexed(expr, _, idx) => {
allocated.extend(expr.allocate(scope));
allocated.extend(idx.allocate(scope));
}
crate::mir::ExprKind::Accessed(expression, _, _) => {
mir::ExprKind::Accessed(expression, _, _) => {
allocated.extend(expression.allocate(scope));
}
crate::mir::ExprKind::Array(expressions) => {
mir::ExprKind::Array(expressions) => {
for expression in expressions {
allocated.extend(expression.allocate(scope));
}
}
crate::mir::ExprKind::Struct(_, items) => {
mir::ExprKind::Struct(_, items) => {
for (_, expression) in items {
allocated.extend(expression.allocate(scope));
}
}
crate::mir::ExprKind::Literal(_) => {}
crate::mir::ExprKind::BinOp(_, lhs, rhs, _) => {
mir::ExprKind::Literal(_) => {}
mir::ExprKind::BinOp(_, lhs, rhs, _) => {
allocated.extend(lhs.allocate(scope));
allocated.extend(rhs.allocate(scope));
}
crate::mir::ExprKind::FunctionCall(FunctionCall { parameters, .. }) => {
mir::ExprKind::FunctionCall(FunctionCall { parameters, .. }) => {
for param in parameters {
allocated.extend(param.allocate(scope));
}
}
crate::mir::ExprKind::If(IfExpression(cond, then_ex, else_ex)) => {
mir::ExprKind::If(IfExpression(cond, then_ex, else_ex)) => {
allocated.extend(cond.allocate(scope));
allocated.extend(then_ex.allocate(scope));
if let Some(else_ex) = else_ex.as_ref() {
allocated.extend(else_ex.allocate(scope));
}
}
crate::mir::ExprKind::Block(block) => {
mir::ExprKind::Block(block) => {
allocated.extend(block.allocate(scope));
}
crate::mir::ExprKind::Borrow(_, _) => {}
crate::mir::ExprKind::Deref(_) => {}
crate::mir::ExprKind::CastTo(expression, _) => {
mir::ExprKind::Borrow(_, _) => {}
mir::ExprKind::Deref(_) => {}
mir::ExprKind::CastTo(expression, _) => {
allocated.extend(expression.allocate(scope));
}
mir::ExprKind::AssociatedFunctionCall(_, FunctionCall { parameters, .. }) => {
for param in parameters {
allocated.extend(param.allocate(scope));
}
}
}
allocated

View File

@ -1,5 +1,3 @@
use std::marker::PhantomData;
use reid_lib::{builder::InstructionValue, CmpPredicate, Instr};
use crate::{
@ -38,6 +36,20 @@ pub fn form_intrinsics() -> Vec<FunctionDefinition> {
intrinsics
}
pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDefinition> {
match name {
"sizeof" => Some(FunctionDefinition {
name: "sizeof".to_owned(),
is_pub: true,
is_imported: false,
return_type: TypeKind::U64,
parameters: Vec::new(),
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicSizeOf(ty.clone()))),
}),
_ => None,
}
}
fn simple_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
@ -169,28 +181,33 @@ pub fn form_intrinsic_binops() -> Vec<BinopDefinition> {
}
pub trait IntrinsicFunction: std::fmt::Debug {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[&StackValue]) -> Result<StackValue, ErrorKind>;
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, params: &[StackValue]) -> Result<StackValue, ErrorKind>;
}
macro_rules! intrinsic_debug {
($kind:ty, $name:literal) => {
impl<T> std::fmt::Debug for $kind
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple($name).finish()
}
}
};
}
#[derive(Clone)]
pub struct IntrinsicSimpleInstr<T>(T)
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
impl<T> std::fmt::Debug for IntrinsicSimpleInstr<T>
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("IntrinsicSimpleInstr").finish()
}
}
intrinsic_debug!(IntrinsicSimpleInstr<T>, "IntrinsicSimpleInstr");
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleInstr<T>
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[&StackValue]) -> Result<StackValue, ErrorKind> {
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
let lhs = params.get(0).unwrap();
let rhs = params.get(1).unwrap();
let instr = self.clone().0(scope, lhs.instr(), rhs.instr());
@ -202,21 +219,13 @@ where
pub struct IntrinsicBooleanInstr<T>(T)
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
impl<T> std::fmt::Debug for IntrinsicBooleanInstr<T>
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("IntrinsicBooleanInstr").finish()
}
}
intrinsic_debug!(IntrinsicBooleanInstr<T>, "IntrinsicBooleanInstr");
impl<T: Clone> IntrinsicFunction for IntrinsicBooleanInstr<T>
where
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
{
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[&StackValue]) -> Result<StackValue, ErrorKind> {
fn codegen<'b, 'c>(&self, scope: &mut Scope<'b, 'c>, params: &[StackValue]) -> Result<StackValue, ErrorKind> {
let lhs = params.get(0).unwrap();
let rhs = params.get(1).unwrap();
let instr = self.clone().0(scope, lhs.instr(), rhs.instr());
@ -224,6 +233,24 @@ where
}
}
#[derive(Clone)]
pub struct IntrinsicSizeOf(TypeKind);
impl std::fmt::Debug for IntrinsicSizeOf {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("IntrinsicSizeOf").finish()
}
}
impl IntrinsicFunction for IntrinsicSizeOf {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
let instr = scope
.block
.build(Instr::Constant(reid_lib::ConstValue::U64(self.0.size_of())))
.unwrap();
Ok(StackValue(StackValueKind::Literal(instr), self.0.clone()))
}
}
// impl IntrinsicFunction for IntrinsicIAdd {
// fn codegen<'ctx, 'a>(
// &self,

View File

@ -15,8 +15,11 @@ use scope::*;
use crate::{
mir::{
self, implement::TypeCategory, pass::BinopKey, CustomTypeKey, FunctionDefinitionKind, NamedVariableRef,
SourceModuleId, StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
self,
implement::TypeCategory,
pass::{AssociatedFunctionKey, BinopKey},
CustomTypeKey, FunctionCall, FunctionDefinitionKind, NamedVariableRef, SourceModuleId, StructField, StructType,
TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
},
util::try_all,
};
@ -208,7 +211,50 @@ impl mir::Module {
};
if let Some(func) = func {
functions.insert(function.name.clone(), func);
functions.insert(function.name.clone(), ScopeFunctionKind::UserGenerated(func));
}
}
let mut associated_functions = HashMap::new();
for (ty, function) in &self.associated_functions {
let param_types: Vec<Type> = function
.parameters
.iter()
.map(|(_, p)| p.get_type(&type_values))
.collect();
let is_main = self.is_main && function.name == "main";
let func = match &function.kind {
mir::FunctionDefinitionKind::Local(_, _) => Some(module.function(
&format!("{}::{}", ty, function.name),
function.return_type.get_type(&type_values),
param_types,
FunctionFlags {
is_pub: function.is_pub || is_main,
is_main,
is_imported: function.is_imported,
..FunctionFlags::default()
},
)),
mir::FunctionDefinitionKind::Extern(imported) => Some(module.function(
&function.name,
function.return_type.get_type(&type_values),
param_types,
FunctionFlags {
is_extern: true,
is_imported: *imported,
..FunctionFlags::default()
},
)),
mir::FunctionDefinitionKind::Intrinsic(_) => None,
};
if let Some(func) = func {
associated_functions.insert(
AssociatedFunctionKey(ty.clone(), function.name.clone()),
ScopeFunctionKind::UserGenerated(func),
);
}
}
@ -227,7 +273,7 @@ impl mir::Module {
parameters: (binop.lhs.clone(), binop.rhs.clone()),
return_ty: binop.return_type.clone(),
kind: match &binop.fn_kind {
FunctionDefinitionKind::Local(block, metadata) => {
FunctionDefinitionKind::Local(..) => {
let ir_function = module.function(
&binop_fn_name,
binop.return_type.get_type(&type_values),
@ -246,7 +292,6 @@ impl mir::Module {
&vec![binop.lhs.clone(), binop.rhs.clone()],
&mut AllocatorScope {
block: &mut entry,
module_id: self.module_id,
type_values: &type_values,
},
);
@ -259,6 +304,7 @@ impl mir::Module {
module_id: self.module_id,
function: &ir_function,
block: entry,
assoc_functions: &associated_functions,
functions: &functions,
types: &types,
type_values: &type_values,
@ -289,10 +335,9 @@ impl mir::Module {
)
.unwrap();
StackBinopFunctionKind::UserGenerated(ir_function)
ScopeFunctionKind::UserGenerated(ir_function)
}
FunctionDefinitionKind::Extern(imported) => {
StackBinopFunctionKind::UserGenerated(module.function(
FunctionDefinitionKind::Extern(imported) => ScopeFunctionKind::UserGenerated(module.function(
&binop_fn_name,
binop.return_type.get_type(&type_values),
vec![binop.lhs.1.get_type(&type_values), binop.rhs.1.get_type(&type_values)],
@ -301,10 +346,9 @@ impl mir::Module {
is_imported: *imported,
..FunctionFlags::default()
},
))
}
)),
FunctionDefinitionKind::Intrinsic(intrinsic_function) => {
StackBinopFunctionKind::Intrinsic(intrinsic_function)
ScopeFunctionKind::Intrinsic(intrinsic_function)
}
},
},
@ -312,7 +356,7 @@ impl mir::Module {
}
for mir_function in &self.functions {
let function = functions.get(&mir_function.name).unwrap();
if let ScopeFunctionKind::UserGenerated(function) = functions.get(&mir_function.name).unwrap() {
let mut entry = function.block("entry");
let allocator = Allocator::from(
@ -320,7 +364,6 @@ impl mir::Module {
&mir_function.parameters,
&mut AllocatorScope {
block: &mut entry,
module_id: self.module_id,
type_values: &type_values,
},
);
@ -333,6 +376,7 @@ impl mir::Module {
module_id: self.module_id,
function,
block: entry,
assoc_functions: &associated_functions,
functions: &functions,
types: &types,
type_values: &type_values,
@ -356,13 +400,75 @@ impl mir::Module {
&mir_function.return_type,
&function,
match &mir_function.kind {
FunctionDefinitionKind::Local(..) => mir_function.signature().into_debug(tokens, compile_unit),
FunctionDefinitionKind::Local(..) => {
mir_function.signature().into_debug(tokens, compile_unit)
}
FunctionDefinitionKind::Extern(_) => None,
FunctionDefinitionKind::Intrinsic(_) => None,
},
)
.unwrap();
}
}
for (ty, mir_function) in &self.associated_functions {
if let ScopeFunctionKind::UserGenerated(function) = associated_functions
.get(&AssociatedFunctionKey(ty.clone(), mir_function.name.clone()))
.unwrap()
{
let mut entry = function.block("entry");
let allocator = Allocator::from(
&mir_function.kind,
&mir_function.parameters,
&mut AllocatorScope {
block: &mut entry,
type_values: &type_values,
},
);
let mut scope = Scope {
context,
modules: &modules,
tokens,
module: &module,
module_id: self.module_id,
function,
block: entry,
assoc_functions: &associated_functions,
functions: &functions,
types: &types,
type_values: &type_values,
stack_values: HashMap::new(),
debug: Some(Debug {
info: &debug,
scope: compile_unit,
types: &debug_types,
}),
binops: &binops,
allocator: Rc::new(RefCell::new(allocator)),
};
mir_function
.kind
.codegen(
mir_function.name.clone(),
mir_function.is_pub,
&mut scope,
&mir_function.parameters,
&mir_function.return_type,
&function,
match &mir_function.kind {
FunctionDefinitionKind::Local(..) => {
mir_function.signature().into_debug(tokens, compile_unit)
}
FunctionDefinitionKind::Extern(_) => None,
FunctionDefinitionKind::Intrinsic(_) => None,
},
)
.unwrap();
}
}
Ok(ModuleCodegen { module })
}
@ -723,7 +829,7 @@ impl mir::Expression {
});
if let Some(operation) = operation {
let a = operation.codegen(&lhs_val, &rhs_val, scope)?;
let a = operation.codegen(lhs_val.clone(), rhs_val.clone(), scope)?;
Some(a)
} else {
let lhs_type = lhs_exp.return_type(&Default::default(), scope.module_id).unwrap().1;
@ -792,72 +898,7 @@ impl mir::Expression {
))
}
}
mir::ExprKind::FunctionCall(call) => {
let ret_type_kind = call.return_type.known().expect("function return type unknown");
let ret_type = ret_type_kind.get_type(scope.type_values);
let params = try_all(
call.parameters
.iter()
.map(|e| e.codegen(scope, state))
.collect::<Vec<_>>(),
)
.map_err(|e| e.first().cloned().unwrap())?
.into_iter()
.map(|v| v.unwrap())
.collect::<Vec<_>>();
let param_instrs = params.iter().map(|e| e.instr()).collect();
let callee = scope.functions.get(&call.name).expect("function not found!");
let val = scope
.block
.build_named(call.name.clone(), Instr::FunctionCall(callee.value(), param_instrs))
.unwrap();
if let Some(debug) = &scope.debug {
let location = call.meta.into_debug(scope.tokens, debug.scope).unwrap();
let location_val = debug.info.location(&debug.scope, location);
val.with_location(&mut scope.block, location_val);
}
let ptr = if ret_type_kind != TypeKind::Void {
let ptr = scope
.block
.build_named(&call.name, Instr::Alloca(ret_type.clone()))
.unwrap();
scope
.block
.build_named(format!("{}.store", call.name), Instr::Store(ptr, val))
.unwrap();
Some(ptr)
} else {
None
};
if let Some(ptr) = ptr {
if state.should_load {
Some(StackValue(
StackValueKind::Immutable(
scope
.block
.build_named(call.name.clone(), Instr::Load(ptr, ret_type))
.unwrap(),
),
ret_type_kind,
))
} else {
Some(StackValue(
StackValueKind::Immutable(ptr),
TypeKind::CodegenPtr(Box::new(ret_type_kind)),
))
}
} else {
None
}
}
mir::ExprKind::FunctionCall(call) => codegen_function_call(None, call, scope, state)?,
mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state)?,
mir::ExprKind::Block(block) => {
let inner = scope.function.block("inner");
@ -1217,6 +1258,7 @@ impl mir::Expression {
}
}
}
mir::ExprKind::AssociatedFunctionCall(ty, call) => codegen_function_call(Some(ty), call, scope, state)?,
};
if let Some(value) = &value {
value.instr().maybe_location(&mut scope.block, location);
@ -1225,6 +1267,103 @@ impl mir::Expression {
}
}
fn codegen_function_call<'ctx, 'a>(
associated_type: Option<&TypeKind>,
call: &FunctionCall,
scope: &mut Scope<'ctx, 'a>,
state: &State,
) -> Result<Option<StackValue>, ErrorKind> {
let ret_type_kind = call.return_type.known().expect("function return type unknown");
let call_name = if let Some(ty) = &associated_type {
format!("{}::{}", ty, call.name)
} else {
String::from(call.name.clone())
};
let ret_type = ret_type_kind.get_type(scope.type_values);
let params = try_all(
call.parameters
.iter()
.map(|e| e.codegen(scope, state))
.collect::<Vec<_>>(),
)
.map_err(|e| e.first().cloned().unwrap())?
.into_iter()
.map(|v| v.unwrap())
.collect::<Vec<_>>();
let location = if let Some(debug) = &scope.debug {
call.meta.into_debug(scope.tokens, debug.scope)
} else {
None
};
let val = if let Some(ty) = associated_type {
let assoc_key = AssociatedFunctionKey(ty.clone(), call.name.clone());
let intrinsic_def = get_intrinsic_assoc_func(&ty, &call.name);
let intrinsic = intrinsic_def.map(|func_def| {
let FunctionDefinitionKind::Intrinsic(intrinsic) = func_def.kind else {
panic!();
};
ScopeFunctionKind::IntrinsicOwned(intrinsic)
});
let callee = scope
.assoc_functions
.get(&assoc_key)
.or(intrinsic.as_ref())
.expect(&format!("Function {} does not exist!", call_name));
callee
.codegen(&call_name, params.as_slice(), &call.return_type, location, scope)
.unwrap()
} else {
let callee = scope
.functions
.get(&call.name)
.expect(&format!("Function {} does not exist!", call_name));
callee
.codegen(&call_name, params.as_slice(), &call.return_type, location, scope)
.unwrap()
};
let ptr = if ret_type_kind != TypeKind::Void {
let ptr = scope
.block
.build_named(&call.name, Instr::Alloca(ret_type.clone()))
.unwrap();
scope
.block
.build_named(format!("{}.store", call_name), Instr::Store(ptr, val.instr()))
.unwrap();
Some(ptr)
} else {
None
};
Ok(if let Some(ptr) = ptr {
if state.should_load {
Some(StackValue(
StackValueKind::Immutable(
scope
.block
.build_named(call.name.clone(), Instr::Load(ptr, ret_type))
.unwrap(),
),
ret_type_kind,
))
} else {
Some(StackValue(
StackValueKind::Immutable(ptr),
TypeKind::CodegenPtr(Box::new(ret_type_kind)),
))
}
} else {
None
})
}
impl mir::IfExpression {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Result<Option<StackValue>, ErrorKind> {
let condition = self.0.codegen(scope, state)?.unwrap();

View File

@ -2,13 +2,16 @@ use std::{cell::RefCell, collections::HashMap, mem, rc::Rc};
use reid_lib::{
builder::{InstructionValue, TypeValue},
debug_information::{DebugInformation, DebugProgramValue, DebugTypeValue},
debug_information::{DebugInformation, DebugLocation, DebugProgramValue, DebugTypeValue},
Block, Context, Function, Instr, Module,
};
use crate::{
lexer::FullToken,
mir::{pass::BinopKey, CustomTypeKey, SourceModuleId, TypeDefinition, TypeKind},
mir::{
pass::{AssociatedFunctionKey, BinopKey},
CustomTypeKey, SourceModuleId, TypeDefinition, TypeKind,
},
};
use super::{allocator::Allocator, ErrorKind, IntrinsicFunction, ModuleCodegen};
@ -23,7 +26,8 @@ pub struct Scope<'ctx, 'scope> {
pub(super) block: Block<'ctx>,
pub(super) types: &'scope HashMap<TypeValue, TypeDefinition>,
pub(super) type_values: &'scope HashMap<CustomTypeKey, TypeValue>,
pub(super) functions: &'scope HashMap<String, Function<'ctx>>,
pub(super) assoc_functions: &'scope HashMap<AssociatedFunctionKey, ScopeFunctionKind<'ctx>>,
pub(super) functions: &'scope HashMap<String, ScopeFunctionKind<'ctx>>,
pub(super) binops: &'scope HashMap<BinopKey, StackBinopDefinition<'ctx>>,
pub(super) stack_values: HashMap<String, StackValue>,
pub(super) debug: Option<Debug<'ctx>>,
@ -40,6 +44,7 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
context: self.context,
module: self.module,
module_id: self.module_id,
assoc_functions: self.assoc_functions,
functions: self.functions,
types: self.types,
type_values: self.type_values,
@ -126,19 +131,20 @@ impl StackValueKind {
pub struct StackBinopDefinition<'ctx> {
pub(super) parameters: ((String, TypeKind), (String, TypeKind)),
pub(super) return_ty: TypeKind,
pub(super) kind: StackBinopFunctionKind<'ctx>,
pub(super) kind: ScopeFunctionKind<'ctx>,
}
pub enum StackBinopFunctionKind<'ctx> {
pub enum ScopeFunctionKind<'ctx> {
UserGenerated(Function<'ctx>),
Intrinsic(&'ctx Box<dyn IntrinsicFunction>),
IntrinsicOwned(Box<dyn IntrinsicFunction>),
}
impl<'ctx> StackBinopDefinition<'ctx> {
pub fn codegen<'a>(
&self,
lhs: &StackValue,
rhs: &StackValue,
lhs: StackValue,
rhs: StackValue,
scope: &mut Scope<'ctx, 'a>,
) -> Result<StackValue, ErrorKind> {
let (lhs, rhs) = if lhs.1 == self.parameters.0 .1 && rhs.1 == self.parameters.1 .1 {
@ -146,15 +152,43 @@ impl<'ctx> StackBinopDefinition<'ctx> {
} else {
(rhs, lhs)
};
match &self.kind {
StackBinopFunctionKind::UserGenerated(ir) => {
let instr = scope
.block
.build(Instr::FunctionCall(ir.value(), vec![lhs.instr(), rhs.instr()]))
.unwrap();
Ok(StackValue(StackValueKind::Immutable(instr), self.return_ty.clone()))
let name = format!(
"binop.{}.{}.{}.call",
self.parameters.0 .1, self.parameters.1 .1, self.return_ty
);
self.kind.codegen(&name, &[lhs, rhs], &self.return_ty, None, scope)
}
StackBinopFunctionKind::Intrinsic(fun) => fun.codegen(scope, &[&lhs, &rhs]),
}
impl<'ctx> ScopeFunctionKind<'ctx> {
pub fn codegen<'a>(
&self,
name: &str,
params: &[StackValue],
return_ty: &TypeKind,
location: Option<DebugLocation>,
scope: &mut Scope<'ctx, 'a>,
) -> Result<StackValue, ErrorKind> {
match self {
ScopeFunctionKind::UserGenerated(function) => {
let val = scope
.block
.build_named(
name,
Instr::FunctionCall(function.value(), params.iter().map(|p| p.instr()).collect()),
)
.unwrap();
if let Some(debug) = &scope.debug {
if let Some(location) = location {
let location_val = debug.info.location(&debug.scope, location);
val.with_location(&mut scope.block, location_val);
}
}
Ok(StackValue(StackValueKind::Immutable(val), return_ty.clone()))
}
ScopeFunctionKind::Intrinsic(fun) => fun.codegen(scope, params),
ScopeFunctionKind::IntrinsicOwned(fun) => fun.codegen(scope, params),
}
}
}

View File

@ -2,7 +2,7 @@ use std::fmt::{Debug, Display, Write};
use crate::pad_adapter::PadAdapter;
use super::{typecheck::typerefs::TypeRefs, *};
use super::*;
impl Display for Context {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -49,6 +49,9 @@ impl Display for Module {
for typedef in &self.typedefs {
writeln!(inner_f, "{}", typedef)?;
}
for (ty, fun) in &self.associated_functions {
writeln!(inner_f, "(Assoc {}) {}", ty, fun)?;
}
for fun in &self.functions {
writeln!(inner_f, "{}", fun)?;
}
@ -272,6 +275,11 @@ impl Display for ExprKind {
ExprKind::Borrow(var_ref, true) => write!(f, "&mut {}", var_ref),
ExprKind::Deref(var_ref) => write!(f, "*{}", var_ref),
ExprKind::CastTo(expression, type_kind) => write!(f, "{} as {}", expression, type_kind),
ExprKind::AssociatedFunctionCall(type_kind, function_call) => {
Display::fmt(type_kind, f)?;
write!(f, "::")?;
Display::fmt(function_call, f)
}
}
}
}

View File

@ -1,6 +1,6 @@
use crate::util::maybe;
use super::{pass::ScopeBinopDef, typecheck::typerefs::TypeRefs, *};
use super::{typecheck::typerefs::TypeRefs, *};
#[derive(Debug, Clone)]
pub enum ReturnTypeOther {
@ -443,6 +443,7 @@ impl Expression {
},
Err(_) => Ok((ReturnKind::Soft, type_kind.clone())),
},
AssociatedFunctionCall(_, fcall) => fcall.return_type(),
}
}
@ -461,6 +462,7 @@ impl Expression {
ExprKind::FunctionCall(_) => None,
ExprKind::If(_) => None,
ExprKind::CastTo(expression, _) => expression.backing_var(),
ExprKind::AssociatedFunctionCall(..) => None,
}
}
@ -499,6 +501,7 @@ impl Expression {
ExprKind::Borrow(_, _) => None,
ExprKind::Deref(_) => None,
ExprKind::CastTo(expression, _) => expression.num_value()?,
ExprKind::AssociatedFunctionCall(..) => None,
})
}
}

View File

@ -8,7 +8,6 @@ use std::{
};
use crate::{
codegen::scope,
compile_module,
error_raporting::{ErrorModules, ReidError},
mir::{
@ -254,7 +253,7 @@ impl<'map> Pass for LinkerPass<'map> {
binop.exported = true;
already_imported_binops.insert(binop_key);
match &binop.fn_kind {
FunctionDefinitionKind::Local(block, metadata) => {
FunctionDefinitionKind::Local(..) => {
importer_module.binop_defs.push(BinopDefinition {
lhs: binop.lhs.clone(),
op: binop.op,

View File

@ -258,6 +258,7 @@ pub enum ExprKind {
Literal(Literal),
BinOp(BinaryOperator, Box<Expression>, Box<Expression>, TypeKind),
FunctionCall(FunctionCall),
AssociatedFunctionCall(TypeKind, FunctionCall),
If(IfExpression),
Block(Block),
Borrow(NamedVariableRef, bool),
@ -292,6 +293,12 @@ pub struct FunctionDefinition {
pub kind: FunctionDefinitionKind,
}
pub enum SelfKind {
Borrow,
MutBorrow,
None,
}
#[derive(Debug)]
pub enum FunctionDefinitionKind {
/// Actual definition block and surrounding signature range
@ -393,6 +400,7 @@ pub struct Module {
pub name: String,
pub module_id: SourceModuleId,
pub imports: Vec<Import>,
pub associated_functions: Vec<(TypeKind, FunctionDefinition)>,
pub functions: Vec<FunctionDefinition>,
pub typedefs: Vec<TypeDefinition>,
pub binop_defs: Vec<BinopDefinition>,

View File

@ -5,7 +5,7 @@ use std::collections::HashMap;
use std::convert::Infallible;
use std::error::Error as STDError;
use crate::codegen::intrinsics::form_intrinsic_binops;
use crate::codegen::intrinsics::{form_intrinsic_binops, get_intrinsic_assoc_func};
use crate::error_raporting::ReidError;
use super::*;
@ -123,7 +123,8 @@ pub type BinopMap = Storage<BinopKey, ScopeBinopDef>;
pub struct Scope<Data: Clone + Default> {
pub module_id: Option<SourceModuleId>,
pub binops: BinopMap,
pub function_returns: Storage<String, ScopeFunction>,
pub associated_functions: Storage<AssociatedFunctionKey, ScopeFunction>,
pub functions: Storage<String, ScopeFunction>,
pub variables: Storage<String, ScopeVariable>,
pub types: Storage<CustomTypeKey, TypeDefinition>,
/// Hard Return type of this scope, if inside a function
@ -135,7 +136,8 @@ impl<Data: Clone + Default> Scope<Data> {
pub fn inner(&self) -> Scope<Data> {
Scope {
module_id: self.module_id,
function_returns: self.function_returns.clone(),
associated_functions: self.associated_functions.clone(),
functions: self.functions.clone(),
variables: self.variables.clone(),
binops: self.binops.clone(),
types: self.types.clone(),
@ -167,6 +169,24 @@ impl<Data: Clone + Default> Scope<Data> {
.find(|(key, def)| key.0 == typekey.0 && def.importer == Some(typekey.1))
.map(|(_, v)| v))
}
pub fn get_associated_function(&mut self, key: &AssociatedFunctionKey) -> Option<ScopeFunction> {
let func = self.associated_functions.get(key);
if let Some(func) = func {
Some(func.clone())
} else if let Some(func) = get_intrinsic_assoc_func(&key.0, &key.1) {
self.associated_functions.set(
key.clone(),
ScopeFunction {
ret: func.return_type,
params: func.parameters.iter().map(|(_, p)| p.clone()).collect(),
},
);
self.associated_functions.get(key).cloned()
} else {
None
}
}
}
#[derive(Clone, Debug)]
@ -181,6 +201,9 @@ pub struct ScopeVariable {
pub mutable: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AssociatedFunctionKey(pub TypeKind, pub String);
#[derive(Clone, Debug, Eq)]
pub struct BinopKey {
pub params: (TypeKind, TypeKind),
@ -389,7 +412,7 @@ impl Module {
for function in &self.functions {
scope
.function_returns
.functions
.set(
function.name.clone(),
ScopeFunction {
@ -400,6 +423,19 @@ impl Module {
.ok();
}
for (ty, function) in &self.associated_functions {
scope
.associated_functions
.set(
AssociatedFunctionKey(ty.clone(), function.name.clone()),
ScopeFunction {
ret: function.return_type.clone(),
params: function.parameters.iter().cloned().map(|v| v.1).collect(),
},
)
.ok();
}
pass.module(self, PassState::from(state, scope, Some(self.module_id)))?;
for function in &mut self.functions {

View File

@ -24,12 +24,16 @@ pub enum ErrorKind {
TypesIncompatible(TypeKind, TypeKind),
#[error("Variable not defined: {0}")]
VariableNotDefined(String),
#[error("Function not defined: {0}")]
#[error("Function {0} not defined")]
FunctionNotDefined(String),
#[error("Function {0} not defined for type {1}")]
AssocFunctionNotDefined(String, TypeKind),
#[error("Expected a return type of {0}, got {1} instead")]
ReturnTypeMismatch(TypeKind, TypeKind),
#[error("Function {0} already defined {1}")]
FunctionAlreadyDefined(String, ErrorTypedefKind),
#[error("Function {0}::{1} already defined {2}")]
AssocFunctionAlreadyDefined(TypeKind, String, ErrorTypedefKind),
#[error("Variable already defined: {0}")]
VariableAlreadyDefined(String),
#[error("Variable {0} is not declared as mutable")]
@ -170,7 +174,7 @@ impl TypeKind {
return self.clone();
}
match (self, other) {
(TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => {
(TypeKind::Vague(Vague::Unknown), _) | (_, TypeKind::Vague(Vague::Unknown)) => {
TypeKind::Vague(VagueType::Unknown)
}
(TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => match other {

View File

@ -68,6 +68,11 @@ impl<'t> Pass for TypeCheck<'t> {
state.ok(res, binop.block_meta().unwrap_or(binop.signature()));
}
for (_, function) in &mut module.associated_functions {
let res = function.typecheck(&self.refs, &mut state.inner());
state.ok(res, function.block_meta());
}
for function in &mut module.functions {
let res = function.typecheck(&self.refs, &mut state.inner());
state.ok(res, function.block_meta());
@ -443,7 +448,7 @@ impl Expression {
ExprKind::FunctionCall(function_call) => {
let true_function = state
.scope
.function_returns
.functions
.get(&function_call.name)
.cloned()
.ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()));
@ -724,6 +729,54 @@ impl Expression {
let expr = expression.typecheck(state, typerefs, HintKind::Default)?;
expr.resolve_ref(typerefs).cast_into(type_kind)
}
ExprKind::AssociatedFunctionCall(type_kind, function_call) => {
let true_function = state
.scope
.get_associated_function(&pass::AssociatedFunctionKey(
type_kind.clone(),
function_call.name.clone(),
))
.ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()));
if let Some(f) = state.ok(true_function, self.1) {
let param_len_given = function_call.parameters.len();
let param_len_expected = f.params.len();
// Check that there are the same number of parameters given
// as expected
if param_len_given != param_len_expected {
state.ok::<_, Infallible>(
Err(ErrorKind::InvalidAmountParameters(
function_call.name.clone(),
param_len_given,
param_len_expected,
)),
self.1,
);
}
let true_params_iter = f
.params
.into_iter()
.chain(iter::repeat(TypeKind::Vague(Vague::Unknown)));
for (param, true_param_t) in function_call.parameters.iter_mut().zip(true_params_iter) {
// Typecheck every param separately
let param_res = param.typecheck(state, &typerefs, HintKind::Coerce(true_param_t.clone()));
let param_t = state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1);
state.ok(param_t.narrow_into(&true_param_t), param.1);
}
// Make sure function return type is the same as the claimed
// return type
let ret_t = f.ret.narrow_into(&function_call.return_type.resolve_ref(typerefs))?;
// Update typing to be more accurate
function_call.return_type = ret_t.clone();
Ok(ret_t.resolve_ref(typerefs))
} else {
Ok(function_call.return_type.clone().resolve_ref(typerefs))
}
}
}
}
}

View File

@ -12,15 +12,15 @@ use std::{
use crate::{
mir::{
BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement,
pass::AssociatedFunctionKey, BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition,
FunctionDefinitionKind, IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement,
},
util::try_all,
};
use super::{
super::{
pass::{BinopKey, Pass, PassResult, PassState},
pass::{BinopKey, Pass, PassResult},
TypeKind::*,
VagueType::*,
},
@ -60,6 +60,29 @@ impl<'t> Pass for TypeInference<'t> {
}
}
let mut seen_assoc_functions = HashMap::new();
for (ty, function) in &mut module.associated_functions {
if let Some(kind) = seen_assoc_functions.get(&(ty.clone(), function.name.clone())) {
state.note_errors(
&vec![ErrorKind::AssocFunctionAlreadyDefined(
ty.clone(),
function.name.clone(),
*kind,
)],
function.signature(),
);
} else {
seen_assoc_functions.insert(
(ty.clone(), function.name.clone()),
match function.kind {
FunctionDefinitionKind::Local(..) => ErrorTypedefKind::Local,
FunctionDefinitionKind::Extern(..) => ErrorTypedefKind::Extern,
FunctionDefinitionKind::Intrinsic(..) => ErrorTypedefKind::Intrinsic,
},
);
}
}
let mut seen_binops = HashSet::new();
for binop in &module.binop_defs {
let binop_key = BinopKey {
@ -97,6 +120,11 @@ impl<'t> Pass for TypeInference<'t> {
state.ok(res, binop.block_meta().unwrap_or(binop.signature()));
}
for (_, function) in &mut module.associated_functions {
let res = function.infer_types(&self.refs, &mut state.inner());
state.ok(res, function.block_meta());
}
for function in &mut module.functions {
let res = function.infer_types(&self.refs, &mut state.inner());
state.ok(res, function.block_meta());
@ -365,7 +393,7 @@ impl Expression {
// Get function definition and types
let fn_call = state
.scope
.function_returns
.functions
.get(&function_call.name)
.ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()))?
.clone();
@ -566,6 +594,32 @@ impl Expression {
expression.infer_types(state, type_refs)?;
Ok(type_refs.from_type(type_kind).unwrap())
}
ExprKind::AssociatedFunctionCall(type_kind, function_call) => {
// Get function definition and types
let fn_call = state
.scope
.get_associated_function(&AssociatedFunctionKey(type_kind.clone(), function_call.name.clone()))
.ok_or(ErrorKind::AssocFunctionNotDefined(
function_call.name.clone(),
type_kind.clone(),
))?
.clone();
// Infer param expression types and narrow them to the
// expected function parameters (or Unknown types if too
// many were provided)
let true_params_iter = fn_call.params.iter().chain(iter::repeat(&Vague(Unknown)));
for (param_expr, param_t) in function_call.parameters.iter_mut().zip(true_params_iter) {
let expr_res = param_expr.infer_types(state, type_refs);
if let Some(mut param_ref) = state.ok(expr_res, param_expr.1) {
param_ref.narrow(&mut type_refs.from_type(param_t).unwrap());
}
}
// Provide function return type
Ok(type_refs.from_type(&fn_call.ret).unwrap())
}
}
}
}

View File

@ -4,15 +4,9 @@ use std::{
rc::Rc,
};
use crate::{
ast::BinopDefinition,
mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType},
};
use crate::mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType};
use super::{
super::pass::{BinopKey, ScopeBinopDef, Storage},
ErrorKind,
};
use super::{super::pass::ScopeBinopDef, ErrorKind};
#[derive(Clone)]
pub struct TypeRef<'scope>(pub(super) TypeIdRef, pub(super) &'scope ScopeTypeRefs<'scope>);

View File

@ -1,10 +1,4 @@
use std::{
alloc::System,
path::PathBuf,
process::Command,
thread,
time::{Duration, SystemTime},
};
use std::{path::PathBuf, process::Command, time::SystemTime};
use reid::{
compile_module,
@ -149,3 +143,12 @@ fn array_short_compiles_well() {
fn imported_type_compiles_well() {
test(include_str!("../../examples/imported_type.reid"), "test", Some(0));
}
#[test]
fn associated_functions() {
test(
include_str!("../../examples/associated_functions.reid"),
"test",
Some(32),
);
}