Compare commits
16 Commits
185bd36cd9
...
acc2964305
Author | SHA1 | Date | |
---|---|---|---|
acc2964305 | |||
f3471473a2 | |||
537167fe4f | |||
0613fc5c53 | |||
7c6f1a7f9b | |||
4f57ed399f | |||
24f11a77d2 | |||
4d7c17a854 | |||
46668b7099 | |||
ab94bd7df0 | |||
09f1784810 | |||
5eef265652 | |||
a253c032d8 | |||
bee31f4b92 | |||
b03adf0ab6 | |||
3e2ec6ed6b |
10
README.md
10
README.md
@ -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)
|
||||
|
28
examples/associated_functions.reid
Normal file
28
examples/associated_functions.reid
Normal 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;
|
||||
}
|
@ -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)]
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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,22 +335,20 @@ impl mir::Module {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
StackBinopFunctionKind::UserGenerated(ir_function)
|
||||
}
|
||||
FunctionDefinitionKind::Extern(imported) => {
|
||||
StackBinopFunctionKind::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)],
|
||||
FunctionFlags {
|
||||
is_extern: true,
|
||||
is_imported: *imported,
|
||||
..FunctionFlags::default()
|
||||
},
|
||||
))
|
||||
ScopeFunctionKind::UserGenerated(ir_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)],
|
||||
FunctionFlags {
|
||||
is_extern: true,
|
||||
is_imported: *imported,
|
||||
..FunctionFlags::default()
|
||||
},
|
||||
)),
|
||||
FunctionDefinitionKind::Intrinsic(intrinsic_function) => {
|
||||
StackBinopFunctionKind::Intrinsic(intrinsic_function)
|
||||
ScopeFunctionKind::Intrinsic(intrinsic_function)
|
||||
}
|
||||
},
|
||||
},
|
||||
@ -312,56 +356,118 @@ impl mir::Module {
|
||||
}
|
||||
|
||||
for mir_function in &self.functions {
|
||||
let function = functions.get(&mir_function.name).unwrap();
|
||||
let mut entry = function.block("entry");
|
||||
if let ScopeFunctionKind::UserGenerated(function) = functions.get(&mir_function.name).unwrap() {
|
||||
let mut entry = function.block("entry");
|
||||
|
||||
let allocator = Allocator::from(
|
||||
&mir_function.kind,
|
||||
&mir_function.parameters,
|
||||
&mut AllocatorScope {
|
||||
block: &mut entry,
|
||||
module_id: self.module_id,
|
||||
type_values: &type_values,
|
||||
},
|
||||
);
|
||||
|
||||
let mut scope = Scope {
|
||||
context,
|
||||
modules: &modules,
|
||||
tokens,
|
||||
module: &module,
|
||||
module_id: self.module_id,
|
||||
function,
|
||||
block: entry,
|
||||
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,
|
||||
let allocator = Allocator::from(
|
||||
&mir_function.kind,
|
||||
&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,
|
||||
&mut AllocatorScope {
|
||||
block: &mut entry,
|
||||
type_values: &type_values,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
@ -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
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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(Instr::FunctionCall(ir.value(), vec![lhs.instr(), rhs.instr()]))
|
||||
.build_named(
|
||||
name,
|
||||
Instr::FunctionCall(function.value(), params.iter().map(|p| p.instr()).collect()),
|
||||
)
|
||||
.unwrap();
|
||||
Ok(StackValue(StackValueKind::Immutable(instr), self.return_ty.clone()))
|
||||
|
||||
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()))
|
||||
}
|
||||
StackBinopFunctionKind::Intrinsic(fun) => fun.codegen(scope, &[&lhs, &rhs]),
|
||||
ScopeFunctionKind::Intrinsic(fun) => fun.codegen(scope, params),
|
||||
ScopeFunctionKind::IntrinsicOwned(fun) => fun.codegen(scope, params),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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>,
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>);
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user