Compare commits
7 Commits
1224c612c7
...
bbdfae081d
Author | SHA1 | Date | |
---|---|---|---|
bbdfae081d | |||
3d73c52cb4 | |||
81ce1dfc2e | |||
78a1e9f06b | |||
f35f1ef701 | |||
fa6b7bdf87 | |||
e9bca63f0d |
@ -478,7 +478,7 @@ impl Builder {
|
||||
Instr::SIToFP(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||
Instr::PtrToInt(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||
Instr::IntToPtr(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||
Instr::BitCast(instr, ty) => instr.cast_to(self, &ty).map(|_| ()),
|
||||
Instr::BitCast(..) => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -628,7 +628,7 @@ impl InstructionValue {
|
||||
SIToFP(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||
PtrToInt(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||
IntToPtr(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||
BitCast(instr, ty) => instr.cast_to(builder, ty).map(|_| ty.clone()),
|
||||
BitCast(_, ty) => Ok(ty.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -376,8 +376,8 @@ impl DebugLocationHolder {
|
||||
unsafe {
|
||||
LLVMDIBuilderCreateDebugLocation(
|
||||
context.context_ref,
|
||||
self.location.line,
|
||||
self.location.column,
|
||||
self.location.pos.line,
|
||||
self.location.pos.column,
|
||||
*debug.programs.get(&self.program).unwrap(),
|
||||
null_mut(),
|
||||
)
|
||||
@ -399,8 +399,8 @@ impl DebugScopeHolder {
|
||||
di_builder,
|
||||
parent,
|
||||
file,
|
||||
location.line,
|
||||
location.column,
|
||||
location.pos.line,
|
||||
location.pos.column,
|
||||
)
|
||||
} else {
|
||||
LLVMDIBuilderCreateLexicalBlockFile(di_builder, parent, file, 0)
|
||||
@ -421,23 +421,23 @@ impl DebugMetadataHolder {
|
||||
match &self.data {
|
||||
DebugMetadata::ParamVar(param) => LLVMDIBuilderCreateParameterVariable(
|
||||
debug.builder,
|
||||
*debug.programs.get(&self.program).unwrap(),
|
||||
*debug.programs.get(&self.location.scope).unwrap(),
|
||||
into_cstring(param.name.clone()).as_ptr(),
|
||||
param.name.len(),
|
||||
param.arg_idx + 1,
|
||||
debug.file_ref,
|
||||
param.location.line,
|
||||
self.location.pos.line,
|
||||
*debug.types.get(¶m.ty).unwrap(),
|
||||
param.always_preserve as i32,
|
||||
param.flags.as_llvm(),
|
||||
),
|
||||
DebugMetadata::LocalVar(var) => LLVMDIBuilderCreateAutoVariable(
|
||||
debug.builder,
|
||||
*debug.programs.get(&self.program).unwrap(),
|
||||
*debug.programs.get(&self.location.scope).unwrap(),
|
||||
into_cstring(var.name.clone()).as_ptr(),
|
||||
var.name.len(),
|
||||
debug.file_ref,
|
||||
var.location.line,
|
||||
self.location.pos.line,
|
||||
*debug.types.get(&var.ty).unwrap(),
|
||||
var.always_preserve as i32,
|
||||
var.flags.as_llvm(),
|
||||
@ -508,7 +508,7 @@ impl DebugTypeHolder {
|
||||
into_cstring(field.name.clone()).as_ptr(),
|
||||
field.name.len(),
|
||||
debug.file_ref,
|
||||
field.location.line,
|
||||
field.pos.map(|p| p.line).unwrap_or(1),
|
||||
field.size_bits,
|
||||
0,
|
||||
1,
|
||||
@ -523,7 +523,7 @@ impl DebugTypeHolder {
|
||||
into_cstring(st.name.clone()).as_ptr(),
|
||||
st.name.len(),
|
||||
debug.file_ref,
|
||||
st.location.line,
|
||||
st.pos.map(|p| p.line).unwrap_or(1),
|
||||
st.size_bits,
|
||||
0,
|
||||
st.flags.as_llvm(),
|
||||
@ -617,7 +617,7 @@ impl FunctionHolder {
|
||||
mangled_name,
|
||||
mangled_length,
|
||||
debug.file_ref,
|
||||
subprogram.location.line,
|
||||
subprogram.location.pos.line,
|
||||
*debug.types.get(&subprogram.ty).unwrap(),
|
||||
subprogram.opts.is_local as i32,
|
||||
subprogram.opts.is_definition as i32,
|
||||
@ -1027,8 +1027,8 @@ impl InstructionHolder {
|
||||
|
||||
let location = LLVMDIBuilderCreateDebugLocation(
|
||||
module.context_ref,
|
||||
record.location.line,
|
||||
record.location.column,
|
||||
record.location.pos.line,
|
||||
record.location.pos.column,
|
||||
*debug.programs.get(&record.scope).unwrap(),
|
||||
null_mut(),
|
||||
);
|
||||
|
@ -34,7 +34,7 @@ pub(crate) struct DebugScopeHolder {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DebugMetadataHolder {
|
||||
pub(crate) program: DebugProgramValue,
|
||||
pub(crate) location: DebugLocation,
|
||||
pub(crate) value: DebugMetadataValue,
|
||||
pub(crate) data: DebugMetadata,
|
||||
}
|
||||
@ -140,11 +140,11 @@ impl DebugInformation {
|
||||
value
|
||||
}
|
||||
|
||||
pub fn metadata(&self, program: &DebugProgramValue, kind: DebugMetadata) -> DebugMetadataValue {
|
||||
pub fn metadata(&self, location: &DebugLocation, kind: DebugMetadata) -> DebugMetadataValue {
|
||||
let mut metadata = self.metadata.borrow_mut();
|
||||
let value = DebugMetadataValue(metadata.len());
|
||||
metadata.push(DebugMetadataHolder {
|
||||
program: *program,
|
||||
location: *location,
|
||||
value: value.clone(),
|
||||
data: kind,
|
||||
});
|
||||
@ -165,6 +165,10 @@ impl DebugInformation {
|
||||
unsafe { self.metadata.borrow().get_unchecked(value.0).data.clone() }
|
||||
}
|
||||
|
||||
pub fn get_metadata_location(&self, value: DebugMetadataValue) -> DebugLocation {
|
||||
unsafe { self.metadata.borrow().get_unchecked(value.0).location }
|
||||
}
|
||||
|
||||
pub fn get_subprogram_data(&self, value: DebugProgramValue) -> Option<DebugSubprogramData> {
|
||||
if value.0 == 0 {
|
||||
None
|
||||
@ -218,8 +222,14 @@ impl DebugInformation {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct DebugLocation {
|
||||
pub scope: DebugProgramValue,
|
||||
pub pos: DebugPosition,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct DebugPosition {
|
||||
pub line: u32,
|
||||
pub column: u32,
|
||||
}
|
||||
@ -238,8 +248,6 @@ pub struct DebugParamVariable {
|
||||
/// parameters. arg_idx should not conflict with other parameters of the
|
||||
/// same subprogram.
|
||||
pub arg_idx: u32,
|
||||
/// Used for line number
|
||||
pub location: DebugLocation,
|
||||
pub ty: DebugTypeValue,
|
||||
/// If this variable will be referenced from its containing subprogram, and
|
||||
/// will survive some optimizations.
|
||||
@ -250,7 +258,6 @@ pub struct DebugParamVariable {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DebugLocalVariable {
|
||||
pub name: String,
|
||||
pub location: DebugLocation,
|
||||
pub ty: DebugTypeValue,
|
||||
pub always_preserve: bool,
|
||||
pub flags: DwarfFlags,
|
||||
@ -309,7 +316,7 @@ pub struct DebugPointerType {
|
||||
pub struct DebugStructType {
|
||||
pub name: String,
|
||||
pub scope: DebugProgramValue,
|
||||
pub location: DebugLocation,
|
||||
pub pos: Option<DebugPosition>,
|
||||
pub size_bits: u64,
|
||||
pub flags: DwarfFlags,
|
||||
pub fields: Vec<DebugFieldType>,
|
||||
@ -318,7 +325,8 @@ pub struct DebugStructType {
|
||||
#[derive(Clone)]
|
||||
pub struct DebugFieldType {
|
||||
pub name: String,
|
||||
pub location: DebugLocation,
|
||||
pub scope: DebugProgramValue,
|
||||
pub pos: Option<DebugPosition>,
|
||||
pub size_bits: u64,
|
||||
pub offset: u64,
|
||||
pub flags: DwarfFlags,
|
||||
|
@ -11,8 +11,8 @@ use crate::{
|
||||
debug_information::{
|
||||
DebugArrayType, DebugBasicType, DebugFieldType, DebugInformation, DebugLocalVariable,
|
||||
DebugLocation, DebugLocationValue, DebugMetadata, DebugMetadataValue, DebugParamVariable,
|
||||
DebugPointerType, DebugProgramValue, DebugRecordKind, DebugScopeValue, DebugStructType,
|
||||
DebugSubprogramType, DebugTypeData, DebugTypeHolder, DebugTypeValue,
|
||||
DebugPointerType, DebugPosition, DebugProgramValue, DebugRecordKind, DebugScopeValue,
|
||||
DebugStructType, DebugSubprogramType, DebugTypeData, DebugTypeHolder, DebugTypeValue,
|
||||
},
|
||||
pad_adapter::PadAdapter,
|
||||
};
|
||||
@ -157,26 +157,26 @@ impl InstructionHolder {
|
||||
|
||||
impl DebugMetadataValue {
|
||||
fn hr(&self, debug: &DebugInformation) -> String {
|
||||
match debug.get_metadata(*self) {
|
||||
let kind = match debug.get_metadata(*self) {
|
||||
DebugMetadata::ParamVar(DebugParamVariable {
|
||||
name,
|
||||
arg_idx,
|
||||
location,
|
||||
ty,
|
||||
..
|
||||
}) => format!(
|
||||
"param {} (idx {}) (type {:?}) at {}",
|
||||
name, arg_idx, ty, location
|
||||
),
|
||||
DebugMetadata::LocalVar(DebugLocalVariable {
|
||||
name, location, ty, ..
|
||||
}) => format!("var {} (type {:?}) at {}", name, ty, location),
|
||||
name, arg_idx, ty, ..
|
||||
}) => format!("param {} (idx {}) (type {:?}) ", name, arg_idx, ty),
|
||||
DebugMetadata::LocalVar(DebugLocalVariable { name, ty, .. }) => {
|
||||
format!("var {} (type {:?}) ", name, ty)
|
||||
}
|
||||
DebugMetadata::VarAssignment => todo!(),
|
||||
}
|
||||
};
|
||||
format!("{} at {}", kind, debug.get_metadata_location(*self))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DebugLocation {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?} on scope {:?}", self.pos, self.scope)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for DebugPosition {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "line {}, col {}", self.line, self.column)
|
||||
}
|
||||
@ -491,7 +491,7 @@ impl Debug for DebugStructType {
|
||||
f.debug_struct("Struct")
|
||||
.field("name", &self.name)
|
||||
.field("scope", &self.scope)
|
||||
.field("location", &self.location)
|
||||
.field("pos", &self.pos)
|
||||
.field("size_bit", &self.size_bits)
|
||||
.field("flags", &self.flags)
|
||||
.field("elements", &self.fields)
|
||||
@ -502,7 +502,8 @@ impl Debug for DebugStructType {
|
||||
impl Debug for DebugFieldType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct(&format!("Field({})", self.name))
|
||||
.field("location", &self.location)
|
||||
.field("scope", &self.scope)
|
||||
.field("pos", &self.pos)
|
||||
.field("size_bits", &self.size_bits)
|
||||
.field("offset", &self.offset)
|
||||
.field("flags", &self.flags)
|
||||
@ -576,6 +577,12 @@ impl Debug for DebugLocationValue {
|
||||
}
|
||||
|
||||
impl Debug for DebugLocation {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?} on scope {:?}", self.pos, self.scope)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for DebugPosition {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "ln {}, col {}", self.line, self.column)
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ pub struct ModuleData {
|
||||
is_main: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Module<'ctx> {
|
||||
phantom: PhantomData<&'ctx ()>,
|
||||
builder: Builder,
|
||||
@ -520,7 +521,7 @@ impl ConstValue {
|
||||
ConstValue::U32(_) => U32,
|
||||
ConstValue::U64(_) => U64,
|
||||
ConstValue::U128(_) => U128,
|
||||
ConstValue::Str(_) => Type::Ptr(Box::new(I8)),
|
||||
ConstValue::Str(_) => Type::Ptr(Box::new(U8)),
|
||||
ConstValue::Bool(_) => Bool,
|
||||
ConstValue::F16(_) => F16,
|
||||
ConstValue::F32B(_) => F32B,
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
extern fn puts(message: *char) -> i32;
|
||||
extern fn malloc(size: u64) -> *u8;
|
||||
extern fn free(ptr: *u8);
|
||||
extern fn div(numerator: i32, denominator: i32) -> div_t;
|
||||
|
||||
struct div_t {
|
||||
@ -8,8 +9,8 @@ struct div_t {
|
||||
remainder: i32,
|
||||
}
|
||||
|
||||
pub fn print(message: *char) {
|
||||
puts(message);
|
||||
pub fn print(message: &String) {
|
||||
puts(*message.inner);
|
||||
}
|
||||
|
||||
pub fn int_div(numerator: i32, denominator: i32) -> div_t {
|
||||
@ -20,6 +21,42 @@ pub fn allocate(size: u64) -> *u8 {
|
||||
malloc(size)
|
||||
}
|
||||
|
||||
fn main() -> u16 {
|
||||
return 0;
|
||||
struct String {
|
||||
inner: *char,
|
||||
length: u64,
|
||||
max_length: u64,
|
||||
}
|
||||
|
||||
pub fn new_string() -> String {
|
||||
String {
|
||||
inner: allocate(0),
|
||||
length: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_char(string: &mut String, c: char) {
|
||||
if ((*string).length + 1) >= (*string).max_length {
|
||||
let new = allocate((*string).max_length + 4) as *char;
|
||||
copy_bits((*string).inner, new, 0, (*string).max_length);
|
||||
|
||||
free((*string).inner as *u8);
|
||||
(*string).max_length = (*string).max_length + 4;
|
||||
(*string).inner = new;
|
||||
|
||||
}
|
||||
(*string).inner[(*string).length] = c;
|
||||
(((*string).inner) as *u8)[((*string).length + 1)] = 0;
|
||||
(*string).length = (*string).length + 1;
|
||||
}
|
||||
|
||||
fn copy_bits(from: *char, to: *char, pos: u64, max: u64) -> u8 {
|
||||
if (pos >= max) {
|
||||
return 0;
|
||||
}
|
||||
to[pos] = from[pos];
|
||||
return copy_bits(from, to, pos + 1, max);
|
||||
}
|
||||
|
||||
pub fn free_string(string: &mut String) {
|
||||
free((*string).inner as *u8);
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
//! used for unwrapping syntax sugar, and then be transformed into Reid MIR.
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::token_stream::TokenRange;
|
||||
use crate::{lexer::FullToken, token_stream::TokenRange};
|
||||
|
||||
pub mod parse;
|
||||
pub mod process;
|
||||
@ -206,6 +206,7 @@ pub enum TopLevelStatement {
|
||||
#[derive(Debug)]
|
||||
pub struct Module {
|
||||
pub name: String,
|
||||
pub tokens: Vec<FullToken>,
|
||||
pub top_level_statements: Vec<TopLevelStatement>,
|
||||
pub path: Option<PathBuf>,
|
||||
pub is_main: bool,
|
||||
|
@ -1,18 +1,25 @@
|
||||
use std::{path::PathBuf, process};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{
|
||||
ast::{self},
|
||||
mir::{self, NamedVariableRef, SourceModuleId, StmtKind, StructField, StructType},
|
||||
mir::{
|
||||
self, ModuleMap, NamedVariableRef, SourceModuleId, StmtKind, StructField, StructType,
|
||||
CustomTypeKey,
|
||||
},
|
||||
};
|
||||
|
||||
impl mir::Context {
|
||||
pub fn from(modules: Vec<mir::Module>, base: PathBuf) -> mir::Context {
|
||||
mir::Context { modules, base }
|
||||
let mut map = ModuleMap::new();
|
||||
for module in modules {
|
||||
map.insert(module.module_id, module);
|
||||
}
|
||||
mir::Context { modules: map, base }
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::Module {
|
||||
pub fn process(&self, module_id: SourceModuleId) -> mir::Module {
|
||||
pub fn process(self, module_id: SourceModuleId) -> mir::Module {
|
||||
let mut imports = Vec::new();
|
||||
let mut functions = Vec::new();
|
||||
let mut typedefs = Vec::new();
|
||||
@ -31,13 +38,13 @@ impl ast::Module {
|
||||
return_type: signature
|
||||
.return_type
|
||||
.clone()
|
||||
.map(|r| r.0.into())
|
||||
.map(|r| r.0.into_mir(module_id))
|
||||
.unwrap_or(mir::TypeKind::Void),
|
||||
parameters: signature
|
||||
.args
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|p| (p.0, p.1.into()))
|
||||
.map(|p| (p.0, p.1 .0.into_mir(module_id)))
|
||||
.collect(),
|
||||
kind: mir::FunctionDefinitionKind::Local(
|
||||
block.into_mir(module_id),
|
||||
@ -54,13 +61,13 @@ impl ast::Module {
|
||||
return_type: signature
|
||||
.return_type
|
||||
.clone()
|
||||
.map(|r| r.0.into())
|
||||
.map(|r| r.0.into_mir(module_id))
|
||||
.unwrap_or(mir::TypeKind::Void),
|
||||
parameters: signature
|
||||
.args
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|p| (p.0, p.1.into()))
|
||||
.map(|p| (p.0, p.1 .0.into_mir(module_id)))
|
||||
.collect(),
|
||||
kind: mir::FunctionDefinitionKind::Extern(false),
|
||||
};
|
||||
@ -77,7 +84,7 @@ impl ast::Module {
|
||||
.map(|s| {
|
||||
StructField(
|
||||
s.name.clone(),
|
||||
s.ty.clone().into(),
|
||||
s.ty.clone().0.into_mir(module_id),
|
||||
s.range.as_meta(module_id),
|
||||
)
|
||||
})
|
||||
@ -86,6 +93,7 @@ impl ast::Module {
|
||||
}
|
||||
},
|
||||
meta: (*range).as_meta(module_id),
|
||||
source_module: module_id,
|
||||
};
|
||||
typedefs.push(def);
|
||||
}
|
||||
@ -99,6 +107,7 @@ impl ast::Module {
|
||||
functions,
|
||||
path: self.path.clone(),
|
||||
is_main: self.is_main,
|
||||
tokens: self.tokens,
|
||||
typedefs,
|
||||
}
|
||||
}
|
||||
@ -116,7 +125,7 @@ impl ast::Block {
|
||||
s_let
|
||||
.ty
|
||||
.clone()
|
||||
.map(|t| t.0.into())
|
||||
.map(|t| t.0.into_mir(module_id))
|
||||
.unwrap_or(mir::TypeKind::Vague(mir::VagueType::Unknown)),
|
||||
s_let.name.clone(),
|
||||
s_let.name_range.as_meta(module_id),
|
||||
@ -256,9 +265,10 @@ impl ast::Expression {
|
||||
Box::new(expr.process(module_id)),
|
||||
),
|
||||
},
|
||||
ast::ExpressionKind::CastTo(expression, ty) => {
|
||||
mir::ExprKind::CastTo(Box::new(expression.process(module_id)), ty.0.clone().into())
|
||||
}
|
||||
ast::ExpressionKind::CastTo(expression, ty) => mir::ExprKind::CastTo(
|
||||
Box::new(expression.process(module_id)),
|
||||
ty.0.clone().into_mir(module_id),
|
||||
),
|
||||
};
|
||||
|
||||
mir::Expression(kind, self.1.as_meta(module_id))
|
||||
@ -294,9 +304,9 @@ impl ast::Literal {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ast::TypeKind> for mir::TypeKind {
|
||||
fn from(value: ast::TypeKind) -> Self {
|
||||
match &value {
|
||||
impl ast::TypeKind {
|
||||
fn into_mir(&self, source_mod: SourceModuleId) -> mir::TypeKind {
|
||||
match &self {
|
||||
ast::TypeKind::Bool => mir::TypeKind::Bool,
|
||||
ast::TypeKind::I8 => mir::TypeKind::I8,
|
||||
ast::TypeKind::I16 => mir::TypeKind::I16,
|
||||
@ -309,14 +319,16 @@ impl From<ast::TypeKind> for mir::TypeKind {
|
||||
ast::TypeKind::U64 => mir::TypeKind::U64,
|
||||
ast::TypeKind::U128 => mir::TypeKind::U128,
|
||||
ast::TypeKind::Array(type_kind, length) => {
|
||||
mir::TypeKind::Array(Box::new(mir::TypeKind::from(*type_kind.clone())), *length)
|
||||
mir::TypeKind::Array(Box::new(type_kind.clone().into_mir(source_mod)), *length)
|
||||
}
|
||||
ast::TypeKind::Custom(name) => {
|
||||
mir::TypeKind::CustomType(CustomTypeKey(name.clone(), source_mod))
|
||||
}
|
||||
ast::TypeKind::Custom(name) => mir::TypeKind::CustomType(name.clone()),
|
||||
ast::TypeKind::Borrow(type_kind, mutable) => {
|
||||
mir::TypeKind::Borrow(Box::new(mir::TypeKind::from(*type_kind.clone())), *mutable)
|
||||
mir::TypeKind::Borrow(Box::new(type_kind.clone().into_mir(source_mod)), *mutable)
|
||||
}
|
||||
ast::TypeKind::Ptr(type_kind) => {
|
||||
mir::TypeKind::UserPtr(Box::new(mir::TypeKind::from(*type_kind.clone())))
|
||||
mir::TypeKind::UserPtr(Box::new(type_kind.clone().into_mir(source_mod)))
|
||||
}
|
||||
ast::TypeKind::F16 => mir::TypeKind::F16,
|
||||
ast::TypeKind::F32B => mir::TypeKind::F32B,
|
||||
@ -329,9 +341,3 @@ impl From<ast::TypeKind> for mir::TypeKind {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ast::Type> for mir::TypeKind {
|
||||
fn from(value: ast::Type) -> Self {
|
||||
value.0.into()
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
use std::{array, collections::HashMap, mem};
|
||||
use std::{array, collections::HashMap, hash::Hash, mem};
|
||||
|
||||
use reid_lib::{
|
||||
builder::{InstructionValue, TypeValue},
|
||||
builder::{InstructionValue, ModuleValue, TypeValue},
|
||||
compile::CompiledModule,
|
||||
debug_information::{
|
||||
DebugArrayType, DebugBasicType, DebugFieldType, DebugFileData, DebugInformation,
|
||||
DebugLocalVariable, DebugLocation, DebugMetadata, DebugParamVariable, DebugPointerType,
|
||||
DebugProgramValue, DebugRecordKind, DebugStructType, DebugSubprogramData,
|
||||
DebugPosition, DebugProgramValue, DebugRecordKind, DebugStructType, DebugSubprogramData,
|
||||
DebugSubprogramOptionals, DebugSubprogramType, DebugTypeData, DebugTypeValue,
|
||||
DwarfEncoding, DwarfFlags, InstructionDebugRecordData,
|
||||
},
|
||||
@ -15,11 +15,12 @@ use reid_lib::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error_raporting::ModuleMap,
|
||||
error_raporting::ErrorModules,
|
||||
lexer::{FullToken, Position},
|
||||
mir::{
|
||||
self, implement::TypeCategory, Metadata, NamedVariableRef, StructField, StructType,
|
||||
TypeDefinition, TypeDefinitionKind, TypeKind, VagueLiteral,
|
||||
self, implement::TypeCategory, CustomTypeKey, Metadata, ModuleMap, NamedVariableRef,
|
||||
SourceModuleId, StructField, StructType, TypeDefinition, TypeDefinitionKind, TypeKind,
|
||||
VagueLiteral,
|
||||
},
|
||||
};
|
||||
|
||||
@ -40,31 +41,25 @@ impl<'ctx> CodegenContext<'ctx> {
|
||||
|
||||
impl mir::Context {
|
||||
/// Compile MIR [`Context`] into [`CodegenContext`] containing LLIR.
|
||||
pub fn codegen<'ctx>(
|
||||
&self,
|
||||
context: &'ctx Context,
|
||||
mod_map: &ModuleMap,
|
||||
) -> CodegenContext<'ctx> {
|
||||
let mut modules = Vec::new();
|
||||
for module in &self.modules {
|
||||
modules.push(
|
||||
module.codegen(
|
||||
context,
|
||||
mod_map
|
||||
.module(&module.module_id)
|
||||
.unwrap()
|
||||
.tokens
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
),
|
||||
);
|
||||
pub fn codegen<'ctx>(&self, context: &'ctx Context) -> CodegenContext<'ctx> {
|
||||
let mut modules = HashMap::new();
|
||||
let mut modules_sorted = self.modules.iter().map(|(_, m)| m).collect::<Vec<_>>();
|
||||
modules_sorted.sort_by(|m1, m2| m2.module_id.cmp(&m1.module_id));
|
||||
|
||||
for module in &modules_sorted {
|
||||
let codegen = module.codegen(context, modules.clone());
|
||||
modules.insert(module.module_id, codegen);
|
||||
}
|
||||
CodegenContext { context }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ModuleCodegen<'ctx> {
|
||||
module: Module<'ctx>,
|
||||
tokens: &'ctx Vec<FullToken>,
|
||||
debug_types: Option<HashMap<TypeKind, DebugTypeValue>>,
|
||||
type_values: HashMap<CustomTypeKey, TypeValue>,
|
||||
}
|
||||
|
||||
impl<'ctx> std::fmt::Debug for ModuleCodegen<'ctx> {
|
||||
@ -73,15 +68,17 @@ impl<'ctx> std::fmt::Debug for ModuleCodegen<'ctx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Scope<'ctx, 'a> {
|
||||
pub struct Scope<'ctx, 'scope> {
|
||||
context: &'ctx Context,
|
||||
modules: &'scope HashMap<SourceModuleId, ModuleCodegen<'ctx>>,
|
||||
tokens: &'ctx Vec<FullToken>,
|
||||
module: &'ctx Module<'ctx>,
|
||||
module_id: SourceModuleId,
|
||||
function: &'ctx StackFunction<'ctx>,
|
||||
block: Block<'ctx>,
|
||||
types: &'a HashMap<TypeValue, TypeDefinition>,
|
||||
type_values: &'a HashMap<String, TypeValue>,
|
||||
functions: &'a HashMap<String, StackFunction<'ctx>>,
|
||||
types: &'scope HashMap<TypeValue, TypeDefinition>,
|
||||
type_values: &'scope HashMap<CustomTypeKey, TypeValue>,
|
||||
functions: &'scope HashMap<String, StackFunction<'ctx>>,
|
||||
stack_values: HashMap<String, StackValue>,
|
||||
debug: Option<Debug<'ctx>>,
|
||||
}
|
||||
@ -150,10 +147,12 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
|
||||
fn with_block(&self, block: Block<'ctx>) -> Scope<'ctx, 'a> {
|
||||
Scope {
|
||||
block,
|
||||
modules: self.modules,
|
||||
tokens: self.tokens,
|
||||
function: self.function,
|
||||
context: self.context,
|
||||
module: self.module,
|
||||
module_id: self.module_id,
|
||||
functions: self.functions,
|
||||
types: self.types,
|
||||
type_values: self.type_values,
|
||||
@ -170,8 +169,8 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
|
||||
old_block
|
||||
}
|
||||
|
||||
fn get_typedef(&self, name: &String) -> Option<&TypeDefinition> {
|
||||
self.type_values.get(name).and_then(|v| self.types.get(v))
|
||||
fn get_typedef(&self, key: &CustomTypeKey) -> Option<&TypeDefinition> {
|
||||
self.type_values.get(key).and_then(|v| self.types.get(v))
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,11 +196,12 @@ impl Default for State {
|
||||
|
||||
impl mir::Module {
|
||||
fn codegen<'ctx>(
|
||||
&self,
|
||||
&'ctx self,
|
||||
context: &'ctx Context,
|
||||
tokens: &Vec<FullToken>,
|
||||
modules: HashMap<SourceModuleId, ModuleCodegen<'ctx>>,
|
||||
) -> ModuleCodegen<'ctx> {
|
||||
let mut module = context.module(&self.name, self.is_main);
|
||||
let tokens = &self.tokens;
|
||||
|
||||
let (debug, compile_unit) = if let Some(path) = &self.path {
|
||||
module.create_debug_info(DebugFileData {
|
||||
@ -229,7 +229,9 @@ impl mir::Module {
|
||||
&debug_types,
|
||||
&type_values,
|
||||
&types,
|
||||
tokens,
|
||||
self.module_id,
|
||||
&self.tokens,
|
||||
&modules,
|
||||
),
|
||||
)
|
||||
};
|
||||
@ -249,7 +251,11 @@ impl mir::Module {
|
||||
insert_debug!(&TypeKind::Void);
|
||||
insert_debug!(&TypeKind::Char);
|
||||
|
||||
for typedef in &self.typedefs {
|
||||
let mut typedefs = self.typedefs.clone();
|
||||
typedefs.sort_by(|a, b| b.source_module.cmp(&a.source_module));
|
||||
|
||||
for typedef in typedefs {
|
||||
let type_key = CustomTypeKey(typedef.name.clone(), typedef.source_module);
|
||||
let type_value = match &typedef.kind {
|
||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
||||
module.custom_type(CustomTypeKind::NamedStruct(NamedStruct(
|
||||
@ -265,8 +271,8 @@ impl mir::Module {
|
||||
}
|
||||
};
|
||||
types.insert(type_value, typedef.clone());
|
||||
type_values.insert(typedef.name.clone(), type_value);
|
||||
insert_debug!(&TypeKind::CustomType(typedef.name.clone()));
|
||||
type_values.insert(type_key.clone(), type_value);
|
||||
insert_debug!(&TypeKind::CustomType(type_key.clone()));
|
||||
}
|
||||
|
||||
let mut functions = HashMap::new();
|
||||
@ -308,116 +314,126 @@ impl mir::Module {
|
||||
|
||||
for mir_function in &self.functions {
|
||||
let function = functions.get(&mir_function.name).unwrap();
|
||||
let mut entry = function.ir.block("entry");
|
||||
|
||||
// Insert debug information
|
||||
let debug_scope = if let Some(location) = mir_function.signature().into_debug(tokens) {
|
||||
// let debug_scope = debug.inner_scope(&outer_scope, location);
|
||||
|
||||
let fn_param_ty = &mir_function.return_type.get_debug_type_hard(
|
||||
compile_unit,
|
||||
&debug,
|
||||
&debug_types,
|
||||
&type_values,
|
||||
&types,
|
||||
tokens,
|
||||
);
|
||||
|
||||
let debug_ty = debug.debug_type(DebugTypeData::Subprogram(DebugSubprogramType {
|
||||
parameters: vec![*fn_param_ty],
|
||||
flags: DwarfFlags,
|
||||
}));
|
||||
|
||||
let subprogram = debug.subprogram(DebugSubprogramData {
|
||||
name: mir_function.name.clone(),
|
||||
outer_scope: compile_unit.clone(),
|
||||
location,
|
||||
ty: debug_ty,
|
||||
opts: DebugSubprogramOptionals {
|
||||
is_local: !mir_function.is_pub,
|
||||
is_definition: true,
|
||||
..DebugSubprogramOptionals::default()
|
||||
},
|
||||
});
|
||||
|
||||
function.ir.set_debug(subprogram);
|
||||
|
||||
Some(subprogram)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Compile actual IR part
|
||||
let mut stack_values = HashMap::new();
|
||||
for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() {
|
||||
// Codegen actual parameters
|
||||
let arg_name = format!("arg.{}", p_name);
|
||||
let param = entry
|
||||
.build_named(format!("{}.get", arg_name), Instr::Param(i))
|
||||
.unwrap();
|
||||
let alloca = entry
|
||||
.build_named(
|
||||
&arg_name,
|
||||
Instr::Alloca(p_ty.get_type(&type_values, &types)),
|
||||
)
|
||||
.unwrap();
|
||||
entry
|
||||
.build_named(format!("{}.store", arg_name), Instr::Store(alloca, param))
|
||||
.unwrap();
|
||||
stack_values.insert(
|
||||
p_name.clone(),
|
||||
StackValue(
|
||||
StackValueKind::mutable(p_ty.is_mutable(), alloca),
|
||||
TypeKind::CodegenPtr(Box::new(p_ty.clone())),
|
||||
),
|
||||
);
|
||||
|
||||
// Generate debug info
|
||||
if let (Some(debug_scope), Some(location)) =
|
||||
(&debug_scope, mir_function.signature().into_debug(tokens))
|
||||
{
|
||||
debug.metadata(
|
||||
&debug_scope,
|
||||
DebugMetadata::ParamVar(DebugParamVariable {
|
||||
name: p_name.clone(),
|
||||
arg_idx: i as u32,
|
||||
location,
|
||||
ty: p_ty.get_debug_type_hard(
|
||||
*debug_scope,
|
||||
&debug,
|
||||
&debug_types,
|
||||
&type_values,
|
||||
&types,
|
||||
tokens,
|
||||
),
|
||||
always_preserve: true,
|
||||
flags: DwarfFlags,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let mut scope = Scope {
|
||||
context,
|
||||
tokens,
|
||||
module: &module,
|
||||
function,
|
||||
block: entry,
|
||||
functions: &functions,
|
||||
types: &types,
|
||||
type_values: &type_values,
|
||||
stack_values,
|
||||
debug: debug_scope.and_then(|scope| {
|
||||
Some(Debug {
|
||||
info: &debug,
|
||||
scope,
|
||||
types: &debug_types,
|
||||
})
|
||||
}),
|
||||
};
|
||||
|
||||
match &mir_function.kind {
|
||||
mir::FunctionDefinitionKind::Local(block, _) => {
|
||||
let mut entry = function.ir.block("entry");
|
||||
|
||||
// Insert debug information
|
||||
let debug_scope = if let Some(location) =
|
||||
mir_function.signature().into_debug(tokens, compile_unit)
|
||||
{
|
||||
// let debug_scope = debug.inner_scope(&outer_scope, location);
|
||||
|
||||
let fn_param_ty = &mir_function.return_type.get_debug_type_hard(
|
||||
compile_unit,
|
||||
&debug,
|
||||
&debug_types,
|
||||
&type_values,
|
||||
&types,
|
||||
self.module_id,
|
||||
&self.tokens,
|
||||
&modules,
|
||||
);
|
||||
|
||||
let debug_ty =
|
||||
debug.debug_type(DebugTypeData::Subprogram(DebugSubprogramType {
|
||||
parameters: vec![*fn_param_ty],
|
||||
flags: DwarfFlags,
|
||||
}));
|
||||
|
||||
let subprogram = debug.subprogram(DebugSubprogramData {
|
||||
name: mir_function.name.clone(),
|
||||
outer_scope: compile_unit.clone(),
|
||||
location,
|
||||
ty: debug_ty,
|
||||
opts: DebugSubprogramOptionals {
|
||||
is_local: !mir_function.is_pub,
|
||||
is_definition: true,
|
||||
..DebugSubprogramOptionals::default()
|
||||
},
|
||||
});
|
||||
|
||||
function.ir.set_debug(subprogram);
|
||||
|
||||
Some(subprogram)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Compile actual IR part
|
||||
let mut stack_values = HashMap::new();
|
||||
for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() {
|
||||
// Codegen actual parameters
|
||||
let arg_name = format!("arg.{}", p_name);
|
||||
let param = entry
|
||||
.build_named(format!("{}.get", arg_name), Instr::Param(i))
|
||||
.unwrap();
|
||||
let alloca = entry
|
||||
.build_named(
|
||||
&arg_name,
|
||||
Instr::Alloca(p_ty.get_type(&type_values, &types)),
|
||||
)
|
||||
.unwrap();
|
||||
entry
|
||||
.build_named(format!("{}.store", arg_name), Instr::Store(alloca, param))
|
||||
.unwrap();
|
||||
stack_values.insert(
|
||||
p_name.clone(),
|
||||
StackValue(
|
||||
StackValueKind::mutable(p_ty.is_mutable(), alloca),
|
||||
TypeKind::CodegenPtr(Box::new(p_ty.clone())),
|
||||
),
|
||||
);
|
||||
|
||||
// Generate debug info
|
||||
if let (Some(debug_scope), Some(location)) = (
|
||||
&debug_scope,
|
||||
mir_function.signature().into_debug(tokens, compile_unit),
|
||||
) {
|
||||
// debug.metadata(
|
||||
// &location,
|
||||
// DebugMetadata::ParamVar(DebugParamVariable {
|
||||
// name: p_name.clone(),
|
||||
// arg_idx: i as u32,
|
||||
// ty: p_ty.get_debug_type_hard(
|
||||
// *debug_scope,
|
||||
// &debug,
|
||||
// &debug_types,
|
||||
// &type_values,
|
||||
// &types,
|
||||
// self.module_id,
|
||||
// &self.tokens,
|
||||
// &modules,
|
||||
// ),
|
||||
// always_preserve: true,
|
||||
// flags: DwarfFlags,
|
||||
// }),
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
let mut scope = Scope {
|
||||
context,
|
||||
modules: &modules,
|
||||
tokens,
|
||||
module: &module,
|
||||
module_id: self.module_id,
|
||||
function,
|
||||
block: entry,
|
||||
functions: &functions,
|
||||
types: &types,
|
||||
type_values: &type_values,
|
||||
stack_values,
|
||||
debug: debug_scope.and_then(|scope| {
|
||||
Some(Debug {
|
||||
info: &debug,
|
||||
scope,
|
||||
types: &debug_types,
|
||||
})
|
||||
}),
|
||||
};
|
||||
|
||||
let state = State::default();
|
||||
if let Some(ret) = block.codegen(&mut scope, &state) {
|
||||
scope.block.terminate(Term::Ret(ret.instr())).unwrap();
|
||||
@ -430,7 +446,8 @@ impl mir::Module {
|
||||
}
|
||||
|
||||
if let Some(debug) = scope.debug {
|
||||
let location = &block.return_meta().into_debug(tokens).unwrap();
|
||||
let location =
|
||||
&block.return_meta().into_debug(tokens, debug.scope).unwrap();
|
||||
let location = debug.info.location(&debug.scope, *location);
|
||||
scope.block.set_terminator_location(location).unwrap();
|
||||
}
|
||||
@ -439,7 +456,12 @@ impl mir::Module {
|
||||
}
|
||||
}
|
||||
|
||||
ModuleCodegen { module }
|
||||
ModuleCodegen {
|
||||
module,
|
||||
debug_types: Some(debug_types),
|
||||
type_values,
|
||||
tokens: &self.tokens,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -452,7 +474,7 @@ impl mir::Block {
|
||||
for stmt in &self.statements {
|
||||
stmt.codegen(&mut scope, state).map(|s| {
|
||||
if let Some(debug) = &scope.debug {
|
||||
let location = stmt.1.into_debug(scope.tokens).unwrap();
|
||||
let location = stmt.1.into_debug(scope.tokens, debug.scope).unwrap();
|
||||
let loc_val = debug.info.location(&debug.scope, location);
|
||||
s.instr().with_location(&mut scope.block, loc_val);
|
||||
}
|
||||
@ -476,11 +498,10 @@ impl mir::Block {
|
||||
|
||||
impl mir::Statement {
|
||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Option<StackValue> {
|
||||
let location = self.1.into_debug(scope.tokens).unwrap();
|
||||
let location = scope
|
||||
.debug
|
||||
.as_ref()
|
||||
.map(|d| d.info.location(&d.scope, location));
|
||||
let location = scope.debug.clone().map(|d| {
|
||||
let location = self.1.into_debug(scope.tokens, d.scope).unwrap();
|
||||
d.info.location(&d.scope, location)
|
||||
});
|
||||
|
||||
match &self.0 {
|
||||
mir::StmtKind::Let(NamedVariableRef(ty, name, _), mutable, expression) => {
|
||||
@ -514,12 +535,11 @@ impl mir::Statement {
|
||||
StackValue(stack_value, TypeKind::CodegenPtr(Box::new(value.clone().1))),
|
||||
);
|
||||
if let Some(debug) = &scope.debug {
|
||||
let location = self.1.into_debug(scope.tokens).unwrap();
|
||||
let location = self.1.into_debug(scope.tokens, debug.scope).unwrap();
|
||||
let var = debug.info.metadata(
|
||||
&debug.scope,
|
||||
&location,
|
||||
DebugMetadata::LocalVar(DebugLocalVariable {
|
||||
name: name.clone(),
|
||||
location,
|
||||
ty: ty.clone().get_debug_type(debug, scope),
|
||||
always_preserve: true,
|
||||
flags: DwarfFlags,
|
||||
@ -577,11 +597,10 @@ impl mir::Statement {
|
||||
impl mir::Expression {
|
||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Option<StackValue> {
|
||||
let location = if let Some(debug) = &scope.debug {
|
||||
Some(
|
||||
debug
|
||||
.info
|
||||
.location(&debug.scope, self.1.into_debug(scope.tokens).unwrap()),
|
||||
)
|
||||
Some(debug.info.location(
|
||||
&debug.scope,
|
||||
self.1.into_debug(scope.tokens, debug.scope).unwrap(),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -632,7 +651,10 @@ impl mir::Expression {
|
||||
.codegen(scope, state)
|
||||
.expect("rhs has no return value")
|
||||
.instr();
|
||||
let lhs_type = lhs_exp.return_type(&Default::default()).unwrap().1;
|
||||
let lhs_type = lhs_exp
|
||||
.return_type(&Default::default(), scope.module_id)
|
||||
.unwrap()
|
||||
.1;
|
||||
let instr = match (
|
||||
binop,
|
||||
lhs_type.signed(),
|
||||
@ -664,8 +686,9 @@ impl mir::Expression {
|
||||
let params = call
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|e| e.codegen(scope, &mut state.load(true)).unwrap().instr())
|
||||
.collect();
|
||||
.map(|e| e.codegen(scope, state).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
let param_instrs = params.iter().map(|e| e.instr()).collect();
|
||||
let callee = scope
|
||||
.functions
|
||||
.get(&call.name)
|
||||
@ -675,12 +698,12 @@ impl mir::Expression {
|
||||
.block
|
||||
.build_named(
|
||||
call.name.clone(),
|
||||
Instr::FunctionCall(callee.ir.value(), params),
|
||||
Instr::FunctionCall(callee.ir.value(), param_instrs),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if let Some(debug) = &scope.debug {
|
||||
let location = call.meta.into_debug(scope.tokens).unwrap();
|
||||
let location = call.meta.into_debug(scope.tokens, debug.scope).unwrap();
|
||||
let location_val = debug.info.location(&debug.scope, location);
|
||||
val.with_location(&mut scope.block, location_val);
|
||||
}
|
||||
@ -753,7 +776,6 @@ impl mir::Expression {
|
||||
};
|
||||
|
||||
let (ptr, contained_ty) = if let TypeKind::UserPtr(further_inner) = *inner.clone() {
|
||||
dbg!(&further_inner, &val_t);
|
||||
let loaded = scope
|
||||
.block
|
||||
.build_named(
|
||||
@ -790,7 +812,6 @@ impl mir::Expression {
|
||||
};
|
||||
|
||||
if state.should_load {
|
||||
dbg!(&contained_ty);
|
||||
Some(StackValue(
|
||||
kind.derive(
|
||||
scope
|
||||
@ -887,15 +908,15 @@ impl mir::Expression {
|
||||
let TypeKind::CodegenPtr(inner) = &struct_val.1 else {
|
||||
panic!("tried accessing non-pointer");
|
||||
};
|
||||
let TypeKind::CustomType(name) = *inner.clone() else {
|
||||
let TypeKind::CustomType(key) = *inner.clone() else {
|
||||
panic!("tried accessing non-custom-type");
|
||||
};
|
||||
let TypeDefinitionKind::Struct(struct_ty) =
|
||||
scope.get_typedef(&name).unwrap().kind.clone();
|
||||
scope.get_typedef(&key).unwrap().kind.clone();
|
||||
let idx = struct_ty.find_index(field).unwrap();
|
||||
|
||||
let gep_n = format!("{}.{}.gep", name, field);
|
||||
let load_n = format!("{}.{}.load", name, field);
|
||||
let gep_n = format!("{}.{}.gep", key.0, field);
|
||||
let load_n = format!("{}.{}.load", key.0, field);
|
||||
|
||||
let value = scope
|
||||
.block
|
||||
@ -933,7 +954,8 @@ impl mir::Expression {
|
||||
}
|
||||
}
|
||||
mir::ExprKind::Struct(name, items) => {
|
||||
let struct_ty = Type::CustomType(*scope.type_values.get(name)?);
|
||||
let type_key = CustomTypeKey(name.clone(), scope.module_id);
|
||||
let struct_ty = Type::CustomType(*scope.type_values.get(&type_key)?);
|
||||
|
||||
let load_n = format!("{}.load", name);
|
||||
|
||||
@ -968,7 +990,7 @@ impl mir::Expression {
|
||||
|
||||
Some(StackValue(
|
||||
StackValueKind::Literal(struct_val),
|
||||
TypeKind::CustomType(name.clone()),
|
||||
TypeKind::CustomType(type_key),
|
||||
))
|
||||
}
|
||||
mir::ExprKind::Borrow(varref, mutable) => {
|
||||
@ -1026,30 +1048,69 @@ impl mir::Expression {
|
||||
panic!("Variable was not a pointer?!?")
|
||||
}
|
||||
} else {
|
||||
StackValue(v.0.derive(var_ptr_instr), *ptr_inner.clone())
|
||||
let TypeKind::Borrow(borrow_inner, mutable) = *ptr_inner.clone() else {
|
||||
panic!();
|
||||
};
|
||||
StackValue(
|
||||
StackValueKind::mutable(mutable, var_ptr_instr),
|
||||
TypeKind::CodegenPtr(borrow_inner.clone()),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
mir::ExprKind::CastTo(expression, type_kind) => {
|
||||
let val = expression.codegen(scope, state)?;
|
||||
|
||||
if val.1 == *type_kind {
|
||||
Some(val)
|
||||
} else if let (TypeKind::UserPtr(_), TypeKind::UserPtr(_)) = (&val.1, type_kind) {
|
||||
Some(val)
|
||||
} else {
|
||||
let cast_instr = val
|
||||
.1
|
||||
.get_type(scope.type_values, scope.types)
|
||||
.cast_instruction(
|
||||
val.instr(),
|
||||
&type_kind.get_type(scope.type_values, scope.types),
|
||||
)
|
||||
.unwrap();
|
||||
match (&val.1, type_kind) {
|
||||
(TypeKind::CodegenPtr(inner), TypeKind::UserPtr(_)) => match *inner.clone()
|
||||
{
|
||||
TypeKind::UserPtr(_) => Some(StackValue(
|
||||
val.0.derive(
|
||||
scope
|
||||
.block
|
||||
.build(Instr::BitCast(
|
||||
val.instr(),
|
||||
Type::Ptr(Box::new(
|
||||
type_kind.get_type(scope.type_values, scope.types),
|
||||
)),
|
||||
))
|
||||
.unwrap(),
|
||||
),
|
||||
TypeKind::CodegenPtr(Box::new(type_kind.clone())),
|
||||
)),
|
||||
_ => panic!(),
|
||||
},
|
||||
(TypeKind::UserPtr(_), TypeKind::UserPtr(_)) => Some(StackValue(
|
||||
val.0.derive(
|
||||
scope
|
||||
.block
|
||||
.build(Instr::BitCast(
|
||||
val.instr(),
|
||||
type_kind.get_type(scope.type_values, scope.types),
|
||||
))
|
||||
.unwrap(),
|
||||
),
|
||||
type_kind.clone(),
|
||||
)),
|
||||
_ => {
|
||||
let cast_instr = val
|
||||
.1
|
||||
.get_type(scope.type_values, scope.types)
|
||||
.cast_instruction(
|
||||
val.instr(),
|
||||
&type_kind.get_type(scope.type_values, scope.types),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
Some(StackValue(
|
||||
val.0.derive(scope.block.build(cast_instr).unwrap()),
|
||||
type_kind.clone(),
|
||||
))
|
||||
Some(StackValue(
|
||||
val.0.derive(scope.block.build(cast_instr).unwrap()),
|
||||
type_kind.clone(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1070,16 +1131,23 @@ impl mir::IfExpression {
|
||||
let after_b = scope.function.ir.block("after");
|
||||
|
||||
if let Some(debug) = &scope.debug {
|
||||
let before_location = self.0 .1.into_debug(scope.tokens).unwrap();
|
||||
let before_location = self.0 .1.into_debug(scope.tokens, debug.scope).unwrap();
|
||||
let before_v = debug.info.location(&debug.scope, before_location);
|
||||
scope.block.set_terminator_location(before_v).unwrap();
|
||||
|
||||
let then_location = self.1.return_meta().into_debug(scope.tokens).unwrap();
|
||||
let then_location = self
|
||||
.1
|
||||
.return_meta()
|
||||
.into_debug(scope.tokens, debug.scope)
|
||||
.unwrap();
|
||||
let then_v = debug.info.location(&debug.scope, then_location);
|
||||
then_b.set_terminator_location(then_v).unwrap();
|
||||
|
||||
let else_location = if let Some(else_block) = &self.2 {
|
||||
else_block.return_meta().into_debug(scope.tokens).unwrap()
|
||||
else_block
|
||||
.return_meta()
|
||||
.into_debug(scope.tokens, debug.scope)
|
||||
.unwrap()
|
||||
} else {
|
||||
then_location
|
||||
};
|
||||
@ -1209,7 +1277,7 @@ impl mir::Literal {
|
||||
impl TypeKind {
|
||||
fn get_type(
|
||||
&self,
|
||||
type_vals: &HashMap<String, TypeValue>,
|
||||
type_vals: &HashMap<CustomTypeKey, TypeValue>,
|
||||
typedefs: &HashMap<TypeValue, TypeDefinition>,
|
||||
) -> Type {
|
||||
match &self {
|
||||
@ -1231,7 +1299,7 @@ impl TypeKind {
|
||||
TypeKind::F128 => Type::F128,
|
||||
TypeKind::F80 => Type::F80,
|
||||
TypeKind::F128PPC => Type::F128PPC,
|
||||
TypeKind::Char => Type::I8,
|
||||
TypeKind::Char => Type::U8,
|
||||
TypeKind::Array(elem_t, len) => {
|
||||
Type::Array(Box::new(elem_t.get_type(type_vals, typedefs)), *len)
|
||||
}
|
||||
@ -1262,7 +1330,9 @@ impl TypeKind {
|
||||
debug.types,
|
||||
scope.type_values,
|
||||
scope.types,
|
||||
scope.module_id,
|
||||
scope.tokens,
|
||||
scope.modules,
|
||||
)
|
||||
}
|
||||
|
||||
@ -1271,9 +1341,11 @@ impl TypeKind {
|
||||
scope: DebugProgramValue,
|
||||
debug_info: &DebugInformation,
|
||||
debug_types: &HashMap<TypeKind, DebugTypeValue>,
|
||||
type_values: &HashMap<String, TypeValue>,
|
||||
type_values: &HashMap<CustomTypeKey, TypeValue>,
|
||||
types: &HashMap<TypeValue, TypeDefinition>,
|
||||
local_mod: SourceModuleId,
|
||||
tokens: &Vec<FullToken>,
|
||||
modules: &HashMap<SourceModuleId, ModuleCodegen>,
|
||||
) -> DebugTypeValue {
|
||||
if let Some(ty) = debug_types.get(self) {
|
||||
return *ty;
|
||||
@ -1291,7 +1363,9 @@ impl TypeKind {
|
||||
debug_types,
|
||||
type_values,
|
||||
types,
|
||||
local_mod,
|
||||
tokens,
|
||||
modules,
|
||||
),
|
||||
size_bits: self.size_of(),
|
||||
})
|
||||
@ -1303,7 +1377,9 @@ impl TypeKind {
|
||||
debug_types,
|
||||
type_values,
|
||||
types,
|
||||
local_mod,
|
||||
tokens,
|
||||
modules,
|
||||
);
|
||||
DebugTypeData::Array(DebugArrayType {
|
||||
size_bits: self.size_of(),
|
||||
@ -1312,17 +1388,23 @@ impl TypeKind {
|
||||
length: *len,
|
||||
})
|
||||
}
|
||||
TypeKind::CustomType(name) => {
|
||||
let typedef = types.get(type_values.get(name).unwrap()).unwrap();
|
||||
|
||||
TypeKind::CustomType(key) => {
|
||||
let typedef = types.get(type_values.get(key).unwrap()).unwrap();
|
||||
match &typedef.kind {
|
||||
TypeDefinitionKind::Struct(struct_type) => {
|
||||
let mut fields = Vec::new();
|
||||
let mut size_bits = 0;
|
||||
|
||||
for field in &struct_type.0 {
|
||||
let location = if typedef.source_module != local_mod {
|
||||
None
|
||||
} else {
|
||||
field.2.into_debug(&tokens, scope)
|
||||
};
|
||||
fields.push(DebugFieldType {
|
||||
name: field.0.clone(),
|
||||
location: field.2.into_debug(tokens).unwrap(),
|
||||
scope,
|
||||
pos: location.map(|l| l.pos),
|
||||
size_bits: field.1.size_of(),
|
||||
offset: size_bits,
|
||||
flags: DwarfFlags,
|
||||
@ -1332,16 +1414,23 @@ impl TypeKind {
|
||||
debug_types,
|
||||
type_values,
|
||||
types,
|
||||
local_mod,
|
||||
tokens,
|
||||
modules,
|
||||
),
|
||||
});
|
||||
size_bits += field.1.size_of();
|
||||
}
|
||||
{
|
||||
let location = if typedef.source_module != local_mod {
|
||||
None
|
||||
} else {
|
||||
typedef.meta.into_debug(&tokens, scope)
|
||||
};
|
||||
DebugTypeData::Struct(DebugStructType {
|
||||
name: name.clone(),
|
||||
name: key.0.clone(),
|
||||
scope,
|
||||
location: typedef.meta.into_debug(tokens).unwrap(),
|
||||
pos: location.map(|l| l.pos),
|
||||
size_bits,
|
||||
flags: DwarfFlags,
|
||||
fields,
|
||||
@ -1384,20 +1473,27 @@ impl TypeKind {
|
||||
}
|
||||
|
||||
impl Metadata {
|
||||
pub fn into_debug(&self, tokens: &Vec<FullToken>) -> Option<DebugLocation> {
|
||||
pub fn into_debug(
|
||||
&self,
|
||||
tokens: &Vec<FullToken>,
|
||||
scope: DebugProgramValue,
|
||||
) -> Option<DebugLocation> {
|
||||
if let Some((start, _)) = self.into_positions(tokens) {
|
||||
Some(start.into())
|
||||
Some(start.debug(scope))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<DebugLocation> for Position {
|
||||
fn into(self) -> DebugLocation {
|
||||
impl Position {
|
||||
fn debug(self, scope: DebugProgramValue) -> DebugLocation {
|
||||
DebugLocation {
|
||||
line: self.1,
|
||||
column: self.0,
|
||||
pos: DebugPosition {
|
||||
line: self.1,
|
||||
column: self.0,
|
||||
},
|
||||
scope,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,24 +63,24 @@ impl PartialOrd for ErrorKind {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Module {
|
||||
pub struct ErrorModule {
|
||||
pub name: String,
|
||||
pub tokens: Option<Vec<FullToken>>,
|
||||
pub source: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct ModuleMap {
|
||||
module_map: HashMap<mir::SourceModuleId, Module>,
|
||||
pub struct ErrorModules {
|
||||
module_map: HashMap<mir::SourceModuleId, ErrorModule>,
|
||||
module_counter: mir::SourceModuleId,
|
||||
}
|
||||
|
||||
impl ModuleMap {
|
||||
impl ErrorModules {
|
||||
pub fn add_module<T: Into<String>>(&mut self, name: T) -> Option<mir::SourceModuleId> {
|
||||
let id = self.module_counter.increment();
|
||||
self.module_map.insert(
|
||||
id,
|
||||
Module {
|
||||
ErrorModule {
|
||||
name: name.into(),
|
||||
tokens: None,
|
||||
source: None,
|
||||
@ -101,21 +101,21 @@ impl ModuleMap {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn module(&self, id: &mir::SourceModuleId) -> Option<&Module> {
|
||||
pub fn module(&self, id: &mir::SourceModuleId) -> Option<&ErrorModule> {
|
||||
self.module_map.get(id)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ReidError {
|
||||
map: ModuleMap,
|
||||
map: ErrorModules,
|
||||
errors: Vec<ErrorKind>,
|
||||
}
|
||||
|
||||
impl ReidError {
|
||||
pub fn from_lexer<U>(
|
||||
result: Result<U, lexer::Error>,
|
||||
map: ModuleMap,
|
||||
map: ErrorModules,
|
||||
module: SourceModuleId,
|
||||
) -> Result<U, ReidError> {
|
||||
result.map_err(|error| {
|
||||
@ -136,7 +136,7 @@ impl ReidError {
|
||||
|
||||
pub fn from_parser<U>(
|
||||
result: Result<U, token_stream::Error>,
|
||||
map: ModuleMap,
|
||||
map: ErrorModules,
|
||||
module: SourceModuleId,
|
||||
) -> Result<U, ReidError> {
|
||||
result.map_err(|error| {
|
||||
@ -155,7 +155,7 @@ impl ReidError {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_kind<U>(errors: Vec<ErrorKind>, map: ModuleMap) -> ReidError {
|
||||
pub fn from_kind<U>(errors: Vec<ErrorKind>, map: ErrorModules) -> ReidError {
|
||||
ReidError { map, errors }
|
||||
}
|
||||
}
|
||||
|
@ -366,6 +366,7 @@ fn escape_char(c: &char) -> char {
|
||||
't' => '\t',
|
||||
'n' => '\n',
|
||||
'r' => '\r',
|
||||
'0' => '\0',
|
||||
_ => *c,
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use error_raporting::{ErrorKind as ErrorRapKind, ModuleMap, ReidError};
|
||||
use error_raporting::{ErrorKind as ErrorRapKind, ErrorModules, ReidError};
|
||||
use lexer::FullToken;
|
||||
use mir::{
|
||||
linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs,
|
||||
@ -64,7 +64,7 @@ mod util;
|
||||
pub fn parse_module<'map, T: Into<String>>(
|
||||
source: &str,
|
||||
name: T,
|
||||
map: &'map mut ModuleMap,
|
||||
map: &'map mut ErrorModules,
|
||||
) -> Result<(mir::SourceModuleId, Vec<FullToken>), ReidError> {
|
||||
let id = map.add_module(name.into()).unwrap();
|
||||
map.set_source(id, source.to_owned());
|
||||
@ -81,8 +81,8 @@ pub fn parse_module<'map, T: Into<String>>(
|
||||
|
||||
pub fn compile_module<'map>(
|
||||
module_id: mir::SourceModuleId,
|
||||
tokens: &Vec<FullToken>,
|
||||
map: &'map mut ModuleMap,
|
||||
tokens: Vec<FullToken>,
|
||||
map: &'map mut ErrorModules,
|
||||
path: Option<PathBuf>,
|
||||
is_main: bool,
|
||||
) -> Result<mir::Module, ReidError> {
|
||||
@ -101,8 +101,11 @@ pub fn compile_module<'map>(
|
||||
statements.push(statement);
|
||||
}
|
||||
|
||||
drop(token_stream);
|
||||
|
||||
let ast_module = ast::Module {
|
||||
name: module.name,
|
||||
tokens: tokens,
|
||||
top_level_statements: statements,
|
||||
path,
|
||||
is_main,
|
||||
@ -113,7 +116,7 @@ pub fn compile_module<'map>(
|
||||
|
||||
pub fn perform_all_passes<'map>(
|
||||
context: &mut mir::Context,
|
||||
module_map: &'map mut ModuleMap,
|
||||
module_map: &'map mut ErrorModules,
|
||||
) -> Result<(), ReidError> {
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(&context);
|
||||
@ -147,7 +150,7 @@ pub fn perform_all_passes<'map>(
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{:-^100}", "TYPE INFERRER OUTPUT");
|
||||
#[cfg(debug_assertions)]
|
||||
dbg!(&refs);
|
||||
println!("{}", &refs);
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{}", &context);
|
||||
#[cfg(debug_assertions)]
|
||||
@ -193,13 +196,13 @@ pub fn perform_all_passes<'map>(
|
||||
pub fn compile_and_pass<'map>(
|
||||
source: &str,
|
||||
path: PathBuf,
|
||||
module_map: &'map mut ModuleMap,
|
||||
module_map: &'map mut ErrorModules,
|
||||
) -> Result<CompileOutput, ReidError> {
|
||||
let path = path.canonicalize().unwrap();
|
||||
let name = path.file_name().unwrap().to_str().unwrap().to_owned();
|
||||
|
||||
let (id, tokens) = parse_module(source, name, module_map)?;
|
||||
let module = compile_module(id, &tokens, module_map, Some(path.clone()), true)?;
|
||||
let module = compile_module(id, tokens, module_map, Some(path.clone()), true)?;
|
||||
|
||||
let mut mir_context = mir::Context::from(vec![module], path.parent().unwrap().to_owned());
|
||||
|
||||
@ -211,7 +214,7 @@ pub fn compile_and_pass<'map>(
|
||||
println!("{}", &mir_context);
|
||||
|
||||
let mut context = Context::new(format!("Reid ({})", env!("CARGO_PKG_VERSION")));
|
||||
let codegen_modules = mir_context.codegen(&mut context, &module_map);
|
||||
let codegen_modules = mir_context.codegen(&mut context);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
println!("{}", &codegen_modules.context);
|
||||
@ -221,6 +224,6 @@ pub fn compile_and_pass<'map>(
|
||||
}
|
||||
|
||||
pub fn compile_simple(source: &str, path: PathBuf) -> Result<CompileOutput, ReidError> {
|
||||
let mut map = ModuleMap::default();
|
||||
let mut map = ErrorModules::default();
|
||||
compile_and_pass(source, path, &mut map)
|
||||
}
|
||||
|
@ -2,11 +2,31 @@ use std::fmt::{Debug, Display, Write};
|
||||
|
||||
use crate::pad_adapter::PadAdapter;
|
||||
|
||||
use super::*;
|
||||
use super::{
|
||||
typerefs::{TypeRef, TypeRefs},
|
||||
*,
|
||||
};
|
||||
|
||||
impl Display for TypeRefs {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for (i, typeref) in self.type_refs.borrow().iter().enumerate() {
|
||||
let idx = *typeref.borrow();
|
||||
writeln!(
|
||||
f,
|
||||
"{:<3} = {:<3} = {:?} = {}",
|
||||
i,
|
||||
unsafe { *self.recurse_type_ref(idx).borrow() },
|
||||
self.retrieve_type(idx),
|
||||
TypeKind::Vague(VagueType::TypeRef(idx)).resolve_ref(self)
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Context {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for module in &self.modules {
|
||||
for (_, module) in &self.modules {
|
||||
Display::fmt(&module, f)?;
|
||||
}
|
||||
Ok(())
|
||||
@ -345,7 +365,7 @@ impl Display for TypeKind {
|
||||
Display::fmt(len, f)?;
|
||||
f.write_char(']')
|
||||
}
|
||||
TypeKind::CustomType(name) => write!(f, "{}", name),
|
||||
TypeKind::CustomType(CustomTypeKey(name, mod_id)) => write!(f, "{}:{}", mod_id, name),
|
||||
TypeKind::Borrow(type_kind, false) => {
|
||||
write!(f, "&")?;
|
||||
Display::fmt(type_kind, f)
|
||||
|
@ -122,12 +122,12 @@ impl TypeKind {
|
||||
TypeKind::U128 => false,
|
||||
TypeKind::Void => false,
|
||||
TypeKind::Char => false,
|
||||
TypeKind::Array(_, _) => false,
|
||||
TypeKind::CustomType(_) => false,
|
||||
TypeKind::CodegenPtr(_) => false,
|
||||
TypeKind::Vague(_) => false,
|
||||
TypeKind::Borrow(_, _) => false,
|
||||
TypeKind::UserPtr(_) => false,
|
||||
TypeKind::Array(..) => false,
|
||||
TypeKind::CustomType(..) => false,
|
||||
TypeKind::CodegenPtr(..) => false,
|
||||
TypeKind::Vague(..) => false,
|
||||
TypeKind::Borrow(..) => false,
|
||||
TypeKind::UserPtr(..) => false,
|
||||
TypeKind::F16 => true,
|
||||
TypeKind::F32B => true,
|
||||
TypeKind::F32 => true,
|
||||
@ -154,10 +154,10 @@ impl TypeKind {
|
||||
TypeKind::Void => 0,
|
||||
TypeKind::Char => 8,
|
||||
TypeKind::Array(type_kind, len) => type_kind.size_of() * len,
|
||||
TypeKind::CustomType(_) => 32,
|
||||
TypeKind::CustomType(..) => 32,
|
||||
TypeKind::CodegenPtr(_) => 64,
|
||||
TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"),
|
||||
TypeKind::Borrow(_, _) => 64,
|
||||
TypeKind::Borrow(..) => 64,
|
||||
TypeKind::UserPtr(_) => 64,
|
||||
TypeKind::F16 => 16,
|
||||
TypeKind::F32B => 16,
|
||||
@ -185,7 +185,7 @@ impl TypeKind {
|
||||
TypeKind::Void => 0,
|
||||
TypeKind::Char => 8,
|
||||
TypeKind::Array(type_kind, _) => type_kind.alignment(),
|
||||
TypeKind::CustomType(_) => 32,
|
||||
TypeKind::CustomType(..) => 32,
|
||||
TypeKind::CodegenPtr(_) => 64,
|
||||
TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"),
|
||||
TypeKind::Borrow(_, _) => 64,
|
||||
@ -230,7 +230,7 @@ impl TypeKind {
|
||||
TypeKind::Void => TypeCategory::Other,
|
||||
TypeKind::Bool => TypeCategory::Other,
|
||||
TypeKind::Array(_, _) => TypeCategory::Other,
|
||||
TypeKind::CustomType(_) => TypeCategory::Other,
|
||||
TypeKind::CustomType(..) => TypeCategory::Other,
|
||||
TypeKind::Borrow(_, _) => TypeCategory::Other,
|
||||
TypeKind::UserPtr(_) => TypeCategory::Other,
|
||||
TypeKind::CodegenPtr(_) => TypeCategory::Other,
|
||||
@ -278,7 +278,7 @@ impl Block {
|
||||
let mut early_return = None;
|
||||
|
||||
for statement in &self.statements {
|
||||
let ret = statement.return_type(&Default::default());
|
||||
let ret = statement.return_type(&Default::default(), SourceModuleId(0));
|
||||
if let Ok((ReturnKind::Hard, _)) = ret {
|
||||
early_return = Some(statement);
|
||||
}
|
||||
@ -302,11 +302,15 @@ impl Block {
|
||||
.unwrap_or(self.meta)
|
||||
}
|
||||
|
||||
pub fn return_type(&self, refs: &TypeRefs) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||
pub fn return_type(
|
||||
&self,
|
||||
refs: &TypeRefs,
|
||||
mod_id: SourceModuleId,
|
||||
) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||
let mut early_return = None;
|
||||
|
||||
for statement in &self.statements {
|
||||
let ret = statement.return_type(refs);
|
||||
let ret = statement.return_type(refs, mod_id);
|
||||
if let Ok((ReturnKind::Hard, _)) = ret {
|
||||
early_return = early_return.or(ret.ok());
|
||||
}
|
||||
@ -319,7 +323,7 @@ impl Block {
|
||||
self.return_expression
|
||||
.as_ref()
|
||||
.ok_or(ReturnTypeOther::NoBlockReturn(self.meta))
|
||||
.and_then(|(kind, stmt)| Ok((*kind, stmt.return_type(refs)?.1)))
|
||||
.and_then(|(kind, stmt)| Ok((*kind, stmt.return_type(refs, mod_id)?.1)))
|
||||
}
|
||||
|
||||
pub fn backing_var(&self) -> Option<&NamedVariableRef> {
|
||||
@ -337,19 +341,23 @@ impl Block {
|
||||
}
|
||||
|
||||
impl Statement {
|
||||
pub fn return_type(&self, refs: &TypeRefs) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||
pub fn return_type(
|
||||
&self,
|
||||
refs: &TypeRefs,
|
||||
mod_id: SourceModuleId,
|
||||
) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||
use StmtKind::*;
|
||||
match &self.0 {
|
||||
Let(var, _, expr) => if_hard(
|
||||
expr.return_type(refs)?,
|
||||
expr.return_type(refs, mod_id)?,
|
||||
Err(ReturnTypeOther::Let(var.2 + expr.1)),
|
||||
),
|
||||
Set(lhs, rhs) => if_hard(
|
||||
rhs.return_type(refs)?,
|
||||
rhs.return_type(refs, mod_id)?,
|
||||
Err(ReturnTypeOther::Set(lhs.1 + rhs.1)),
|
||||
),
|
||||
Import(_) => todo!(),
|
||||
Expression(expression) => expression.return_type(refs),
|
||||
Expression(expression) => expression.return_type(refs, mod_id),
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,22 +372,26 @@ impl Statement {
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
pub fn return_type(&self, refs: &TypeRefs) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||
pub fn return_type(
|
||||
&self,
|
||||
refs: &TypeRefs,
|
||||
mod_id: SourceModuleId,
|
||||
) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||
use ExprKind::*;
|
||||
match &self.0 {
|
||||
Literal(lit) => Ok((ReturnKind::Soft, lit.as_type())),
|
||||
Variable(var) => var.return_type(),
|
||||
BinOp(_, then_e, else_e) => {
|
||||
let then_r = then_e.return_type(refs)?;
|
||||
let else_r = else_e.return_type(refs)?;
|
||||
let then_r = then_e.return_type(refs, mod_id)?;
|
||||
let else_r = else_e.return_type(refs, mod_id)?;
|
||||
|
||||
Ok(pick_return(then_r, else_r))
|
||||
}
|
||||
Block(block) => block.return_type(refs),
|
||||
Block(block) => block.return_type(refs, mod_id),
|
||||
FunctionCall(fcall) => fcall.return_type(),
|
||||
If(expr) => expr.return_type(refs),
|
||||
If(expr) => expr.return_type(refs, mod_id),
|
||||
Indexed(expression, _, _) => {
|
||||
let expr_type = expression.return_type(refs)?;
|
||||
let expr_type = expression.return_type(refs, mod_id)?;
|
||||
if let TypeKind::Array(elem_ty, _) = expr_type.1.resolve_weak(refs) {
|
||||
Ok((ReturnKind::Soft, *elem_ty))
|
||||
} else {
|
||||
@ -390,7 +402,7 @@ impl Expression {
|
||||
let first = expressions
|
||||
.iter()
|
||||
.next()
|
||||
.map(|e| e.return_type(refs))
|
||||
.map(|e| e.return_type(refs, mod_id))
|
||||
.unwrap_or(Ok((ReturnKind::Soft, TypeKind::Void)))?;
|
||||
Ok((
|
||||
ReturnKind::Soft,
|
||||
@ -398,7 +410,10 @@ impl Expression {
|
||||
))
|
||||
}
|
||||
Accessed(_, type_kind, _) => Ok((ReturnKind::Soft, type_kind.clone())),
|
||||
Struct(name, _) => Ok((ReturnKind::Soft, TypeKind::CustomType(name.clone()))),
|
||||
Struct(name, _) => Ok((
|
||||
ReturnKind::Soft,
|
||||
TypeKind::CustomType(CustomTypeKey(name.clone(), mod_id)),
|
||||
)),
|
||||
Borrow(var, mutable) => {
|
||||
let ret_type = var.return_type()?;
|
||||
Ok((ret_type.0, TypeKind::Borrow(Box::new(ret_type.1), *mutable)))
|
||||
@ -410,7 +425,7 @@ impl Expression {
|
||||
_ => Err(ReturnTypeOther::DerefNonBorrow(var.2)),
|
||||
}
|
||||
}
|
||||
CastTo(expr, type_kind) => match expr.return_type(refs) {
|
||||
CastTo(expr, type_kind) => match expr.return_type(refs, mod_id) {
|
||||
Ok(ret_type) => match ret_type {
|
||||
(ReturnKind::Hard, ty) => Ok((ReturnKind::Hard, ty)),
|
||||
_ => Ok((ReturnKind::Soft, type_kind.clone())),
|
||||
@ -468,10 +483,14 @@ impl Expression {
|
||||
}
|
||||
|
||||
impl IfExpression {
|
||||
pub fn return_type(&self, refs: &TypeRefs) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||
let then_r = self.1.return_type(refs)?;
|
||||
pub fn return_type(
|
||||
&self,
|
||||
refs: &TypeRefs,
|
||||
mod_id: SourceModuleId,
|
||||
) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
||||
let then_r = self.1.return_type(refs, mod_id)?;
|
||||
if let Some(else_b) = &self.2 {
|
||||
let else_r = else_b.return_type(refs)?;
|
||||
let else_r = else_b.return_type(refs, mod_id)?;
|
||||
|
||||
let kind = if then_r.0 == ReturnKind::Hard && else_r.0 == ReturnKind::Hard {
|
||||
ReturnKind::Hard
|
||||
|
@ -9,9 +9,8 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
compile_module,
|
||||
error_raporting::{ModuleMap, ReidError},
|
||||
lexer::FullToken,
|
||||
mir::{TypeDefinition, TypeKind},
|
||||
error_raporting::{ErrorModules, ReidError},
|
||||
mir::{SourceModuleId, TypeDefinition, CustomTypeKey, TypeKind},
|
||||
parse_module,
|
||||
};
|
||||
|
||||
@ -22,6 +21,7 @@ use super::{
|
||||
};
|
||||
|
||||
pub static STD_SOURCE: &str = include_str!("../../lib/std.reid");
|
||||
pub static STD_NAME: &str = "std";
|
||||
|
||||
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum ErrorKind {
|
||||
@ -47,22 +47,21 @@ pub enum ErrorKind {
|
||||
FunctionIsPrivate(String, String),
|
||||
}
|
||||
|
||||
pub fn compile_std(
|
||||
module_map: &mut ModuleMap,
|
||||
) -> Result<(super::Module, Vec<FullToken>), ReidError> {
|
||||
let (id, tokens) = parse_module(STD_SOURCE, "standard_library", module_map)?;
|
||||
let module = compile_module(id, &tokens, module_map, None, false)?;
|
||||
pub fn compile_std(module_map: &mut ErrorModules) -> Result<Module, ReidError> {
|
||||
let (id, tokens) = parse_module(STD_SOURCE, STD_NAME, module_map)?;
|
||||
let module = compile_module(id, tokens, module_map, None, false)?;
|
||||
|
||||
let module_id = module.module_id;
|
||||
let mut mir_context = super::Context::from(vec![module], Default::default());
|
||||
|
||||
let std_compiled = mir_context.modules.remove(0);
|
||||
Ok((std_compiled, tokens))
|
||||
let std_compiled = mir_context.modules.remove(&module_id).unwrap();
|
||||
Ok(std_compiled)
|
||||
}
|
||||
|
||||
/// Struct used to implement a type-checking pass that can be performed on the
|
||||
/// MIR.
|
||||
pub struct LinkerPass<'map> {
|
||||
pub module_map: &'map mut ModuleMap,
|
||||
pub module_map: &'map mut ErrorModules,
|
||||
pub is_lib: bool,
|
||||
}
|
||||
|
||||
@ -75,13 +74,13 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
let mains = context
|
||||
.modules
|
||||
.iter_mut()
|
||||
.filter(|m| m.is_main)
|
||||
.filter(|(_, module)| module.is_main)
|
||||
.collect::<Vec<_>>();
|
||||
if mains.len() > 1 {
|
||||
state.note_errors(&vec![ErrorKind::MultipleMainsAtStart], Metadata::default());
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(main) = mains.first() {
|
||||
if let Some((_, main)) = mains.first() {
|
||||
if let None = main.functions.iter().find(|f| f.name == "main") {
|
||||
if !self.is_lib {
|
||||
state.note_errors(&vec![ErrorKind::NoMainFunction], Metadata::default());
|
||||
@ -95,26 +94,19 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
}
|
||||
};
|
||||
|
||||
let mut modules = HashMap::<String, Rc<RefCell<_>>>::new();
|
||||
let mut modules = HashMap::<SourceModuleId, Rc<RefCell<_>>>::new();
|
||||
let mut module_ids = HashMap::<String, SourceModuleId>::new();
|
||||
|
||||
for module in context.modules.drain(..) {
|
||||
let tokens = self
|
||||
.module_map
|
||||
.module(&module.module_id)
|
||||
.unwrap()
|
||||
.tokens
|
||||
.clone()
|
||||
.unwrap();
|
||||
modules.insert(module.name.clone(), Rc::new(RefCell::new((module, tokens))));
|
||||
for (mod_id, module) in context.modules.drain() {
|
||||
modules.insert(mod_id, Rc::new(RefCell::new(module)));
|
||||
}
|
||||
|
||||
let mut modules_to_process: Vec<Rc<RefCell<(Module, Vec<FullToken>)>>> =
|
||||
modules.values().cloned().collect();
|
||||
let mut modules_to_process: Vec<Rc<RefCell<_>>> = modules.values().cloned().collect();
|
||||
|
||||
while let Some(module) = modules_to_process.pop() {
|
||||
let mut importer_module = module.borrow_mut();
|
||||
|
||||
for import in importer_module.0.imports.clone() {
|
||||
for import in importer_module.imports.clone() {
|
||||
let Import(path, _) = &import;
|
||||
if path.len() != 2 {
|
||||
state.ok::<_, Infallible>(
|
||||
@ -125,14 +117,16 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
|
||||
let module_name = unsafe { path.get_unchecked(0) };
|
||||
|
||||
let mut imported = if let Some(module) = modules.get_mut(module_name) {
|
||||
module
|
||||
} else if module_name == "std" {
|
||||
let mut imported = if let Some(mod_id) = module_ids.get(module_name) {
|
||||
modules.get(mod_id).unwrap()
|
||||
} else if module_name == STD_NAME {
|
||||
let std = compile_std(&mut self.module_map)?;
|
||||
modules.insert(
|
||||
"std".to_owned(),
|
||||
std.module_id,
|
||||
Rc::new(RefCell::new(compile_std(&mut self.module_map)?)),
|
||||
);
|
||||
modules.get("std").unwrap()
|
||||
module_ids.insert(std.name, std.module_id);
|
||||
modules.get(&std.module_id).unwrap()
|
||||
} else {
|
||||
let file_path =
|
||||
PathBuf::from(&context.base.clone()).join(module_name.to_owned() + ".reid");
|
||||
@ -160,8 +154,7 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
}
|
||||
};
|
||||
|
||||
match compile_module(id, &tokens, &mut self.module_map, Some(file_path), false)
|
||||
{
|
||||
match compile_module(id, tokens, &mut self.module_map, Some(file_path), false) {
|
||||
Ok(imported_module) => {
|
||||
if imported_module.is_main {
|
||||
state.ok::<_, Infallible>(
|
||||
@ -170,12 +163,11 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
let module_name = imported_module.name.clone();
|
||||
modules.insert(
|
||||
module_name.clone(),
|
||||
Rc::new(RefCell::new((imported_module, tokens))),
|
||||
);
|
||||
let imported = modules.get_mut(&module_name).unwrap();
|
||||
let module_id = imported_module.module_id;
|
||||
module_ids
|
||||
.insert(imported_module.name.clone(), imported_module.module_id);
|
||||
modules.insert(module_id, Rc::new(RefCell::new(imported_module)));
|
||||
let imported = modules.get_mut(&module_id).unwrap();
|
||||
modules_to_process.push(imported.clone());
|
||||
imported
|
||||
}
|
||||
@ -194,14 +186,9 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
.borrow_mut();
|
||||
|
||||
let func_name = unsafe { path.get_unchecked(1) };
|
||||
let imported_mod_name = imported.0.name.clone();
|
||||
let imported_mod_typedefs = imported.0.typedefs.clone();
|
||||
let imported_mod_name = imported.name.clone();
|
||||
|
||||
let Some(func) = imported
|
||||
.0
|
||||
.functions
|
||||
.iter_mut()
|
||||
.find(|f| f.name == *func_name)
|
||||
let Some(func) = imported.functions.iter_mut().find(|f| f.name == *func_name)
|
||||
else {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::NoSuchFunctionInModule(
|
||||
@ -213,6 +200,8 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
continue;
|
||||
};
|
||||
|
||||
let func_name = func.name.clone();
|
||||
|
||||
if !func.is_pub {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::FunctionIsPrivate(
|
||||
@ -227,7 +216,6 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
func.is_imported = true;
|
||||
|
||||
if let Some(existing) = importer_module
|
||||
.0
|
||||
.functions
|
||||
.iter()
|
||||
.find(|f| f.name == *func_name)
|
||||
@ -244,14 +232,12 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
}
|
||||
}
|
||||
|
||||
fn import_type(base: &String, ty: &TypeKind) -> (TypeKind, Vec<String>) {
|
||||
fn import_type(base: &String, ty: &TypeKind) -> (TypeKind, Vec<CustomTypeKey>) {
|
||||
let mut imported_types = Vec::new();
|
||||
let ty = match &ty {
|
||||
TypeKind::CustomType(name) => {
|
||||
imported_types.push(name.clone());
|
||||
|
||||
let name = format!("{}::{}", base, name);
|
||||
TypeKind::CustomType(name)
|
||||
TypeKind::CustomType(key) => {
|
||||
imported_types.push(key.clone());
|
||||
TypeKind::CustomType(key.clone())
|
||||
}
|
||||
_ => ty.clone(),
|
||||
};
|
||||
@ -272,27 +258,28 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
|
||||
fn find_inner_types(
|
||||
typedef: &TypeDefinition,
|
||||
mut seen: HashSet<String>,
|
||||
) -> Vec<String> {
|
||||
mut seen: HashSet<CustomTypeKey>,
|
||||
mod_id: SourceModuleId,
|
||||
) -> Vec<CustomTypeKey> {
|
||||
match &typedef.kind {
|
||||
crate::mir::TypeDefinitionKind::Struct(struct_type) => {
|
||||
let typenames = struct_type
|
||||
.0
|
||||
.iter()
|
||||
.filter(|t| matches!(t.1, TypeKind::CustomType(_)))
|
||||
.filter(|t| matches!(t.1, TypeKind::CustomType(..)))
|
||||
.map(|t| match &t.1 {
|
||||
TypeKind::CustomType(t) => t,
|
||||
TypeKind::CustomType(CustomTypeKey(t, _)) => t,
|
||||
_ => panic!(),
|
||||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
for typename in typenames {
|
||||
if seen.contains(&typename) {
|
||||
if seen.contains(&CustomTypeKey(typename.clone(), mod_id)) {
|
||||
continue;
|
||||
}
|
||||
let inner = find_inner_types(typedef, seen.clone());
|
||||
seen.insert(typename);
|
||||
let inner = find_inner_types(typedef, seen.clone(), mod_id);
|
||||
seen.insert(CustomTypeKey(typename, mod_id));
|
||||
seen.extend(inner);
|
||||
}
|
||||
|
||||
@ -304,28 +291,30 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
let mut seen = HashSet::new();
|
||||
seen.extend(imported_types.clone());
|
||||
|
||||
for typename in imported_types.clone() {
|
||||
let imported_mod_id = imported.module_id;
|
||||
let imported_mod_typedefs = &mut imported.typedefs;
|
||||
|
||||
for typekey in imported_types.clone() {
|
||||
let typedef = imported_mod_typedefs
|
||||
.iter()
|
||||
.find(|ty| ty.name == typename)
|
||||
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey)
|
||||
.unwrap();
|
||||
let inner = find_inner_types(typedef, seen.clone());
|
||||
let inner = find_inner_types(typedef, seen.clone(), imported_mod_id);
|
||||
seen.extend(inner);
|
||||
}
|
||||
|
||||
for typename in seen.into_iter() {
|
||||
let mut typedef = imported_mod_typedefs
|
||||
for typekey in seen.into_iter() {
|
||||
let typedef = imported_mod_typedefs
|
||||
.iter()
|
||||
.find(|ty| ty.name == typename)
|
||||
.find(|ty| CustomTypeKey(ty.name.clone(), imported_mod_id) == typekey)
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
typedef.name = format!("{}::{}", imported_mod_name, typedef.name);
|
||||
importer_module.0.typedefs.push(typedef);
|
||||
importer_module.typedefs.push(typedef.clone());
|
||||
}
|
||||
|
||||
importer_module.0.functions.push(FunctionDefinition {
|
||||
name: func.name.clone(),
|
||||
importer_module.functions.push(FunctionDefinition {
|
||||
name: func_name,
|
||||
is_pub: false,
|
||||
is_imported: false,
|
||||
return_type: return_type,
|
||||
@ -335,11 +324,15 @@ impl<'map> Pass for LinkerPass<'map> {
|
||||
}
|
||||
}
|
||||
|
||||
context.modules = modules
|
||||
let mut modules: Vec<Module> = modules
|
||||
.into_values()
|
||||
.map(|v| Rc::into_inner(v).unwrap().into_inner().0)
|
||||
.map(|v| Rc::into_inner(v).unwrap().into_inner())
|
||||
.collect();
|
||||
|
||||
for module in modules.drain(..) {
|
||||
context.modules.insert(module.module_id, module);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ pub mod typeinference;
|
||||
pub mod typerefs;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash)]
|
||||
pub struct SourceModuleId(u32);
|
||||
pub struct SourceModuleId(pub u32);
|
||||
|
||||
impl SourceModuleId {
|
||||
pub fn increment(&mut self) -> SourceModuleId {
|
||||
@ -77,6 +77,9 @@ impl TokenRange {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||
pub struct CustomTypeKey(pub String, pub SourceModuleId);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum TypeKind {
|
||||
Bool,
|
||||
@ -100,7 +103,7 @@ pub enum TypeKind {
|
||||
F128PPC,
|
||||
Char,
|
||||
Array(Box<TypeKind>, u64),
|
||||
CustomType(String),
|
||||
CustomType(CustomTypeKey),
|
||||
Borrow(Box<TypeKind>, bool),
|
||||
UserPtr(Box<TypeKind>),
|
||||
CodegenPtr(Box<TypeKind>),
|
||||
@ -335,6 +338,7 @@ pub struct TypeDefinition {
|
||||
pub name: String,
|
||||
pub kind: TypeDefinitionKind,
|
||||
pub meta: Metadata,
|
||||
pub source_module: SourceModuleId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -350,11 +354,14 @@ pub struct Module {
|
||||
pub functions: Vec<FunctionDefinition>,
|
||||
pub typedefs: Vec<TypeDefinition>,
|
||||
pub path: Option<PathBuf>,
|
||||
pub tokens: Vec<FullToken>,
|
||||
pub is_main: bool,
|
||||
}
|
||||
|
||||
pub type ModuleMap = HashMap<SourceModuleId, Module>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Context {
|
||||
pub modules: Vec<Module>,
|
||||
pub modules: ModuleMap,
|
||||
pub base: PathBuf,
|
||||
}
|
||||
|
@ -90,16 +90,16 @@ impl<TErr: STDError> State<TErr> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Storage<T: std::fmt::Debug>(HashMap<String, T>);
|
||||
pub struct Storage<Key: std::hash::Hash, T: std::fmt::Debug>(HashMap<Key, T>);
|
||||
|
||||
impl<T: std::fmt::Debug> Default for Storage<T> {
|
||||
impl<Key: std::hash::Hash, T: std::fmt::Debug> Default for Storage<Key, T> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone + std::fmt::Debug> Storage<T> {
|
||||
pub fn set(&mut self, key: String, value: T) -> Result<T, ()> {
|
||||
impl<Key: std::hash::Hash + Eq, T: Clone + std::fmt::Debug> Storage<Key, T> {
|
||||
pub fn set(&mut self, key: Key, value: T) -> Result<T, ()> {
|
||||
if let Some(_) = self.0.get(&key) {
|
||||
Err(())
|
||||
} else {
|
||||
@ -108,16 +108,16 @@ impl<T: Clone + std::fmt::Debug> Storage<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &String) -> Option<&T> {
|
||||
pub fn get(&self, key: &Key) -> Option<&T> {
|
||||
self.0.get(key)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct Scope<Data: Clone + Default> {
|
||||
pub function_returns: Storage<ScopeFunction>,
|
||||
pub variables: Storage<ScopeVariable>,
|
||||
pub types: Storage<TypeDefinitionKind>,
|
||||
pub function_returns: Storage<String, ScopeFunction>,
|
||||
pub variables: Storage<String, ScopeVariable>,
|
||||
pub types: Storage<CustomTypeKey, TypeDefinition>,
|
||||
/// Hard Return type of this scope, if inside a function
|
||||
pub return_type_hint: Option<TypeKind>,
|
||||
pub data: Data,
|
||||
@ -134,12 +134,20 @@ impl<Data: Clone + Default> Scope<Data> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_struct_type(&self, name: &String) -> Option<&StructType> {
|
||||
let ty = self.types.get(&name)?;
|
||||
match ty {
|
||||
pub fn get_struct_type(&self, key: &CustomTypeKey) -> Option<&StructType> {
|
||||
let ty = self.types.get(&key)?;
|
||||
match &ty.kind {
|
||||
TypeDefinitionKind::Struct(struct_ty) => Some(struct_ty),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_type(&self, name: &String) -> Option<&CustomTypeKey> {
|
||||
self.types
|
||||
.0
|
||||
.iter()
|
||||
.find(|(CustomTypeKey(n, _), _)| n == name)
|
||||
.map(|(key, _)| key)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -158,14 +166,20 @@ pub struct PassState<'st, 'sc, Data: Clone + Default, TError: STDError + Clone>
|
||||
state: &'st mut State<TError>,
|
||||
pub scope: &'sc mut Scope<Data>,
|
||||
inner: Vec<Scope<Data>>,
|
||||
pub module_id: Option<SourceModuleId>,
|
||||
}
|
||||
|
||||
impl<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> PassState<'st, 'sc, Data, TError> {
|
||||
fn from(state: &'st mut State<TError>, scope: &'sc mut Scope<Data>) -> Self {
|
||||
fn from(
|
||||
state: &'st mut State<TError>,
|
||||
scope: &'sc mut Scope<Data>,
|
||||
module_id: Option<SourceModuleId>,
|
||||
) -> Self {
|
||||
PassState {
|
||||
state,
|
||||
scope,
|
||||
inner: Vec::new(),
|
||||
module_id: module_id,
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,6 +217,7 @@ impl<'st, 'sc, Data: Clone + Default, TError: STDError + Clone> PassState<'st, '
|
||||
state: self.state,
|
||||
scope,
|
||||
inner: Vec::new(),
|
||||
module_id: self.module_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -261,8 +276,8 @@ impl Context {
|
||||
pub fn pass<T: Pass>(&mut self, pass: &mut T) -> Result<State<T::TError>, ReidError> {
|
||||
let mut state = State::new();
|
||||
let mut scope = Scope::default();
|
||||
pass.context(self, PassState::from(&mut state, &mut scope))?;
|
||||
for module in &mut self.modules {
|
||||
pass.context(self, PassState::from(&mut state, &mut scope, None))?;
|
||||
for (_, module) in &mut self.modules {
|
||||
module.pass(pass, &mut state, &mut scope.inner())?;
|
||||
}
|
||||
Ok(state)
|
||||
@ -277,10 +292,13 @@ impl Module {
|
||||
scope: &mut Scope<T::Data>,
|
||||
) -> PassResult {
|
||||
for typedef in &self.typedefs {
|
||||
let kind = match &typedef.kind {
|
||||
TypeDefinitionKind::Struct(fields) => TypeDefinitionKind::Struct(fields.clone()),
|
||||
};
|
||||
scope.types.set(typedef.name.clone(), kind).ok();
|
||||
scope
|
||||
.types
|
||||
.set(
|
||||
CustomTypeKey(typedef.name.clone(), self.module_id),
|
||||
typedef.clone(),
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
|
||||
for function in &self.functions {
|
||||
@ -296,10 +314,10 @@ impl Module {
|
||||
.ok();
|
||||
}
|
||||
|
||||
pass.module(self, PassState::from(state, scope))?;
|
||||
pass.module(self, PassState::from(state, scope, Some(self.module_id)))?;
|
||||
|
||||
for function in &mut self.functions {
|
||||
function.pass(pass, state, &mut scope.inner())?;
|
||||
function.pass(pass, state, &mut scope.inner(), self.module_id)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -311,6 +329,7 @@ impl FunctionDefinition {
|
||||
pass: &mut T,
|
||||
state: &mut State<T::TError>,
|
||||
scope: &mut Scope<T::Data>,
|
||||
mod_id: SourceModuleId,
|
||||
) -> PassResult {
|
||||
for param in &self.parameters {
|
||||
scope
|
||||
@ -325,12 +344,12 @@ impl FunctionDefinition {
|
||||
.ok();
|
||||
}
|
||||
|
||||
pass.function(self, PassState::from(state, scope))?;
|
||||
pass.function(self, PassState::from(state, scope, Some(mod_id)))?;
|
||||
|
||||
match &mut self.kind {
|
||||
FunctionDefinitionKind::Local(block, _) => {
|
||||
scope.return_type_hint = Some(self.return_type.clone());
|
||||
block.pass(pass, state, scope)?;
|
||||
block.pass(pass, state, scope, mod_id)?;
|
||||
}
|
||||
FunctionDefinitionKind::Extern(_) => {}
|
||||
};
|
||||
@ -344,14 +363,15 @@ impl Block {
|
||||
pass: &mut T,
|
||||
state: &mut State<T::TError>,
|
||||
scope: &mut Scope<T::Data>,
|
||||
mod_id: SourceModuleId,
|
||||
) -> PassResult {
|
||||
let mut scope = scope.inner();
|
||||
|
||||
for statement in &mut self.statements {
|
||||
statement.pass(pass, state, &mut scope)?;
|
||||
statement.pass(pass, state, &mut scope, mod_id)?;
|
||||
}
|
||||
|
||||
pass.block(self, PassState::from(state, &mut scope))
|
||||
pass.block(self, PassState::from(state, &mut scope, Some(mod_id)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -361,21 +381,22 @@ impl Statement {
|
||||
pass: &mut T,
|
||||
state: &mut State<T::TError>,
|
||||
scope: &mut Scope<T::Data>,
|
||||
mod_id: SourceModuleId,
|
||||
) -> PassResult {
|
||||
match &mut self.0 {
|
||||
StmtKind::Let(_, _, expression) => {
|
||||
expression.pass(pass, state, scope)?;
|
||||
expression.pass(pass, state, scope, mod_id)?;
|
||||
}
|
||||
StmtKind::Set(_, expression) => {
|
||||
expression.pass(pass, state, scope)?;
|
||||
expression.pass(pass, state, scope, mod_id)?;
|
||||
}
|
||||
StmtKind::Import(_) => {} // Never exists at this stage
|
||||
StmtKind::Expression(expression) => {
|
||||
expression.pass(pass, state, scope)?;
|
||||
expression.pass(pass, state, scope, mod_id)?;
|
||||
}
|
||||
}
|
||||
|
||||
pass.stmt(self, PassState::from(state, scope))?;
|
||||
pass.stmt(self, PassState::from(state, scope, Some(mod_id)))?;
|
||||
|
||||
match &mut self.0 {
|
||||
StmtKind::Let(variable_reference, mutable, _) => {
|
||||
@ -404,8 +425,9 @@ impl Expression {
|
||||
pass: &mut T,
|
||||
state: &mut State<T::TError>,
|
||||
scope: &mut Scope<T::Data>,
|
||||
mod_id: SourceModuleId,
|
||||
) -> PassResult {
|
||||
pass.expr(self, PassState::from(state, scope))?;
|
||||
pass.expr(self, PassState::from(state, scope, Some(mod_id)))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ pub enum ErrorKind {
|
||||
TriedIndexingNonIndexable(TypeKind),
|
||||
#[error("Index {0} out of bounds ({1})")]
|
||||
IndexOutOfBounds(u64, u64),
|
||||
#[error("No such type {0} could be found")]
|
||||
NoSuchType(String),
|
||||
#[error("No such type {0} could be found in module {1}")]
|
||||
NoSuchType(String, SourceModuleId),
|
||||
#[error("Attempted to access field of non-struct type of {0}")]
|
||||
TriedAccessingNonStruct(TypeKind),
|
||||
#[error("No such struct-field on type {0}")]
|
||||
@ -85,7 +85,13 @@ impl<'t> Pass for TypeCheck<'t> {
|
||||
fn module(&mut self, module: &mut Module, mut state: TypecheckPassState) -> PassResult {
|
||||
let mut defmap = HashMap::new();
|
||||
for typedef in &module.typedefs {
|
||||
let TypeDefinition { name, kind, meta } = &typedef;
|
||||
let TypeDefinition {
|
||||
name,
|
||||
kind,
|
||||
meta,
|
||||
source_module,
|
||||
} = &typedef;
|
||||
|
||||
match kind {
|
||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
||||
let mut fieldmap = HashMap::new();
|
||||
@ -132,7 +138,7 @@ fn check_typedefs_for_recursion<'a, 'b>(
|
||||
match &typedef.kind {
|
||||
TypeDefinitionKind::Struct(StructType(fields)) => {
|
||||
for field_ty in fields.iter().map(|StructField(_, ty, _)| ty) {
|
||||
if let TypeKind::CustomType(name) = field_ty {
|
||||
if let TypeKind::CustomType(CustomTypeKey(name, _)) = field_ty {
|
||||
if seen.contains(name) {
|
||||
state.ok::<_, Infallible>(
|
||||
Err(ErrorKind::RecursiveTypeDefinition(
|
||||
@ -319,7 +325,9 @@ impl Block {
|
||||
StmtKind::Expression(expression) => {
|
||||
let res = expression.typecheck(&mut state, &typerefs, None);
|
||||
state.or_else(res, TypeKind::Void, expression.1);
|
||||
if let Ok((kind, _)) = expression.return_type(typerefs) {
|
||||
if let Ok((kind, _)) =
|
||||
expression.return_type(typerefs, state.module_id.unwrap())
|
||||
{
|
||||
Some((kind, expression))
|
||||
} else {
|
||||
None
|
||||
@ -605,11 +613,11 @@ impl Expression {
|
||||
let expr_ty =
|
||||
state.or_else(expr_res, TypeKind::Vague(Vague::Unknown), expression.1);
|
||||
|
||||
if let TypeKind::CustomType(struct_name) = expr_ty {
|
||||
if let TypeKind::CustomType(key) = expr_ty {
|
||||
let struct_type = state
|
||||
.scope
|
||||
.get_struct_type(&struct_name)
|
||||
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?;
|
||||
.get_struct_type(&key)
|
||||
.ok_or(ErrorKind::NoSuchType(key.0.clone(), key.1))?;
|
||||
if let Some(expr_field_ty) = struct_type.get_field_ty(&field_name) {
|
||||
// Make sure they are the same
|
||||
let true_ty = state.or_else(
|
||||
@ -628,10 +636,11 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
ExprKind::Struct(struct_name, items) => {
|
||||
let type_key = CustomTypeKey(struct_name.clone(), state.module_id.unwrap());
|
||||
let struct_def = state
|
||||
.scope
|
||||
.get_struct_type(struct_name)
|
||||
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?
|
||||
.get_struct_type(&type_key)
|
||||
.ok_or(ErrorKind::NoSuchType(struct_name.clone(), type_key.1))?
|
||||
.clone();
|
||||
for (field_name, field_expr) in items {
|
||||
// Get expected type, or error if field does not exist
|
||||
@ -654,7 +663,7 @@ impl Expression {
|
||||
// Make sure both are the same type, report error if not
|
||||
state.ok(expr_ty.collapse_into(&expr_ty), field_expr.1);
|
||||
}
|
||||
Ok(TypeKind::CustomType(struct_name.clone()))
|
||||
Ok(TypeKind::CustomType(type_key))
|
||||
}
|
||||
ExprKind::Borrow(var_ref, mutable) => {
|
||||
let scope_var = state.scope.variables.get(&var_ref.1).cloned();
|
||||
|
@ -13,8 +13,8 @@ use super::{
|
||||
pass::{Pass, PassResult, PassState},
|
||||
typecheck::ErrorKind,
|
||||
typerefs::{ScopeTypeRefs, TypeRef, TypeRefs},
|
||||
Block, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind, IfExpression, Module,
|
||||
ReturnKind, StmtKind,
|
||||
Block, CustomTypeKey, ExprKind, Expression, FunctionDefinition, FunctionDefinitionKind,
|
||||
IfExpression, Module, ReturnKind, StmtKind,
|
||||
TypeKind::*,
|
||||
VagueType::*,
|
||||
};
|
||||
@ -138,7 +138,7 @@ impl Block {
|
||||
|
||||
// Fetch the declared return type
|
||||
let (kind, ty) = self
|
||||
.return_type(inner_refs.types)
|
||||
.return_type(inner_refs.types, state.module_id.unwrap())
|
||||
.ok()
|
||||
.unwrap_or((ReturnKind::Soft, Void));
|
||||
let mut ret_type_ref = outer_refs.from_type(&ty).unwrap();
|
||||
@ -183,8 +183,8 @@ impl Expression {
|
||||
type_refs
|
||||
.binop(op, &mut lhs_ref, &mut rhs_ref)
|
||||
.ok_or(ErrorKind::TypesIncompatible(
|
||||
lhs_ref.as_type(),
|
||||
rhs_ref.as_type(),
|
||||
lhs_ref.resolve_deep().unwrap(),
|
||||
rhs_ref.resolve_deep().unwrap(),
|
||||
))
|
||||
}
|
||||
ExprKind::FunctionCall(function_call) => {
|
||||
@ -320,11 +320,11 @@ impl Expression {
|
||||
// need for further resolution.
|
||||
let kind = expr_ty.resolve_weak().unwrap();
|
||||
match kind {
|
||||
CustomType(name) => {
|
||||
CustomType(key) => {
|
||||
let struct_ty = state
|
||||
.scope
|
||||
.get_struct_type(&name)
|
||||
.ok_or(ErrorKind::NoSuchType(name.clone()))?;
|
||||
.get_struct_type(&key)
|
||||
.ok_or(ErrorKind::NoSuchType(key.0.clone(), key.1))?;
|
||||
match struct_ty.get_field_ty(&field_name) {
|
||||
Some(field_ty) => {
|
||||
let mut elem_ty = type_refs.from_type(&type_kind).unwrap();
|
||||
@ -339,10 +339,14 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
ExprKind::Struct(struct_name, fields) => {
|
||||
let type_key = CustomTypeKey(struct_name.clone(), state.module_id.unwrap());
|
||||
let expected_struct_ty = state
|
||||
.scope
|
||||
.get_struct_type(&struct_name)
|
||||
.ok_or(ErrorKind::NoSuchType(struct_name.clone()))?
|
||||
.get_struct_type(&type_key)
|
||||
.ok_or(ErrorKind::NoSuchType(
|
||||
struct_name.clone(),
|
||||
state.module_id.unwrap(),
|
||||
))?
|
||||
.clone();
|
||||
for field in fields {
|
||||
if let Some(expected_field_ty) = expected_struct_ty.get_field_ty(&field.0) {
|
||||
@ -361,7 +365,7 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
Ok(type_refs
|
||||
.from_type(&TypeKind::CustomType(struct_name.clone()))
|
||||
.from_type(&TypeKind::CustomType(type_key.clone()))
|
||||
.unwrap())
|
||||
}
|
||||
ExprKind::Borrow(var, mutable) => {
|
||||
|
@ -9,7 +9,10 @@ use crate::mir::VagueType;
|
||||
use super::{typecheck::ErrorKind, BinaryOperator, TypeKind};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TypeRef<'scope>(TypeIdRef, &'scope ScopeTypeRefs<'scope>);
|
||||
pub struct TypeRef<'scope>(
|
||||
pub(super) TypeIdRef,
|
||||
pub(super) &'scope ScopeTypeRefs<'scope>,
|
||||
);
|
||||
|
||||
impl<'scope> TypeRef<'scope> {
|
||||
/// Resolve current type in a weak manner, not resolving any Arrays or
|
||||
@ -54,9 +57,9 @@ type TypeIdRef = Rc<RefCell<usize>>;
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TypeRefs {
|
||||
/// Simple list of types that variables can refrence
|
||||
hints: RefCell<Vec<TypeKind>>,
|
||||
pub(super) hints: RefCell<Vec<TypeKind>>,
|
||||
/// Indirect ID-references, referring to hints-vec
|
||||
type_refs: RefCell<Vec<TypeIdRef>>,
|
||||
pub(super) type_refs: RefCell<Vec<TypeIdRef>>,
|
||||
}
|
||||
|
||||
impl TypeRefs {
|
||||
@ -89,7 +92,7 @@ impl TypeRefs {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn recurse_type_ref(&self, mut idx: usize) -> TypeIdRef {
|
||||
pub(super) unsafe fn recurse_type_ref(&self, mut idx: usize) -> TypeIdRef {
|
||||
let refs = self.type_refs.borrow();
|
||||
let mut inner_idx = refs.get_unchecked(idx);
|
||||
let mut seen = HashSet::new();
|
||||
|
@ -10,13 +10,10 @@ mod util;
|
||||
fn test(source: &str, name: &str) {
|
||||
let mut map = Default::default();
|
||||
let (id, tokens) = assert_err(parse_module(source, name, &mut map));
|
||||
let module = assert_err(compile_module(id, &tokens, &mut map, None, true));
|
||||
let module = assert_err(compile_module(id, tokens, &mut map, None, true));
|
||||
|
||||
assert_err(perform_all_passes(
|
||||
&mut mir::Context {
|
||||
modules: vec![module],
|
||||
base: Default::default(),
|
||||
},
|
||||
&mut mir::Context::from(vec![module], Default::default()),
|
||||
&mut map,
|
||||
));
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ fn compiles() {
|
||||
#[test]
|
||||
fn passes_all_passes() {
|
||||
let mut map = Default::default();
|
||||
let Ok((mut std, _)) = compile_std(&mut map) else {
|
||||
let Ok(mut std) = compile_std(&mut map) else {
|
||||
panic!()
|
||||
};
|
||||
|
||||
@ -22,10 +22,7 @@ fn passes_all_passes() {
|
||||
std.is_main = true;
|
||||
|
||||
assert_err(perform_all_passes(
|
||||
&mut mir::Context {
|
||||
modules: vec![std],
|
||||
base: Default::default(),
|
||||
},
|
||||
&mut mir::Context::from(vec![std], Default::default()),
|
||||
&mut map,
|
||||
));
|
||||
}
|
||||
|
@ -1,8 +1,19 @@
|
||||
import std::print;
|
||||
import std::new_string;
|
||||
import std::add_char;
|
||||
import std::free_string;
|
||||
|
||||
fn main() -> i32 {
|
||||
let test = "hello world";
|
||||
print(test);
|
||||
let mut test = new_string();
|
||||
add_char(&mut test, 'h');
|
||||
add_char(&mut test, 'e');
|
||||
add_char(&mut test, 'l');
|
||||
add_char(&mut test, 'l');
|
||||
add_char(&mut test, 'o');
|
||||
|
||||
print(&test);
|
||||
|
||||
free_string(&mut test);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user