Compare commits

...

13 Commits

25 changed files with 689 additions and 203 deletions

View File

@ -36,7 +36,7 @@ Currently missing relevant features (TODOs) are:
- ~~Arrays~~ (DONE)
- Structs (and custom types as such)
- Extern functions
- Strings
- ~~Strings~~ (DONE)
- Loops
### Why "Reid"

View File

@ -1,4 +1,4 @@
use reid_lib::{ConstValue, Context, Instr, CmpPredicate, TerminatorKind, Type};
use reid_lib::{CmpPredicate, ConstValue, Context, FunctionFlags, Instr, TerminatorKind, Type};
fn main() {
use ConstValue::*;
@ -6,12 +6,17 @@ fn main() {
let context = Context::new();
let mut module = context.module("test");
let mut module = context.module("test", true);
let main = module.function("main", Type::I32, Vec::new());
let main = module.function("main", Type::I32, Vec::new(), FunctionFlags::default());
let mut m_entry = main.block("entry");
let fibonacci = module.function("fibonacci", Type::I32, vec![Type::I32]);
let fibonacci = module.function(
"fibonacci",
Type::I32,
vec![Type::I32],
FunctionFlags::default(),
);
let arg = m_entry.build(Constant(I32(5))).unwrap();
let fibonacci_call = m_entry

View File

@ -202,6 +202,10 @@ impl Builder {
}
}
pub(crate) fn find_module<'ctx>(&'ctx self, value: ModuleValue) -> ModuleHolder {
unsafe { self.modules.borrow().get_unchecked(value.0).clone() }
}
pub(crate) fn get_modules(&self) -> Rc<RefCell<Vec<ModuleHolder>>> {
self.modules.clone()
}
@ -268,7 +272,6 @@ impl Builder {
}
Store(ptr, _) => {
if let Ok(ty) = ptr.get_type(&self) {
dbg!(&ty);
if let Type::Ptr(_) = ty {
Ok(())
} else {
@ -369,7 +372,7 @@ impl ConstValue {
ConstValue::U32(_) => U32,
ConstValue::U64(_) => U64,
ConstValue::U128(_) => U128,
ConstValue::String(val) => String(val.len() as u32),
ConstValue::String(_) => Ptr(Box::new(I8)),
ConstValue::Bool(_) => Bool,
}
}
@ -390,7 +393,6 @@ impl Type {
Type::U128 => true,
Type::Bool => true,
Type::Void => false,
Type::String(_) => false,
Type::Ptr(_) => false,
}
}
@ -409,7 +411,6 @@ impl Type {
Type::U128 => false,
Type::Bool => false,
Type::Void => false,
Type::String(_) => false,
Type::Ptr(_) => false,
}
}

View File

@ -5,9 +5,10 @@
use std::{collections::HashMap, ffi::CString, ptr::null_mut};
use llvm_sys::{
LLVMIntPredicate,
LLVMIntPredicate, LLVMLinkage,
analysis::LLVMVerifyModule,
core::*,
linker::LLVMLinkModules2,
prelude::*,
target::{
LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos,
@ -34,8 +35,87 @@ pub struct LLVMContext {
builder_ref: LLVMBuilderRef,
}
impl Drop for LLVMContext {
fn drop(&mut self) {
unsafe {
LLVMDisposeBuilder(self.builder_ref);
LLVMContextDispose(self.context_ref);
}
}
}
pub struct CompiledModule {
module_ref: LLVMModuleRef,
_context: LLVMContext,
}
impl CompiledModule {
pub fn output(&self) {
unsafe {
LLVM_InitializeAllTargets();
LLVM_InitializeAllTargetInfos();
LLVM_InitializeAllTargetMCs();
LLVM_InitializeAllAsmParsers();
LLVM_InitializeAllAsmPrinters();
let triple = LLVMGetDefaultTargetTriple();
let mut target: _ = null_mut();
let mut err = ErrorMessageHolder::null();
LLVMGetTargetFromTriple(triple, &mut target, err.borrow_mut());
println!("{:?}, {:?}", from_cstring(triple), target);
err.into_result().unwrap();
let target_machine = LLVMCreateTargetMachine(
target,
triple,
c"generic".as_ptr(),
c"".as_ptr(),
llvm_sys::target_machine::LLVMCodeGenOptLevel::LLVMCodeGenLevelNone,
llvm_sys::target_machine::LLVMRelocMode::LLVMRelocDefault,
llvm_sys::target_machine::LLVMCodeModel::LLVMCodeModelDefault,
);
let data_layout = LLVMCreateTargetDataLayout(target_machine);
LLVMSetTarget(self.module_ref, triple);
LLVMSetModuleDataLayout(self.module_ref, data_layout);
let mut err = ErrorMessageHolder::null();
LLVMVerifyModule(
self.module_ref,
llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction,
err.borrow_mut(),
);
err.into_result().unwrap();
let mut err = ErrorMessageHolder::null();
LLVMTargetMachineEmitToFile(
target_machine,
self.module_ref,
CString::new("hello.asm").unwrap().into_raw(),
LLVMCodeGenFileType::LLVMAssemblyFile,
err.borrow_mut(),
);
err.into_result().unwrap();
let mut err = ErrorMessageHolder::null();
LLVMTargetMachineEmitToFile(
target_machine,
self.module_ref,
CString::new("hello.o").unwrap().into_raw(),
LLVMCodeGenFileType::LLVMObjectFile,
err.borrow_mut(),
);
err.into_result().unwrap();
let module_str = from_cstring(LLVMPrintModuleToString(self.module_ref));
println!("{}", module_str.unwrap());
}
}
}
impl Context {
pub fn compile(&self) {
pub fn compile(&self) -> CompiledModule {
unsafe {
let context_ref = LLVMContextCreate();
@ -44,12 +124,29 @@ impl Context {
builder_ref: LLVMCreateBuilderInContext(context_ref),
};
for holder in self.builder.get_modules().borrow().iter() {
holder.compile(&context, &self.builder);
let module_holders = self.builder.get_modules();
let main_module = module_holders
.borrow()
.iter()
.find(|m| m.data.name == "main")
.unwrap_or(module_holders.borrow().first().unwrap())
.clone();
let main_module_ref = main_module.compile(&context, &self.builder);
for holder in module_holders.borrow().iter() {
if holder.value == main_module.value {
continue;
}
let module_ref = holder.compile(&context, &self.builder);
LLVMLinkModules2(main_module_ref, module_ref);
}
LLVMDisposeBuilder(context.builder_ref);
LLVMContextDispose(context.context_ref);
CompiledModule {
module_ref: main_module_ref,
_context: context,
}
}
}
}
@ -77,7 +174,7 @@ pub struct LLVMValue {
}
impl ModuleHolder {
fn compile(&self, context: &LLVMContext, builder: &Builder) {
fn compile(&self, context: &LLVMContext, builder: &Builder) -> LLVMModuleRef {
unsafe {
let module_ref = LLVMModuleCreateWithNameInContext(
into_cstring(&self.data.name).as_ptr(),
@ -106,67 +203,10 @@ impl ModuleHolder {
};
for function in &self.functions {
function.compile(&mut module);
function.compile(&mut module, self.data.is_main);
}
LLVM_InitializeAllTargets();
LLVM_InitializeAllTargetInfos();
LLVM_InitializeAllTargetMCs();
LLVM_InitializeAllAsmParsers();
LLVM_InitializeAllAsmPrinters();
let triple = LLVMGetDefaultTargetTriple();
let mut target: _ = null_mut();
let mut err = ErrorMessageHolder::null();
LLVMGetTargetFromTriple(triple, &mut target, err.borrow_mut());
println!("{:?}, {:?}", from_cstring(triple), target);
err.into_result().unwrap();
let target_machine = LLVMCreateTargetMachine(
target,
triple,
c"generic".as_ptr(),
c"".as_ptr(),
llvm_sys::target_machine::LLVMCodeGenOptLevel::LLVMCodeGenLevelNone,
llvm_sys::target_machine::LLVMRelocMode::LLVMRelocDefault,
llvm_sys::target_machine::LLVMCodeModel::LLVMCodeModelDefault,
);
let data_layout = LLVMCreateTargetDataLayout(target_machine);
LLVMSetTarget(module_ref, triple);
LLVMSetModuleDataLayout(module_ref, data_layout);
let mut err = ErrorMessageHolder::null();
LLVMVerifyModule(
module_ref,
llvm_sys::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction,
err.borrow_mut(),
);
err.into_result().unwrap();
let mut err = ErrorMessageHolder::null();
LLVMTargetMachineEmitToFile(
target_machine,
module_ref,
CString::new("hello.asm").unwrap().into_raw(),
LLVMCodeGenFileType::LLVMAssemblyFile,
err.borrow_mut(),
);
err.into_result().unwrap();
let mut err = ErrorMessageHolder::null();
LLVMTargetMachineEmitToFile(
target_machine,
module_ref,
CString::new("hello.o").unwrap().into_raw(),
LLVMCodeGenFileType::LLVMObjectFile,
err.borrow_mut(),
);
err.into_result().unwrap();
let module_str = from_cstring(LLVMPrintModuleToString(module_ref));
println!("{}", module_str.unwrap());
module_ref
}
}
}
@ -200,10 +240,26 @@ impl FunctionHolder {
}
}
unsafe fn compile(&self, module: &mut LLVMModule) {
unsafe fn compile(&self, module: &mut LLVMModule, in_main_module: bool) {
unsafe {
let own_function = *module.functions.get(&self.value).unwrap();
if self.data.flags.is_extern {
LLVMSetLinkage(own_function.value_ref, LLVMLinkage::LLVMExternalLinkage);
// Use "available internally" if the other kind of extern
return;
}
if self.data.flags.is_imported && !in_main_module {
LLVMSetLinkage(own_function.value_ref, LLVMLinkage::LLVMExternalLinkage);
} else {
LLVMSetLinkage(own_function.value_ref, LLVMLinkage::LLVMPrivateLinkage);
}
if in_main_module && self.data.flags.is_main {
LLVMSetLinkage(own_function.value_ref, LLVMLinkage::LLVMExternalLinkage);
}
for block in &self.blocks {
if block.data.deleted {
continue;
@ -304,14 +360,22 @@ impl InstructionHolder {
.map(|i| module.values.get(i).unwrap().value_ref)
.collect();
LLVMBuildCall2(
let is_void = module.builder.function_data(&*function_value).ret == Type::Void;
if is_void {
LLVMContextSetDiscardValueNames(module.context_ref, 1);
}
let value = LLVMBuildCall2(
module.builder_ref,
fun.type_ref,
fun.value_ref,
param_list.as_mut_ptr(),
param_list.len() as u32,
c"call".as_ptr(),
)
);
if is_void {
LLVMContextSetDiscardValueNames(module.context_ref, 0);
}
value
}
Phi(values) => {
let mut inc_values = Vec::new();
@ -457,9 +521,11 @@ impl ConstValue {
ConstValue::U32(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::U64(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::U128(val) => LLVMConstInt(t, *val as u64, 1),
ConstValue::String(val) => {
LLVMBuildGlobalString(builder, into_cstring(val).as_ptr(), c"string".as_ptr())
}
ConstValue::String(val) => LLVMBuildGlobalStringPtr(
builder,
into_cstring(val).as_ptr(),
c"string".as_ptr(),
),
}
}
}
@ -476,9 +542,8 @@ impl Type {
I64 | U64 => LLVMInt64TypeInContext(context),
I128 | U128 => LLVMInt128TypeInContext(context),
Bool => LLVMInt1TypeInContext(context),
Void => LLVMVoidType(),
Void => LLVMVoidTypeInContext(context),
Ptr(ty) => LLVMPointerType(ty.as_llvm(context), 0),
String(length) => LLVMArrayType(LLVMInt8TypeInContext(context), *length),
}
}
}

View File

@ -1,6 +1,9 @@
//! Debug implementations for relevant types
use std::fmt::{Debug, Write};
use std::{
fmt::{Debug, Write},
marker::PhantomData,
};
use crate::{CmpPredicate, Instr, InstructionData, TerminatorKind, builder::*};
@ -11,6 +14,17 @@ impl Debug for Builder {
}
}
pub struct PrintableModule<'ctx> {
pub phantom: PhantomData<&'ctx ()>,
pub module: ModuleHolder,
}
impl<'ctx> Debug for PrintableModule<'ctx> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.module.fmt(f)
}
}
impl Debug for ModuleHolder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(&format!("{}({:#?}) ", self.data.name, self.value))

View File

@ -2,9 +2,10 @@
//! Low-Level IR (LLIR) using [`Context`] and [`Builder`]. This Builder can then
//! be used at the end to compile said LLIR into LLVM IR.
use std::marker::PhantomData;
use std::{fmt::Debug, marker::PhantomData};
use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue};
use debug::PrintableModule;
pub mod builder;
pub mod compile;
@ -25,9 +26,10 @@ impl Context {
}
}
pub fn module<'ctx>(&'ctx self, name: &str) -> Module<'ctx> {
pub fn module<'ctx>(&'ctx self, name: &str, main: bool) -> Module<'ctx> {
let value = self.builder.add_module(ModuleData {
name: name.to_owned(),
is_main: main,
});
Module {
phantom: PhantomData,
@ -40,6 +42,7 @@ impl Context {
#[derive(Debug, Clone, Hash)]
pub struct ModuleData {
name: String,
is_main: bool,
}
pub struct Module<'ctx> {
@ -49,7 +52,13 @@ pub struct Module<'ctx> {
}
impl<'ctx> Module<'ctx> {
pub fn function(&mut self, name: &str, ret: Type, params: Vec<Type>) -> Function<'ctx> {
pub fn function(
&mut self,
name: &str,
ret: Type,
params: Vec<Type>,
flags: FunctionFlags,
) -> Function<'ctx> {
unsafe {
Function {
phantom: PhantomData,
@ -60,6 +69,7 @@ impl<'ctx> Module<'ctx> {
name: name.to_owned(),
ret,
params,
flags,
},
),
}
@ -69,6 +79,13 @@ impl<'ctx> Module<'ctx> {
pub fn value(&self) -> ModuleValue {
self.value
}
pub fn as_printable(&self) -> PrintableModule<'ctx> {
PrintableModule {
phantom: PhantomData,
module: self.builder.find_module(self.value),
}
}
}
#[derive(Debug, Clone, Hash)]
@ -76,6 +93,26 @@ pub struct FunctionData {
name: String,
ret: Type,
params: Vec<Type>,
flags: FunctionFlags,
}
#[derive(Debug, Clone, Copy, Hash)]
pub struct FunctionFlags {
pub is_extern: bool,
pub is_main: bool,
pub is_pub: bool,
pub is_imported: bool,
}
impl Default for FunctionFlags {
fn default() -> FunctionFlags {
FunctionFlags {
is_extern: false,
is_main: false,
is_pub: false,
is_imported: false,
}
}
}
pub struct Function<'ctx> {
@ -200,7 +237,6 @@ pub enum Type {
U128,
Bool,
Void,
String(u32),
Ptr(Box<Type>),
}

View File

@ -1,12 +1,14 @@
use std::{env, fs};
use std::{env, fs, path::PathBuf};
use reid::compile;
fn main() -> Result<(), std::io::Error> {
let args: Vec<String> = env::args().collect();
if let Some(filename) = args.get(1) {
let text = fs::read_to_string(filename)?;
let output = match compile(&text) {
let path = PathBuf::from(filename);
let text = fs::read_to_string(&path)?;
let output = match compile(&text, PathBuf::from(path)) {
Ok(t) => t,
Err(e) => panic!("{}", e),
};

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use reid::mir::{self, *};
use reid_lib::Context;
@ -7,6 +9,8 @@ fn main() {
let fibonacci = FunctionDefinition {
name: fibonacci_name.clone(),
is_pub: false,
is_imported: false,
return_type: TypeKind::I32,
parameters: vec![(fibonacci_n.clone(), TypeKind::I32)],
kind: FunctionDefinitionKind::Local(
@ -127,6 +131,8 @@ fn main() {
let main = FunctionDefinition {
name: "main".to_owned(),
is_pub: false,
is_imported: false,
return_type: TypeKind::I32,
parameters: vec![],
kind: FunctionDefinitionKind::Local(
@ -157,7 +163,10 @@ fn main() {
name: "test module".to_owned(),
imports: vec![],
functions: vec![fibonacci, main],
path: None,
is_main: true,
}],
base: PathBuf::new(),
};
println!("test1");

View File

@ -1,6 +1,8 @@
//! This is the module that contains relevant code to parsing Reid, that is to
//! say transforming a Vec of FullTokens into a loose parsed AST that can be
//! used for unwrapping syntax sugar, and then be transformed into Reid MIR.
use std::path::PathBuf;
use crate::token_stream::TokenRange;
pub mod parse;
@ -22,6 +24,7 @@ pub enum TypeKind {
U32,
U64,
U128,
String,
Array(Box<TypeKind>, u64),
}
@ -109,7 +112,7 @@ pub struct LetStatement(
pub struct ImportStatement(pub Vec<String>, pub TokenRange);
#[derive(Debug)]
pub struct FunctionDefinition(pub FunctionSignature, pub Block, pub TokenRange);
pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub TokenRange);
#[derive(Debug, Clone)]
pub struct FunctionSignature {
@ -157,6 +160,7 @@ pub enum BlockLevelStatement {
#[derive(Debug)]
pub enum TopLevelStatement {
Import(ImportStatement),
ExternFunction(FunctionSignature),
FunctionDefinition(FunctionDefinition),
}
@ -164,4 +168,6 @@ pub enum TopLevelStatement {
pub struct Module {
pub name: String,
pub top_level_statements: Vec<TopLevelStatement>,
pub path: Option<PathBuf>,
pub is_main: bool,
}

View File

@ -38,6 +38,7 @@ impl Parse for Type {
"u32" => TypeKind::U32,
"u64" => TypeKind::U64,
"u128" => TypeKind::U128,
"string" => TypeKind::String,
_ => Err(stream.expected_err("known type identifier")?)?,
}
} else {
@ -307,9 +308,17 @@ impl Parse for ImportStatement {
impl Parse for FunctionDefinition {
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
let is_pub = if let Some(Token::PubKeyword) = stream.peek() {
stream.next(); // Consume pub
true
} else {
false
};
stream.expect(Token::FnKeyword)?;
Ok(FunctionDefinition(
stream.parse()?,
is_pub,
stream.parse()?,
stream.get_range().unwrap(),
))
@ -392,9 +401,7 @@ impl Parse for VariableReference {
stream.get_range().unwrap(),
);
dbg!(&var_ref);
while let Ok(ValueIndex(idx)) = stream.parse() {
dbg!(idx);
var_ref = VariableReference(
VariableReferenceKind::Index(Box::new(var_ref), idx),
stream.get_range().unwrap(),
@ -474,7 +481,16 @@ impl Parse for TopLevelStatement {
use TopLevelStatement as Stmt;
Ok(match stream.peek() {
Some(Token::ImportKeyword) => Stmt::Import(stream.parse()?),
Some(Token::FnKeyword) => Stmt::FunctionDefinition(stream.parse()?),
Some(Token::Extern) => {
stream.next(); // Consume Extern
stream.expect(Token::FnKeyword)?;
let extern_fn = Stmt::ExternFunction(stream.parse()?);
stream.expect(Token::Semi)?;
extern_fn
}
Some(Token::FnKeyword) | Some(Token::PubKeyword) => {
Stmt::FunctionDefinition(stream.parse()?)
}
_ => Err(stream.expected_err("import or fn")?)?,
})
}

View File

@ -1,18 +1,18 @@
use std::path::PathBuf;
use crate::{
ast::{self},
mir::{self, NamedVariableRef, StmtKind},
};
impl mir::Context {
pub fn from(modules: Vec<ast::Module>) -> mir::Context {
mir::Context {
modules: modules.iter().map(|m| m.process()).collect(),
}
pub fn from(modules: Vec<mir::Module>, base: PathBuf) -> mir::Context {
mir::Context { modules, base }
}
}
impl ast::Module {
fn process(&self) -> mir::Module {
pub fn process(&self) -> mir::Module {
let mut imports = Vec::new();
let mut functions = Vec::new();
@ -20,13 +20,13 @@ impl ast::Module {
for stmt in &self.top_level_statements {
match stmt {
Import(import) => {
for name in &import.0 {
imports.push(mir::Import(name.clone(), import.1.into()));
}
imports.push(mir::Import(import.0.clone(), import.1.into()));
}
FunctionDefinition(ast::FunctionDefinition(signature, block, range)) => {
FunctionDefinition(ast::FunctionDefinition(signature, is_pub, block, range)) => {
let def = mir::FunctionDefinition {
name: signature.name.clone(),
is_pub: *is_pub,
is_imported: false,
return_type: signature
.return_type
.clone()
@ -42,6 +42,26 @@ impl ast::Module {
};
functions.push(def);
}
ExternFunction(signature) => {
let def = mir::FunctionDefinition {
name: signature.name.clone(),
is_pub: false,
is_imported: false,
return_type: signature
.return_type
.clone()
.map(|r| r.0.into())
.unwrap_or(mir::TypeKind::Void),
parameters: signature
.args
.iter()
.cloned()
.map(|p| (p.0, p.1.into()))
.collect(),
kind: mir::FunctionDefinitionKind::Extern,
};
functions.push(def);
}
}
}
@ -49,6 +69,8 @@ impl ast::Module {
name: self.name.clone(),
imports,
functions,
path: self.path.clone(),
is_main: self.is_main,
}
}
}
@ -226,6 +248,7 @@ impl From<ast::TypeKind> for mir::TypeKind {
ast::TypeKind::Array(type_kind, length) => {
mir::TypeKind::Array(Box::new(mir::TypeKind::from(*type_kind.clone())), *length)
}
ast::TypeKind::String => mir::TypeKind::StringPtr,
}
}
}

View File

@ -1,8 +1,8 @@
use std::{collections::HashMap, mem};
use reid_lib::{
builder::InstructionValue, Block, CmpPredicate, ConstValue, Context, Function, Instr, Module,
TerminatorKind as Term, Type,
builder::InstructionValue, compile::CompiledModule, Block, CmpPredicate, ConstValue, Context,
Function, FunctionFlags, Instr, Module, TerminatorKind as Term, Type,
};
use crate::mir::{self, types::ReturnType, IndexedVariableReference, NamedVariableRef, TypeKind};
@ -11,16 +11,14 @@ use crate::mir::{self, types::ReturnType, IndexedVariableReference, NamedVariabl
/// LLIR that can then be finally compiled into LLVM IR.
#[derive(Debug)]
pub struct CodegenContext<'ctx> {
modules: Vec<ModuleCodegen<'ctx>>,
context: &'ctx Context,
}
impl<'ctx> CodegenContext<'ctx> {
/// Compile contained LLIR into LLVM IR and produce `hello.o` and
/// `hello.asm`
pub fn compile(&self) {
for module in &self.modules {
module.context.compile();
}
pub fn compile(&self) -> CompiledModule {
self.context.compile()
}
}
@ -31,24 +29,23 @@ impl mir::Context {
for module in &self.modules {
modules.push(module.codegen(context));
}
CodegenContext { modules }
CodegenContext { context }
}
}
struct ModuleCodegen<'ctx> {
pub context: &'ctx Context,
_module: Module<'ctx>,
module: Module<'ctx>,
}
impl<'ctx> std::fmt::Debug for ModuleCodegen<'ctx> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.context.fmt(f)
std::fmt::Debug::fmt(&self.module.as_printable(), f)
}
}
impl mir::Module {
fn codegen<'ctx>(&self, context: &'ctx Context) -> ModuleCodegen<'ctx> {
let mut module = context.module(&self.name);
let mut module = context.module(&self.name, self.is_main);
let mut functions = HashMap::new();
@ -59,11 +56,28 @@ impl mir::Module {
.map(|(_, p)| p.get_type())
.collect();
let is_main = self.is_main && function.name == "main";
let func = match &function.kind {
mir::FunctionDefinitionKind::Local(_, _) => {
module.function(&function.name, function.return_type.get_type(), param_types)
}
mir::FunctionDefinitionKind::Extern => todo!(),
mir::FunctionDefinitionKind::Local(_, _) => module.function(
&function.name,
function.return_type.get_type(),
param_types,
FunctionFlags {
is_pub: function.is_pub || is_main,
is_main,
is_imported: function.is_imported,
..FunctionFlags::default()
},
),
mir::FunctionDefinitionKind::Extern => module.function(
&function.name,
function.return_type.get_type(),
param_types,
FunctionFlags {
is_extern: true,
..FunctionFlags::default()
},
),
};
functions.insert(function.name.clone(), func);
}
@ -107,10 +121,7 @@ impl mir::Module {
}
}
ModuleCodegen {
context,
_module: module,
}
ModuleCodegen { module }
}
}
@ -495,7 +506,7 @@ impl TypeKind {
TypeKind::U64 => Type::U64,
TypeKind::U128 => Type::U128,
TypeKind::Bool => Type::Bool,
TypeKind::String(length) => Type::String(*length as u32),
TypeKind::StringPtr => Type::Ptr(Box::new(Type::I8)),
TypeKind::Array(elem_t, _) => Type::Ptr(Box::new(elem_t.get_type())),
TypeKind::Void => Type::Void,
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),

View File

@ -22,6 +22,8 @@ pub enum Token {
ReturnKeyword,
/// `fn`
FnKeyword,
/// `pub`
PubKeyword,
/// `->`
Arrow,
/// `if`
@ -32,6 +34,8 @@ pub enum Token {
True,
/// `false`
False,
/// `extern`
Extern,
// Symbols
/// `;`
@ -205,6 +209,8 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
"else" => Token::Else,
"true" => Token::True,
"false" => Token::False,
"extern" => Token::Extern,
"pub" => Token::PubKeyword,
_ => Token::Identifier(value),
};
variant
@ -261,7 +267,7 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
Ok(tokens)
}
#[derive(thiserror::Error, Debug)]
#[derive(thiserror::Error, Debug, Clone)]
pub enum Error {
#[error("Invalid token '{}' at Ln {}, Col {}", .0, (.1).1, (.1).0)]
InvalidToken(char, Position),

View File

@ -36,11 +36,15 @@
//! - ~~Arrays~~ (DONE)
//! - Structs (and custom types as such)
//! - Extern functions
//! - Strings
//! - ~~Strings~~ (DONE)
//! - Loops
//! ```
use mir::{typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs};
use std::path::PathBuf;
use mir::{
linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs,
};
use reid_lib::Context;
use crate::{ast::TopLevelStatement, lexer::Token, token_stream::TokenStream};
@ -53,7 +57,7 @@ mod pad_adapter;
mod token_stream;
mod util;
#[derive(thiserror::Error, Debug)]
#[derive(thiserror::Error, Debug, Clone)]
pub enum ReidError {
#[error(transparent)]
LexerError(#[from] lexer::Error),
@ -61,12 +65,18 @@ pub enum ReidError {
ParserError(#[from] token_stream::Error),
#[error("Errors during typecheck: {0:?}")]
TypeCheckErrors(Vec<mir::pass::Error<mir::typecheck::ErrorKind>>),
#[error("Errors during type inference: {0:?}")]
TypeInferenceErrors(Vec<mir::pass::Error<mir::typecheck::ErrorKind>>),
#[error("Errors during linking: {0:?}")]
LinkerErrors(Vec<mir::pass::Error<mir::linker::ErrorKind>>),
}
/// Takes in a bit of source code, parses and compiles it and produces `hello.o`
/// and `hello.asm` from it, which can be linked using `ld` to produce an
/// executable file.
pub fn compile(source: &str) -> Result<String, ReidError> {
pub fn compile_module(
source: &str,
name: String,
path: Option<PathBuf>,
is_main: bool,
) -> Result<mir::Module, ReidError> {
let tokens = lexer::tokenize(source)?;
dbg!(&tokens);
@ -81,15 +91,41 @@ pub fn compile(source: &str) -> Result<String, ReidError> {
}
let ast_module = ast::Module {
name: "test".to_owned(),
name,
top_level_statements: statements,
path,
is_main,
};
dbg!(&ast_module);
let mut mir_context = mir::Context::from(vec![ast_module]);
Ok(ast_module.process())
}
/// Takes in a bit of source code, parses and compiles it and produces `hello.o`
/// and `hello.asm` from it, which can be linked using `ld` to produce an
/// executable file.
pub fn compile(source: &str, path: PathBuf) -> Result<String, ReidError> {
let path = path.canonicalize().unwrap();
let mut mir_context = mir::Context::from(
vec![compile_module(
source,
path.file_name().unwrap().to_str().unwrap().to_owned(),
Some(path.clone()),
true,
)?],
path.parent().unwrap().to_owned(),
);
println!("{}", &mir_context);
let state = mir_context.pass(&mut LinkerPass);
dbg!(&state);
println!("{}", &mir_context);
if !state.errors.is_empty() {
return Err(ReidError::LinkerErrors(state.errors));
}
let refs = TypeRefs::default();
let state = mir_context.pass(&mut TypeInference { refs: &refs });
@ -97,6 +133,10 @@ pub fn compile(source: &str) -> Result<String, ReidError> {
dbg!(&mir_context);
println!("{}", &mir_context);
// if !state.errors.is_empty() {
// return Err(ReidError::TypeInferenceErrors(state.errors));
// }
let state = mir_context.pass(&mut TypeCheck { refs: &refs });
dbg!(&state);
println!("{}", &mir_context);
@ -109,7 +149,8 @@ pub fn compile(source: &str) -> Result<String, ReidError> {
let codegen_modules = mir_context.codegen(&mut context);
dbg!(&codegen_modules);
codegen_modules.compile();
let compiled = codegen_modules.compile();
compiled.output();
Ok(String::new())
}

View File

@ -32,7 +32,7 @@ impl Display for Module {
impl Display for Import {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "import {}", self.0)
write!(f, "import {}", self.0.join("::"))
}
}
@ -40,7 +40,8 @@ impl Display for FunctionDefinition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"fn {}({}) -> {} ",
"{}fn {}({}) -> {} ",
if self.is_pub { "pub " } else { "" },
self.name,
self.parameters
.iter()

193
reid/src/mir/linker.rs Normal file
View File

@ -0,0 +1,193 @@
use std::{
cell::RefCell,
collections::HashMap,
convert::Infallible,
fs::{self},
path::PathBuf,
rc::Rc,
};
use crate::{compile_module, ReidError};
use super::{
pass::{Pass, PassState},
types::EqualsIssue,
Context, FunctionDefinition, Import, Metadata, Module,
};
#[derive(thiserror::Error, Debug, Clone)]
pub enum ErrorKind {
#[error("Unable to import inner modules, not yet supported: {0}")]
InnerModulesNotYetSupported(Import),
#[error("No such module: {0}")]
ModuleNotFound(String),
#[error("Error while compiling module {0}: {1}")]
ModuleCompilationError(String, ReidError),
#[error("No such function {0} found in module {1}")]
NoSuchFunctionInModule(String, String),
#[error("Importing function {0}::{1} not possible: {2}")]
FunctionImportIssue(String, String, EqualsIssue),
#[error("Tried linking another main module: {0}")]
TriedLinkingMain(String),
#[error("Multiple Mains at the start!")]
MultipleMainsAtStart,
#[error("No Main-module found!")]
NoMainDefined,
#[error("Main module has no main-function!")]
NoMainFunction,
#[error("Function {1} in module {0} is private!")]
FunctionIsPrivate(String, String),
}
/// Struct used to implement a type-checking pass that can be performed on the
/// MIR.
pub struct LinkerPass;
impl Pass for LinkerPass {
type TError = ErrorKind;
fn context(&mut self, context: &mut Context, mut state: PassState<Self::TError>) {
let mains = context
.modules
.iter()
.filter(|m| m.is_main)
.collect::<Vec<_>>();
if mains.len() > 1 {
state.note_errors(&vec![ErrorKind::MultipleMainsAtStart], Metadata::default());
return;
}
let Some(main) = mains.first() else {
state.note_errors(&vec![ErrorKind::NoMainDefined], Metadata::default());
return;
};
let Some(_) = main.functions.iter().find(|f| f.name == "main") else {
state.note_errors(&vec![ErrorKind::NoMainFunction], Metadata::default());
return;
};
let mut modules = HashMap::<String, Rc<RefCell<Module>>>::new();
for module in context.modules.drain(..) {
modules.insert(module.name.clone(), Rc::new(RefCell::new(module)));
}
let mut modules_to_process: Vec<Rc<RefCell<Module>>> = modules.values().cloned().collect();
while let Some(module) = modules_to_process.pop() {
let mut importer_module = module.borrow_mut();
for import in importer_module.imports.clone() {
let Import(path, _) = &import;
if path.len() != 2 {
state.ok::<_, Infallible>(
Err(ErrorKind::InnerModulesNotYetSupported(import.clone())),
import.1,
);
}
let module_name = unsafe { path.get_unchecked(0) };
let mut imported = if let Some(module) = modules.get_mut(module_name) {
module
} else {
let file_path =
PathBuf::from(&context.base.clone()).join(module_name.to_owned() + ".reid");
let Ok(source) = fs::read_to_string(&file_path) else {
state.ok::<_, Infallible>(
Err(ErrorKind::ModuleNotFound(module_name.clone())),
import.1,
);
continue;
};
match compile_module(&source, module_name.clone(), Some(file_path), false) {
Ok(imported_module) => {
if imported_module.is_main {
state.ok::<_, Infallible>(
Err(ErrorKind::TriedLinkingMain(module_name.clone())),
import.1,
);
continue;
}
let module_name = imported_module.name.clone();
modules.insert(
module_name.clone(),
Rc::new(RefCell::new(imported_module)),
);
let imported = modules.get_mut(&module_name).unwrap();
modules_to_process.push(imported.clone());
imported
}
Err(err) => {
state.ok::<_, Infallible>(
Err(ErrorKind::ModuleCompilationError(module_name.clone(), err)),
import.1,
);
continue;
}
}
}
.borrow_mut();
let func_name = unsafe { path.get_unchecked(1) };
let Some(func) = imported.functions.iter_mut().find(|f| f.name == *func_name)
else {
state.ok::<_, Infallible>(
Err(ErrorKind::NoSuchFunctionInModule(
module_name.clone(),
func_name.clone(),
)),
import.1,
);
continue;
};
if !func.is_pub {
state.ok::<_, Infallible>(
Err(ErrorKind::FunctionIsPrivate(
module_name.clone(),
func_name.clone(),
)),
import.1,
);
continue;
}
func.is_imported = true;
if let Some(existing) = importer_module
.functions
.iter()
.find(|f| f.name == *func_name)
{
if let Err(e) = existing.equals_as_imported(func) {
state.ok::<_, Infallible>(
Err(ErrorKind::FunctionImportIssue(
module_name.clone(),
func_name.clone(),
e,
)),
import.1,
);
}
}
importer_module.functions.push(FunctionDefinition {
name: func.name.clone(),
is_pub: false,
is_imported: false,
return_type: func.return_type.clone(),
parameters: func.parameters.clone(),
kind: super::FunctionDefinitionKind::Extern,
});
}
}
context.modules = modules
.into_values()
.map(|v| Rc::into_inner(v).unwrap().into_inner())
.collect();
}
}

View File

@ -2,9 +2,12 @@
//! Reid. It contains a simplified version of Reid which can be e.g.
//! typechecked.
use std::path::PathBuf;
use crate::token_stream::TokenRange;
mod display;
pub mod linker;
pub mod pass;
pub mod typecheck;
pub mod typeinference;
@ -59,7 +62,7 @@ pub enum TypeKind {
#[error("void")]
Void,
#[error("string")]
String(usize),
StringPtr,
#[error("[{0}; {1}]")]
Array(Box<TypeKind>, u64),
#[error(transparent)]
@ -102,7 +105,7 @@ impl TypeKind {
TypeKind::U32 => false,
TypeKind::U64 => false,
TypeKind::U128 => false,
TypeKind::String(_) => false,
TypeKind::StringPtr => false,
TypeKind::Array(_, _) => false,
}
}
@ -123,7 +126,7 @@ impl TypeKind {
Bool => true,
Vague(_) => false,
Void => false,
TypeKind::String(_) => false,
TypeKind::StringPtr => false,
Array(_, _) => false,
}
}
@ -165,7 +168,7 @@ impl Literal {
Literal::U64(_) => TypeKind::U64,
Literal::U128(_) => TypeKind::U128,
Literal::Bool(_) => TypeKind::Bool,
Literal::String(val) => TypeKind::String(val.len()),
Literal::String(_) => TypeKind::StringPtr,
Literal::Vague(VagueLiteral::Number(_)) => TypeKind::Vague(VagueType::Number),
}
}
@ -208,8 +211,8 @@ pub enum ReturnKind {
#[derive(Debug)]
pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata);
#[derive(Debug)]
pub struct Import(pub String, pub Metadata);
#[derive(Debug, Clone)]
pub struct Import(pub Vec<String>, pub Metadata);
#[derive(Debug)]
pub enum ExprKind {
@ -240,6 +243,8 @@ pub struct FunctionCall {
#[derive(Debug)]
pub struct FunctionDefinition {
pub name: String,
pub is_pub: bool,
pub is_imported: bool,
pub return_type: TypeKind,
pub parameters: Vec<(String, TypeKind)>,
pub kind: FunctionDefinitionKind,
@ -305,9 +310,12 @@ pub struct Module {
pub name: String,
pub imports: Vec<Import>,
pub functions: Vec<FunctionDefinition>,
pub path: Option<PathBuf>,
pub is_main: bool,
}
#[derive(Debug)]
pub struct Context {
pub modules: Vec<Module>,
pub base: PathBuf,
}

View File

@ -191,6 +191,7 @@ impl<'st, 'sc, TError: STDError + Clone> PassState<'st, 'sc, TError> {
pub trait Pass {
type TError: STDError + Clone;
fn context(&mut self, _context: &mut Context, mut _state: PassState<Self::TError>) {}
fn module(&mut self, _module: &mut Module, mut _state: PassState<Self::TError>) {}
fn function(
&mut self,
@ -207,6 +208,7 @@ impl Context {
pub fn pass<T: Pass>(&mut self, pass: &mut T) -> State<T::TError> {
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 {
module.pass(pass, &mut state, &mut scope);
}
@ -232,7 +234,7 @@ impl Module {
pass.module(self, PassState::from(state, scope));
for function in &mut self.functions {
function.pass(pass, state, scope);
function.pass(pass, state, &mut scope.inner());
}
}
}

View File

@ -3,7 +3,7 @@
use std::{convert::Infallible, iter};
use crate::{mir::*, util::try_all};
use VagueType::*;
use VagueType as Vague;
use super::{
pass::{Pass, PassState, ScopeFunction, ScopeVariable, Storage},
@ -56,7 +56,7 @@ impl<'t> Pass for TypeCheck<'t> {
fn module(&mut self, module: &mut Module, mut state: PassState<ErrorKind>) {
for function in &mut module.functions {
let res = function.typecheck(&self.refs, &mut state);
let res = function.typecheck(&self.refs, &mut state.inner());
state.ok(res, function.block_meta());
}
}
@ -71,7 +71,7 @@ impl FunctionDefinition {
for param in &self.parameters {
let param_t = state.or_else(
param.1.assert_known(),
TypeKind::Vague(Unknown),
TypeKind::Vague(Vague::Unknown),
self.signature(),
);
let res = state
@ -92,9 +92,11 @@ impl FunctionDefinition {
let inferred = match &mut self.kind {
FunctionDefinitionKind::Local(block, _) => {
state.scope.return_type_hint = Some(self.return_type.clone());
block.typecheck(state, &hints, Some(&return_type))
block.typecheck(&mut state.inner(), &hints, Some(&return_type))
}
FunctionDefinitionKind::Extern => {
Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)))
}
FunctionDefinitionKind::Extern => Ok((ReturnKind::Soft, TypeKind::Vague(Unknown))),
};
match inferred {
@ -128,12 +130,12 @@ impl Block {
// If expression resolution itself was erronous, resolve as
// Unknown and note error.
let res = state.or_else(res, TypeKind::Vague(Unknown), expression.1);
let res = state.or_else(res, TypeKind::Vague(Vague::Unknown), expression.1);
// Make sure the expression and variable type really is the same
let res_t = state.or_else(
res.collapse_into(&var_t_resolved),
TypeKind::Vague(Unknown),
TypeKind::Vague(Vague::Unknown),
variable_reference.2 + expression.1,
);
@ -141,7 +143,7 @@ impl Block {
// Unable to infer variable type even from expression! Default it
let res_t = state.or_else(
res_t.or_default(),
TypeKind::Vague(Unknown),
TypeKind::Vague(Vague::Unknown),
variable_reference.2,
);
@ -187,13 +189,14 @@ impl Block {
// If expression resolution itself was erronous, resolve as
// Unknown.
let expr_ty = state.or_else(res, TypeKind::Vague(Unknown), expression.1);
let expr_ty =
state.or_else(res, TypeKind::Vague(Vague::Unknown), expression.1);
// Make sure the expression and variable type to really
// be the same
let res_t = state.or_else(
expr_ty.collapse_into(&var.ty.resolve_hinted(&hints)),
TypeKind::Vague(Unknown),
TypeKind::Vague(Vague::Unknown),
variable_reference.meta + expression.1,
);
@ -241,7 +244,7 @@ impl Block {
let res = expr.typecheck(&mut state, &hints, hint.as_ref());
return Ok((
ReturnKind::Hard,
state.or_else(res, TypeKind::Vague(Unknown), expr.1),
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
));
}
@ -254,7 +257,7 @@ impl Block {
let res = expr.typecheck(&mut state, &hints, ret_hint_t.as_ref());
Ok((
*return_kind,
state.or_else(res, TypeKind::Vague(Unknown), expr.1),
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
))
} else {
Ok((ReturnKind::Soft, TypeKind::Void))
@ -280,7 +283,7 @@ impl Expression {
.map(|var| &var.ty)
.cloned()
.ok_or(ErrorKind::VariableNotDefined(var_ref.1.clone())),
TypeKind::Vague(Unknown),
TypeKind::Vague(Vague::Unknown),
var_ref.2,
)
.resolve_hinted(hints);
@ -288,7 +291,7 @@ impl Expression {
// Update typing to be more accurate
var_ref.0 = state.or_else(
var_ref.0.resolve_hinted(hints).collapse_into(&existing),
TypeKind::Vague(Unknown),
TypeKind::Vague(Vague::Unknown),
var_ref.2,
);
@ -302,9 +305,9 @@ impl Expression {
// TODO make sure lhs and rhs can actually do this binary
// operation once relevant
let lhs_res = lhs.typecheck(state, &hints, None);
let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Unknown), lhs.1);
let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
let rhs_res = rhs.typecheck(state, &hints, Some(&lhs_type));
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Unknown), rhs.1);
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
if let Some(collapsed) = state.ok(rhs_type.collapse_into(&rhs_type), self.1) {
// Try to coerce both sides again with collapsed type
@ -323,7 +326,7 @@ impl Expression {
.cloned()
.ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()));
if let Ok(f) = true_function {
if let Some(f) = state.ok(true_function, self.1) {
let param_len_given = function_call.parameters.len();
let param_len_expected = f.params.len();
@ -343,14 +346,15 @@ impl Expression {
let true_params_iter = f
.params
.into_iter()
.chain(iter::repeat(TypeKind::Vague(Unknown)));
.chain(iter::repeat(TypeKind::Vague(Vague::Unknown)));
for (param, true_param_t) in
function_call.parameters.iter_mut().zip(true_params_iter)
{
// Typecheck every param separately
let param_res = param.typecheck(state, &hints, Some(&true_param_t));
let param_t = state.or_else(param_res, TypeKind::Vague(Unknown), param.1);
let param_t =
state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1);
state.ok(param_t.collapse_into(&true_param_t), param.1);
}
@ -368,7 +372,7 @@ impl Expression {
}
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
let cond_res = cond.typecheck(state, &hints, Some(&TypeKind::Bool));
let cond_t = state.or_else(cond_res, TypeKind::Vague(Unknown), cond.1);
let cond_t = state.or_else(cond_res, TypeKind::Vague(Vague::Unknown), cond.1);
state.ok(cond_t.collapse_into(&TypeKind::Bool), cond.1);
// Typecheck then/else return types and make sure they are the
@ -376,14 +380,14 @@ impl Expression {
let then_res = lhs.typecheck(state, &hints, hint_t);
let (then_ret_kind, then_ret_t) = state.or_else(
then_res,
(ReturnKind::Soft, TypeKind::Vague(Unknown)),
(ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)),
lhs.meta,
);
let else_ret_t = if let Some(else_block) = rhs {
let res = else_block.typecheck(state, &hints, hint_t);
let (else_ret_kind, else_ret_t) = state.or_else(
res,
(ReturnKind::Soft, TypeKind::Vague(Unknown)),
(ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)),
else_block.meta,
);
@ -437,7 +441,7 @@ impl Expression {
}
let ty = state.or_else(
elem_ty.resolve_hinted(hints).collapse_into(&inferred_ty),
TypeKind::Vague(Unknown),
TypeKind::Vague(Vague::Unknown),
self.1,
);
*elem_ty = ty.clone();
@ -477,7 +481,7 @@ impl Expression {
Err(errors) => {
state.note_errors(errors, self.1);
Ok(TypeKind::Array(
Box::new(TypeKind::Vague(Unknown)),
Box::new(TypeKind::Vague(Vague::Unknown)),
expressions.len() as u64,
))
}
@ -532,16 +536,7 @@ impl Literal {
(L::U64(_), TypeKind::U64) => self,
(L::U128(_), TypeKind::U128) => self,
(L::Bool(_), TypeKind::Bool) => self,
(L::String(val), TypeKind::String(len)) => {
if val.len() == *len {
L::String(val)
} else {
Err(ErrorKind::LiteralIncompatible(
L::String(val),
TypeKind::String(*len),
))?
}
}
(L::String(_), TypeKind::StringPtr) => self,
// TODO make sure that v is actually able to fit in the
// requested type
(L::Vague(VagueL::Number(v)), TypeKind::I8) => L::I8(v as i8),
@ -575,9 +570,9 @@ impl TypeKind {
fn or_default(&self) -> Result<TypeKind, ErrorKind> {
match self {
TypeKind::Vague(vague_type) => match &vague_type {
Unknown => Err(ErrorKind::TypeIsVague(*vague_type)),
Number => Ok(TypeKind::I32),
TypeRef(_) => panic!("Hinted default!"),
Vague::Unknown => Err(ErrorKind::TypeIsVague(*vague_type)),
Vague::Number => Ok(TypeKind::I32),
Vague::TypeRef(_) => panic!("Hinted default!"),
},
_ => Ok(self.clone()),
}
@ -585,7 +580,7 @@ impl TypeKind {
fn resolve_hinted(&self, hints: &TypeRefs) -> TypeKind {
let resolved = match self {
TypeKind::Vague(TypeRef(idx)) => hints.retrieve_type(*idx).unwrap(),
TypeKind::Vague(Vague::TypeRef(idx)) => hints.retrieve_type(*idx).unwrap(),
_ => self.clone(),
};
match resolved {
@ -608,22 +603,24 @@ impl Collapsable for TypeKind {
}
match (self, other) {
(TypeKind::Vague(Number), other) | (other, TypeKind::Vague(Number)) => match other {
TypeKind::Vague(Unknown) => Ok(TypeKind::Vague(Number)),
TypeKind::Vague(Number) => Ok(TypeKind::Vague(Number)),
TypeKind::I8
| TypeKind::I16
| TypeKind::I32
| TypeKind::I64
| TypeKind::I128
| TypeKind::U8
| TypeKind::U16
| TypeKind::U32
| TypeKind::U64
| TypeKind::U128 => Ok(other.clone()),
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
},
(TypeKind::Vague(Unknown), other) | (other, TypeKind::Vague(Unknown)) => {
(TypeKind::Vague(Vague::Number), other) | (other, TypeKind::Vague(Vague::Number)) => {
match other {
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Number)),
TypeKind::Vague(Vague::Number) => Ok(TypeKind::Vague(Vague::Number)),
TypeKind::I8
| TypeKind::I16
| TypeKind::I32
| TypeKind::I64
| TypeKind::I128
| TypeKind::U8
| TypeKind::U16
| TypeKind::U32
| TypeKind::U64
| TypeKind::U128 => Ok(other.clone()),
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
}
}
(TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => {
Ok(other.clone())
}
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),

View File

@ -31,7 +31,7 @@ impl<'t> Pass for TypeInference<'t> {
fn module(&mut self, module: &mut Module, mut state: PassState<ErrorKind>) {
for function in &mut module.functions {
let res = function.infer_types(&self.refs, &mut state);
let res = function.infer_types(&self.refs, &mut state.inner());
state.ok(res, function.block_meta());
}
}

View File

@ -28,7 +28,6 @@ impl<'scope> TypeRef<'scope> {
match resolved {
TypeKind::Array(elem_ty, len) => {
let resolved_elem_ty = self.1.from_type(&elem_ty).unwrap().resolve_type();
dbg!(&elem_ty, &resolved_elem_ty);
TypeKind::Array(Box::new(resolved_elem_ty), len)
}
_ => resolved,

View File

@ -180,3 +180,34 @@ impl IndexedVariableReference {
}
}
}
#[derive(Debug, Clone, Copy, thiserror::Error)]
pub enum EqualsIssue {
#[error("Function is already defined locally at {:?}", (.0).range)]
ExistsLocally(Metadata),
#[error("asd")]
Equals,
#[error("asd")]
ConflictingImports,
}
impl FunctionDefinition {
pub fn equals_as_imported(&self, other: &FunctionDefinition) -> Result<(), EqualsIssue> {
match &self.kind {
FunctionDefinitionKind::Local(_, metadata) => {
Err(EqualsIssue::ExistsLocally(*metadata))
}
FunctionDefinitionKind::Extern => {
if self.is_pub == other.is_pub
&& self.name == other.name
&& self.parameters == other.parameters
&& self.return_type == other.return_type
{
Ok(())
} else {
Err(EqualsIssue::ConflictingImports)
}
}
}
}
}

View File

@ -205,7 +205,7 @@ impl std::iter::Sum for TokenRange {
}
}
#[derive(thiserror::Error, Debug)]
#[derive(thiserror::Error, Debug, Clone)]
pub enum Error {
#[error("Expected {} at Ln {}, Col {}, got {:?}", .0, (.2).1, (.2).0, .1)]
Expected(String, Token, Position),

10
reid_src/hello_world.reid Normal file
View File

@ -0,0 +1,10 @@
import std::print;
fn main() -> u16 {
let hello = "hello world";
print(hello);
return 0;
}

10
reid_src/std.reid Normal file
View File

@ -0,0 +1,10 @@
extern fn puts(message: string) -> i32;
pub fn print(message: string) {
puts(message);
}
fn main() -> u16 {
return 0;
}