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)
|
- ~~Intrinsic functions~~ (DONE)
|
||||||
- ~~Ability to specify types in literals and variable definitions~~ (DONE)
|
- ~~Ability to specify types in literals and variable definitions~~ (DONE)
|
||||||
- ~~Debug Information~~ (DONE)
|
- ~~Debug Information~~ (DONE)
|
||||||
- ~~Fix struct initialization (wrong order and missing fields allowed now)~~
|
- ~~Fix struct initialization (wrong order and missing fields allowed now)~~ (DONE)
|
||||||
- ~~Not-Unary~~
|
- ~~Not-Unary~~ (DONE)
|
||||||
- ~~Importing types from other modules~~
|
- ~~Importing types from other modules~~ (DONE)
|
||||||
- ~~Importable binops?~~
|
- ~~Importable binops?~~ (DONE)
|
||||||
- Associated functions (for e.g. sizeof)
|
- ~~Associated functions (for e.g. sizeof)~~ (DONE)
|
||||||
|
|
||||||
Big features that I want later but are not necessary:
|
Big features that I want later but are not necessary:
|
||||||
- ~~User-defined binary operations~~ (DONE)
|
- ~~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),
|
Custom(String),
|
||||||
Borrow(Box<TypeKind>, bool),
|
Borrow(Box<TypeKind>, bool),
|
||||||
Ptr(Box<TypeKind>),
|
Ptr(Box<TypeKind>),
|
||||||
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -90,6 +91,7 @@ pub enum ExpressionKind {
|
|||||||
Accessed(Box<Expression>, String),
|
Accessed(Box<Expression>, String),
|
||||||
Binop(BinaryOperator, Box<Expression>, Box<Expression>),
|
Binop(BinaryOperator, Box<Expression>, Box<Expression>),
|
||||||
FunctionCall(Box<FunctionCallExpression>),
|
FunctionCall(Box<FunctionCallExpression>),
|
||||||
|
AssociatedFunctionCall(Type, Box<FunctionCallExpression>),
|
||||||
BlockExpr(Box<Block>),
|
BlockExpr(Box<Block>),
|
||||||
IfExpr(Box<IfExpression>),
|
IfExpr(Box<IfExpression>),
|
||||||
StructExpression(StructExpression),
|
StructExpression(StructExpression),
|
||||||
@ -170,12 +172,21 @@ pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub To
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FunctionSignature {
|
pub struct FunctionSignature {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub args: Vec<(String, Type)>,
|
pub self_kind: SelfKind,
|
||||||
|
pub params: Vec<(String, Type)>,
|
||||||
pub return_type: Option<Type>,
|
pub return_type: Option<Type>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub range: TokenRange,
|
pub range: TokenRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum SelfKind {
|
||||||
|
Owned(TypeKind),
|
||||||
|
Borrow(TypeKind),
|
||||||
|
MutBorrow(TypeKind),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum ReturnType {
|
pub enum ReturnType {
|
||||||
Soft,
|
Soft,
|
||||||
@ -236,6 +247,7 @@ pub enum TopLevelStatement {
|
|||||||
FunctionDefinition(FunctionDefinition),
|
FunctionDefinition(FunctionDefinition),
|
||||||
TypeDefinition(TypeDefinition),
|
TypeDefinition(TypeDefinition),
|
||||||
BinopDefinition(BinopDefinition),
|
BinopDefinition(BinopDefinition),
|
||||||
|
AssociatedFunction(Type, Vec<FunctionDefinition>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[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)]
|
#[derive(Debug)]
|
||||||
pub struct PrimaryExpression(Expression);
|
pub struct PrimaryExpression(Expression);
|
||||||
|
|
||||||
@ -200,6 +212,11 @@ impl Parse for PrimaryExpression {
|
|||||||
Kind::UnaryOperation(unary, Box::new(stream.parse()?)),
|
Kind::UnaryOperation(unary, Box::new(stream.parse()?)),
|
||||||
stream.get_range().unwrap(),
|
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() {
|
} else if let Some(token) = stream.peek() {
|
||||||
match &token {
|
match &token {
|
||||||
Token::Identifier(v) => {
|
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 {
|
impl Parse for FunctionSignature {
|
||||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||||
if let Some(Token::Identifier(name)) = stream.next() {
|
if let Some(Token::Identifier(name)) = stream.next() {
|
||||||
stream.expect(Token::ParenOpen)?;
|
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>() {
|
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() {
|
while let Some(Token::Comma) = stream.peek() {
|
||||||
stream.next();
|
stream.next();
|
||||||
let param = stream.parse::<FunctionParam>()?;
|
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 {
|
Ok(FunctionSignature {
|
||||||
name,
|
name,
|
||||||
args,
|
params,
|
||||||
|
self_kind,
|
||||||
return_type,
|
return_type,
|
||||||
range: stream.get_range().unwrap(),
|
range: stream.get_range().unwrap(),
|
||||||
})
|
})
|
||||||
@ -874,7 +932,14 @@ impl Parse for TopLevelStatement {
|
|||||||
range,
|
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")?)?,
|
_ => 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 {
|
impl ast::Module {
|
||||||
pub fn process(self, module_id: SourceModuleId) -> mir::Module {
|
pub fn process(self, module_id: SourceModuleId) -> mir::Module {
|
||||||
let mut imports = Vec::new();
|
let mut imports = Vec::new();
|
||||||
|
let mut associated_functions = Vec::new();
|
||||||
let mut functions = Vec::new();
|
let mut functions = Vec::new();
|
||||||
let mut typedefs = Vec::new();
|
let mut typedefs = Vec::new();
|
||||||
let mut binops = Vec::new();
|
let mut binops = Vec::new();
|
||||||
@ -31,29 +32,7 @@ impl ast::Module {
|
|||||||
Import(import) => {
|
Import(import) => {
|
||||||
imports.push(mir::Import(import.0.clone(), import.1.as_meta(module_id)));
|
imports.push(mir::Import(import.0.clone(), import.1.as_meta(module_id)));
|
||||||
}
|
}
|
||||||
FunctionDefinition(ast::FunctionDefinition(signature, is_pub, block, range)) => {
|
FunctionDefinition(function_def) => functions.push(function_def.into_mir(module_id)),
|
||||||
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);
|
|
||||||
}
|
|
||||||
ExternFunction(signature) => {
|
ExternFunction(signature) => {
|
||||||
let def = mir::FunctionDefinition {
|
let def = mir::FunctionDefinition {
|
||||||
name: signature.name.clone(),
|
name: signature.name.clone(),
|
||||||
@ -65,7 +44,7 @@ impl ast::Module {
|
|||||||
.map(|r| r.0.into_mir(module_id))
|
.map(|r| r.0.into_mir(module_id))
|
||||||
.unwrap_or(mir::TypeKind::Void),
|
.unwrap_or(mir::TypeKind::Void),
|
||||||
parameters: signature
|
parameters: signature
|
||||||
.args
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|p| (p.0, p.1 .0.into_mir(module_id)))
|
.map(|p| (p.0, p.1 .0.into_mir(module_id)))
|
||||||
@ -120,6 +99,11 @@ impl ast::Module {
|
|||||||
exported: false,
|
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,
|
module_id: module_id,
|
||||||
binop_defs: binops,
|
binop_defs: binops,
|
||||||
imports,
|
imports,
|
||||||
|
associated_functions,
|
||||||
functions,
|
functions,
|
||||||
path: self.path.clone(),
|
path: self.path.clone(),
|
||||||
is_main: self.is_main,
|
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 {
|
impl ast::Block {
|
||||||
pub fn into_mir(&self, module_id: SourceModuleId) -> mir::Block {
|
pub fn into_mir(&self, module_id: SourceModuleId) -> mir::Block {
|
||||||
let mut mir_statements = Vec::new();
|
let mut mir_statements = Vec::new();
|
||||||
@ -388,6 +413,15 @@ impl ast::Expression {
|
|||||||
.map(|e| e.process(module_id))
|
.map(|e| e.process(module_id))
|
||||||
.collect(),
|
.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))
|
mir::Expression(kind, self.1.as_meta(module_id))
|
||||||
@ -474,6 +508,7 @@ impl ast::TypeKind {
|
|||||||
ast::TypeKind::F128 => mir::TypeKind::F128,
|
ast::TypeKind::F128 => mir::TypeKind::F128,
|
||||||
ast::TypeKind::F128PPC => mir::TypeKind::F128PPC,
|
ast::TypeKind::F128PPC => mir::TypeKind::F128PPC,
|
||||||
ast::TypeKind::Char => mir::TypeKind::Char,
|
ast::TypeKind::Char => mir::TypeKind::Char,
|
||||||
|
ast::TypeKind::Unknown => mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,9 @@ use reid_lib::{
|
|||||||
Block,
|
Block,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::mir::{
|
use mir::{CustomTypeKey, FunctionCall, FunctionDefinitionKind, IfExpression, TypeKind, WhileStatement};
|
||||||
self, CustomTypeKey, FunctionCall, FunctionDefinitionKind, IfExpression, SourceModuleId, TypeKind, WhileStatement,
|
|
||||||
};
|
use crate::mir;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Allocator {
|
pub struct Allocator {
|
||||||
@ -16,17 +16,10 @@ pub struct Allocator {
|
|||||||
|
|
||||||
pub struct AllocatorScope<'ctx, 'a> {
|
pub struct AllocatorScope<'ctx, 'a> {
|
||||||
pub(super) block: &'a mut Block<'ctx>,
|
pub(super) block: &'a mut Block<'ctx>,
|
||||||
pub(super) module_id: SourceModuleId,
|
|
||||||
pub(super) type_values: &'a HashMap<CustomTypeKey, TypeValue>,
|
pub(super) type_values: &'a HashMap<CustomTypeKey, TypeValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Allocator {
|
impl Allocator {
|
||||||
pub fn empty() -> Allocator {
|
|
||||||
Allocator {
|
|
||||||
allocations: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from(
|
pub fn from(
|
||||||
func: &FunctionDefinitionKind,
|
func: &FunctionDefinitionKind,
|
||||||
params: &Vec<(String, TypeKind)>,
|
params: &Vec<(String, TypeKind)>,
|
||||||
@ -100,7 +93,7 @@ impl mir::Statement {
|
|||||||
let mut allocated = Vec::new();
|
let mut allocated = Vec::new();
|
||||||
|
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
crate::mir::StmtKind::Let(named_variable_ref, _, expression) => {
|
mir::StmtKind::Let(named_variable_ref, _, expression) => {
|
||||||
allocated.extend(expression.allocate(scope));
|
allocated.extend(expression.allocate(scope));
|
||||||
let allocation = scope
|
let allocation = scope
|
||||||
.block
|
.block
|
||||||
@ -115,15 +108,15 @@ impl mir::Statement {
|
|||||||
allocation,
|
allocation,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
crate::mir::StmtKind::Set(lhs, rhs) => {
|
mir::StmtKind::Set(lhs, rhs) => {
|
||||||
allocated.extend(lhs.allocate(scope));
|
allocated.extend(lhs.allocate(scope));
|
||||||
allocated.extend(rhs.allocate(scope));
|
allocated.extend(rhs.allocate(scope));
|
||||||
}
|
}
|
||||||
crate::mir::StmtKind::Import(_) => {}
|
mir::StmtKind::Import(_) => {}
|
||||||
crate::mir::StmtKind::Expression(expression) => {
|
mir::StmtKind::Expression(expression) => {
|
||||||
allocated.extend(expression.allocate(scope));
|
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(condition.allocate(scope));
|
||||||
allocated.extend(block.allocate(scope));
|
allocated.extend(block.allocate(scope));
|
||||||
}
|
}
|
||||||
@ -138,49 +131,54 @@ impl mir::Expression {
|
|||||||
let mut allocated = Vec::new();
|
let mut allocated = Vec::new();
|
||||||
|
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
crate::mir::ExprKind::Variable(_) => {}
|
mir::ExprKind::Variable(_) => {}
|
||||||
crate::mir::ExprKind::Indexed(expr, _, idx) => {
|
mir::ExprKind::Indexed(expr, _, idx) => {
|
||||||
allocated.extend(expr.allocate(scope));
|
allocated.extend(expr.allocate(scope));
|
||||||
allocated.extend(idx.allocate(scope));
|
allocated.extend(idx.allocate(scope));
|
||||||
}
|
}
|
||||||
crate::mir::ExprKind::Accessed(expression, _, _) => {
|
mir::ExprKind::Accessed(expression, _, _) => {
|
||||||
allocated.extend(expression.allocate(scope));
|
allocated.extend(expression.allocate(scope));
|
||||||
}
|
}
|
||||||
crate::mir::ExprKind::Array(expressions) => {
|
mir::ExprKind::Array(expressions) => {
|
||||||
for expression in expressions {
|
for expression in expressions {
|
||||||
allocated.extend(expression.allocate(scope));
|
allocated.extend(expression.allocate(scope));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
crate::mir::ExprKind::Struct(_, items) => {
|
mir::ExprKind::Struct(_, items) => {
|
||||||
for (_, expression) in items {
|
for (_, expression) in items {
|
||||||
allocated.extend(expression.allocate(scope));
|
allocated.extend(expression.allocate(scope));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
crate::mir::ExprKind::Literal(_) => {}
|
mir::ExprKind::Literal(_) => {}
|
||||||
crate::mir::ExprKind::BinOp(_, lhs, rhs, _) => {
|
mir::ExprKind::BinOp(_, lhs, rhs, _) => {
|
||||||
allocated.extend(lhs.allocate(scope));
|
allocated.extend(lhs.allocate(scope));
|
||||||
allocated.extend(rhs.allocate(scope));
|
allocated.extend(rhs.allocate(scope));
|
||||||
}
|
}
|
||||||
crate::mir::ExprKind::FunctionCall(FunctionCall { parameters, .. }) => {
|
mir::ExprKind::FunctionCall(FunctionCall { parameters, .. }) => {
|
||||||
for param in parameters {
|
for param in parameters {
|
||||||
allocated.extend(param.allocate(scope));
|
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(cond.allocate(scope));
|
||||||
allocated.extend(then_ex.allocate(scope));
|
allocated.extend(then_ex.allocate(scope));
|
||||||
if let Some(else_ex) = else_ex.as_ref() {
|
if let Some(else_ex) = else_ex.as_ref() {
|
||||||
allocated.extend(else_ex.allocate(scope));
|
allocated.extend(else_ex.allocate(scope));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
crate::mir::ExprKind::Block(block) => {
|
mir::ExprKind::Block(block) => {
|
||||||
allocated.extend(block.allocate(scope));
|
allocated.extend(block.allocate(scope));
|
||||||
}
|
}
|
||||||
crate::mir::ExprKind::Borrow(_, _) => {}
|
mir::ExprKind::Borrow(_, _) => {}
|
||||||
crate::mir::ExprKind::Deref(_) => {}
|
mir::ExprKind::Deref(_) => {}
|
||||||
crate::mir::ExprKind::CastTo(expression, _) => {
|
mir::ExprKind::CastTo(expression, _) => {
|
||||||
allocated.extend(expression.allocate(scope));
|
allocated.extend(expression.allocate(scope));
|
||||||
}
|
}
|
||||||
|
mir::ExprKind::AssociatedFunctionCall(_, FunctionCall { parameters, .. }) => {
|
||||||
|
for param in parameters {
|
||||||
|
allocated.extend(param.allocate(scope));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allocated
|
allocated
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use std::marker::PhantomData;
|
|
||||||
|
|
||||||
use reid_lib::{builder::InstructionValue, CmpPredicate, Instr};
|
use reid_lib::{builder::InstructionValue, CmpPredicate, Instr};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -38,6 +36,20 @@ pub fn form_intrinsics() -> Vec<FunctionDefinition> {
|
|||||||
intrinsics
|
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
|
fn simple_binop_def<T: Clone + 'static>(op: BinaryOperator, ty: &TypeKind, fun: T) -> BinopDefinition
|
||||||
where
|
where
|
||||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
||||||
@ -169,28 +181,33 @@ pub fn form_intrinsic_binops() -> Vec<BinopDefinition> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait IntrinsicFunction: std::fmt::Debug {
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct IntrinsicSimpleInstr<T>(T)
|
pub struct IntrinsicSimpleInstr<T>(T)
|
||||||
where
|
where
|
||||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
|
||||||
|
intrinsic_debug!(IntrinsicSimpleInstr<T>, "IntrinsicSimpleInstr");
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleInstr<T>
|
impl<T: Clone> IntrinsicFunction for IntrinsicSimpleInstr<T>
|
||||||
where
|
where
|
||||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
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 lhs = params.get(0).unwrap();
|
||||||
let rhs = params.get(1).unwrap();
|
let rhs = params.get(1).unwrap();
|
||||||
let instr = self.clone().0(scope, lhs.instr(), rhs.instr());
|
let instr = self.clone().0(scope, lhs.instr(), rhs.instr());
|
||||||
@ -202,21 +219,13 @@ where
|
|||||||
pub struct IntrinsicBooleanInstr<T>(T)
|
pub struct IntrinsicBooleanInstr<T>(T)
|
||||||
where
|
where
|
||||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
|
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue;
|
||||||
|
intrinsic_debug!(IntrinsicBooleanInstr<T>, "IntrinsicBooleanInstr");
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone> IntrinsicFunction for IntrinsicBooleanInstr<T>
|
impl<T: Clone> IntrinsicFunction for IntrinsicBooleanInstr<T>
|
||||||
where
|
where
|
||||||
T: FnOnce(&mut Scope, InstructionValue, InstructionValue) -> InstructionValue,
|
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 lhs = params.get(0).unwrap();
|
||||||
let rhs = params.get(1).unwrap();
|
let rhs = params.get(1).unwrap();
|
||||||
let instr = self.clone().0(scope, lhs.instr(), rhs.instr());
|
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 {
|
// impl IntrinsicFunction for IntrinsicIAdd {
|
||||||
// fn codegen<'ctx, 'a>(
|
// fn codegen<'ctx, 'a>(
|
||||||
// &self,
|
// &self,
|
||||||
|
@ -15,8 +15,11 @@ use scope::*;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mir::{
|
mir::{
|
||||||
self, implement::TypeCategory, pass::BinopKey, CustomTypeKey, FunctionDefinitionKind, NamedVariableRef,
|
self,
|
||||||
SourceModuleId, StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
|
implement::TypeCategory,
|
||||||
|
pass::{AssociatedFunctionKey, BinopKey},
|
||||||
|
CustomTypeKey, FunctionCall, FunctionDefinitionKind, NamedVariableRef, SourceModuleId, StructField, StructType,
|
||||||
|
TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
|
||||||
},
|
},
|
||||||
util::try_all,
|
util::try_all,
|
||||||
};
|
};
|
||||||
@ -208,7 +211,50 @@ impl mir::Module {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(func) = func {
|
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()),
|
parameters: (binop.lhs.clone(), binop.rhs.clone()),
|
||||||
return_ty: binop.return_type.clone(),
|
return_ty: binop.return_type.clone(),
|
||||||
kind: match &binop.fn_kind {
|
kind: match &binop.fn_kind {
|
||||||
FunctionDefinitionKind::Local(block, metadata) => {
|
FunctionDefinitionKind::Local(..) => {
|
||||||
let ir_function = module.function(
|
let ir_function = module.function(
|
||||||
&binop_fn_name,
|
&binop_fn_name,
|
||||||
binop.return_type.get_type(&type_values),
|
binop.return_type.get_type(&type_values),
|
||||||
@ -246,7 +292,6 @@ impl mir::Module {
|
|||||||
&vec![binop.lhs.clone(), binop.rhs.clone()],
|
&vec![binop.lhs.clone(), binop.rhs.clone()],
|
||||||
&mut AllocatorScope {
|
&mut AllocatorScope {
|
||||||
block: &mut entry,
|
block: &mut entry,
|
||||||
module_id: self.module_id,
|
|
||||||
type_values: &type_values,
|
type_values: &type_values,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -259,6 +304,7 @@ impl mir::Module {
|
|||||||
module_id: self.module_id,
|
module_id: self.module_id,
|
||||||
function: &ir_function,
|
function: &ir_function,
|
||||||
block: entry,
|
block: entry,
|
||||||
|
assoc_functions: &associated_functions,
|
||||||
functions: &functions,
|
functions: &functions,
|
||||||
types: &types,
|
types: &types,
|
||||||
type_values: &type_values,
|
type_values: &type_values,
|
||||||
@ -289,22 +335,20 @@ impl mir::Module {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
StackBinopFunctionKind::UserGenerated(ir_function)
|
ScopeFunctionKind::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()
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
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) => {
|
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 {
|
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 mut entry = function.block("entry");
|
||||||
|
|
||||||
let allocator = Allocator::from(
|
let allocator = Allocator::from(
|
||||||
&mir_function.kind,
|
&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,
|
|
||||||
&mir_function.parameters,
|
&mir_function.parameters,
|
||||||
&mir_function.return_type,
|
&mut AllocatorScope {
|
||||||
&function,
|
block: &mut entry,
|
||||||
match &mir_function.kind {
|
type_values: &type_values,
|
||||||
FunctionDefinitionKind::Local(..) => mir_function.signature().into_debug(tokens, compile_unit),
|
|
||||||
FunctionDefinitionKind::Extern(_) => None,
|
|
||||||
FunctionDefinitionKind::Intrinsic(_) => None,
|
|
||||||
},
|
},
|
||||||
)
|
);
|
||||||
.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 })
|
Ok(ModuleCodegen { module })
|
||||||
@ -723,7 +829,7 @@ impl mir::Expression {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if let Some(operation) = operation {
|
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)
|
Some(a)
|
||||||
} else {
|
} else {
|
||||||
let lhs_type = lhs_exp.return_type(&Default::default(), scope.module_id).unwrap().1;
|
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) => {
|
mir::ExprKind::FunctionCall(call) => codegen_function_call(None, call, scope, state)?,
|
||||||
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::If(if_expression) => if_expression.codegen(scope, state)?,
|
mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state)?,
|
||||||
mir::ExprKind::Block(block) => {
|
mir::ExprKind::Block(block) => {
|
||||||
let inner = scope.function.block("inner");
|
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 {
|
if let Some(value) = &value {
|
||||||
value.instr().maybe_location(&mut scope.block, location);
|
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 {
|
impl mir::IfExpression {
|
||||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Result<Option<StackValue>, ErrorKind> {
|
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Result<Option<StackValue>, ErrorKind> {
|
||||||
let condition = self.0.codegen(scope, state)?.unwrap();
|
let condition = self.0.codegen(scope, state)?.unwrap();
|
||||||
|
@ -2,13 +2,16 @@ use std::{cell::RefCell, collections::HashMap, mem, rc::Rc};
|
|||||||
|
|
||||||
use reid_lib::{
|
use reid_lib::{
|
||||||
builder::{InstructionValue, TypeValue},
|
builder::{InstructionValue, TypeValue},
|
||||||
debug_information::{DebugInformation, DebugProgramValue, DebugTypeValue},
|
debug_information::{DebugInformation, DebugLocation, DebugProgramValue, DebugTypeValue},
|
||||||
Block, Context, Function, Instr, Module,
|
Block, Context, Function, Instr, Module,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
lexer::FullToken,
|
lexer::FullToken,
|
||||||
mir::{pass::BinopKey, CustomTypeKey, SourceModuleId, TypeDefinition, TypeKind},
|
mir::{
|
||||||
|
pass::{AssociatedFunctionKey, BinopKey},
|
||||||
|
CustomTypeKey, SourceModuleId, TypeDefinition, TypeKind,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{allocator::Allocator, ErrorKind, IntrinsicFunction, ModuleCodegen};
|
use super::{allocator::Allocator, ErrorKind, IntrinsicFunction, ModuleCodegen};
|
||||||
@ -23,7 +26,8 @@ pub struct Scope<'ctx, 'scope> {
|
|||||||
pub(super) block: Block<'ctx>,
|
pub(super) block: Block<'ctx>,
|
||||||
pub(super) types: &'scope HashMap<TypeValue, TypeDefinition>,
|
pub(super) types: &'scope HashMap<TypeValue, TypeDefinition>,
|
||||||
pub(super) type_values: &'scope HashMap<CustomTypeKey, TypeValue>,
|
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) binops: &'scope HashMap<BinopKey, StackBinopDefinition<'ctx>>,
|
||||||
pub(super) stack_values: HashMap<String, StackValue>,
|
pub(super) stack_values: HashMap<String, StackValue>,
|
||||||
pub(super) debug: Option<Debug<'ctx>>,
|
pub(super) debug: Option<Debug<'ctx>>,
|
||||||
@ -40,6 +44,7 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
|
|||||||
context: self.context,
|
context: self.context,
|
||||||
module: self.module,
|
module: self.module,
|
||||||
module_id: self.module_id,
|
module_id: self.module_id,
|
||||||
|
assoc_functions: self.assoc_functions,
|
||||||
functions: self.functions,
|
functions: self.functions,
|
||||||
types: self.types,
|
types: self.types,
|
||||||
type_values: self.type_values,
|
type_values: self.type_values,
|
||||||
@ -126,19 +131,20 @@ impl StackValueKind {
|
|||||||
pub struct StackBinopDefinition<'ctx> {
|
pub struct StackBinopDefinition<'ctx> {
|
||||||
pub(super) parameters: ((String, TypeKind), (String, TypeKind)),
|
pub(super) parameters: ((String, TypeKind), (String, TypeKind)),
|
||||||
pub(super) return_ty: 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>),
|
UserGenerated(Function<'ctx>),
|
||||||
Intrinsic(&'ctx Box<dyn IntrinsicFunction>),
|
Intrinsic(&'ctx Box<dyn IntrinsicFunction>),
|
||||||
|
IntrinsicOwned(Box<dyn IntrinsicFunction>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> StackBinopDefinition<'ctx> {
|
impl<'ctx> StackBinopDefinition<'ctx> {
|
||||||
pub fn codegen<'a>(
|
pub fn codegen<'a>(
|
||||||
&self,
|
&self,
|
||||||
lhs: &StackValue,
|
lhs: StackValue,
|
||||||
rhs: &StackValue,
|
rhs: StackValue,
|
||||||
scope: &mut Scope<'ctx, 'a>,
|
scope: &mut Scope<'ctx, 'a>,
|
||||||
) -> Result<StackValue, ErrorKind> {
|
) -> Result<StackValue, ErrorKind> {
|
||||||
let (lhs, rhs) = if lhs.1 == self.parameters.0 .1 && rhs.1 == self.parameters.1 .1 {
|
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 {
|
} else {
|
||||||
(rhs, lhs)
|
(rhs, lhs)
|
||||||
};
|
};
|
||||||
match &self.kind {
|
let name = format!(
|
||||||
StackBinopFunctionKind::UserGenerated(ir) => {
|
"binop.{}.{}.{}.call",
|
||||||
let instr = scope
|
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
|
.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();
|
.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 crate::pad_adapter::PadAdapter;
|
||||||
|
|
||||||
use super::{typecheck::typerefs::TypeRefs, *};
|
use super::*;
|
||||||
|
|
||||||
impl Display for Context {
|
impl Display for Context {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
@ -49,6 +49,9 @@ impl Display for Module {
|
|||||||
for typedef in &self.typedefs {
|
for typedef in &self.typedefs {
|
||||||
writeln!(inner_f, "{}", typedef)?;
|
writeln!(inner_f, "{}", typedef)?;
|
||||||
}
|
}
|
||||||
|
for (ty, fun) in &self.associated_functions {
|
||||||
|
writeln!(inner_f, "(Assoc {}) {}", ty, fun)?;
|
||||||
|
}
|
||||||
for fun in &self.functions {
|
for fun in &self.functions {
|
||||||
writeln!(inner_f, "{}", fun)?;
|
writeln!(inner_f, "{}", fun)?;
|
||||||
}
|
}
|
||||||
@ -272,6 +275,11 @@ impl Display for ExprKind {
|
|||||||
ExprKind::Borrow(var_ref, true) => write!(f, "&mut {}", var_ref),
|
ExprKind::Borrow(var_ref, true) => write!(f, "&mut {}", var_ref),
|
||||||
ExprKind::Deref(var_ref) => write!(f, "*{}", var_ref),
|
ExprKind::Deref(var_ref) => write!(f, "*{}", var_ref),
|
||||||
ExprKind::CastTo(expression, type_kind) => write!(f, "{} as {}", expression, type_kind),
|
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 crate::util::maybe;
|
||||||
|
|
||||||
use super::{pass::ScopeBinopDef, typecheck::typerefs::TypeRefs, *};
|
use super::{typecheck::typerefs::TypeRefs, *};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ReturnTypeOther {
|
pub enum ReturnTypeOther {
|
||||||
@ -443,6 +443,7 @@ impl Expression {
|
|||||||
},
|
},
|
||||||
Err(_) => Ok((ReturnKind::Soft, type_kind.clone())),
|
Err(_) => Ok((ReturnKind::Soft, type_kind.clone())),
|
||||||
},
|
},
|
||||||
|
AssociatedFunctionCall(_, fcall) => fcall.return_type(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,6 +462,7 @@ impl Expression {
|
|||||||
ExprKind::FunctionCall(_) => None,
|
ExprKind::FunctionCall(_) => None,
|
||||||
ExprKind::If(_) => None,
|
ExprKind::If(_) => None,
|
||||||
ExprKind::CastTo(expression, _) => expression.backing_var(),
|
ExprKind::CastTo(expression, _) => expression.backing_var(),
|
||||||
|
ExprKind::AssociatedFunctionCall(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -499,6 +501,7 @@ impl Expression {
|
|||||||
ExprKind::Borrow(_, _) => None,
|
ExprKind::Borrow(_, _) => None,
|
||||||
ExprKind::Deref(_) => None,
|
ExprKind::Deref(_) => None,
|
||||||
ExprKind::CastTo(expression, _) => expression.num_value()?,
|
ExprKind::CastTo(expression, _) => expression.num_value()?,
|
||||||
|
ExprKind::AssociatedFunctionCall(..) => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::scope,
|
|
||||||
compile_module,
|
compile_module,
|
||||||
error_raporting::{ErrorModules, ReidError},
|
error_raporting::{ErrorModules, ReidError},
|
||||||
mir::{
|
mir::{
|
||||||
@ -254,7 +253,7 @@ impl<'map> Pass for LinkerPass<'map> {
|
|||||||
binop.exported = true;
|
binop.exported = true;
|
||||||
already_imported_binops.insert(binop_key);
|
already_imported_binops.insert(binop_key);
|
||||||
match &binop.fn_kind {
|
match &binop.fn_kind {
|
||||||
FunctionDefinitionKind::Local(block, metadata) => {
|
FunctionDefinitionKind::Local(..) => {
|
||||||
importer_module.binop_defs.push(BinopDefinition {
|
importer_module.binop_defs.push(BinopDefinition {
|
||||||
lhs: binop.lhs.clone(),
|
lhs: binop.lhs.clone(),
|
||||||
op: binop.op,
|
op: binop.op,
|
||||||
|
@ -258,6 +258,7 @@ pub enum ExprKind {
|
|||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
BinOp(BinaryOperator, Box<Expression>, Box<Expression>, TypeKind),
|
BinOp(BinaryOperator, Box<Expression>, Box<Expression>, TypeKind),
|
||||||
FunctionCall(FunctionCall),
|
FunctionCall(FunctionCall),
|
||||||
|
AssociatedFunctionCall(TypeKind, FunctionCall),
|
||||||
If(IfExpression),
|
If(IfExpression),
|
||||||
Block(Block),
|
Block(Block),
|
||||||
Borrow(NamedVariableRef, bool),
|
Borrow(NamedVariableRef, bool),
|
||||||
@ -292,6 +293,12 @@ pub struct FunctionDefinition {
|
|||||||
pub kind: FunctionDefinitionKind,
|
pub kind: FunctionDefinitionKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum SelfKind {
|
||||||
|
Borrow,
|
||||||
|
MutBorrow,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FunctionDefinitionKind {
|
pub enum FunctionDefinitionKind {
|
||||||
/// Actual definition block and surrounding signature range
|
/// Actual definition block and surrounding signature range
|
||||||
@ -393,6 +400,7 @@ pub struct Module {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub module_id: SourceModuleId,
|
pub module_id: SourceModuleId,
|
||||||
pub imports: Vec<Import>,
|
pub imports: Vec<Import>,
|
||||||
|
pub associated_functions: Vec<(TypeKind, FunctionDefinition)>,
|
||||||
pub functions: Vec<FunctionDefinition>,
|
pub functions: Vec<FunctionDefinition>,
|
||||||
pub typedefs: Vec<TypeDefinition>,
|
pub typedefs: Vec<TypeDefinition>,
|
||||||
pub binop_defs: Vec<BinopDefinition>,
|
pub binop_defs: Vec<BinopDefinition>,
|
||||||
|
@ -5,7 +5,7 @@ use std::collections::HashMap;
|
|||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use std::error::Error as STDError;
|
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 crate::error_raporting::ReidError;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -123,7 +123,8 @@ pub type BinopMap = Storage<BinopKey, ScopeBinopDef>;
|
|||||||
pub struct Scope<Data: Clone + Default> {
|
pub struct Scope<Data: Clone + Default> {
|
||||||
pub module_id: Option<SourceModuleId>,
|
pub module_id: Option<SourceModuleId>,
|
||||||
pub binops: BinopMap,
|
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 variables: Storage<String, ScopeVariable>,
|
||||||
pub types: Storage<CustomTypeKey, TypeDefinition>,
|
pub types: Storage<CustomTypeKey, TypeDefinition>,
|
||||||
/// Hard Return type of this scope, if inside a function
|
/// 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> {
|
pub fn inner(&self) -> Scope<Data> {
|
||||||
Scope {
|
Scope {
|
||||||
module_id: self.module_id,
|
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(),
|
variables: self.variables.clone(),
|
||||||
binops: self.binops.clone(),
|
binops: self.binops.clone(),
|
||||||
types: self.types.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))
|
.find(|(key, def)| key.0 == typekey.0 && def.importer == Some(typekey.1))
|
||||||
.map(|(_, v)| v))
|
.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)]
|
#[derive(Clone, Debug)]
|
||||||
@ -181,6 +201,9 @@ pub struct ScopeVariable {
|
|||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AssociatedFunctionKey(pub TypeKind, pub String);
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq)]
|
#[derive(Clone, Debug, Eq)]
|
||||||
pub struct BinopKey {
|
pub struct BinopKey {
|
||||||
pub params: (TypeKind, TypeKind),
|
pub params: (TypeKind, TypeKind),
|
||||||
@ -389,7 +412,7 @@ impl Module {
|
|||||||
|
|
||||||
for function in &self.functions {
|
for function in &self.functions {
|
||||||
scope
|
scope
|
||||||
.function_returns
|
.functions
|
||||||
.set(
|
.set(
|
||||||
function.name.clone(),
|
function.name.clone(),
|
||||||
ScopeFunction {
|
ScopeFunction {
|
||||||
@ -400,6 +423,19 @@ impl Module {
|
|||||||
.ok();
|
.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)))?;
|
pass.module(self, PassState::from(state, scope, Some(self.module_id)))?;
|
||||||
|
|
||||||
for function in &mut self.functions {
|
for function in &mut self.functions {
|
||||||
|
@ -24,12 +24,16 @@ pub enum ErrorKind {
|
|||||||
TypesIncompatible(TypeKind, TypeKind),
|
TypesIncompatible(TypeKind, TypeKind),
|
||||||
#[error("Variable not defined: {0}")]
|
#[error("Variable not defined: {0}")]
|
||||||
VariableNotDefined(String),
|
VariableNotDefined(String),
|
||||||
#[error("Function not defined: {0}")]
|
#[error("Function {0} not defined")]
|
||||||
FunctionNotDefined(String),
|
FunctionNotDefined(String),
|
||||||
|
#[error("Function {0} not defined for type {1}")]
|
||||||
|
AssocFunctionNotDefined(String, TypeKind),
|
||||||
#[error("Expected a return type of {0}, got {1} instead")]
|
#[error("Expected a return type of {0}, got {1} instead")]
|
||||||
ReturnTypeMismatch(TypeKind, TypeKind),
|
ReturnTypeMismatch(TypeKind, TypeKind),
|
||||||
#[error("Function {0} already defined {1}")]
|
#[error("Function {0} already defined {1}")]
|
||||||
FunctionAlreadyDefined(String, ErrorTypedefKind),
|
FunctionAlreadyDefined(String, ErrorTypedefKind),
|
||||||
|
#[error("Function {0}::{1} already defined {2}")]
|
||||||
|
AssocFunctionAlreadyDefined(TypeKind, String, ErrorTypedefKind),
|
||||||
#[error("Variable already defined: {0}")]
|
#[error("Variable already defined: {0}")]
|
||||||
VariableAlreadyDefined(String),
|
VariableAlreadyDefined(String),
|
||||||
#[error("Variable {0} is not declared as mutable")]
|
#[error("Variable {0} is not declared as mutable")]
|
||||||
@ -170,7 +174,7 @@ impl TypeKind {
|
|||||||
return self.clone();
|
return self.clone();
|
||||||
}
|
}
|
||||||
match (self, other) {
|
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(VagueType::Unknown)
|
||||||
}
|
}
|
||||||
(TypeKind::Vague(Vague::Integer), other) | (other, TypeKind::Vague(Vague::Integer)) => match other {
|
(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()));
|
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 {
|
for function in &mut module.functions {
|
||||||
let res = function.typecheck(&self.refs, &mut state.inner());
|
let res = function.typecheck(&self.refs, &mut state.inner());
|
||||||
state.ok(res, function.block_meta());
|
state.ok(res, function.block_meta());
|
||||||
@ -443,7 +448,7 @@ impl Expression {
|
|||||||
ExprKind::FunctionCall(function_call) => {
|
ExprKind::FunctionCall(function_call) => {
|
||||||
let true_function = state
|
let true_function = state
|
||||||
.scope
|
.scope
|
||||||
.function_returns
|
.functions
|
||||||
.get(&function_call.name)
|
.get(&function_call.name)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()));
|
.ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()));
|
||||||
@ -724,6 +729,54 @@ impl Expression {
|
|||||||
let expr = expression.typecheck(state, typerefs, HintKind::Default)?;
|
let expr = expression.typecheck(state, typerefs, HintKind::Default)?;
|
||||||
expr.resolve_ref(typerefs).cast_into(type_kind)
|
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::{
|
use crate::{
|
||||||
mir::{
|
mir::{
|
||||||
BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
|
pass::AssociatedFunctionKey, BinopDefinition, Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition,
|
||||||
IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement,
|
FunctionDefinitionKind, IfExpression, Module, ReturnKind, StmtKind, TypeKind, WhileStatement,
|
||||||
},
|
},
|
||||||
util::try_all,
|
util::try_all,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
super::{
|
super::{
|
||||||
pass::{BinopKey, Pass, PassResult, PassState},
|
pass::{BinopKey, Pass, PassResult},
|
||||||
TypeKind::*,
|
TypeKind::*,
|
||||||
VagueType::*,
|
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();
|
let mut seen_binops = HashSet::new();
|
||||||
for binop in &module.binop_defs {
|
for binop in &module.binop_defs {
|
||||||
let binop_key = BinopKey {
|
let binop_key = BinopKey {
|
||||||
@ -97,6 +120,11 @@ impl<'t> Pass for TypeInference<'t> {
|
|||||||
state.ok(res, binop.block_meta().unwrap_or(binop.signature()));
|
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 {
|
for function in &mut module.functions {
|
||||||
let res = function.infer_types(&self.refs, &mut state.inner());
|
let res = function.infer_types(&self.refs, &mut state.inner());
|
||||||
state.ok(res, function.block_meta());
|
state.ok(res, function.block_meta());
|
||||||
@ -365,7 +393,7 @@ impl Expression {
|
|||||||
// Get function definition and types
|
// Get function definition and types
|
||||||
let fn_call = state
|
let fn_call = state
|
||||||
.scope
|
.scope
|
||||||
.function_returns
|
.functions
|
||||||
.get(&function_call.name)
|
.get(&function_call.name)
|
||||||
.ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()))?
|
.ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()))?
|
||||||
.clone();
|
.clone();
|
||||||
@ -566,6 +594,32 @@ impl Expression {
|
|||||||
expression.infer_types(state, type_refs)?;
|
expression.infer_types(state, type_refs)?;
|
||||||
Ok(type_refs.from_type(type_kind).unwrap())
|
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,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType};
|
||||||
ast::BinopDefinition,
|
|
||||||
mir::{pass::BinopMap, BinaryOperator, TypeKind, VagueType},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{super::pass::ScopeBinopDef, ErrorKind};
|
||||||
super::pass::{BinopKey, ScopeBinopDef, Storage},
|
|
||||||
ErrorKind,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TypeRef<'scope>(pub(super) TypeIdRef, pub(super) &'scope ScopeTypeRefs<'scope>);
|
pub struct TypeRef<'scope>(pub(super) TypeIdRef, pub(super) &'scope ScopeTypeRefs<'scope>);
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
use std::{
|
use std::{path::PathBuf, process::Command, time::SystemTime};
|
||||||
alloc::System,
|
|
||||||
path::PathBuf,
|
|
||||||
process::Command,
|
|
||||||
thread,
|
|
||||||
time::{Duration, SystemTime},
|
|
||||||
};
|
|
||||||
|
|
||||||
use reid::{
|
use reid::{
|
||||||
compile_module,
|
compile_module,
|
||||||
@ -149,3 +143,12 @@ fn array_short_compiles_well() {
|
|||||||
fn imported_type_compiles_well() {
|
fn imported_type_compiles_well() {
|
||||||
test(include_str!("../../examples/imported_type.reid"), "test", Some(0));
|
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