Compare commits

...

21 Commits

Author SHA1 Message Date
2303bf757a Rename macro to include_bytes!() 2025-07-29 15:57:26 +03:00
7234cad5f0 Allow &[ty; _] to be cast into *ty 2025-07-29 15:56:06 +03:00
baa068a371 Load file contents relative to module path instead of PWD 2025-07-29 15:44:14 +03:00
8b1d1084a6 Improve formatting for globals 2025-07-29 15:25:14 +03:00
f5f55079a9 Make global identifier for macro-generated globals better 2025-07-29 15:19:14 +03:00
baa7bafafc Add length-intrinsic 2025-07-29 01:15:09 +03:00
f700c577f1 Add reading file to buffer macro, only works for one global per file 2025-07-29 00:50:07 +03:00
ebe7fc8d75 Add GetGlobal "instruction" 2025-07-29 00:29:04 +03:00
140d963d9b Read file contents to binary within macro 2025-07-29 00:18:50 +03:00
480ba5155a Initialize global arrays in macros 2025-07-29 00:07:40 +03:00
2207c3df83 Add initial support for array globals 2025-07-29 00:06:47 +03:00
735c3231b1 Make macros generate globals 2025-07-28 23:49:22 +03:00
50a875ad21 Add compilation of global values 2025-07-28 23:32:47 +03:00
30257e1a2b Add global api support for llvm-lib 2025-07-28 23:20:13 +03:00
a7ac974f46 Change macro pass workflow a little bit 2025-07-28 22:57:06 +03:00
3d8f4bbd24 Implement macro-pass 2025-07-28 22:37:24 +03:00
33ed1fd813 Add macro call convention 2025-07-28 22:18:30 +03:00
67a5fcd002 Basically revert everything, create macro-pass 2025-07-28 22:11:46 +03:00
80bdf4eba8 Merge branch 'main' into macros 2025-07-28 22:03:06 +03:00
bd8994bb37 Fix linking associated functions, fix other examples 2025-07-28 22:02:49 +03:00
2e153922f1 Start adding macros 2025-07-28 21:54:51 +03:00
29 changed files with 779 additions and 135 deletions

View File

@ -1,6 +1,5 @@
// Arithmetic, function calls and imports! // Arithmetic, function calls and imports!
import std::allocate;
import std::print; import std::print;
fn other() -> i16 { fn other() -> i16 {
@ -9,7 +8,7 @@ fn other() -> i16 {
fn main() -> u32 { fn main() -> u32 {
let mut v = (allocate(4) as *u32); let mut v = (malloc(4) as *u32);
v[0] = other() as u32; v[0] = other() as u32;
return v[0]; return v[0];

8
examples/macro_easy.reid Normal file
View File

@ -0,0 +1,8 @@
import std::String;
import std::print;
fn main() -> u8 {
let bytes = include_bytes!("./macro_easy_file.txt");
print(String::new() + bytes.length());
return (bytes as *u8)[0];
}

View File

@ -0,0 +1 @@
hello

View File

@ -1,7 +1,7 @@
// Arithmetic, function calls and imports! // Arithmetic, function calls and imports!
fn main() -> u8 { fn main() -> u8 {
let mut ptr = u8::alloca(4); let mut ptr = u8::malloc(4);
ptr[0] = 5; ptr[0] = 5;

View File

@ -1,7 +1,7 @@
use reid_lib::{CmpPredicate, ConstValue, Context, FunctionFlags, Instr, TerminatorKind, Type}; use reid_lib::{CmpPredicate, ConstValueKind, Context, FunctionFlags, Instr, TerminatorKind, Type};
fn main() { fn main() {
use ConstValue::*; use ConstValueKind::*;
use Instr::*; use Instr::*;
let context = Context::new("libtest"); let context = Context::new("libtest");

View File

@ -4,8 +4,8 @@
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use crate::{ use crate::{
Block, BlockData, CompileResult, CustomTypeKind, ErrorKind, FunctionData, Instr, InstructionData, ModuleData, Block, BlockData, CompileResult, ConstValueKind, CustomTypeKind, ErrorKind, FunctionData, Instr, InstructionData,
NamedStruct, TerminatorKind, Type, TypeCategory, TypeData, ModuleData, NamedStruct, TerminatorKind, Type, TypeCategory, TypeData,
debug_information::{ debug_information::{
DebugInformation, DebugLocationValue, DebugMetadataValue, DebugScopeValue, InstructionDebugRecordData, DebugInformation, DebugLocationValue, DebugMetadataValue, DebugScopeValue, InstructionDebugRecordData,
}, },
@ -27,6 +27,12 @@ pub struct BlockValue(pub(crate) FunctionValue, pub(crate) usize);
#[derive(Clone, Hash, Copy, PartialEq, Eq)] #[derive(Clone, Hash, Copy, PartialEq, Eq)]
pub struct InstructionValue(pub(crate) BlockValue, pub(crate) usize); pub struct InstructionValue(pub(crate) BlockValue, pub(crate) usize);
#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)]
pub struct ConstantValue(pub(crate) ModuleValue, pub(crate) usize);
#[derive(Debug, Clone, Hash, Copy, PartialEq, Eq)]
pub struct GlobalValue(pub(crate) ModuleValue, pub(crate) usize);
#[derive(Clone)] #[derive(Clone)]
pub struct ModuleHolder { pub struct ModuleHolder {
pub(crate) value: ModuleValue, pub(crate) value: ModuleValue,
@ -34,6 +40,20 @@ pub struct ModuleHolder {
pub(crate) functions: Vec<FunctionHolder>, pub(crate) functions: Vec<FunctionHolder>,
pub(crate) types: Vec<TypeHolder>, pub(crate) types: Vec<TypeHolder>,
pub(crate) debug_information: Option<DebugInformation>, pub(crate) debug_information: Option<DebugInformation>,
pub(crate) constants: Vec<ConstantValueHolder>,
pub(crate) globals: Vec<GlobalValueHolder>,
}
#[derive(Clone)]
pub struct ConstantValueHolder {
pub(crate) value: ConstantValue,
pub(crate) kind: ConstValueKind,
}
#[derive(Clone)]
pub struct GlobalValueHolder {
pub(crate) value: GlobalValue,
pub(crate) name: String,
pub(crate) initializer: ConstantValue,
} }
#[derive(Clone)] #[derive(Clone)]
@ -88,6 +108,8 @@ impl Builder {
functions: Vec::new(), functions: Vec::new(),
types: Vec::new(), types: Vec::new(),
debug_information: None, debug_information: None,
constants: Vec::new(),
globals: Vec::new(),
}); });
value value
} }
@ -168,6 +190,35 @@ impl Builder {
} }
} }
pub(crate) unsafe fn build_constant(&self, module: ModuleValue, kind: ConstValueKind) -> ConstantValue {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(module.0);
let value = ConstantValue(module.value, module.constants.len());
module.constants.push(ConstantValueHolder { value, kind });
value
}
}
pub(crate) unsafe fn add_global(
&self,
module: ModuleValue,
name: String,
initializer: ConstantValue,
) -> GlobalValue {
unsafe {
let mut modules = self.modules.borrow_mut();
let module = modules.get_unchecked_mut(module.0);
let value = GlobalValue(module.value, module.globals.len());
module.globals.push(GlobalValueHolder {
value,
name,
initializer,
});
value
}
}
pub(crate) unsafe fn find_function(&self, module: ModuleValue, name: &String) -> Option<FunctionValue> { pub(crate) unsafe fn find_function(&self, module: ModuleValue, name: &String) -> Option<FunctionValue> {
unsafe { unsafe {
let mut modules = self.modules.borrow_mut(); let mut modules = self.modules.borrow_mut();
@ -332,6 +383,24 @@ impl Builder {
self.modules.clone() self.modules.clone()
} }
pub(crate) fn get_global_initializer(&self, value: GlobalValue) -> ConstantValue {
unsafe {
let modules = self.modules.borrow();
let module = modules.get_unchecked(value.0.0);
let global = module.globals.get_unchecked(value.1);
global.initializer
}
}
pub(crate) fn get_const_kind(&self, value: ConstantValue) -> ConstValueKind {
unsafe {
let modules = self.modules.borrow();
let module = modules.get_unchecked(value.0.0);
let constant = module.constants.get_unchecked(value.1);
constant.kind.clone()
}
}
pub fn check_instruction(&self, instruction: &InstructionValue) -> CompileResult<()> { pub fn check_instruction(&self, instruction: &InstructionValue) -> CompileResult<()> {
unsafe { unsafe {
match self.instr_data(&instruction).kind { match self.instr_data(&instruction).kind {
@ -566,6 +635,7 @@ impl Builder {
Err(ErrorKind::Null) Err(ErrorKind::Null)
} }
} }
Instr::GetGlobal(_) => Ok(()),
} }
} }
} }
@ -717,6 +787,11 @@ impl InstructionValue {
ShiftRightLogical(lhs, _) => lhs.get_type(builder), ShiftRightLogical(lhs, _) => lhs.get_type(builder),
ShiftRightArithmetic(lhs, _) => lhs.get_type(builder), ShiftRightArithmetic(lhs, _) => lhs.get_type(builder),
ShiftLeft(lhs, _) => lhs.get_type(builder), ShiftLeft(lhs, _) => lhs.get_type(builder),
GetGlobal(global_value) => {
let constant = builder.get_global_initializer(*global_value);
let kind = builder.get_const_kind(constant);
Ok(kind.get_type())
}
} }
} }
} }

View File

@ -27,13 +27,13 @@ use llvm_sys::{
use crate::{ use crate::{
CustomTypeKind, CustomTypeKind,
builder::{TypeHolder, TypeValue}, builder::{ConstantValue, GlobalValue, TypeHolder, TypeValue},
debug_information::*, debug_information::*,
util::{ErrorMessageHolder, MemoryBufferHolder, from_cstring, into_cstring}, util::{ErrorMessageHolder, MemoryBufferHolder, from_cstring, into_cstring},
}; };
use super::{ use super::{
CmpPredicate, ConstValue, Context, TerminatorKind, Type, CmpPredicate, ConstValueKind, Context, TerminatorKind, Type,
builder::{ builder::{
BlockHolder, BlockValue, Builder, FunctionHolder, FunctionValue, InstructionHolder, InstructionValue, BlockHolder, BlockValue, Builder, FunctionHolder, FunctionValue, InstructionHolder, InstructionValue,
ModuleHolder, ModuleHolder,
@ -193,6 +193,8 @@ pub struct LLVMModule<'a> {
blocks: HashMap<BlockValue, LLVMBasicBlockRef>, blocks: HashMap<BlockValue, LLVMBasicBlockRef>,
values: HashMap<InstructionValue, LLVMValue>, values: HashMap<InstructionValue, LLVMValue>,
types: HashMap<TypeValue, LLVMTypeRef>, types: HashMap<TypeValue, LLVMTypeRef>,
constants: HashMap<ConstantValue, LLVMValue>,
globals: HashMap<GlobalValue, LLVMValueRef>,
debug: Option<LLVMDebugInformation<'a>>, debug: Option<LLVMDebugInformation<'a>>,
} }
@ -237,6 +239,8 @@ impl ModuleHolder {
// Compile the contents // Compile the contents
let mut types = HashMap::new(); let mut types = HashMap::new();
let mut constants = HashMap::new();
let mut globals = HashMap::new();
let mut metadata = HashMap::new(); let mut metadata = HashMap::new();
let mut scopes = HashMap::new(); let mut scopes = HashMap::new();
let mut locations = HashMap::new(); let mut locations = HashMap::new();
@ -320,6 +324,29 @@ impl ModuleHolder {
types.insert(ty.value, ty.compile_type(context, &types)); types.insert(ty.value, ty.compile_type(context, &types));
} }
for constant in &self.constants {
constants.insert(
constant.value,
LLVMValue {
ty: constant.kind.get_type(),
value_ref: constant
.kind
.as_llvm(context.context_ref, context.builder_ref, &constants, &types),
},
);
}
for global in &self.globals {
let initializer = constants.get(&global.initializer).expect("No initializer?");
let global_value = LLVMAddGlobal(
module_ref,
initializer.ty.as_llvm(context.context_ref, &types),
into_cstring(global.name.clone()).as_ptr(),
);
LLVMSetInitializer(global_value, initializer.value_ref);
globals.insert(global.value, global_value);
}
let mut functions = HashMap::new(); let mut functions = HashMap::new();
for function in &self.functions { for function in &self.functions {
let func = function.compile_signature(context, module_ref, &types, &mut debug); let func = function.compile_signature(context, module_ref, &types, &mut debug);
@ -358,6 +385,8 @@ impl ModuleHolder {
types, types,
blocks: HashMap::new(), blocks: HashMap::new(),
values: HashMap::new(), values: HashMap::new(),
constants,
globals,
debug, debug,
}; };
@ -732,7 +761,7 @@ impl InstructionHolder {
use super::Instr::*; use super::Instr::*;
match &self.data.kind { match &self.data.kind {
Param(nth) => LLVMGetParam(function.value_ref, *nth as u32), Param(nth) => LLVMGetParam(function.value_ref, *nth as u32),
Constant(val) => val.as_llvm(module), Constant(val) => val.as_llvm(module.context_ref, module.builder_ref, &module.constants, &module.types),
Add(lhs, rhs) => { Add(lhs, rhs) => {
let lhs_val = module.values.get(&lhs).unwrap().value_ref; let lhs_val = module.values.get(&lhs).unwrap().value_ref;
let rhs_val = module.values.get(&rhs).unwrap().value_ref; let rhs_val = module.values.get(&rhs).unwrap().value_ref;
@ -1023,6 +1052,7 @@ impl InstructionHolder {
let rhs_val = module.values.get(&rhs).unwrap().value_ref; let rhs_val = module.values.get(&rhs).unwrap().value_ref;
LLVMBuildShl(module.builder_ref, lhs_val, rhs_val, name.as_ptr()) LLVMBuildShl(module.builder_ref, lhs_val, rhs_val, name.as_ptr())
} }
GetGlobal(global_value) => module.globals.get(global_value).unwrap().clone(),
} }
}; };
if let Some(record) = &self.record { if let Some(record) = &self.record {
@ -1144,32 +1174,50 @@ impl CmpPredicate {
} }
} }
impl ConstValue { impl ConstValueKind {
fn as_llvm(&self, module: &LLVMModule) -> LLVMValueRef { fn as_llvm(
&self,
context: LLVMContextRef,
builder: LLVMBuilderRef,
constants: &HashMap<ConstantValue, LLVMValue>,
types: &HashMap<TypeValue, LLVMTypeRef>,
) -> LLVMValueRef {
unsafe { unsafe {
let t = self.get_type().as_llvm(module.context_ref, &module.types); let t = self.get_type().as_llvm(context, &types);
match self { match self {
ConstValue::Bool(val) => LLVMConstInt(t, *val as u64, 1), ConstValueKind::Bool(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::I8(val) => LLVMConstInt(t, *val as u64, 1), ConstValueKind::I8(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::I16(val) => LLVMConstInt(t, *val as u64, 1), ConstValueKind::I16(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::I32(val) => LLVMConstInt(t, *val as u64, 1), ConstValueKind::I32(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::I64(val) => LLVMConstInt(t, *val as u64, 1), ConstValueKind::I64(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::I128(val) => LLVMConstInt(t, *val as u64, 1), ConstValueKind::I128(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::U8(val) => LLVMConstInt(t, *val as u64, 1), ConstValueKind::U8(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::U16(val) => LLVMConstInt(t, *val as u64, 1), ConstValueKind::U16(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::U32(val) => LLVMConstInt(t, *val as u64, 1), ConstValueKind::U32(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::U64(val) => LLVMConstInt(t, *val as u64, 1), ConstValueKind::U64(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::U128(val) => LLVMConstInt(t, *val as u64, 1), ConstValueKind::U128(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::Str(val) => { ConstValueKind::Str(val) => {
LLVMBuildGlobalString(module.builder_ref, into_cstring(val).as_ptr(), c"string".as_ptr()) LLVMBuildGlobalString(builder, into_cstring(val).as_ptr(), c"string".as_ptr())
}
ConstValueKind::F16(val) => LLVMConstReal(t, *val as f64),
ConstValueKind::F32B(val) => LLVMConstReal(t, *val as f64),
ConstValueKind::F32(val) => LLVMConstReal(t, *val as f64),
ConstValueKind::F64(val) => LLVMConstReal(t, *val as f64),
ConstValueKind::F80(val) => LLVMConstReal(t, *val as f64),
ConstValueKind::F128(val) => LLVMConstReal(t, *val as f64),
ConstValueKind::F128PPC(val) => LLVMConstReal(t, *val as f64),
ConstValueKind::Array(constant_values, elem_ty) => {
let mut values = constant_values
.iter()
.map(|v| constants.get(v).unwrap().value_ref)
.collect::<Vec<_>>();
LLVMConstArray2(
elem_ty.as_llvm(context, &types),
values.as_mut_ptr(),
values.len() as u64,
)
} }
ConstValue::F16(val) => LLVMConstReal(t, *val as f64),
ConstValue::F32B(val) => LLVMConstReal(t, *val as f64),
ConstValue::F32(val) => LLVMConstReal(t, *val as f64),
ConstValue::F64(val) => LLVMConstReal(t, *val as f64),
ConstValue::F80(val) => LLVMConstReal(t, *val as f64),
ConstValue::F128(val) => LLVMConstReal(t, *val as f64),
ConstValue::F128PPC(val) => LLVMConstReal(t, *val as f64),
} }
} }
} }

View File

@ -392,6 +392,7 @@ impl Debug for Instr {
Instr::ShiftRightLogical(lhs, rhs) => fmt_binop(f, lhs, &">>l", rhs), Instr::ShiftRightLogical(lhs, rhs) => fmt_binop(f, lhs, &">>l", rhs),
Instr::ShiftRightArithmetic(lhs, rhs) => fmt_binop(f, lhs, &">>a", rhs), Instr::ShiftRightArithmetic(lhs, rhs) => fmt_binop(f, lhs, &">>a", rhs),
Instr::ShiftLeft(lhs, rhs) => fmt_binop(f, lhs, &"<<", rhs), Instr::ShiftLeft(lhs, rhs) => fmt_binop(f, lhs, &"<<", rhs),
Instr::GetGlobal(global_value) => write!(f, "global {:?}", global_value),
} }
} }
} }

View File

@ -8,7 +8,10 @@ use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue,
use debug_information::{DebugFileData, DebugInformation, DebugLocationValue, DebugMetadataValue}; use debug_information::{DebugFileData, DebugInformation, DebugLocationValue, DebugMetadataValue};
use fmt::PrintableModule; use fmt::PrintableModule;
use crate::debug_information::DebugScopeValue; use crate::{
builder::{ConstantValue, GlobalValue},
debug_information::DebugScopeValue,
};
pub mod builder; pub mod builder;
pub mod compile; pub mod compile;
@ -121,6 +124,14 @@ impl<'ctx> Module<'ctx> {
pub fn get_debug_info(&self) -> &Option<DebugInformation> { pub fn get_debug_info(&self) -> &Option<DebugInformation> {
&self.debug_info &self.debug_info
} }
pub fn add_constant(&self, constant: ConstValueKind) -> ConstantValue {
unsafe { self.builder.build_constant(self.value, constant) }
}
pub fn add_global<T: Into<String>>(&self, name: T, constant: ConstantValue) -> GlobalValue {
unsafe { self.builder.add_global(self.value, name.into(), constant) }
}
} }
impl<'ctx> Drop for Module<'ctx> { impl<'ctx> Drop for Module<'ctx> {
@ -265,6 +276,7 @@ impl Instr {
Instr::ShiftRightLogical(..) => "lshr", Instr::ShiftRightLogical(..) => "lshr",
Instr::ShiftRightArithmetic(..) => "ashr", Instr::ShiftRightArithmetic(..) => "ashr",
Instr::ShiftLeft(..) => "shl", Instr::ShiftLeft(..) => "shl",
Instr::GetGlobal(..) => "global",
} }
} }
} }
@ -361,7 +373,8 @@ pub enum CmpPredicate {
#[derive(Clone)] #[derive(Clone)]
pub enum Instr { pub enum Instr {
Param(usize), Param(usize),
Constant(ConstValue), Constant(ConstValueKind),
GetGlobal(GlobalValue),
/// Add two integers /// Add two integers
Add(InstructionValue, InstructionValue), Add(InstructionValue, InstructionValue),
@ -487,7 +500,7 @@ pub enum Type {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ConstValue { pub enum ConstValueKind {
I8(i8), I8(i8),
I16(i16), I16(i16),
I32(i32), I32(i32),
@ -507,6 +520,7 @@ pub enum ConstValue {
F80(f64), F80(f64),
F128(f64), F128(f64),
F128PPC(f64), F128PPC(f64),
Array(Vec<ConstantValue>, Type),
} }
#[derive(Clone, Hash)] #[derive(Clone, Hash)]
@ -531,29 +545,30 @@ pub enum CustomTypeKind {
#[derive(Debug, PartialEq, Eq, Clone, Hash)] #[derive(Debug, PartialEq, Eq, Clone, Hash)]
pub struct NamedStruct(pub String, pub Vec<Type>); pub struct NamedStruct(pub String, pub Vec<Type>);
impl ConstValue { impl ConstValueKind {
pub fn get_type(&self) -> Type { pub fn get_type(&self) -> Type {
use Type::*; use Type::*;
match self { match self {
ConstValue::I8(_) => I8, ConstValueKind::I8(_) => I8,
ConstValue::I16(_) => I16, ConstValueKind::I16(_) => I16,
ConstValue::I32(_) => I32, ConstValueKind::I32(_) => I32,
ConstValue::I64(_) => I64, ConstValueKind::I64(_) => I64,
ConstValue::I128(_) => I128, ConstValueKind::I128(_) => I128,
ConstValue::U8(_) => U8, ConstValueKind::U8(_) => U8,
ConstValue::U16(_) => U16, ConstValueKind::U16(_) => U16,
ConstValue::U32(_) => U32, ConstValueKind::U32(_) => U32,
ConstValue::U64(_) => U64, ConstValueKind::U64(_) => U64,
ConstValue::U128(_) => U128, ConstValueKind::U128(_) => U128,
ConstValue::Str(_) => Type::Ptr(Box::new(U8)), ConstValueKind::Str(_) => Type::Ptr(Box::new(U8)),
ConstValue::Bool(_) => Bool, ConstValueKind::Bool(_) => Bool,
ConstValue::F16(_) => F16, ConstValueKind::F16(_) => F16,
ConstValue::F32B(_) => F32B, ConstValueKind::F32B(_) => F32B,
ConstValue::F32(_) => F32, ConstValueKind::F32(_) => F32,
ConstValue::F64(_) => F64, ConstValueKind::F64(_) => F64,
ConstValue::F80(_) => F80, ConstValueKind::F80(_) => F80,
ConstValue::F128(_) => F128, ConstValueKind::F128(_) => F128,
ConstValue::F128PPC(_) => F128PPC, ConstValueKind::F128PPC(_) => F128PPC,
ConstValueKind::Array(vals, ty) => Type::Array(Box::new(ty.clone()), vals.len() as u64),
} }
} }
} }

View File

@ -159,7 +159,12 @@ impl BinaryOperator {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FunctionCallExpression(pub String, pub Vec<Expression>, pub TokenRange); pub struct FunctionCallExpression {
pub name: String,
pub params: Vec<Expression>,
pub range: TokenRange,
pub is_macro: bool,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct IfExpression( pub struct IfExpression(

View File

@ -537,8 +537,20 @@ impl Parse for BinaryOperator {
impl Parse for FunctionCallExpression { impl Parse for FunctionCallExpression {
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() {
let is_macro = if let Some(Token::Exclamation) = stream.peek() {
stream.next(); // Consume !
true
} else {
false
};
let args = stream.parse::<FunctionArgs>()?; let args = stream.parse::<FunctionArgs>()?;
Ok(FunctionCallExpression(name, args.0, stream.get_range().unwrap())) Ok(FunctionCallExpression {
name,
params: args.0,
range: stream.get_range().unwrap(),
is_macro,
})
} else { } else {
Err(stream.expected_err("identifier")?) Err(stream.expected_err("identifier")?)
} }
@ -894,11 +906,12 @@ impl Parse for DotIndexKind {
stream.expect(Token::Dot)?; stream.expect(Token::Dot)?;
if let Some(Token::Identifier(name)) = stream.next() { if let Some(Token::Identifier(name)) = stream.next() {
if let Ok(args) = stream.parse::<FunctionArgs>() { if let Ok(args) = stream.parse::<FunctionArgs>() {
Ok(Self::FunctionCall(FunctionCallExpression( Ok(Self::FunctionCall(FunctionCallExpression {
name, name,
args.0, params: args.0,
stream.get_range_prev().unwrap(), range: stream.get_range_prev().unwrap(),
))) is_macro: false,
}))
} else { } else {
Ok(Self::StructValueIndex(name)) Ok(Self::StructValueIndex(name))
} }

View File

@ -128,6 +128,7 @@ impl ast::Module {
imports, imports,
associated_functions, associated_functions,
functions, functions,
globals: Vec::new(),
path: self.path.clone(), path: self.path.clone(),
is_main: self.is_main, is_main: self.is_main,
tokens: self.tokens, tokens: self.tokens,
@ -340,10 +341,11 @@ impl ast::Expression {
mir::TypeKind::Vague(mir::VagueType::Unknown), mir::TypeKind::Vague(mir::VagueType::Unknown),
), ),
ast::ExpressionKind::FunctionCall(fn_call_expr) => mir::ExprKind::FunctionCall(mir::FunctionCall { ast::ExpressionKind::FunctionCall(fn_call_expr) => mir::ExprKind::FunctionCall(mir::FunctionCall {
name: fn_call_expr.0.clone(), name: fn_call_expr.name.clone(),
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown), return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
parameters: fn_call_expr.1.iter().map(|e| e.process(module_id)).collect(), parameters: fn_call_expr.params.iter().map(|e| e.process(module_id)).collect(),
meta: fn_call_expr.2.as_meta(module_id), meta: fn_call_expr.range.as_meta(module_id),
is_macro: fn_call_expr.is_macro,
}), }),
ast::ExpressionKind::BlockExpr(block) => mir::ExprKind::Block(block.into_mir(module_id)), ast::ExpressionKind::BlockExpr(block) => mir::ExprKind::Block(block.into_mir(module_id)),
ast::ExpressionKind::IfExpr(if_expression) => { ast::ExpressionKind::IfExpr(if_expression) => {
@ -427,14 +429,15 @@ impl ast::Expression {
ast::ExpressionKind::AssociatedFunctionCall(ty, fn_call_expr) => mir::ExprKind::AssociatedFunctionCall( ast::ExpressionKind::AssociatedFunctionCall(ty, fn_call_expr) => mir::ExprKind::AssociatedFunctionCall(
ty.0.into_mir(module_id), ty.0.into_mir(module_id),
mir::FunctionCall { mir::FunctionCall {
name: fn_call_expr.0.clone(), name: fn_call_expr.name.clone(),
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown), return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
parameters: fn_call_expr.1.iter().map(|e| e.process(module_id)).collect(), parameters: fn_call_expr.params.iter().map(|e| e.process(module_id)).collect(),
meta: fn_call_expr.2.as_meta(module_id), meta: fn_call_expr.range.as_meta(module_id),
is_macro: fn_call_expr.is_macro,
}, },
), ),
ast::ExpressionKind::AccessCall(expression, fn_call_expr) => { ast::ExpressionKind::AccessCall(expression, fn_call_expr) => {
let mut params: Vec<_> = fn_call_expr.1.iter().map(|e| e.process(module_id)).collect(); let mut params: Vec<_> = fn_call_expr.params.iter().map(|e| e.process(module_id)).collect();
params.insert( params.insert(
0, 0,
mir::Expression( mir::Expression(
@ -442,13 +445,18 @@ impl ast::Expression {
expression.1.as_meta(module_id), expression.1.as_meta(module_id),
), ),
); );
if fn_call_expr.is_macro {
panic!("Macros aren't supported as access-calls!");
};
mir::ExprKind::AssociatedFunctionCall( mir::ExprKind::AssociatedFunctionCall(
mir::TypeKind::Vague(mir::VagueType::Unknown), mir::TypeKind::Vague(mir::VagueType::Unknown),
mir::FunctionCall { mir::FunctionCall {
name: fn_call_expr.0.clone(), name: fn_call_expr.name.clone(),
return_type: mir::TypeKind::Vague(mir::VagueType::Unknown), return_type: mir::TypeKind::Vague(mir::VagueType::Unknown),
parameters: params, parameters: params,
meta: fn_call_expr.2.as_meta(module_id), meta: fn_call_expr.range.as_meta(module_id),
is_macro: fn_call_expr.is_macro,
}, },
) )
} }

View File

@ -195,6 +195,7 @@ impl mir::Expression {
mir::ExprKind::AssociatedFunctionCall(ty, fn_call) => { mir::ExprKind::AssociatedFunctionCall(ty, fn_call) => {
allocated.extend(fn_call.allocate(&format!("{}::{}", ty, fn_call.name), scope)) allocated.extend(fn_call.allocate(&format!("{}::{}", ty, fn_call.name), scope))
} }
mir::ExprKind::GlobalRef(..) => {}
} }
allocated allocated

View File

@ -1,4 +1,4 @@
use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValue, Instr, Type}; use reid_lib::{builder::InstructionValue, CmpPredicate, ConstValueKind, Instr, Type};
use crate::{ use crate::{
codegen::{ErrorKind, StackValueKind}, codegen::{ErrorKind, StackValueKind},
@ -58,6 +58,28 @@ pub fn form_intrinsics() -> Vec<FunctionDefinition> {
} }
pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDefinition> { pub fn get_intrinsic_assoc_func(ty: &TypeKind, name: &str) -> Option<FunctionDefinition> {
if let TypeKind::Array(_, len) = ty {
match name {
"length" => {
return Some(FunctionDefinition {
name: "length".to_owned(),
linkage_name: None,
is_pub: true,
is_imported: false,
return_type: TypeKind::U64,
parameters: vec![FunctionParam {
name: String::from("self"),
ty: TypeKind::Borrow(Box::new(ty.clone()), false),
meta: Default::default(),
}],
kind: FunctionDefinitionKind::Intrinsic(Box::new(IntrinsicConst(*len))),
source: None,
})
}
_ => {}
}
}
match name { match name {
"sizeof" => Some(FunctionDefinition { "sizeof" => Some(FunctionDefinition {
name: "sizeof".to_owned(), name: "sizeof".to_owned(),
@ -364,7 +386,7 @@ impl IntrinsicFunction for IntrinsicSizeOf {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
let instr = scope let instr = scope
.block .block
.build(Instr::Constant(reid_lib::ConstValue::U64(self.0.size_of() / 8))) .build(Instr::Constant(reid_lib::ConstValueKind::U64(self.0.size_of() / 8)))
.unwrap(); .unwrap();
Ok(StackValue(StackValueKind::Literal(instr), self.0.clone())) Ok(StackValue(StackValueKind::Literal(instr), self.0.clone()))
} }
@ -382,7 +404,7 @@ impl IntrinsicFunction for IntrinsicMalloc {
let sizeof = scope let sizeof = scope
.block .block
.build(Instr::Constant(ConstValue::U64(self.0.size_of() / 8))) .build(Instr::Constant(ConstValueKind::U64(self.0.size_of() / 8)))
.unwrap(); .unwrap();
let bytes = scope.block.build(Instr::Mul(sizeof, amount.instr())).unwrap(); let bytes = scope.block.build(Instr::Mul(sizeof, amount.instr())).unwrap();
let instr = scope.block.build(Instr::FunctionCall(function, vec![bytes])).unwrap(); let instr = scope.block.build(Instr::FunctionCall(function, vec![bytes])).unwrap();
@ -394,7 +416,7 @@ impl IntrinsicFunction for IntrinsicMalloc {
pub struct IntrinsicNullPtr(TypeKind); pub struct IntrinsicNullPtr(TypeKind);
impl IntrinsicFunction for IntrinsicNullPtr { impl IntrinsicFunction for IntrinsicNullPtr {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> { fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
let zero = scope.block.build(Instr::Constant(ConstValue::I8(0))).unwrap(); let zero = scope.block.build(Instr::Constant(ConstValueKind::I8(0))).unwrap();
let instr = scope let instr = scope
.block .block
.build(Instr::IntToPtr( .build(Instr::IntToPtr(
@ -408,6 +430,14 @@ impl IntrinsicFunction for IntrinsicNullPtr {
)) ))
} }
} }
#[derive(Clone, Debug)]
pub struct IntrinsicConst(u64);
impl IntrinsicFunction for IntrinsicConst {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, _: &[StackValue]) -> Result<StackValue, ErrorKind> {
let zero = scope.block.build(Instr::Constant(ConstValueKind::U64(self.0))).unwrap();
Ok(StackValue(StackValueKind::Literal(zero), TypeKind::U64))
}
}
// impl IntrinsicFunction for IntrinsicIAdd { // impl IntrinsicFunction for IntrinsicIAdd {
// fn codegen<'ctx, 'a>( // fn codegen<'ctx, 'a>(

View File

@ -3,13 +3,14 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc};
use allocator::{Allocator, AllocatorScope}; use allocator::{Allocator, AllocatorScope};
use intrinsics::*; use intrinsics::*;
use reid_lib::{ use reid_lib::{
builder::ConstantValue,
compile::CompiledModule, compile::CompiledModule,
debug_information::{ debug_information::{
DebugFileData, DebugLexicalScope, DebugLocalVariable, DebugLocation, DebugMetadata, DebugRecordKind, DebugFileData, DebugLexicalScope, DebugLocalVariable, DebugLocation, DebugMetadata, DebugRecordKind,
DebugSubprogramData, DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, DwarfFlags, DebugSubprogramData, DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, DwarfFlags,
InstructionDebugRecordData, InstructionDebugRecordData,
}, },
CmpPredicate, ConstValue, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module, NamedStruct, CmpPredicate, ConstValueKind, Context, CustomTypeKind, Function, FunctionFlags, Instr, Module, NamedStruct,
TerminatorKind as Term, Type, TerminatorKind as Term, Type,
}; };
use scope::*; use scope::*;
@ -96,6 +97,29 @@ impl Default for State {
} }
} }
impl mir::GlobalKind {
fn codegen<'ctx>(
&'ctx self,
context: &'ctx Context,
types: &HashMap<CustomTypeKey, reid_lib::builder::TypeValue>,
module: &Module,
) -> Result<(ConstantValue, TypeKind), ErrorKind> {
Ok(match self {
mir::GlobalKind::Literal(literal) => (module.add_constant(literal.as_const_kind()), literal.as_type()),
mir::GlobalKind::Array(globals) => {
let values = try_all(globals.into_iter().map(|g| g.codegen(context, types, module)).collect())
.map_err(|e| e.first().unwrap().clone())?;
let elem_ty = values.iter().map(|(_, t)| t.clone()).next().unwrap_or(TypeKind::Void);
let values = values.iter().map(|(v, _)| *v).collect::<Vec<_>>();
(
module.add_constant(ConstValueKind::Array(values, elem_ty.get_type(&types))),
TypeKind::Array(Box::new(elem_ty), globals.len() as u64),
)
}
})
}
}
impl mir::Module { impl mir::Module {
fn codegen<'ctx>( fn codegen<'ctx>(
&'ctx self, &'ctx self,
@ -177,6 +201,12 @@ impl mir::Module {
insert_debug!(&TypeKind::CustomType(type_key.clone())); insert_debug!(&TypeKind::CustomType(type_key.clone()));
} }
let mut globals = HashMap::new();
for global in &self.globals {
let (const_value, _) = global.kind.codegen(context, &type_values, &module)?;
globals.insert(global.name.clone(), module.add_global(&global.name, const_value));
}
let mut functions = HashMap::new(); let mut functions = HashMap::new();
for function in &self.functions { for function in &self.functions {
@ -254,18 +284,19 @@ impl mir::Module {
.collect(); .collect();
let is_main = self.is_main && function.name == "main"; let is_main = self.is_main && function.name == "main";
let module_name = if let Some(module) = function.source { let module_prefix = if let Some(module) = function.source {
if module == self.module_id { if module == self.module_id {
format!("reid.{}", self.name) format!("reid.{}.", self.name)
} else { } else {
format!("reid.{}", modules.get(&module).unwrap().name) format!("reid.{}.", modules.get(&module).unwrap().name)
} }
} else { } else {
format!("reid.intrinsic") format!("reid.intrinsic.")
}; };
let full_name = format!("{}{}::{}", module_prefix, ty, function.name);
let func = match &function.kind { let func = match &function.kind {
mir::FunctionDefinitionKind::Local(_, _) => Some(module.function( mir::FunctionDefinitionKind::Local(_, _) => Some(module.function(
&format!("{}.{}.{}", module_name, ty, function.name), &full_name,
None, None,
function.return_type.get_type(&type_values), function.return_type.get_type(&type_values),
param_types, param_types,
@ -277,7 +308,7 @@ impl mir::Module {
}, },
)), )),
mir::FunctionDefinitionKind::Extern(imported) => Some(module.function( mir::FunctionDefinitionKind::Extern(imported) => Some(module.function(
&function.linkage_name.clone().unwrap_or(function.name.clone()), &full_name,
None, None,
function.return_type.get_type(&type_values), function.return_type.get_type(&type_values),
param_types, param_types,
@ -349,6 +380,7 @@ impl mir::Module {
functions: &functions, functions: &functions,
types: &types, types: &types,
type_values: &type_values, type_values: &type_values,
globals: &globals,
stack_values: HashMap::new(), stack_values: HashMap::new(),
debug: Some(Debug { debug: Some(Debug {
info: &debug, info: &debug,
@ -431,6 +463,7 @@ impl mir::Module {
scope: compile_unit.clone(), scope: compile_unit.clone(),
types: &debug_types, types: &debug_types,
}), }),
globals: &globals,
binops: &binops, binops: &binops,
allocator: Rc::new(RefCell::new(allocator)), allocator: Rc::new(RefCell::new(allocator)),
}; };
@ -491,6 +524,7 @@ impl mir::Module {
scope: compile_unit.clone(), scope: compile_unit.clone(),
types: &debug_types, types: &debug_types,
}), }),
globals: &globals,
binops: &binops, binops: &binops,
allocator: Rc::new(RefCell::new(allocator)), allocator: Rc::new(RefCell::new(allocator)),
}; };
@ -694,6 +728,7 @@ impl mir::Statement {
mir::StmtKind::Let(NamedVariableRef(ty, name, meta), mutable, expression) => { mir::StmtKind::Let(NamedVariableRef(ty, name, meta), mutable, expression) => {
let value = expression.codegen(scope, &state)?.unwrap(); let value = expression.codegen(scope, &state)?.unwrap();
dbg!(&scope.allocator, &meta, &value.1);
let alloca = scope let alloca = scope
.allocate(meta, &value.1) .allocate(meta, &value.1)
.unwrap() .unwrap()
@ -783,7 +818,7 @@ impl mir::Statement {
let condition_res = condition.codegen(&mut condition_scope, state)?.unwrap(); let condition_res = condition.codegen(&mut condition_scope, state)?.unwrap();
let true_instr = condition_scope let true_instr = condition_scope
.block .block
.build(Instr::Constant(ConstValue::Bool(true))) .build(Instr::Constant(ConstValueKind::Bool(true)))
.unwrap(); .unwrap();
let check = condition_scope let check = condition_scope
.block .block
@ -1030,7 +1065,7 @@ impl mir::Expression {
let first = scope let first = scope
.block .block
.build_named("array.zero", Instr::Constant(ConstValue::U32(0))) .build_named("array.zero", Instr::Constant(ConstValueKind::U32(0)))
.unwrap(); .unwrap();
( (
scope scope
@ -1097,11 +1132,11 @@ impl mir::Expression {
let index_expr = scope let index_expr = scope
.block .block
.build_named(index.to_string(), Instr::Constant(ConstValue::U32(index as u32))) .build_named(index.to_string(), Instr::Constant(ConstValueKind::U32(index as u32)))
.unwrap(); .unwrap();
let first = scope let first = scope
.block .block
.build_named("zero", Instr::Constant(ConstValue::U32(0))) .build_named("zero", Instr::Constant(ConstValueKind::U32(0)))
.unwrap(); .unwrap();
let ptr = scope let ptr = scope
.block .block
@ -1278,7 +1313,7 @@ impl mir::Expression {
Some(val) Some(val)
} else { } else {
match (&val.1, type_kind) { match (&val.1, type_kind) {
(TypeKind::CodegenPtr(inner), TypeKind::UserPtr(_)) => match *inner.clone() { (TypeKind::CodegenPtr(inner), TypeKind::UserPtr(ty2)) => match *inner.clone() {
TypeKind::UserPtr(_) => Some(StackValue( TypeKind::UserPtr(_) => Some(StackValue(
val.0.derive( val.0.derive(
scope scope
@ -1291,6 +1326,27 @@ impl mir::Expression {
), ),
TypeKind::CodegenPtr(Box::new(type_kind.clone())), TypeKind::CodegenPtr(Box::new(type_kind.clone())),
)), )),
TypeKind::Borrow(ty1, _) => match *ty1.clone() {
TypeKind::Array(ty1, _) => {
if ty1 == *ty2 {
Some(StackValue(
val.0.derive(
scope
.block
.build(Instr::BitCast(
val.instr(),
Type::Ptr(Box::new(type_kind.get_type(scope.type_values))),
))
.unwrap(),
),
TypeKind::CodegenPtr(Box::new(type_kind.clone())),
))
} else {
return Err(ErrorKind::Null);
}
}
_ => return Err(ErrorKind::Null),
},
_ => panic!(), _ => panic!(),
}, },
(TypeKind::UserPtr(_), TypeKind::UserPtr(_)) (TypeKind::UserPtr(_), TypeKind::UserPtr(_))
@ -1321,6 +1377,14 @@ impl mir::Expression {
} }
} }
mir::ExprKind::AssociatedFunctionCall(ty, call) => codegen_function_call(Some(ty), call, scope, state)?, mir::ExprKind::AssociatedFunctionCall(ty, call) => codegen_function_call(Some(ty), call, scope, state)?,
mir::ExprKind::GlobalRef(global_name, ty) => {
let global_value = scope.globals.get(global_name).unwrap();
let a = Some(StackValue(
StackValueKind::Literal(scope.block.build(Instr::GetGlobal(global_value.clone())).unwrap()),
ty.clone(),
));
a
}
}; };
if let Some(value) = &value { if let Some(value) = &value {
value.instr().maybe_location(&mut scope.block, location.clone()); value.instr().maybe_location(&mut scope.block, location.clone());

View File

@ -1,7 +1,7 @@
use std::{cell::RefCell, collections::HashMap, mem, rc::Rc}; use std::{cell::RefCell, collections::HashMap, mem, rc::Rc};
use reid_lib::{ use reid_lib::{
builder::{InstructionValue, TypeValue}, builder::{GlobalValue, InstructionValue, TypeValue},
debug_information::{DebugInformation, DebugLocation, DebugScopeValue, DebugTypeValue}, debug_information::{DebugInformation, DebugLocation, DebugScopeValue, DebugTypeValue},
Block, Context, Function, Instr, Module, Block, Context, Function, Instr, Module,
}; };
@ -30,6 +30,7 @@ pub struct Scope<'ctx, 'scope> {
pub(super) functions: &'scope HashMap<String, 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) globals: &'scope HashMap<String, GlobalValue>,
pub(super) debug: Option<Debug<'ctx>>, pub(super) debug: Option<Debug<'ctx>>,
pub(super) allocator: Rc<RefCell<Allocator>>, pub(super) allocator: Rc<RefCell<Allocator>>,
} }
@ -51,6 +52,7 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
stack_values: self.stack_values.clone(), stack_values: self.stack_values.clone(),
debug: self.debug.clone(), debug: self.debug.clone(),
allocator: self.allocator.clone(), allocator: self.allocator.clone(),
globals: self.globals,
binops: self.binops, binops: self.binops,
} }
} }

View File

@ -6,7 +6,7 @@ use reid_lib::{
DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocation, DebugPointerType, DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocation, DebugPointerType,
DebugPosition, DebugScopeValue, DebugStructType, DebugTypeData, DebugTypeValue, DwarfEncoding, DwarfFlags, DebugPosition, DebugScopeValue, DebugStructType, DebugTypeData, DebugTypeValue, DwarfEncoding, DwarfFlags,
}, },
Block, CmpPredicate, ConstValue, Instr, Type, Block, CmpPredicate, ConstValueKind, Instr, Type,
}; };
use crate::{ use crate::{
@ -34,34 +34,36 @@ impl mir::CmpOperator {
impl mir::Literal { impl mir::Literal {
pub(super) fn as_const(&self, block: &mut Block) -> InstructionValue { pub(super) fn as_const(&self, block: &mut Block) -> InstructionValue {
block.build_named(format!("{}", self), self.as_const_kind()).unwrap() block
.build_named(format!("{}", self), Instr::Constant(self.as_const_kind()))
.unwrap()
} }
pub(super) fn as_const_kind(&self) -> Instr { pub(super) fn as_const_kind(&self) -> ConstValueKind {
Instr::Constant(match self.clone() { match self.clone() {
mir::Literal::I8(val) => ConstValue::I8(val), mir::Literal::I8(val) => ConstValueKind::I8(val),
mir::Literal::I16(val) => ConstValue::I16(val), mir::Literal::I16(val) => ConstValueKind::I16(val),
mir::Literal::I32(val) => ConstValue::I32(val), mir::Literal::I32(val) => ConstValueKind::I32(val),
mir::Literal::I64(val) => ConstValue::I64(val), mir::Literal::I64(val) => ConstValueKind::I64(val),
mir::Literal::I128(val) => ConstValue::I128(val), mir::Literal::I128(val) => ConstValueKind::I128(val),
mir::Literal::U8(val) => ConstValue::U8(val), mir::Literal::U8(val) => ConstValueKind::U8(val),
mir::Literal::U16(val) => ConstValue::U16(val), mir::Literal::U16(val) => ConstValueKind::U16(val),
mir::Literal::U32(val) => ConstValue::U32(val), mir::Literal::U32(val) => ConstValueKind::U32(val),
mir::Literal::U64(val) => ConstValue::U64(val), mir::Literal::U64(val) => ConstValueKind::U64(val),
mir::Literal::U128(val) => ConstValue::U128(val), mir::Literal::U128(val) => ConstValueKind::U128(val),
mir::Literal::Bool(val) => ConstValue::Bool(val), mir::Literal::Bool(val) => ConstValueKind::Bool(val),
mir::Literal::String(val) => ConstValue::Str(val.clone()), mir::Literal::String(val) => ConstValueKind::Str(val.clone()),
mir::Literal::Vague(VagueLiteral::Number(val)) => ConstValue::I32(val as i32), mir::Literal::Vague(VagueLiteral::Number(val)) => ConstValueKind::I32(val as i32),
mir::Literal::Vague(VagueLiteral::Decimal(val)) => ConstValue::F32(val as f32), mir::Literal::Vague(VagueLiteral::Decimal(val)) => ConstValueKind::F32(val as f32),
mir::Literal::F16(val) => ConstValue::F16(val), mir::Literal::F16(val) => ConstValueKind::F16(val),
mir::Literal::F32B(val) => ConstValue::F32B(val), mir::Literal::F32B(val) => ConstValueKind::F32B(val),
mir::Literal::F32(val) => ConstValue::F32(val), mir::Literal::F32(val) => ConstValueKind::F32(val),
mir::Literal::F64(val) => ConstValue::F64(val), mir::Literal::F64(val) => ConstValueKind::F64(val),
mir::Literal::F80(val) => ConstValue::F80(val), mir::Literal::F80(val) => ConstValueKind::F80(val),
mir::Literal::F128(val) => ConstValue::F128(val), mir::Literal::F128(val) => ConstValueKind::F128(val),
mir::Literal::F128PPC(val) => ConstValue::F128PPC(val), mir::Literal::F128PPC(val) => ConstValueKind::F128PPC(val),
mir::Literal::Char(c) => ConstValue::U8(c as u8), mir::Literal::Char(c) => ConstValueKind::U8(c as u8),
}) }
} }
} }

View File

@ -7,7 +7,7 @@ use crate::{
ast::token_stream::{self, TokenRange}, ast::token_stream::{self, TokenRange},
codegen, codegen,
lexer::{self, Cursor, FullToken, Position}, lexer::{self, Cursor, FullToken, Position},
mir::{self, pass, typecheck, Metadata, SourceModuleId}, mir::{self, macros, pass, typecheck, Metadata, SourceModuleId},
}; };
use crate::mir::typecheck::ErrorKind as TypecheckError; use crate::mir::typecheck::ErrorKind as TypecheckError;
@ -33,6 +33,8 @@ pub enum ErrorKind {
TypeInferenceError(#[source] mir::pass::Error<TypecheckError>), TypeInferenceError(#[source] mir::pass::Error<TypecheckError>),
#[error("{}{}", label("(Linker) "), .0.kind)] #[error("{}{}", label("(Linker) "), .0.kind)]
LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>), LinkerError(#[from] mir::pass::Error<mir::linker::ErrorKind>),
#[error("{}{}", label("(Macro) "), .0)]
MacroError(#[from] mir::pass::Error<macros::ErrorKind>),
#[error("{}{}", label("(Codegen) "), .0)] #[error("{}{}", label("(Codegen) "), .0)]
CodegenError(#[from] codegen::ErrorKind), CodegenError(#[from] codegen::ErrorKind),
} }
@ -58,6 +60,7 @@ impl ErrorKind {
ErrorKind::CodegenError(error) => match error { ErrorKind::CodegenError(error) => match error {
codegen::ErrorKind::Null => Default::default(), codegen::ErrorKind::Null => Default::default(),
}, },
ErrorKind::MacroError(error) => error.metadata,
} }
} }
} }
@ -79,7 +82,7 @@ pub struct ErrorModule {
#[derive(Debug, Clone, PartialEq, Eq, Default)] #[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ErrorModules { pub struct ErrorModules {
module_map: HashMap<mir::SourceModuleId, ErrorModule>, pub(super) module_map: HashMap<mir::SourceModuleId, ErrorModule>,
module_counter: mir::SourceModuleId, module_counter: mir::SourceModuleId,
} }

View File

@ -41,7 +41,7 @@
//! - Debug Symbols //! - Debug Symbols
//! ``` //! ```
use std::{path::PathBuf, thread, time::Duration}; use std::{collections::HashMap, path::PathBuf, thread, time::Duration};
use ast::{ use ast::{
lexer::{self, FullToken, Token}, lexer::{self, FullToken, Token},
@ -56,7 +56,10 @@ use mir::{
}; };
use reid_lib::{compile::CompileOutput, Context}; use reid_lib::{compile::CompileOutput, Context};
use crate::ast::TopLevelStatement; use crate::{
ast::TopLevelStatement,
mir::macros::{form_macros, MacroModule, MacroPass},
};
mod ast; mod ast;
mod codegen; mod codegen;
@ -133,6 +136,12 @@ pub fn perform_all_passes<'map>(
is_lib: true, is_lib: true,
})?; })?;
for module in &mut context.modules {
for intrinsic in form_intrinsics() {
module.1.functions.insert(0, intrinsic);
}
}
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
println!("{:-^100}", "LINKER OUTPUT"); println!("{:-^100}", "LINKER OUTPUT");
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -140,6 +149,38 @@ pub fn perform_all_passes<'map>(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
dbg!(&state); dbg!(&state);
if !state.errors.is_empty() {
return Err(ReidError::from_kind(
state.errors.iter().map(|e| e.clone().into()).collect(),
module_map.clone(),
));
}
let mut macro_modules: HashMap<_, MacroModule> = HashMap::new();
for (k, v) in &context.modules {
macro_modules.insert(k.clone(), v.into());
}
let mut macro_pass = MacroPass {
macros: form_macros(),
module_map: macro_modules,
};
let state = context.pass(&mut macro_pass)?;
#[cfg(debug_assertions)]
println!("{:-^100}", "MACRO OUTPUT");
#[cfg(debug_assertions)]
println!("{:#}", &context);
#[cfg(debug_assertions)]
dbg!(&state);
if !state.errors.is_empty() {
return Err(ReidError::from_kind(
state.errors.iter().map(|e| e.clone().into()).collect(),
module_map.clone(),
));
}
let mut binops = BinopMap::default(); let mut binops = BinopMap::default();
for module in &mut context.modules { for module in &mut context.modules {
for intrinsic in form_intrinsic_binops() { for intrinsic in form_intrinsic_binops() {
@ -160,19 +201,6 @@ pub fn perform_all_passes<'map>(
} }
} }
for module in &mut context.modules {
for intrinsic in form_intrinsics() {
module.1.functions.insert(0, intrinsic);
}
}
if !state.errors.is_empty() {
return Err(ReidError::from_kind(
state.errors.iter().map(|e| e.clone().into()).collect(),
module_map.clone(),
));
}
let mut refs = TypeRefs::with_binops(binops); let mut refs = TypeRefs::with_binops(binops);
let state = context.pass(&mut TypeInference { refs: &mut refs })?; let state = context.pass(&mut TypeInference { refs: &mut refs })?;

View File

@ -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 global in &self.globals {
writeln!(inner_f, "global {} = {}", global.name, global.kind)?;
}
for (ty, fun) in &self.associated_functions { for (ty, fun) in &self.associated_functions {
writeln!(inner_f, "(Assoc {}) {}", ty, fun)?; writeln!(inner_f, "(Assoc {}) {}", ty, fun)?;
} }
@ -59,6 +62,26 @@ impl Display for Module {
} }
} }
impl Display for GlobalKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
GlobalKind::Literal(literal) => Display::fmt(literal, f),
GlobalKind::Array(global_kinds) => {
f.write_char('[')?;
let mut iter = global_kinds.iter();
if let Some(global) = iter.next() {
Display::fmt(global, f)?;
while let Some(global) = iter.next() {
write!(f, ", ")?;
Display::fmt(global, f)?;
}
}
f.write_char(']')
}
}
}
}
impl Display for Import { impl Display for Import {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "import {}", self.0.join("::")) write!(f, "import {}", self.0.join("::"))
@ -280,6 +303,7 @@ impl Display for ExprKind {
write!(f, "::")?; write!(f, "::")?;
Display::fmt(function_call, f) Display::fmt(function_call, f)
} }
ExprKind::GlobalRef(global_value, type_kind) => write!(f, "global<{}>(${})", type_kind, global_value),
} }
} }
} }

View File

@ -429,6 +429,7 @@ impl Expression {
Err(_) => Ok((ReturnKind::Soft, type_kind.clone())), Err(_) => Ok((ReturnKind::Soft, type_kind.clone())),
}, },
AssociatedFunctionCall(_, fcall) => fcall.return_type(), AssociatedFunctionCall(_, fcall) => fcall.return_type(),
GlobalRef(_, type_kind) => Ok((ReturnKind::Soft, type_kind.clone())),
} }
} }
@ -448,6 +449,7 @@ impl Expression {
ExprKind::If(_) => None, ExprKind::If(_) => None,
ExprKind::CastTo(expression, _) => expression.backing_var(), ExprKind::CastTo(expression, _) => expression.backing_var(),
ExprKind::AssociatedFunctionCall(..) => None, ExprKind::AssociatedFunctionCall(..) => None,
ExprKind::GlobalRef(..) => None,
} }
} }
@ -493,6 +495,7 @@ impl Expression {
ExprKind::Deref(_) => None, ExprKind::Deref(_) => None,
ExprKind::CastTo(expression, _) => expression.num_value()?, ExprKind::CastTo(expression, _) => expression.num_value()?,
ExprKind::AssociatedFunctionCall(..) => None, ExprKind::AssociatedFunctionCall(..) => None,
ExprKind::GlobalRef(..) => None,
}) })
} }
} }

View File

@ -321,7 +321,7 @@ impl<'map> Pass for LinkerPass<'map> {
ty.clone(), ty.clone(),
FunctionDefinition { FunctionDefinition {
name: func_name.clone(), name: func_name.clone(),
linkage_name: Some(format!("{}.{}", ty, func_name)), linkage_name: Some(format!("{}::{}", ty, func_name)),
is_pub: false, is_pub: false,
is_imported: false, is_imported: false,
return_type, return_type,

273
reid/src/mir/macros.rs Normal file
View File

@ -0,0 +1,273 @@
use std::{collections::HashMap, path::PathBuf};
use crate::mir::{
self, FunctionCall, GlobalKind, GlobalValue, IfExpression, Literal, Module, SourceModuleId, TypeKind,
WhileStatement,
};
use super::pass::{Pass, PassResult, PassState};
pub trait MacroFunction: std::fmt::Debug {
fn generate<'ctx, 'a>(
&self,
module: &MacroModule,
params: &[mir::Literal],
prefix: String,
) -> Result<(Vec<GlobalValue>, mir::ExprKind), ErrorKind>;
}
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum ErrorKind {
#[error("Should never be encountered!")]
Null,
#[error("No such macro {0} defined")]
NoSuchMacro(String),
#[error("Macro arguments may only be literals")]
InvalidMacroArgs,
#[error("Got {0} parameters, expected {1}")]
InvalidAmountOfParams(u32, u32),
#[error("Expected argument type of {0}, got {1}")]
InvalidArgumentType(TypeKind, TypeKind),
#[error("Error executing macro: {0}")]
MacroExecutionError(String),
}
type MacroModuleMap = HashMap<SourceModuleId, MacroModule>;
/// Struct used to implement a type-checking pass that can be performed on the
/// MIR.
pub struct MacroPass {
pub(crate) macros: HashMap<String, Box<dyn MacroFunction>>,
pub module_map: MacroModuleMap,
}
pub struct MacroModule {
path: Option<PathBuf>,
}
impl From<&Module> for MacroModule {
fn from(value: &Module) -> Self {
MacroModule {
path: value.path.clone(),
}
}
}
type MacroPassState<'map, 'st, 'sc> = PassState<'st, 'sc, (), ErrorKind>;
impl Pass for MacroPass {
type Data = ();
type TError = ErrorKind;
fn context(&mut self, _context: &mut mir::Context, mut _state: PassState<Self::Data, Self::TError>) -> PassResult {
Ok(())
}
fn module(&mut self, module: &mut mir::Module, mut state: PassState<Self::Data, Self::TError>) -> PassResult {
for function in &mut module.functions {
let globals = match &mut function.kind {
mir::FunctionDefinitionKind::Local(block, _) => block.gen_macros(self, &mut state, &self.module_map),
_ => Vec::new(),
};
module.globals.extend(globals);
}
Ok(())
}
}
impl mir::Block {
fn gen_macros(&mut self, data: &MacroPass, state: &mut MacroPassState, map: &MacroModuleMap) -> Vec<GlobalValue> {
let mut globals = Vec::new();
for statement in &mut self.statements {
globals.extend(statement.gen_macros(data, state, map));
}
if let Some((_, Some(return_expr))) = &mut self.return_expression {
globals.extend(return_expr.gen_macros(data, state, map));
}
globals
}
}
impl mir::Statement {
fn gen_macros(&mut self, data: &MacroPass, state: &mut MacroPassState, map: &MacroModuleMap) -> Vec<GlobalValue> {
let mut globals = Vec::new();
match &mut self.0 {
mir::StmtKind::Let(.., expr) => {
globals.extend(expr.gen_macros(data, state, map));
}
mir::StmtKind::Set(lhs, rhs) => {
globals.extend(lhs.gen_macros(data, state, map));
globals.extend(rhs.gen_macros(data, state, map));
}
mir::StmtKind::Import(_) => {}
mir::StmtKind::Expression(expr) => {
globals.extend(expr.gen_macros(data, state, map));
}
mir::StmtKind::While(WhileStatement { condition, block, .. }) => {
globals.extend(condition.gen_macros(data, state, map));
globals.extend(block.gen_macros(data, state, map));
}
};
globals
}
}
impl mir::Expression {
fn gen_macros(&mut self, data: &MacroPass, state: &mut MacroPassState, map: &MacroModuleMap) -> Vec<GlobalValue> {
let mut globals = Vec::new();
match &mut self.0 {
mir::ExprKind::FunctionCall(function_call) => {
if function_call.is_macro {
if let Some(existing_macro) = data.macros.get(&function_call.name) {
let mut literals = Vec::new();
for param in &function_call.parameters {
match &param.0 {
super::ExprKind::Literal(literal) => literals.push(literal.clone()),
_ => state.note_errors(&vec![ErrorKind::InvalidMacroArgs], param.1),
}
}
let (generated_globals, expr) = state.or_else(
existing_macro
.generate(
map.get(&state.scope.module_id.unwrap()).unwrap(),
&literals,
format!(
"macro.{}.{}.{}",
function_call.name, self.1.range.start, self.1.range.end
),
)
.map(|(globals, kind)| (globals, mir::Expression(kind, self.1))),
(Vec::new(), self.clone()),
self.1,
);
globals.extend(generated_globals);
*self = expr;
} else {
state.note_errors(
&vec![ErrorKind::NoSuchMacro(function_call.name.clone())],
function_call.meta,
);
}
}
}
mir::ExprKind::Variable(_) => {}
mir::ExprKind::Indexed(expression, _, expression1) => {
globals.extend(expression.gen_macros(data, state, map));
globals.extend(expression1.gen_macros(data, state, map));
}
mir::ExprKind::Accessed(expression, ..) => {
globals.extend(expression.gen_macros(data, state, map));
}
mir::ExprKind::Array(expressions) => {
for expression in expressions {
globals.extend(expression.gen_macros(data, state, map));
}
}
mir::ExprKind::Struct(_, items) => {
for item in items {
globals.extend(item.1.gen_macros(data, state, map));
}
}
mir::ExprKind::Literal(_) => {}
mir::ExprKind::BinOp(_, expression, expression1, _) => {
globals.extend(expression.gen_macros(data, state, map));
globals.extend(expression1.gen_macros(data, state, map));
}
mir::ExprKind::AssociatedFunctionCall(
_,
FunctionCall {
parameters, is_macro, ..
},
) => {
for expression in parameters {
globals.extend(expression.gen_macros(data, state, map));
}
}
mir::ExprKind::If(IfExpression(cond, lhs, rhs)) => {
globals.extend(cond.gen_macros(data, state, map));
globals.extend(lhs.gen_macros(data, state, map));
if let Some(rhs) = rhs.as_mut() {
globals.extend(rhs.gen_macros(data, state, map));
}
}
mir::ExprKind::Block(block) => {
globals.extend(block.gen_macros(data, state, map));
}
mir::ExprKind::Borrow(expression, _) => {
globals.extend(expression.gen_macros(data, state, map));
}
mir::ExprKind::Deref(expression) => {
globals.extend(expression.gen_macros(data, state, map));
}
mir::ExprKind::CastTo(expression, _) => {
globals.extend(expression.gen_macros(data, state, map));
}
mir::ExprKind::GlobalRef(..) => {}
}
globals
}
}
pub fn form_macros() -> HashMap<String, Box<dyn MacroFunction>> {
let mut macros: HashMap<String, Box<dyn MacroFunction>> = HashMap::new();
macros.insert("include_bytes".to_owned(), Box::new(IncludeBytes));
macros
}
#[derive(Debug)]
pub struct IncludeBytes;
impl MacroFunction for IncludeBytes {
fn generate<'ctx, 'a>(
&self,
module: &MacroModule,
literals: &[mir::Literal],
global_name: String,
) -> Result<(Vec<GlobalValue>, mir::ExprKind), ErrorKind> {
if literals.len() != 1 {
return Err(ErrorKind::InvalidAmountOfParams(literals.len() as u32, 1));
}
let literal = literals.get(0).unwrap();
let Literal::String(path) = literal else {
return Err(ErrorKind::InvalidArgumentType(
literal.as_type(),
TypeKind::UserPtr(Box::new(TypeKind::Char)),
));
};
let path = module
.path
.as_ref()
.expect("Module has no path!")
.parent()
.expect("Module path has no parent!")
.join(path);
let contents = match std::fs::read(path) {
Ok(content) => content,
Err(e) => return Err(ErrorKind::MacroExecutionError(format!("{}", e))),
};
let literals = contents
.iter()
.map(|c| GlobalKind::Literal(Literal::U8(*c)))
.collect::<Vec<_>>();
let len = literals.len();
let global = GlobalValue {
name: global_name.clone(),
kind: GlobalKind::Array(literals),
};
Ok((
vec![global.clone()],
mir::ExprKind::GlobalRef(
global_name,
TypeKind::Borrow(Box::new(TypeKind::Array(Box::new(TypeKind::U8), len as u64)), false),
),
))
}
}

View File

@ -13,6 +13,7 @@ use crate::{
mod fmt; mod fmt;
pub mod implement; pub mod implement;
pub mod linker; pub mod linker;
pub mod macros;
pub mod pass; pub mod pass;
pub mod typecheck; pub mod typecheck;
@ -270,6 +271,7 @@ pub enum ExprKind {
Borrow(Box<Expression>, bool), Borrow(Box<Expression>, bool),
Deref(Box<Expression>), Deref(Box<Expression>),
CastTo(Box<Expression>, TypeKind), CastTo(Box<Expression>, TypeKind),
GlobalRef(String, TypeKind),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -284,6 +286,7 @@ pub struct FunctionCall {
pub name: String, pub name: String,
pub return_type: TypeKind, pub return_type: TypeKind,
pub parameters: Vec<Expression>, pub parameters: Vec<Expression>,
pub is_macro: bool,
pub meta: Metadata, pub meta: Metadata,
} }
@ -419,11 +422,24 @@ pub struct Module {
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>,
pub globals: Vec<GlobalValue>,
pub path: Option<PathBuf>, pub path: Option<PathBuf>,
pub tokens: Vec<FullToken>, pub tokens: Vec<FullToken>,
pub is_main: bool, pub is_main: bool,
} }
#[derive(Debug, Clone)]
pub struct GlobalValue {
pub name: String,
pub kind: GlobalKind,
}
#[derive(Debug, Clone)]
pub enum GlobalKind {
Literal(Literal),
Array(Vec<GlobalKind>),
}
pub type ModuleMap = HashMap<SourceModuleId, Module>; pub type ModuleMap = HashMap<SourceModuleId, Module>;
#[derive(Debug)] #[derive(Debug)]

View File

@ -503,6 +503,10 @@ impl Block {
statement.pass(pass, state, &mut scope, mod_id)?; statement.pass(pass, state, &mut scope, mod_id)?;
} }
if let Some((_, Some(return_expr))) = &mut self.return_expression {
return_expr.pass(pass, state, &mut scope, mod_id)?;
}
pass.block(self, PassState::from(state, &mut scope, Some(mod_id))) pass.block(self, PassState::from(state, &mut scope, Some(mod_id)))
} }
} }
@ -611,6 +615,7 @@ impl Expression {
ExprKind::Borrow(expression, _) => expression.pass(pass, state, scope, mod_id)?, ExprKind::Borrow(expression, _) => expression.pass(pass, state, scope, mod_id)?,
ExprKind::Deref(expression) => expression.pass(pass, state, scope, mod_id)?, ExprKind::Deref(expression) => expression.pass(pass, state, scope, mod_id)?,
ExprKind::CastTo(expression, _) => expression.pass(pass, state, scope, mod_id)?, ExprKind::CastTo(expression, _) => expression.pass(pass, state, scope, mod_id)?,
ExprKind::GlobalRef(..) => {}
} }
Ok(()) Ok(())
} }

View File

@ -88,6 +88,8 @@ pub enum ErrorKind {
InvalidBinop(BinaryOperator, TypeKind, TypeKind), InvalidBinop(BinaryOperator, TypeKind, TypeKind),
#[error("Could not infer type for {0:?}. Try adding type annotations.")] #[error("Could not infer type for {0:?}. Try adding type annotations.")]
CouldNotInferType(String), CouldNotInferType(String),
#[error("Arguments for a macro-function may only contain literals")]
MacroMustBeLiterals,
} }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@ -254,6 +256,16 @@ impl TypeKind {
let other_cat = other.category(); let other_cat = other.category();
match (self, other) { match (self, other) {
(TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Ok(other.clone()), (TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Ok(other.clone()),
(TypeKind::Borrow(ty1, _), TypeKind::UserPtr(ty2)) => match *ty1.clone() {
TypeKind::Array(ty1, _) => {
if ty1 == *ty2 {
Ok(other.clone())
} else {
Err(ErrorKind::NotCastableTo(self.clone(), other.clone()))
}
}
_ => Err(ErrorKind::NotCastableTo(self.clone(), other.clone())),
},
(TypeKind::Char, TypeKind::U8) => Ok(other.clone()), (TypeKind::Char, TypeKind::U8) => Ok(other.clone()),
(TypeKind::U8, TypeKind::Char) => Ok(other.clone()), (TypeKind::U8, TypeKind::Char) => Ok(other.clone()),
_ => match (&self_cat, &other_cat) { _ => match (&self_cat, &other_cat) {

View File

@ -193,7 +193,7 @@ impl FunctionDefinitionKind {
block.typecheck(&mut state.inner(), &typerefs, hint.into()) block.typecheck(&mut state.inner(), &typerefs, hint.into())
} }
FunctionDefinitionKind::Extern(_) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))), FunctionDefinitionKind::Extern(_) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))),
FunctionDefinitionKind::Intrinsic(..) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))), FunctionDefinitionKind::Intrinsic(intrinsic) => Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown))),
} }
} }
} }
@ -767,6 +767,10 @@ impl Expression {
Ok(function_call.return_type.clone().resolve_ref(typerefs)) Ok(function_call.return_type.clone().resolve_ref(typerefs))
} }
} }
ExprKind::GlobalRef(global_value, type_kind) => Ok(self
.return_type(typerefs, state.scope.module_id.unwrap())
.map(|r| r.1)
.unwrap()),
} }
} }
} }

View File

@ -660,6 +660,10 @@ impl Expression {
// Provide function return type // Provide function return type
Ok(type_refs.from_type(&fn_call.ret).unwrap()) Ok(type_refs.from_type(&fn_call.ret).unwrap())
} }
ExprKind::GlobalRef(global_value, type_kind) => Ok(self
.return_type(type_refs.types, state.scope.module_id.unwrap())
.map(|r| type_refs.from_type(&r.1).unwrap())
.unwrap()),
} }
} }

View File

@ -149,6 +149,6 @@ fn associated_functions() {
test( test(
include_str!("../../examples/associated_functions.reid"), include_str!("../../examples/associated_functions.reid"),
"test", "test",
Some(32), Some(4),
); );
} }