Compare commits
10 Commits
84233c8f49
...
384703fbd2
Author | SHA1 | Date | |
---|---|---|---|
384703fbd2 | |||
107303aa98 | |||
08626c8559 | |||
ffb3515aaa | |||
1e4667449a | |||
6fbb26ba88 | |||
91fd0d4d5a | |||
13e462def7 | |||
ff83d7b4f0 | |||
663f327ccf |
10
examples/generics.reid
Normal file
10
examples/generics.reid
Normal file
@ -0,0 +1,10 @@
|
||||
// Arithmetic, function calls and imports!
|
||||
|
||||
fn test<T>(value: T) -> T {
|
||||
let b: T = value;
|
||||
return b;
|
||||
}
|
||||
|
||||
fn main() -> u32 {
|
||||
return test<u64>(15) as u32 + test<u32>(5);
|
||||
}
|
@ -16,7 +16,7 @@ BINARY="$(echo $1 | cut -d'.' -f1)"".out"
|
||||
|
||||
echo $1
|
||||
|
||||
cargo run -p reid -- $@ && \
|
||||
cargo run -p reid -- run $@ && \
|
||||
./$BINARY ; echo "Return value: ""$?"
|
||||
|
||||
## Command from: clang -v hello.o -o test
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to the "reid-lsp" extension will be documented in this file.
|
||||
All notable changes to the "reid-language-server" extension will be documented in this file.
|
||||
|
||||
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
|
||||
|
||||
|
@ -13,6 +13,13 @@
|
||||
"Other"
|
||||
],
|
||||
"main": "./dist/extension.js",
|
||||
"icon": "./reid.png",
|
||||
"publisher": "Teascade",
|
||||
"author": {
|
||||
"email": "teascade@teascade.net",
|
||||
"name": "Teascade",
|
||||
"url": "https://teascade.net"
|
||||
},
|
||||
"contributes": {
|
||||
"languages": [
|
||||
{
|
||||
@ -42,7 +49,7 @@
|
||||
"reid-language-server.language-server-path": {
|
||||
"type": "string",
|
||||
"scope": "window",
|
||||
"default": "$HOME/.cargo/bin/reid-lsp",
|
||||
"default": "$HOME/.cargo/bin/reid-language-server",
|
||||
"description": "Path to the Reid Language Server executable"
|
||||
}
|
||||
}
|
||||
|
@ -162,6 +162,7 @@ impl BinaryOperator {
|
||||
pub struct FunctionCallExpression {
|
||||
pub name: String,
|
||||
pub params: Vec<Expression>,
|
||||
pub generics: Vec<Type>,
|
||||
pub range: TokenRange,
|
||||
pub is_macro: bool,
|
||||
}
|
||||
@ -192,6 +193,7 @@ pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub To
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FunctionSignature {
|
||||
pub name: String,
|
||||
pub generics: Vec<String>,
|
||||
pub documentation: Option<String>,
|
||||
pub self_kind: SelfKind,
|
||||
pub params: Vec<(String, Type, TokenRange)>,
|
||||
|
@ -182,6 +182,7 @@ impl Parse for AssociatedFunctionCall {
|
||||
ty,
|
||||
FunctionCallExpression {
|
||||
name: String::new(),
|
||||
generics: Vec::new(),
|
||||
params: Vec::new(),
|
||||
range: stream.get_range_prev_curr().unwrap(),
|
||||
is_macro: false,
|
||||
@ -200,6 +201,7 @@ impl Parse for AssociatedFunctionCall {
|
||||
ty,
|
||||
FunctionCallExpression {
|
||||
name: fn_name,
|
||||
generics: Vec::new(),
|
||||
params: Vec::new(),
|
||||
range: stream.get_range_prev_curr().unwrap(),
|
||||
is_macro: false,
|
||||
@ -211,6 +213,7 @@ impl Parse for AssociatedFunctionCall {
|
||||
ty,
|
||||
FunctionCallExpression {
|
||||
name: String::new(),
|
||||
generics: Vec::new(),
|
||||
params: Vec::new(),
|
||||
range: stream.get_range_prev_curr().unwrap(),
|
||||
is_macro: false,
|
||||
@ -591,7 +594,8 @@ impl Parse for FunctionCallExpression {
|
||||
let args = stream.parse::<FunctionArgs>()?;
|
||||
Ok(FunctionCallExpression {
|
||||
name,
|
||||
params: args.0,
|
||||
generics: args.0,
|
||||
params: args.1,
|
||||
range: stream.get_range().unwrap(),
|
||||
is_macro,
|
||||
})
|
||||
@ -602,10 +606,23 @@ impl Parse for FunctionCallExpression {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FunctionArgs(Vec<Expression>);
|
||||
pub struct FunctionArgs(Vec<Type>, Vec<Expression>);
|
||||
|
||||
impl Parse for FunctionArgs {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||
let mut generics: Vec<Type> = Vec::new();
|
||||
if let Some(Token::LessThan) = stream.peek() {
|
||||
stream.next();
|
||||
if let Ok(ty) = stream.parse() {
|
||||
generics.push(ty);
|
||||
while let Some(Token::Comma) = stream.peek() {
|
||||
stream.next();
|
||||
generics.push(stream.parse()?);
|
||||
}
|
||||
}
|
||||
stream.expect(Token::GreaterThan)?;
|
||||
}
|
||||
|
||||
stream.expect(Token::ParenOpen)?;
|
||||
|
||||
let mut params = Vec::new();
|
||||
@ -618,7 +635,7 @@ impl Parse for FunctionArgs {
|
||||
}
|
||||
stream.expect(Token::ParenClose)?;
|
||||
|
||||
Ok(FunctionArgs(params))
|
||||
Ok(FunctionArgs(generics, params))
|
||||
}
|
||||
}
|
||||
|
||||
@ -780,6 +797,18 @@ impl Parse for SelfParam {
|
||||
impl Parse for FunctionSignature {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||
if let Some(Token::Identifier(name)) = stream.next() {
|
||||
let mut generics = Vec::new();
|
||||
|
||||
if let Some(Token::LessThan) = stream.peek() {
|
||||
stream.next();
|
||||
while let Some(Token::Identifier(ident)) = stream.peek() {
|
||||
stream.next();
|
||||
generics.push(ident);
|
||||
}
|
||||
|
||||
stream.expect(Token::GreaterThan)?;
|
||||
}
|
||||
|
||||
stream.expect(Token::ParenOpen)?;
|
||||
let mut params = Vec::new();
|
||||
|
||||
@ -814,6 +843,7 @@ impl Parse for FunctionSignature {
|
||||
|
||||
Ok(FunctionSignature {
|
||||
name,
|
||||
generics,
|
||||
documentation: None,
|
||||
params,
|
||||
self_kind,
|
||||
@ -961,7 +991,8 @@ impl Parse for DotIndexKind {
|
||||
if let Ok(args) = stream.parse::<FunctionArgs>() {
|
||||
Ok(Self::FunctionCall(FunctionCallExpression {
|
||||
name,
|
||||
params: args.0,
|
||||
generics: args.0,
|
||||
params: args.1,
|
||||
range: stream.get_range_prev().unwrap(),
|
||||
is_macro: false,
|
||||
}))
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::path::PathBuf;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use crate::{
|
||||
ast::{self, ReturnType},
|
||||
ast::{self, ReturnType, TypeKind},
|
||||
mir::{
|
||||
self, CustomTypeKey, FunctionParam, ModuleMap, NamedVariableRef, ReturnKind, SourceModuleId, StmtKind,
|
||||
StructField, StructType, WhileStatement,
|
||||
@ -44,6 +44,11 @@ impl ast::Module {
|
||||
let def = mir::FunctionDefinition {
|
||||
name: signature.name.clone(),
|
||||
documentation: signature.documentation.clone(),
|
||||
generics: signature
|
||||
.generics
|
||||
.iter()
|
||||
.map(|g| (g.clone(), mir::TypeKind::Vague(mir::VagueType::Unknown)))
|
||||
.collect(),
|
||||
linkage_name: None,
|
||||
is_pub: false,
|
||||
is_imported: false,
|
||||
@ -175,9 +180,15 @@ impl ast::FunctionDefinition {
|
||||
ty: p.1 .0.into_mir(module_id),
|
||||
meta: p.2.as_meta(module_id),
|
||||
}));
|
||||
|
||||
mir::FunctionDefinition {
|
||||
name: signature.name.clone(),
|
||||
documentation: signature.documentation.clone(),
|
||||
generics: signature
|
||||
.generics
|
||||
.iter()
|
||||
.map(|g| (g.clone(), mir::TypeKind::Vague(mir::VagueType::Unknown)))
|
||||
.collect(),
|
||||
linkage_name: None,
|
||||
is_pub: *is_pub,
|
||||
is_imported: false,
|
||||
@ -379,6 +390,7 @@ impl ast::Expression {
|
||||
),
|
||||
ast::ExpressionKind::FunctionCall(fn_call_expr) => mir::ExprKind::FunctionCall(mir::FunctionCall {
|
||||
name: fn_call_expr.name.clone(),
|
||||
generics: fn_call_expr.generics.iter().map(|g| g.0.into_mir(module_id)).collect(),
|
||||
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
parameters: fn_call_expr.params.iter().map(|e| e.process(module_id)).collect(),
|
||||
meta: fn_call_expr.range.as_meta(module_id),
|
||||
@ -468,6 +480,7 @@ impl ast::Expression {
|
||||
ty.0.into_mir(module_id),
|
||||
mir::FunctionCall {
|
||||
name: fn_call_expr.name.clone(),
|
||||
generics: fn_call_expr.generics.iter().map(|g| g.0.into_mir(module_id)).collect(),
|
||||
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
parameters: fn_call_expr.params.iter().map(|e| e.process(module_id)).collect(),
|
||||
meta: fn_call_expr.range.as_meta(module_id),
|
||||
@ -491,6 +504,7 @@ impl ast::Expression {
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
mir::FunctionCall {
|
||||
name: fn_call_expr.name.clone(),
|
||||
generics: fn_call_expr.generics.iter().map(|g| g.0.into_mir(module_id)).collect(),
|
||||
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
parameters: params,
|
||||
meta: fn_call_expr.range.as_meta(module_id),
|
||||
|
@ -77,6 +77,7 @@ pub fn form_intrinsics() -> Vec<FunctionDefinition> {
|
||||
|
||||
intrinsics.push(FunctionDefinition {
|
||||
name: MALLOC_IDENT.to_owned(),
|
||||
generics: Vec::new(),
|
||||
documentation: doc!("Allocates `size` bytes and returns a `u8`-pointer."),
|
||||
linkage_name: Some("malloc".to_owned()),
|
||||
is_pub: false,
|
||||
@ -104,6 +105,7 @@ pub fn simple_intrinsic<T: Into<String> + Clone>(
|
||||
) -> FunctionDefinition {
|
||||
FunctionDefinition {
|
||||
name: name.into(),
|
||||
generics: Vec::new(),
|
||||
documentation: Some(doc.into()),
|
||||
linkage_name: None,
|
||||
is_pub: true,
|
||||
@ -124,6 +126,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> {
|
||||
if let TypeKind::Array(_, len) = ty {
|
||||
intrinsics.push(FunctionDefinition {
|
||||
name: "length".to_owned(),
|
||||
generics: Vec::new(),
|
||||
documentation: doc!("Returns the length of this given array"),
|
||||
linkage_name: None,
|
||||
is_pub: true,
|
||||
@ -282,6 +285,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> {
|
||||
));
|
||||
intrinsics.push(FunctionDefinition {
|
||||
name: "powi".to_owned(),
|
||||
generics: Vec::new(),
|
||||
documentation: doc!("Returns `value` raised to the exponent of `exponent`."),
|
||||
linkage_name: None,
|
||||
is_pub: true,
|
||||
@ -326,6 +330,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> {
|
||||
if ty.signed() {
|
||||
intrinsics.push(FunctionDefinition {
|
||||
name: "abs".to_owned(),
|
||||
generics: Vec::new(),
|
||||
documentation: doc!("Returns the absolute value of `value`."),
|
||||
linkage_name: None,
|
||||
is_pub: true,
|
||||
@ -357,6 +362,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> {
|
||||
}
|
||||
intrinsics.push(FunctionDefinition {
|
||||
name: "sizeof".to_owned(),
|
||||
generics: Vec::new(),
|
||||
documentation: doc!("Simply returns the size of type `T` in bytes."),
|
||||
linkage_name: None,
|
||||
is_pub: true,
|
||||
@ -369,6 +375,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> {
|
||||
});
|
||||
intrinsics.push(FunctionDefinition {
|
||||
name: "malloc".to_owned(),
|
||||
generics: Vec::new(),
|
||||
documentation: doc!("Allocates `T::sizeof() * size` bytes and returns a pointer to `T`."),
|
||||
linkage_name: None,
|
||||
is_pub: true,
|
||||
@ -386,6 +393,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> {
|
||||
|
||||
intrinsics.push(FunctionDefinition {
|
||||
name: "memcpy".to_owned(),
|
||||
generics: Vec::new(),
|
||||
documentation: doc!(
|
||||
"Copies `T::sizeof() * size` bytes from pointer `source` to pointer
|
||||
`destination`."
|
||||
@ -418,6 +426,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> {
|
||||
|
||||
intrinsics.push(FunctionDefinition {
|
||||
name: "null".to_owned(),
|
||||
generics: Vec::new(),
|
||||
documentation: doc!("Returns a null-pointer of type `T`."),
|
||||
linkage_name: None,
|
||||
is_pub: true,
|
||||
@ -431,6 +440,7 @@ pub fn get_intrinsic_assoc_functions(ty: &TypeKind) -> Vec<FunctionDefinition> {
|
||||
|
||||
intrinsics.push(FunctionDefinition {
|
||||
name: "is_null".to_owned(),
|
||||
generics: Vec::new(),
|
||||
documentation: doc!("Returns a boolean representing if `val` is a nullptr or not."),
|
||||
linkage_name: None,
|
||||
is_pub: true,
|
||||
|
@ -1218,7 +1218,9 @@ impl mir::Expression {
|
||||
let TypeKind::CustomType(key) = *inner.clone() else {
|
||||
panic!("tried accessing non-custom-type");
|
||||
};
|
||||
let TypeDefinitionKind::Struct(struct_ty) = scope.get_typedef(&key).unwrap().kind.clone();
|
||||
let TypeDefinitionKind::Struct(struct_ty) = scope.get_typedef(&key).unwrap().kind.clone() else {
|
||||
panic!();
|
||||
};
|
||||
let idx = struct_ty.find_index(field).unwrap();
|
||||
|
||||
let gep_n = format!("{}.{}.gep", key.0, field);
|
||||
@ -1259,7 +1261,10 @@ impl mir::Expression {
|
||||
let TypeDefinition {
|
||||
kind: TypeDefinitionKind::Struct(struct_ty),
|
||||
..
|
||||
} = scope.types.get(scope.type_values.get(&key).unwrap()).unwrap();
|
||||
} = scope.types.get(scope.type_values.get(&key).unwrap()).unwrap()
|
||||
else {
|
||||
panic!()
|
||||
};
|
||||
|
||||
let indices = struct_ty.0.iter().enumerate();
|
||||
|
||||
|
@ -8,7 +8,7 @@ use crate::{
|
||||
ast::token_stream::{self, TokenRange},
|
||||
codegen,
|
||||
lexer::{self, Cursor, FullToken, Position},
|
||||
mir::{self, macros, pass, typecheck, Metadata, SourceModuleId},
|
||||
mir::{self, generics, macros, pass, typecheck, Metadata, SourceModuleId},
|
||||
};
|
||||
|
||||
use crate::mir::typecheck::ErrorKind as TypecheckError;
|
||||
@ -36,6 +36,8 @@ pub enum ErrorKind {
|
||||
LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>),
|
||||
#[error("{}{}", label("(Macro) "), .0)]
|
||||
MacroError(#[from] mir::pass::Error<macros::ErrorKind>),
|
||||
#[error("{}{}", label("(Generics) "), .0)]
|
||||
GenericsError(#[from] mir::pass::Error<generics::ErrorKind>),
|
||||
#[error("{}{}", label("(Codegen) "), .0)]
|
||||
CodegenError(#[from] codegen::ErrorKind),
|
||||
}
|
||||
@ -62,6 +64,7 @@ impl ErrorKind {
|
||||
codegen::ErrorKind::Null => Default::default(),
|
||||
},
|
||||
ErrorKind::MacroError(error) => error.metadata,
|
||||
ErrorKind::GenericsError(error) => error.metadata,
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,6 +77,7 @@ impl ErrorKind {
|
||||
ErrorKind::LinkerError(_) => "linker",
|
||||
ErrorKind::MacroError(_) => "macro-pass",
|
||||
ErrorKind::CodegenError(_) => "codegen",
|
||||
ErrorKind::GenericsError(_) => "generics",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ use reid_lib::{compile::CompileOutput, Context};
|
||||
use crate::{
|
||||
ast::TopLevelStatement,
|
||||
mir::{
|
||||
generics::GenericsPass,
|
||||
macros::{form_macros, MacroModule, MacroPass},
|
||||
SourceModuleId,
|
||||
},
|
||||
@ -177,6 +178,24 @@ pub fn perform_all_passes<'map>(
|
||||
is_lib: true,
|
||||
})?;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
log::trace!("{:-^100}", "LINKER OUTPUT");
|
||||
#[cfg(debug_assertions)]
|
||||
log::trace!("{:#}", &context);
|
||||
#[cfg(debug_assertions)]
|
||||
log::trace!("{:#?}", &state);
|
||||
|
||||
if !state.errors.is_empty() {
|
||||
return Err(ReidError::from_kind(
|
||||
state.errors.iter().map(|e| e.clone().into()).collect(),
|
||||
module_map.clone(),
|
||||
));
|
||||
}
|
||||
|
||||
let state = context.pass(&mut GenericsPass {
|
||||
function_map: HashMap::new(),
|
||||
})?;
|
||||
|
||||
for module in &mut context.modules {
|
||||
for intrinsic in form_intrinsics() {
|
||||
module.1.functions.insert(0, intrinsic);
|
||||
@ -184,7 +203,7 @@ pub fn perform_all_passes<'map>(
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
log::trace!("{:-^100}", "LINKER OUTPUT");
|
||||
log::trace!("{:-^100}", "GENERICS OUTPUT");
|
||||
#[cfg(debug_assertions)]
|
||||
log::trace!("{:#}", &context);
|
||||
#[cfg(debug_assertions)]
|
||||
|
@ -157,9 +157,14 @@ impl Display for FunctionDefinition {
|
||||
}
|
||||
write!(
|
||||
f,
|
||||
"{}fn {}({}) -> {:#} ",
|
||||
"{}fn {}<{}>({}) -> {:#} ",
|
||||
if self.is_pub { "pub " } else { "" },
|
||||
self.name,
|
||||
self.generics
|
||||
.iter()
|
||||
.map(|(n, t)| format!("{n} = {:?}", t))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
self.parameters
|
||||
.iter()
|
||||
.map(|FunctionParam { name, ty, .. }| format!("{}: {:#}", name, ty))
|
||||
@ -489,12 +494,14 @@ impl Display for VagueType {
|
||||
VagueType::Integer => write!(f, "Number"),
|
||||
VagueType::TypeRef(id) => write!(f, "TypeRef({0})", id),
|
||||
VagueType::Decimal => write!(f, "Decimal"),
|
||||
VagueType::Named(name) => write!(f, "Named<{name}>"),
|
||||
}
|
||||
} else {
|
||||
match self {
|
||||
VagueType::Unknown => write!(f, "{{unknown}}"),
|
||||
VagueType::Integer => write!(f, "Number"),
|
||||
VagueType::TypeRef(_) => write!(f, "{{unknown}}"),
|
||||
VagueType::Named(name) => write!(f, "{name}"),
|
||||
VagueType::Decimal => write!(f, "Decimal"),
|
||||
}
|
||||
}
|
||||
|
296
reid/src/mir/generics.rs
Normal file
296
reid/src/mir/generics.rs
Normal file
@ -0,0 +1,296 @@
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use log::Metadata;
|
||||
|
||||
use crate::mir::{
|
||||
self, generics, CustomTypeKey, FunctionCall, FunctionDefinition, FunctionParam, GlobalKind, GlobalValue,
|
||||
IfExpression, Literal, Module, SourceModuleId, TypeKind, WhileStatement,
|
||||
};
|
||||
|
||||
use super::pass::{Pass, PassResult, PassState};
|
||||
|
||||
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum ErrorKind {
|
||||
#[error("Should never be encountered!")]
|
||||
Null,
|
||||
#[error("Expected {0} type-arguments, got {1}!")]
|
||||
InvalidNumberTypeArguments(u32, u32),
|
||||
}
|
||||
|
||||
type Calls = Vec<(Vec<TypeKind>, mir::Metadata)>;
|
||||
|
||||
pub struct GenericsPass {
|
||||
pub function_map: HashMap<SourceModuleId, Functions>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Functions {
|
||||
calls: HashMap<String, Calls>,
|
||||
assoc_calls: HashMap<(TypeKind, String), Calls>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct GenericsPassData {
|
||||
generic_types: HashMap<String, TypeKind>,
|
||||
}
|
||||
|
||||
type GenericsPassState<'map, 'st, 'sc> = PassState<'st, 'sc, GenericsPassData, ErrorKind>;
|
||||
|
||||
impl Pass for GenericsPass {
|
||||
type Data = GenericsPassData;
|
||||
type TError = ErrorKind;
|
||||
|
||||
fn context(&mut self, context: &mut mir::Context, mut _state: PassState<Self::Data, Self::TError>) -> PassResult {
|
||||
let mut function_map = HashMap::new();
|
||||
for module in &context.modules {
|
||||
function_map.insert(
|
||||
module.0.clone(),
|
||||
Functions {
|
||||
calls: HashMap::new(),
|
||||
assoc_calls: HashMap::new(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
for module in &mut context.modules {
|
||||
let mut calls = HashMap::new();
|
||||
let mut assoc_calls = HashMap::new();
|
||||
for function in &mut module.1.associated_functions {
|
||||
match &mut function.1.kind {
|
||||
mir::FunctionDefinitionKind::Local(block, _) => block.find_calls(&mut calls, &mut assoc_calls),
|
||||
mir::FunctionDefinitionKind::Extern(_) => {}
|
||||
mir::FunctionDefinitionKind::Intrinsic(_) => {}
|
||||
}
|
||||
}
|
||||
for function in &mut module.1.functions {
|
||||
match &mut function.kind {
|
||||
mir::FunctionDefinitionKind::Local(block, _) => block.find_calls(&mut calls, &mut assoc_calls),
|
||||
mir::FunctionDefinitionKind::Extern(_) => {}
|
||||
mir::FunctionDefinitionKind::Intrinsic(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
for function in &module.1.associated_functions {
|
||||
if let Some(source) = function.1.source {
|
||||
let key = (function.0.clone(), function.1.name.clone());
|
||||
function_map
|
||||
.get_mut(&source)
|
||||
.unwrap()
|
||||
.assoc_calls
|
||||
.insert(key.clone(), assoc_calls.get(&key).cloned().unwrap_or_default());
|
||||
}
|
||||
}
|
||||
for function in &module.1.functions {
|
||||
if let Some(source) = function.source {
|
||||
function_map.get_mut(&source).unwrap().calls.insert(
|
||||
function.name.clone(),
|
||||
calls.get(&function.name).cloned().unwrap_or_default(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.function_map = function_map;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn module(&mut self, module: &mut mir::Module, mut state: PassState<Self::Data, Self::TError>) -> PassResult {
|
||||
for function in module.functions.drain(..).collect::<Vec<_>>() {
|
||||
if let Some(source) = function.source {
|
||||
let functions = self.function_map.get(&source).unwrap();
|
||||
let calls = functions.calls.get(&function.name).unwrap();
|
||||
|
||||
for call in calls {
|
||||
if call.0.len() != function.generics.len() {
|
||||
state.note_errors(
|
||||
&vec![ErrorKind::InvalidNumberTypeArguments(
|
||||
function.generics.len() as u32,
|
||||
call.0.len() as u32,
|
||||
)],
|
||||
call.1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if function.generics.len() > 0 {
|
||||
for call in calls {
|
||||
if let Some(clone) = function.try_clone() {
|
||||
let generics = function
|
||||
.generics
|
||||
.iter()
|
||||
.zip(call.0.clone())
|
||||
.map(|((n, _), t)| (n.clone(), t.clone()))
|
||||
.collect();
|
||||
module.functions.push(FunctionDefinition {
|
||||
name: name_fmt(function.name.clone(), call.0.clone()),
|
||||
return_type: function.return_type.replace_generic(&generics),
|
||||
parameters: function
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|p| FunctionParam {
|
||||
ty: p.ty.replace_generic(&generics),
|
||||
..p.clone()
|
||||
})
|
||||
.collect(),
|
||||
generics,
|
||||
..clone
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
module.functions.push(function);
|
||||
}
|
||||
} else {
|
||||
module.functions.push(function);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn function(
|
||||
&mut self,
|
||||
func: &mut FunctionDefinition,
|
||||
mut state: PassState<Self::Data, Self::TError>,
|
||||
) -> PassResult {
|
||||
for (name, ty) in &func.generics {
|
||||
state.scope.data.generic_types.insert(name.clone(), ty.clone());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stmt(&mut self, stmt: &mut mir::Statement, mut state: PassState<Self::Data, Self::TError>) -> PassResult {
|
||||
match &mut stmt.0 {
|
||||
mir::StmtKind::Let(var_ref, _, _) => match var_ref.0.clone() {
|
||||
TypeKind::CustomType(custom_type_key) => {
|
||||
if let Some(ty) = state.scope.data.generic_types.get(&custom_type_key.0) {
|
||||
var_ref.0 = ty.clone();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl mir::Block {
|
||||
fn find_calls(&mut self, calls: &mut HashMap<String, Calls>, assoc_calls: &mut HashMap<(TypeKind, String), Calls>) {
|
||||
for statement in &mut self.statements {
|
||||
statement.find_calls(calls, assoc_calls);
|
||||
}
|
||||
if let Some((_, Some(e))) = &mut self.return_expression {
|
||||
e.find_calls(calls, assoc_calls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl mir::Statement {
|
||||
fn find_calls(&mut self, calls: &mut HashMap<String, Calls>, assoc_calls: &mut HashMap<(TypeKind, String), Calls>) {
|
||||
match &mut self.0 {
|
||||
mir::StmtKind::Let(_, _, expression) => expression.find_calls(calls, assoc_calls),
|
||||
mir::StmtKind::Set(expression, expression1) => {
|
||||
expression.find_calls(calls, assoc_calls);
|
||||
expression1.find_calls(calls, assoc_calls);
|
||||
}
|
||||
mir::StmtKind::Import(_) => {}
|
||||
mir::StmtKind::Expression(expression) => expression.find_calls(calls, assoc_calls),
|
||||
mir::StmtKind::While(WhileStatement { condition, block, .. }) => {
|
||||
condition.find_calls(calls, assoc_calls);
|
||||
block.find_calls(calls, assoc_calls);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl mir::Expression {
|
||||
fn find_calls(&mut self, calls: &mut HashMap<String, Calls>, assoc_calls: &mut HashMap<(TypeKind, String), Calls>) {
|
||||
match &mut self.0 {
|
||||
mir::ExprKind::Variable(_) => {}
|
||||
mir::ExprKind::Indexed(expression, _, expression1) => {
|
||||
expression.find_calls(calls, assoc_calls);
|
||||
expression1.find_calls(calls, assoc_calls);
|
||||
}
|
||||
mir::ExprKind::Accessed(expression, _, _, _) => {
|
||||
expression.find_calls(calls, assoc_calls);
|
||||
}
|
||||
mir::ExprKind::Array(expressions) => {
|
||||
for expression in expressions {
|
||||
expression.find_calls(calls, assoc_calls);
|
||||
}
|
||||
}
|
||||
mir::ExprKind::Struct(_, items) => {
|
||||
for item in items {
|
||||
item.1.find_calls(calls, assoc_calls);
|
||||
}
|
||||
}
|
||||
mir::ExprKind::Literal(_) => {}
|
||||
mir::ExprKind::BinOp(_, lhs, rhs, _) => {
|
||||
lhs.find_calls(calls, assoc_calls);
|
||||
rhs.find_calls(calls, assoc_calls);
|
||||
}
|
||||
mir::ExprKind::FunctionCall(function_call) => {
|
||||
if let Some(calls) = calls.get_mut(&function_call.name) {
|
||||
calls.push((function_call.generics.clone(), self.1));
|
||||
} else {
|
||||
calls.insert(
|
||||
function_call.name.clone(),
|
||||
vec![(function_call.generics.clone(), self.1)],
|
||||
);
|
||||
}
|
||||
if function_call.generics.len() > 0 {
|
||||
function_call.name = name_fmt(function_call.name.clone(), function_call.generics.clone())
|
||||
}
|
||||
}
|
||||
mir::ExprKind::AssociatedFunctionCall(ty, function_call) => {
|
||||
if let Some(calls) = assoc_calls.get_mut(&(ty.clone(), function_call.name.clone())) {
|
||||
calls.push((function_call.generics.clone(), self.1));
|
||||
} else {
|
||||
assoc_calls.insert(
|
||||
(ty.clone(), function_call.name.clone()),
|
||||
vec![(function_call.generics.clone(), self.1)],
|
||||
);
|
||||
}
|
||||
if function_call.generics.len() > 0 {
|
||||
function_call.name = name_fmt(function_call.name.clone(), function_call.generics.clone())
|
||||
}
|
||||
}
|
||||
mir::ExprKind::If(IfExpression(cond, then_e, else_e)) => {
|
||||
cond.find_calls(calls, assoc_calls);
|
||||
then_e.find_calls(calls, assoc_calls);
|
||||
if let Some(else_e) = else_e.as_mut() {
|
||||
else_e.find_calls(calls, assoc_calls);
|
||||
}
|
||||
}
|
||||
mir::ExprKind::Block(block) => block.find_calls(calls, assoc_calls),
|
||||
mir::ExprKind::Borrow(expression, _) => expression.find_calls(calls, assoc_calls),
|
||||
mir::ExprKind::Deref(expression) => expression.find_calls(calls, assoc_calls),
|
||||
mir::ExprKind::CastTo(expression, _) => expression.find_calls(calls, assoc_calls),
|
||||
mir::ExprKind::GlobalRef(_, _) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn name_fmt(name: String, generics: Vec<TypeKind>) -> String {
|
||||
format!(
|
||||
"{}.{}",
|
||||
name,
|
||||
generics.iter().map(|t| t.to_string()).collect::<Vec<_>>().join(".")
|
||||
)
|
||||
}
|
||||
|
||||
impl TypeKind {
|
||||
fn replace_generic(&self, generics: &Vec<(String, TypeKind)>) -> TypeKind {
|
||||
match self {
|
||||
TypeKind::CustomType(CustomTypeKey(name, _)) => {
|
||||
if let Some((_, inner)) = generics.iter().find(|(n, _)| n == name) {
|
||||
inner.clone()
|
||||
} else {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
_ => self.clone(),
|
||||
}
|
||||
}
|
||||
}
|
@ -171,6 +171,7 @@ impl TypeKind {
|
||||
VagueType::Integer => TypeCategory::Integer,
|
||||
VagueType::Decimal => TypeCategory::Real,
|
||||
VagueType::TypeRef(_) => TypeCategory::TypeRef,
|
||||
VagueType::Named(_) => TypeCategory::Other,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -311,6 +311,7 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
|
||||
importer_module.functions.push(FunctionDefinition {
|
||||
name: function.name.clone(),
|
||||
generics: function.generics.clone(),
|
||||
documentation: function.documentation.clone(),
|
||||
linkage_name: None,
|
||||
is_pub: false,
|
||||
@ -460,6 +461,7 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
FunctionDefinition {
|
||||
name: func_name.clone(),
|
||||
documentation: func.documentation.clone(),
|
||||
generics: func.generics.clone(),
|
||||
linkage_name: Some(format!("{}::{}", ty, func_name)),
|
||||
is_pub: false,
|
||||
is_imported: false,
|
||||
|
@ -11,6 +11,7 @@ use crate::{
|
||||
};
|
||||
|
||||
mod fmt;
|
||||
pub mod generics;
|
||||
pub mod implement;
|
||||
pub mod linker;
|
||||
pub mod macros;
|
||||
@ -135,13 +136,14 @@ pub enum TypeKind {
|
||||
Vague(VagueType),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum VagueType {
|
||||
Unknown,
|
||||
/// Some integer value (e.g. 5)
|
||||
Integer,
|
||||
/// Some decimal fractional value (e.g. 1.5)
|
||||
Decimal,
|
||||
Named(String),
|
||||
TypeRef(usize),
|
||||
}
|
||||
|
||||
@ -164,7 +166,7 @@ impl StructType {
|
||||
impl TypeKind {
|
||||
pub fn known(&self) -> Result<TypeKind, VagueType> {
|
||||
if let TypeKind::Vague(vague) = self {
|
||||
Err(*vague)
|
||||
Err(vague.clone())
|
||||
} else {
|
||||
Ok(self.clone())
|
||||
}
|
||||
@ -309,6 +311,7 @@ pub struct IfExpression(pub Box<Expression>, pub Box<Expression>, pub Box<Option
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FunctionCall {
|
||||
pub name: String,
|
||||
pub generics: Vec<TypeKind>,
|
||||
pub return_type: TypeKind,
|
||||
pub parameters: Vec<Expression>,
|
||||
pub is_macro: bool,
|
||||
@ -320,6 +323,7 @@ pub struct FunctionDefinition {
|
||||
pub name: String,
|
||||
pub documentation: Option<String>,
|
||||
pub linkage_name: Option<String>,
|
||||
pub generics: Vec<(String, TypeKind)>,
|
||||
/// Whether this function is visible to outside modules
|
||||
pub is_pub: bool,
|
||||
/// Whether this module is from an external module, and has been imported
|
||||
@ -331,6 +335,40 @@ pub struct FunctionDefinition {
|
||||
pub signature_meta: Metadata,
|
||||
}
|
||||
|
||||
impl FunctionDefinition {
|
||||
pub fn try_clone(&self) -> Option<FunctionDefinition> {
|
||||
match &self.kind {
|
||||
FunctionDefinitionKind::Local(block, metadata) => Some(FunctionDefinition {
|
||||
name: self.name.clone(),
|
||||
documentation: self.documentation.clone(),
|
||||
linkage_name: self.linkage_name.clone(),
|
||||
generics: self.generics.clone(),
|
||||
is_pub: self.is_pub.clone(),
|
||||
is_imported: self.is_imported.clone(),
|
||||
return_type: self.return_type.clone(),
|
||||
parameters: self.parameters.clone(),
|
||||
kind: FunctionDefinitionKind::Local(block.clone(), metadata.clone()),
|
||||
source: self.source.clone(),
|
||||
signature_meta: self.signature_meta.clone(),
|
||||
}),
|
||||
FunctionDefinitionKind::Extern(e) => Some(FunctionDefinition {
|
||||
name: self.name.clone(),
|
||||
documentation: self.documentation.clone(),
|
||||
linkage_name: self.linkage_name.clone(),
|
||||
generics: self.generics.clone(),
|
||||
is_pub: self.is_pub.clone(),
|
||||
is_imported: self.is_imported.clone(),
|
||||
return_type: self.return_type.clone(),
|
||||
parameters: self.parameters.clone(),
|
||||
kind: FunctionDefinitionKind::Extern(*e),
|
||||
source: self.source.clone(),
|
||||
signature_meta: self.signature_meta.clone(),
|
||||
}),
|
||||
FunctionDefinitionKind::Intrinsic(intrinsic_function) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||
pub struct FunctionParam {
|
||||
pub name: String,
|
||||
|
@ -290,10 +290,11 @@ impl TypeKind {
|
||||
pub(super) fn or_default(&self) -> Result<TypeKind, ErrorKind> {
|
||||
Ok(match self {
|
||||
TypeKind::Vague(vague_type) => match &vague_type {
|
||||
Vague::Unknown => Err(ErrorKind::TypeIsVague(*vague_type))?,
|
||||
Vague::Unknown => Err(ErrorKind::TypeIsVague(vague_type.clone()))?,
|
||||
Vague::Integer => TypeKind::I32,
|
||||
Vague::TypeRef(_) => panic!("Hinted default!"),
|
||||
VagueType::Decimal => TypeKind::F32,
|
||||
VagueType::Named(_) => panic!("Defaulted unknown named!"),
|
||||
},
|
||||
TypeKind::Array(type_kind, len) => TypeKind::Array(Box::new(type_kind.or_default()?), *len),
|
||||
TypeKind::Borrow(type_kind, mutable) => TypeKind::Borrow(Box::new(type_kind.or_default()?), *mutable),
|
||||
@ -339,7 +340,7 @@ impl TypeKind {
|
||||
TypeKind::Borrow(type_kind, _) => type_kind.is_known(state),
|
||||
TypeKind::UserPtr(type_kind) => type_kind.is_known(state),
|
||||
TypeKind::CodegenPtr(type_kind) => type_kind.is_known(state),
|
||||
TypeKind::Vague(vague_type) => Err(ErrorKind::TypeIsVague(*vague_type)),
|
||||
TypeKind::Vague(vague_type) => Err(ErrorKind::TypeIsVague(vague_type.clone())),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
@ -368,6 +368,7 @@ impl<'outer> ScopeTypeRefs<'outer> {
|
||||
self.narrow_to_type(&typeref, &self.try_default_deep(&typeref.resolve_deep()?)?)?
|
||||
.resolve_deep()?
|
||||
}
|
||||
VagueType::Named(_) => ty.clone(),
|
||||
},
|
||||
_ => ty.clone(),
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user