Compare commits
No commits in common. "fa4df50a04b652c0054b0e94c055ec3fa421fcc3" and "83475b144ca96ac323e1f0224018ab67f6ada9e1" have entirely different histories.
fa4df50a04
...
83475b144c
@ -36,7 +36,7 @@ Currently missing relevant features (TODOs) are:
|
|||||||
- ~~Arrays~~ (DONE)
|
- ~~Arrays~~ (DONE)
|
||||||
- Structs (and custom types as such)
|
- Structs (and custom types as such)
|
||||||
- Extern functions
|
- Extern functions
|
||||||
- ~~Strings~~ (DONE)
|
- Strings
|
||||||
- Loops
|
- Loops
|
||||||
|
|
||||||
### Why "Reid"
|
### Why "Reid"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use reid_lib::{CmpPredicate, ConstValue, Context, FunctionFlags, Instr, TerminatorKind, Type};
|
use reid_lib::{ConstValue, Context, Instr, CmpPredicate, TerminatorKind, Type};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
use ConstValue::*;
|
use ConstValue::*;
|
||||||
@ -6,17 +6,12 @@ fn main() {
|
|||||||
|
|
||||||
let context = Context::new();
|
let context = Context::new();
|
||||||
|
|
||||||
let mut module = context.module("test", true);
|
let mut module = context.module("test");
|
||||||
|
|
||||||
let main = module.function("main", Type::I32, Vec::new(), FunctionFlags::default());
|
let main = module.function("main", Type::I32, Vec::new());
|
||||||
let mut m_entry = main.block("entry");
|
let mut m_entry = main.block("entry");
|
||||||
|
|
||||||
let fibonacci = module.function(
|
let fibonacci = module.function("fibonacci", Type::I32, vec![Type::I32]);
|
||||||
"fibonacci",
|
|
||||||
Type::I32,
|
|
||||||
vec![Type::I32],
|
|
||||||
FunctionFlags::default(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let arg = m_entry.build(Constant(I32(5))).unwrap();
|
let arg = m_entry.build(Constant(I32(5))).unwrap();
|
||||||
let fibonacci_call = m_entry
|
let fibonacci_call = m_entry
|
||||||
|
@ -202,10 +202,6 @@ 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>>> {
|
pub(crate) fn get_modules(&self) -> Rc<RefCell<Vec<ModuleHolder>>> {
|
||||||
self.modules.clone()
|
self.modules.clone()
|
||||||
}
|
}
|
||||||
@ -272,6 +268,7 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
Store(ptr, _) => {
|
Store(ptr, _) => {
|
||||||
if let Ok(ty) = ptr.get_type(&self) {
|
if let Ok(ty) = ptr.get_type(&self) {
|
||||||
|
dbg!(&ty);
|
||||||
if let Type::Ptr(_) = ty {
|
if let Type::Ptr(_) = ty {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -372,7 +369,7 @@ impl ConstValue {
|
|||||||
ConstValue::U32(_) => U32,
|
ConstValue::U32(_) => U32,
|
||||||
ConstValue::U64(_) => U64,
|
ConstValue::U64(_) => U64,
|
||||||
ConstValue::U128(_) => U128,
|
ConstValue::U128(_) => U128,
|
||||||
ConstValue::String(_) => Ptr(Box::new(I8)),
|
ConstValue::String(val) => String(val.len() as u32),
|
||||||
ConstValue::Bool(_) => Bool,
|
ConstValue::Bool(_) => Bool,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -393,6 +390,7 @@ impl Type {
|
|||||||
Type::U128 => true,
|
Type::U128 => true,
|
||||||
Type::Bool => true,
|
Type::Bool => true,
|
||||||
Type::Void => false,
|
Type::Void => false,
|
||||||
|
Type::String(_) => false,
|
||||||
Type::Ptr(_) => false,
|
Type::Ptr(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -411,6 +409,7 @@ impl Type {
|
|||||||
Type::U128 => false,
|
Type::U128 => false,
|
||||||
Type::Bool => false,
|
Type::Bool => false,
|
||||||
Type::Void => false,
|
Type::Void => false,
|
||||||
|
Type::String(_) => false,
|
||||||
Type::Ptr(_) => false,
|
Type::Ptr(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,9 @@
|
|||||||
use std::{collections::HashMap, ffi::CString, ptr::null_mut};
|
use std::{collections::HashMap, ffi::CString, ptr::null_mut};
|
||||||
|
|
||||||
use llvm_sys::{
|
use llvm_sys::{
|
||||||
LLVMIntPredicate, LLVMLinkage,
|
LLVMIntPredicate,
|
||||||
analysis::LLVMVerifyModule,
|
analysis::LLVMVerifyModule,
|
||||||
core::*,
|
core::*,
|
||||||
linker::LLVMLinkModules2,
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
target::{
|
target::{
|
||||||
LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos,
|
LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllTargetInfos,
|
||||||
@ -35,87 +34,8 @@ pub struct LLVMContext {
|
|||||||
builder_ref: LLVMBuilderRef,
|
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 {
|
impl Context {
|
||||||
pub fn compile(&self) -> CompiledModule {
|
pub fn compile(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let context_ref = LLVMContextCreate();
|
let context_ref = LLVMContextCreate();
|
||||||
|
|
||||||
@ -124,29 +44,12 @@ impl Context {
|
|||||||
builder_ref: LLVMCreateBuilderInContext(context_ref),
|
builder_ref: LLVMCreateBuilderInContext(context_ref),
|
||||||
};
|
};
|
||||||
|
|
||||||
let module_holders = self.builder.get_modules();
|
for holder in self.builder.get_modules().borrow().iter() {
|
||||||
|
holder.compile(&context, &self.builder);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CompiledModule {
|
LLVMDisposeBuilder(context.builder_ref);
|
||||||
module_ref: main_module_ref,
|
LLVMContextDispose(context.context_ref);
|
||||||
_context: context,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +77,7 @@ pub struct LLVMValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ModuleHolder {
|
impl ModuleHolder {
|
||||||
fn compile(&self, context: &LLVMContext, builder: &Builder) -> LLVMModuleRef {
|
fn compile(&self, context: &LLVMContext, builder: &Builder) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let module_ref = LLVMModuleCreateWithNameInContext(
|
let module_ref = LLVMModuleCreateWithNameInContext(
|
||||||
into_cstring(&self.data.name).as_ptr(),
|
into_cstring(&self.data.name).as_ptr(),
|
||||||
@ -203,10 +106,67 @@ impl ModuleHolder {
|
|||||||
};
|
};
|
||||||
|
|
||||||
for function in &self.functions {
|
for function in &self.functions {
|
||||||
function.compile(&mut module, self.data.is_main);
|
function.compile(&mut module);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_ref
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,26 +200,10 @@ impl FunctionHolder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn compile(&self, module: &mut LLVMModule, in_main_module: bool) {
|
unsafe fn compile(&self, module: &mut LLVMModule) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let own_function = *module.functions.get(&self.value).unwrap();
|
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 {
|
for block in &self.blocks {
|
||||||
if block.data.deleted {
|
if block.data.deleted {
|
||||||
continue;
|
continue;
|
||||||
@ -360,22 +304,14 @@ impl InstructionHolder {
|
|||||||
.map(|i| module.values.get(i).unwrap().value_ref)
|
.map(|i| module.values.get(i).unwrap().value_ref)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let is_void = module.builder.function_data(&*function_value).ret == Type::Void;
|
LLVMBuildCall2(
|
||||||
if is_void {
|
|
||||||
LLVMContextSetDiscardValueNames(module.context_ref, 1);
|
|
||||||
}
|
|
||||||
let value = LLVMBuildCall2(
|
|
||||||
module.builder_ref,
|
module.builder_ref,
|
||||||
fun.type_ref,
|
fun.type_ref,
|
||||||
fun.value_ref,
|
fun.value_ref,
|
||||||
param_list.as_mut_ptr(),
|
param_list.as_mut_ptr(),
|
||||||
param_list.len() as u32,
|
param_list.len() as u32,
|
||||||
c"call".as_ptr(),
|
c"call".as_ptr(),
|
||||||
);
|
)
|
||||||
if is_void {
|
|
||||||
LLVMContextSetDiscardValueNames(module.context_ref, 0);
|
|
||||||
}
|
|
||||||
value
|
|
||||||
}
|
}
|
||||||
Phi(values) => {
|
Phi(values) => {
|
||||||
let mut inc_values = Vec::new();
|
let mut inc_values = Vec::new();
|
||||||
@ -521,11 +457,9 @@ impl ConstValue {
|
|||||||
ConstValue::U32(val) => LLVMConstInt(t, *val as u64, 1),
|
ConstValue::U32(val) => LLVMConstInt(t, *val as u64, 1),
|
||||||
ConstValue::U64(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::U128(val) => LLVMConstInt(t, *val as u64, 1),
|
||||||
ConstValue::String(val) => LLVMBuildGlobalStringPtr(
|
ConstValue::String(val) => {
|
||||||
builder,
|
LLVMBuildGlobalString(builder, into_cstring(val).as_ptr(), c"string".as_ptr())
|
||||||
into_cstring(val).as_ptr(),
|
}
|
||||||
c"string".as_ptr(),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -542,8 +476,9 @@ impl Type {
|
|||||||
I64 | U64 => LLVMInt64TypeInContext(context),
|
I64 | U64 => LLVMInt64TypeInContext(context),
|
||||||
I128 | U128 => LLVMInt128TypeInContext(context),
|
I128 | U128 => LLVMInt128TypeInContext(context),
|
||||||
Bool => LLVMInt1TypeInContext(context),
|
Bool => LLVMInt1TypeInContext(context),
|
||||||
Void => LLVMVoidTypeInContext(context),
|
Void => LLVMVoidType(),
|
||||||
Ptr(ty) => LLVMPointerType(ty.as_llvm(context), 0),
|
Ptr(ty) => LLVMPointerType(ty.as_llvm(context), 0),
|
||||||
|
String(length) => LLVMArrayType(LLVMInt8TypeInContext(context), *length),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
//! Debug implementations for relevant types
|
//! Debug implementations for relevant types
|
||||||
|
|
||||||
use std::{
|
use std::fmt::{Debug, Write};
|
||||||
fmt::{Debug, Write},
|
|
||||||
marker::PhantomData,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{CmpPredicate, Instr, InstructionData, TerminatorKind, builder::*};
|
use crate::{CmpPredicate, Instr, InstructionData, TerminatorKind, builder::*};
|
||||||
|
|
||||||
@ -14,17 +11,6 @@ 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 {
|
impl Debug for ModuleHolder {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_tuple(&format!("{}({:#?}) ", self.data.name, self.value))
|
f.debug_tuple(&format!("{}({:#?}) ", self.data.name, self.value))
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
//! Low-Level IR (LLIR) using [`Context`] and [`Builder`]. This Builder can then
|
//! Low-Level IR (LLIR) using [`Context`] and [`Builder`]. This Builder can then
|
||||||
//! be used at the end to compile said LLIR into LLVM IR.
|
//! be used at the end to compile said LLIR into LLVM IR.
|
||||||
|
|
||||||
use std::{fmt::Debug, marker::PhantomData};
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue};
|
use builder::{BlockValue, Builder, FunctionValue, InstructionValue, ModuleValue};
|
||||||
use debug::PrintableModule;
|
|
||||||
|
|
||||||
pub mod builder;
|
pub mod builder;
|
||||||
pub mod compile;
|
pub mod compile;
|
||||||
@ -26,10 +25,9 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn module<'ctx>(&'ctx self, name: &str, main: bool) -> Module<'ctx> {
|
pub fn module<'ctx>(&'ctx self, name: &str) -> Module<'ctx> {
|
||||||
let value = self.builder.add_module(ModuleData {
|
let value = self.builder.add_module(ModuleData {
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
is_main: main,
|
|
||||||
});
|
});
|
||||||
Module {
|
Module {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
@ -42,7 +40,6 @@ impl Context {
|
|||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub struct ModuleData {
|
pub struct ModuleData {
|
||||||
name: String,
|
name: String,
|
||||||
is_main: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Module<'ctx> {
|
pub struct Module<'ctx> {
|
||||||
@ -52,13 +49,7 @@ pub struct Module<'ctx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> Module<'ctx> {
|
impl<'ctx> Module<'ctx> {
|
||||||
pub fn function(
|
pub fn function(&mut self, name: &str, ret: Type, params: Vec<Type>) -> Function<'ctx> {
|
||||||
&mut self,
|
|
||||||
name: &str,
|
|
||||||
ret: Type,
|
|
||||||
params: Vec<Type>,
|
|
||||||
flags: FunctionFlags,
|
|
||||||
) -> Function<'ctx> {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
Function {
|
Function {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
@ -69,7 +60,6 @@ impl<'ctx> Module<'ctx> {
|
|||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
ret,
|
ret,
|
||||||
params,
|
params,
|
||||||
flags,
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@ -79,13 +69,6 @@ impl<'ctx> Module<'ctx> {
|
|||||||
pub fn value(&self) -> ModuleValue {
|
pub fn value(&self) -> ModuleValue {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_printable(&self) -> PrintableModule<'ctx> {
|
|
||||||
PrintableModule {
|
|
||||||
phantom: PhantomData,
|
|
||||||
module: self.builder.find_module(self.value),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
@ -93,26 +76,6 @@ pub struct FunctionData {
|
|||||||
name: String,
|
name: String,
|
||||||
ret: Type,
|
ret: Type,
|
||||||
params: Vec<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> {
|
pub struct Function<'ctx> {
|
||||||
@ -237,6 +200,7 @@ pub enum Type {
|
|||||||
U128,
|
U128,
|
||||||
Bool,
|
Bool,
|
||||||
Void,
|
Void,
|
||||||
|
String(u32),
|
||||||
Ptr(Box<Type>),
|
Ptr(Box<Type>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
use std::{env, fs, path::PathBuf};
|
use std::{env, fs};
|
||||||
|
|
||||||
use reid::compile;
|
use reid::compile;
|
||||||
|
|
||||||
fn main() -> Result<(), std::io::Error> {
|
fn main() -> Result<(), std::io::Error> {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
if let Some(filename) = args.get(1) {
|
if let Some(filename) = args.get(1) {
|
||||||
let path = PathBuf::from(filename);
|
let text = fs::read_to_string(filename)?;
|
||||||
|
let output = match compile(&text) {
|
||||||
let text = fs::read_to_string(&path)?;
|
|
||||||
let output = match compile(&text, PathBuf::from(path)) {
|
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(e) => panic!("{}", e),
|
Err(e) => panic!("{}", e),
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use reid::mir::{self, *};
|
use reid::mir::{self, *};
|
||||||
use reid_lib::Context;
|
use reid_lib::Context;
|
||||||
|
|
||||||
@ -9,8 +7,6 @@ fn main() {
|
|||||||
|
|
||||||
let fibonacci = FunctionDefinition {
|
let fibonacci = FunctionDefinition {
|
||||||
name: fibonacci_name.clone(),
|
name: fibonacci_name.clone(),
|
||||||
is_pub: false,
|
|
||||||
is_imported: false,
|
|
||||||
return_type: TypeKind::I32,
|
return_type: TypeKind::I32,
|
||||||
parameters: vec![(fibonacci_n.clone(), TypeKind::I32)],
|
parameters: vec![(fibonacci_n.clone(), TypeKind::I32)],
|
||||||
kind: FunctionDefinitionKind::Local(
|
kind: FunctionDefinitionKind::Local(
|
||||||
@ -131,8 +127,6 @@ fn main() {
|
|||||||
|
|
||||||
let main = FunctionDefinition {
|
let main = FunctionDefinition {
|
||||||
name: "main".to_owned(),
|
name: "main".to_owned(),
|
||||||
is_pub: false,
|
|
||||||
is_imported: false,
|
|
||||||
return_type: TypeKind::I32,
|
return_type: TypeKind::I32,
|
||||||
parameters: vec![],
|
parameters: vec![],
|
||||||
kind: FunctionDefinitionKind::Local(
|
kind: FunctionDefinitionKind::Local(
|
||||||
@ -163,10 +157,7 @@ fn main() {
|
|||||||
name: "test module".to_owned(),
|
name: "test module".to_owned(),
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
functions: vec![fibonacci, main],
|
functions: vec![fibonacci, main],
|
||||||
path: None,
|
|
||||||
is_main: true,
|
|
||||||
}],
|
}],
|
||||||
base: PathBuf::new(),
|
|
||||||
};
|
};
|
||||||
println!("test1");
|
println!("test1");
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
//! This is the module that contains relevant code to parsing Reid, that is to
|
//! 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
|
//! 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.
|
//! used for unwrapping syntax sugar, and then be transformed into Reid MIR.
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use crate::token_stream::TokenRange;
|
use crate::token_stream::TokenRange;
|
||||||
|
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
@ -24,7 +22,6 @@ pub enum TypeKind {
|
|||||||
U32,
|
U32,
|
||||||
U64,
|
U64,
|
||||||
U128,
|
U128,
|
||||||
String,
|
|
||||||
Array(Box<TypeKind>, u64),
|
Array(Box<TypeKind>, u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +109,7 @@ pub struct LetStatement(
|
|||||||
pub struct ImportStatement(pub Vec<String>, pub TokenRange);
|
pub struct ImportStatement(pub Vec<String>, pub TokenRange);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionDefinition(pub FunctionSignature, pub bool, pub Block, pub TokenRange);
|
pub struct FunctionDefinition(pub FunctionSignature, pub Block, pub TokenRange);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FunctionSignature {
|
pub struct FunctionSignature {
|
||||||
@ -160,7 +157,6 @@ pub enum BlockLevelStatement {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TopLevelStatement {
|
pub enum TopLevelStatement {
|
||||||
Import(ImportStatement),
|
Import(ImportStatement),
|
||||||
ExternFunction(FunctionSignature),
|
|
||||||
FunctionDefinition(FunctionDefinition),
|
FunctionDefinition(FunctionDefinition),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,6 +164,4 @@ pub enum TopLevelStatement {
|
|||||||
pub struct Module {
|
pub struct Module {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub top_level_statements: Vec<TopLevelStatement>,
|
pub top_level_statements: Vec<TopLevelStatement>,
|
||||||
pub path: Option<PathBuf>,
|
|
||||||
pub is_main: bool,
|
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,6 @@ impl Parse for Type {
|
|||||||
"u32" => TypeKind::U32,
|
"u32" => TypeKind::U32,
|
||||||
"u64" => TypeKind::U64,
|
"u64" => TypeKind::U64,
|
||||||
"u128" => TypeKind::U128,
|
"u128" => TypeKind::U128,
|
||||||
"string" => TypeKind::String,
|
|
||||||
_ => Err(stream.expected_err("known type identifier")?)?,
|
_ => Err(stream.expected_err("known type identifier")?)?,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -308,17 +307,9 @@ impl Parse for ImportStatement {
|
|||||||
|
|
||||||
impl Parse for FunctionDefinition {
|
impl Parse for FunctionDefinition {
|
||||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
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)?;
|
stream.expect(Token::FnKeyword)?;
|
||||||
Ok(FunctionDefinition(
|
Ok(FunctionDefinition(
|
||||||
stream.parse()?,
|
stream.parse()?,
|
||||||
is_pub,
|
|
||||||
stream.parse()?,
|
stream.parse()?,
|
||||||
stream.get_range().unwrap(),
|
stream.get_range().unwrap(),
|
||||||
))
|
))
|
||||||
@ -401,7 +392,9 @@ impl Parse for VariableReference {
|
|||||||
stream.get_range().unwrap(),
|
stream.get_range().unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
dbg!(&var_ref);
|
||||||
while let Ok(ValueIndex(idx)) = stream.parse() {
|
while let Ok(ValueIndex(idx)) = stream.parse() {
|
||||||
|
dbg!(idx);
|
||||||
var_ref = VariableReference(
|
var_ref = VariableReference(
|
||||||
VariableReferenceKind::Index(Box::new(var_ref), idx),
|
VariableReferenceKind::Index(Box::new(var_ref), idx),
|
||||||
stream.get_range().unwrap(),
|
stream.get_range().unwrap(),
|
||||||
@ -481,16 +474,7 @@ impl Parse for TopLevelStatement {
|
|||||||
use TopLevelStatement as Stmt;
|
use TopLevelStatement as Stmt;
|
||||||
Ok(match stream.peek() {
|
Ok(match stream.peek() {
|
||||||
Some(Token::ImportKeyword) => Stmt::Import(stream.parse()?),
|
Some(Token::ImportKeyword) => Stmt::Import(stream.parse()?),
|
||||||
Some(Token::Extern) => {
|
Some(Token::FnKeyword) => Stmt::FunctionDefinition(stream.parse()?),
|
||||||
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")?)?,
|
_ => Err(stream.expected_err("import or fn")?)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self},
|
ast::{self},
|
||||||
mir::{self, NamedVariableRef, StmtKind},
|
mir::{self, NamedVariableRef, StmtKind},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl mir::Context {
|
impl mir::Context {
|
||||||
pub fn from(modules: Vec<mir::Module>, base: PathBuf) -> mir::Context {
|
pub fn from(modules: Vec<ast::Module>) -> mir::Context {
|
||||||
mir::Context { modules, base }
|
mir::Context {
|
||||||
|
modules: modules.iter().map(|m| m.process()).collect(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::Module {
|
impl ast::Module {
|
||||||
pub fn process(&self) -> mir::Module {
|
fn process(&self) -> mir::Module {
|
||||||
let mut imports = Vec::new();
|
let mut imports = Vec::new();
|
||||||
let mut functions = Vec::new();
|
let mut functions = Vec::new();
|
||||||
|
|
||||||
@ -20,13 +20,13 @@ impl ast::Module {
|
|||||||
for stmt in &self.top_level_statements {
|
for stmt in &self.top_level_statements {
|
||||||
match stmt {
|
match stmt {
|
||||||
Import(import) => {
|
Import(import) => {
|
||||||
imports.push(mir::Import(import.0.clone(), import.1.into()));
|
for name in &import.0 {
|
||||||
|
imports.push(mir::Import(name.clone(), import.1.into()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FunctionDefinition(ast::FunctionDefinition(signature, is_pub, block, range)) => {
|
FunctionDefinition(ast::FunctionDefinition(signature, block, range)) => {
|
||||||
let def = mir::FunctionDefinition {
|
let def = mir::FunctionDefinition {
|
||||||
name: signature.name.clone(),
|
name: signature.name.clone(),
|
||||||
is_pub: *is_pub,
|
|
||||||
is_imported: false,
|
|
||||||
return_type: signature
|
return_type: signature
|
||||||
.return_type
|
.return_type
|
||||||
.clone()
|
.clone()
|
||||||
@ -42,26 +42,6 @@ impl ast::Module {
|
|||||||
};
|
};
|
||||||
functions.push(def);
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,8 +49,6 @@ impl ast::Module {
|
|||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
imports,
|
imports,
|
||||||
functions,
|
functions,
|
||||||
path: self.path.clone(),
|
|
||||||
is_main: self.is_main,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,7 +226,6 @@ impl From<ast::TypeKind> for mir::TypeKind {
|
|||||||
ast::TypeKind::Array(type_kind, length) => {
|
ast::TypeKind::Array(type_kind, length) => {
|
||||||
mir::TypeKind::Array(Box::new(mir::TypeKind::from(*type_kind.clone())), *length)
|
mir::TypeKind::Array(Box::new(mir::TypeKind::from(*type_kind.clone())), *length)
|
||||||
}
|
}
|
||||||
ast::TypeKind::String => mir::TypeKind::StringPtr,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use std::{collections::HashMap, mem};
|
use std::{collections::HashMap, mem};
|
||||||
|
|
||||||
use reid_lib::{
|
use reid_lib::{
|
||||||
builder::InstructionValue, compile::CompiledModule, Block, CmpPredicate, ConstValue, Context,
|
builder::InstructionValue, Block, CmpPredicate, ConstValue, Context, Function, Instr, Module,
|
||||||
Function, FunctionFlags, Instr, Module, TerminatorKind as Term, Type,
|
TerminatorKind as Term, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::mir::{self, types::ReturnType, IndexedVariableReference, NamedVariableRef, TypeKind};
|
use crate::mir::{self, types::ReturnType, IndexedVariableReference, NamedVariableRef, TypeKind};
|
||||||
@ -11,14 +11,16 @@ use crate::mir::{self, types::ReturnType, IndexedVariableReference, NamedVariabl
|
|||||||
/// LLIR that can then be finally compiled into LLVM IR.
|
/// LLIR that can then be finally compiled into LLVM IR.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct CodegenContext<'ctx> {
|
pub struct CodegenContext<'ctx> {
|
||||||
context: &'ctx Context,
|
modules: Vec<ModuleCodegen<'ctx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> CodegenContext<'ctx> {
|
impl<'ctx> CodegenContext<'ctx> {
|
||||||
/// Compile contained LLIR into LLVM IR and produce `hello.o` and
|
/// Compile contained LLIR into LLVM IR and produce `hello.o` and
|
||||||
/// `hello.asm`
|
/// `hello.asm`
|
||||||
pub fn compile(&self) -> CompiledModule {
|
pub fn compile(&self) {
|
||||||
self.context.compile()
|
for module in &self.modules {
|
||||||
|
module.context.compile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,23 +31,24 @@ impl mir::Context {
|
|||||||
for module in &self.modules {
|
for module in &self.modules {
|
||||||
modules.push(module.codegen(context));
|
modules.push(module.codegen(context));
|
||||||
}
|
}
|
||||||
CodegenContext { context }
|
CodegenContext { modules }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModuleCodegen<'ctx> {
|
struct ModuleCodegen<'ctx> {
|
||||||
module: Module<'ctx>,
|
pub context: &'ctx Context,
|
||||||
|
_module: Module<'ctx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> std::fmt::Debug for ModuleCodegen<'ctx> {
|
impl<'ctx> std::fmt::Debug for ModuleCodegen<'ctx> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Debug::fmt(&self.module.as_printable(), f)
|
self.context.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl mir::Module {
|
impl mir::Module {
|
||||||
fn codegen<'ctx>(&self, context: &'ctx Context) -> ModuleCodegen<'ctx> {
|
fn codegen<'ctx>(&self, context: &'ctx Context) -> ModuleCodegen<'ctx> {
|
||||||
let mut module = context.module(&self.name, self.is_main);
|
let mut module = context.module(&self.name);
|
||||||
|
|
||||||
let mut functions = HashMap::new();
|
let mut functions = HashMap::new();
|
||||||
|
|
||||||
@ -56,28 +59,11 @@ impl mir::Module {
|
|||||||
.map(|(_, p)| p.get_type())
|
.map(|(_, p)| p.get_type())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let is_main = self.is_main && function.name == "main";
|
|
||||||
let func = match &function.kind {
|
let func = match &function.kind {
|
||||||
mir::FunctionDefinitionKind::Local(_, _) => module.function(
|
mir::FunctionDefinitionKind::Local(_, _) => {
|
||||||
&function.name,
|
module.function(&function.name, function.return_type.get_type(), param_types)
|
||||||
function.return_type.get_type(),
|
}
|
||||||
param_types,
|
mir::FunctionDefinitionKind::Extern => todo!(),
|
||||||
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);
|
functions.insert(function.name.clone(), func);
|
||||||
}
|
}
|
||||||
@ -121,7 +107,10 @@ impl mir::Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleCodegen { module }
|
ModuleCodegen {
|
||||||
|
context,
|
||||||
|
_module: module,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,7 +495,7 @@ impl TypeKind {
|
|||||||
TypeKind::U64 => Type::U64,
|
TypeKind::U64 => Type::U64,
|
||||||
TypeKind::U128 => Type::U128,
|
TypeKind::U128 => Type::U128,
|
||||||
TypeKind::Bool => Type::Bool,
|
TypeKind::Bool => Type::Bool,
|
||||||
TypeKind::StringPtr => Type::Ptr(Box::new(Type::I8)),
|
TypeKind::String(length) => Type::String(*length as u32),
|
||||||
TypeKind::Array(elem_t, _) => Type::Ptr(Box::new(elem_t.get_type())),
|
TypeKind::Array(elem_t, _) => Type::Ptr(Box::new(elem_t.get_type())),
|
||||||
TypeKind::Void => Type::Void,
|
TypeKind::Void => Type::Void,
|
||||||
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
|
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
|
||||||
|
@ -22,8 +22,6 @@ pub enum Token {
|
|||||||
ReturnKeyword,
|
ReturnKeyword,
|
||||||
/// `fn`
|
/// `fn`
|
||||||
FnKeyword,
|
FnKeyword,
|
||||||
/// `pub`
|
|
||||||
PubKeyword,
|
|
||||||
/// `->`
|
/// `->`
|
||||||
Arrow,
|
Arrow,
|
||||||
/// `if`
|
/// `if`
|
||||||
@ -34,8 +32,6 @@ pub enum Token {
|
|||||||
True,
|
True,
|
||||||
/// `false`
|
/// `false`
|
||||||
False,
|
False,
|
||||||
/// `extern`
|
|
||||||
Extern,
|
|
||||||
|
|
||||||
// Symbols
|
// Symbols
|
||||||
/// `;`
|
/// `;`
|
||||||
@ -209,8 +205,6 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
|
|||||||
"else" => Token::Else,
|
"else" => Token::Else,
|
||||||
"true" => Token::True,
|
"true" => Token::True,
|
||||||
"false" => Token::False,
|
"false" => Token::False,
|
||||||
"extern" => Token::Extern,
|
|
||||||
"pub" => Token::PubKeyword,
|
|
||||||
_ => Token::Identifier(value),
|
_ => Token::Identifier(value),
|
||||||
};
|
};
|
||||||
variant
|
variant
|
||||||
@ -267,7 +261,7 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
|
|||||||
Ok(tokens)
|
Ok(tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Invalid token '{}' at Ln {}, Col {}", .0, (.1).1, (.1).0)]
|
#[error("Invalid token '{}' at Ln {}, Col {}", .0, (.1).1, (.1).0)]
|
||||||
InvalidToken(char, Position),
|
InvalidToken(char, Position),
|
||||||
|
@ -36,15 +36,11 @@
|
|||||||
//! - ~~Arrays~~ (DONE)
|
//! - ~~Arrays~~ (DONE)
|
||||||
//! - Structs (and custom types as such)
|
//! - Structs (and custom types as such)
|
||||||
//! - Extern functions
|
//! - Extern functions
|
||||||
//! - ~~Strings~~ (DONE)
|
//! - Strings
|
||||||
//! - Loops
|
//! - Loops
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use mir::{typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs};
|
||||||
|
|
||||||
use mir::{
|
|
||||||
linker::LinkerPass, typecheck::TypeCheck, typeinference::TypeInference, typerefs::TypeRefs,
|
|
||||||
};
|
|
||||||
use reid_lib::Context;
|
use reid_lib::Context;
|
||||||
|
|
||||||
use crate::{ast::TopLevelStatement, lexer::Token, token_stream::TokenStream};
|
use crate::{ast::TopLevelStatement, lexer::Token, token_stream::TokenStream};
|
||||||
@ -57,7 +53,7 @@ mod pad_adapter;
|
|||||||
mod token_stream;
|
mod token_stream;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum ReidError {
|
pub enum ReidError {
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
LexerError(#[from] lexer::Error),
|
LexerError(#[from] lexer::Error),
|
||||||
@ -65,18 +61,12 @@ pub enum ReidError {
|
|||||||
ParserError(#[from] token_stream::Error),
|
ParserError(#[from] token_stream::Error),
|
||||||
#[error("Errors during typecheck: {0:?}")]
|
#[error("Errors during typecheck: {0:?}")]
|
||||||
TypeCheckErrors(Vec<mir::pass::Error<mir::typecheck::ErrorKind>>),
|
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>>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_module(
|
/// Takes in a bit of source code, parses and compiles it and produces `hello.o`
|
||||||
source: &str,
|
/// and `hello.asm` from it, which can be linked using `ld` to produce an
|
||||||
name: String,
|
/// executable file.
|
||||||
path: Option<PathBuf>,
|
pub fn compile(source: &str) -> Result<String, ReidError> {
|
||||||
is_main: bool,
|
|
||||||
) -> Result<mir::Module, ReidError> {
|
|
||||||
let tokens = lexer::tokenize(source)?;
|
let tokens = lexer::tokenize(source)?;
|
||||||
|
|
||||||
dbg!(&tokens);
|
dbg!(&tokens);
|
||||||
@ -91,41 +81,15 @@ pub fn compile_module(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ast_module = ast::Module {
|
let ast_module = ast::Module {
|
||||||
name,
|
name: "test".to_owned(),
|
||||||
top_level_statements: statements,
|
top_level_statements: statements,
|
||||||
path,
|
|
||||||
is_main,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ast_module.process())
|
dbg!(&ast_module);
|
||||||
}
|
let mut mir_context = mir::Context::from(vec![ast_module]);
|
||||||
|
|
||||||
/// 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);
|
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 refs = TypeRefs::default();
|
||||||
|
|
||||||
let state = mir_context.pass(&mut TypeInference { refs: &refs });
|
let state = mir_context.pass(&mut TypeInference { refs: &refs });
|
||||||
@ -133,10 +97,6 @@ pub fn compile(source: &str, path: PathBuf) -> Result<String, ReidError> {
|
|||||||
dbg!(&mir_context);
|
dbg!(&mir_context);
|
||||||
println!("{}", &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 });
|
let state = mir_context.pass(&mut TypeCheck { refs: &refs });
|
||||||
dbg!(&state);
|
dbg!(&state);
|
||||||
println!("{}", &mir_context);
|
println!("{}", &mir_context);
|
||||||
@ -149,8 +109,7 @@ pub fn compile(source: &str, path: PathBuf) -> Result<String, ReidError> {
|
|||||||
let codegen_modules = mir_context.codegen(&mut context);
|
let codegen_modules = mir_context.codegen(&mut context);
|
||||||
|
|
||||||
dbg!(&codegen_modules);
|
dbg!(&codegen_modules);
|
||||||
let compiled = codegen_modules.compile();
|
codegen_modules.compile();
|
||||||
compiled.output();
|
|
||||||
|
|
||||||
Ok(String::new())
|
Ok(String::new())
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ impl Display for Module {
|
|||||||
|
|
||||||
impl Display for Import {
|
impl Display for Import {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "import {}", self.0.join("::"))
|
write!(f, "import {}", self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,8 +40,7 @@ impl Display for FunctionDefinition {
|
|||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}fn {}({}) -> {} ",
|
"fn {}({}) -> {} ",
|
||||||
if self.is_pub { "pub " } else { "" },
|
|
||||||
self.name,
|
self.name,
|
||||||
self.parameters
|
self.parameters
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1,193 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,12 +2,9 @@
|
|||||||
//! Reid. It contains a simplified version of Reid which can be e.g.
|
//! Reid. It contains a simplified version of Reid which can be e.g.
|
||||||
//! typechecked.
|
//! typechecked.
|
||||||
|
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use crate::token_stream::TokenRange;
|
use crate::token_stream::TokenRange;
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
pub mod linker;
|
|
||||||
pub mod pass;
|
pub mod pass;
|
||||||
pub mod typecheck;
|
pub mod typecheck;
|
||||||
pub mod typeinference;
|
pub mod typeinference;
|
||||||
@ -62,7 +59,7 @@ pub enum TypeKind {
|
|||||||
#[error("void")]
|
#[error("void")]
|
||||||
Void,
|
Void,
|
||||||
#[error("string")]
|
#[error("string")]
|
||||||
StringPtr,
|
String(usize),
|
||||||
#[error("[{0}; {1}]")]
|
#[error("[{0}; {1}]")]
|
||||||
Array(Box<TypeKind>, u64),
|
Array(Box<TypeKind>, u64),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
@ -105,7 +102,7 @@ impl TypeKind {
|
|||||||
TypeKind::U32 => false,
|
TypeKind::U32 => false,
|
||||||
TypeKind::U64 => false,
|
TypeKind::U64 => false,
|
||||||
TypeKind::U128 => false,
|
TypeKind::U128 => false,
|
||||||
TypeKind::StringPtr => false,
|
TypeKind::String(_) => false,
|
||||||
TypeKind::Array(_, _) => false,
|
TypeKind::Array(_, _) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,7 +123,7 @@ impl TypeKind {
|
|||||||
Bool => true,
|
Bool => true,
|
||||||
Vague(_) => false,
|
Vague(_) => false,
|
||||||
Void => false,
|
Void => false,
|
||||||
TypeKind::StringPtr => false,
|
TypeKind::String(_) => false,
|
||||||
Array(_, _) => false,
|
Array(_, _) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,7 +165,7 @@ impl Literal {
|
|||||||
Literal::U64(_) => TypeKind::U64,
|
Literal::U64(_) => TypeKind::U64,
|
||||||
Literal::U128(_) => TypeKind::U128,
|
Literal::U128(_) => TypeKind::U128,
|
||||||
Literal::Bool(_) => TypeKind::Bool,
|
Literal::Bool(_) => TypeKind::Bool,
|
||||||
Literal::String(_) => TypeKind::StringPtr,
|
Literal::String(val) => TypeKind::String(val.len()),
|
||||||
Literal::Vague(VagueLiteral::Number(_)) => TypeKind::Vague(VagueType::Number),
|
Literal::Vague(VagueLiteral::Number(_)) => TypeKind::Vague(VagueType::Number),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,8 +208,8 @@ pub enum ReturnKind {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata);
|
pub struct NamedVariableRef(pub TypeKind, pub String, pub Metadata);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub struct Import(pub Vec<String>, pub Metadata);
|
pub struct Import(pub String, pub Metadata);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ExprKind {
|
pub enum ExprKind {
|
||||||
@ -243,8 +240,6 @@ pub struct FunctionCall {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FunctionDefinition {
|
pub struct FunctionDefinition {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub is_pub: bool,
|
|
||||||
pub is_imported: bool,
|
|
||||||
pub return_type: TypeKind,
|
pub return_type: TypeKind,
|
||||||
pub parameters: Vec<(String, TypeKind)>,
|
pub parameters: Vec<(String, TypeKind)>,
|
||||||
pub kind: FunctionDefinitionKind,
|
pub kind: FunctionDefinitionKind,
|
||||||
@ -310,12 +305,9 @@ pub struct Module {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub imports: Vec<Import>,
|
pub imports: Vec<Import>,
|
||||||
pub functions: Vec<FunctionDefinition>,
|
pub functions: Vec<FunctionDefinition>,
|
||||||
pub path: Option<PathBuf>,
|
|
||||||
pub is_main: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub modules: Vec<Module>,
|
pub modules: Vec<Module>,
|
||||||
pub base: PathBuf,
|
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,6 @@ impl<'st, 'sc, TError: STDError + Clone> PassState<'st, 'sc, TError> {
|
|||||||
pub trait Pass {
|
pub trait Pass {
|
||||||
type TError: STDError + Clone;
|
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 module(&mut self, _module: &mut Module, mut _state: PassState<Self::TError>) {}
|
||||||
fn function(
|
fn function(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -208,7 +207,6 @@ impl Context {
|
|||||||
pub fn pass<T: Pass>(&mut self, pass: &mut T) -> State<T::TError> {
|
pub fn pass<T: Pass>(&mut self, pass: &mut T) -> State<T::TError> {
|
||||||
let mut state = State::new();
|
let mut state = State::new();
|
||||||
let mut scope = Scope::default();
|
let mut scope = Scope::default();
|
||||||
pass.context(self, PassState::from(&mut state, &mut scope));
|
|
||||||
for module in &mut self.modules {
|
for module in &mut self.modules {
|
||||||
module.pass(pass, &mut state, &mut scope);
|
module.pass(pass, &mut state, &mut scope);
|
||||||
}
|
}
|
||||||
@ -234,7 +232,7 @@ impl Module {
|
|||||||
pass.module(self, PassState::from(state, scope));
|
pass.module(self, PassState::from(state, scope));
|
||||||
|
|
||||||
for function in &mut self.functions {
|
for function in &mut self.functions {
|
||||||
function.pass(pass, state, &mut scope.inner());
|
function.pass(pass, state, scope);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use std::{convert::Infallible, iter};
|
use std::{convert::Infallible, iter};
|
||||||
|
|
||||||
use crate::{mir::*, util::try_all};
|
use crate::{mir::*, util::try_all};
|
||||||
use VagueType as Vague;
|
use VagueType::*;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
pass::{Pass, PassState, ScopeFunction, ScopeVariable, Storage},
|
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>) {
|
fn module(&mut self, module: &mut Module, mut state: PassState<ErrorKind>) {
|
||||||
for function in &mut module.functions {
|
for function in &mut module.functions {
|
||||||
let res = function.typecheck(&self.refs, &mut state.inner());
|
let res = function.typecheck(&self.refs, &mut state);
|
||||||
state.ok(res, function.block_meta());
|
state.ok(res, function.block_meta());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +71,7 @@ impl FunctionDefinition {
|
|||||||
for param in &self.parameters {
|
for param in &self.parameters {
|
||||||
let param_t = state.or_else(
|
let param_t = state.or_else(
|
||||||
param.1.assert_known(),
|
param.1.assert_known(),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Unknown),
|
||||||
self.signature(),
|
self.signature(),
|
||||||
);
|
);
|
||||||
let res = state
|
let res = state
|
||||||
@ -92,11 +92,9 @@ impl FunctionDefinition {
|
|||||||
let inferred = match &mut self.kind {
|
let inferred = match &mut self.kind {
|
||||||
FunctionDefinitionKind::Local(block, _) => {
|
FunctionDefinitionKind::Local(block, _) => {
|
||||||
state.scope.return_type_hint = Some(self.return_type.clone());
|
state.scope.return_type_hint = Some(self.return_type.clone());
|
||||||
block.typecheck(&mut state.inner(), &hints, Some(&return_type))
|
block.typecheck(state, &hints, Some(&return_type))
|
||||||
}
|
|
||||||
FunctionDefinitionKind::Extern => {
|
|
||||||
Ok((ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)))
|
|
||||||
}
|
}
|
||||||
|
FunctionDefinitionKind::Extern => Ok((ReturnKind::Soft, TypeKind::Vague(Unknown))),
|
||||||
};
|
};
|
||||||
|
|
||||||
match inferred {
|
match inferred {
|
||||||
@ -130,12 +128,12 @@ impl Block {
|
|||||||
|
|
||||||
// If expression resolution itself was erronous, resolve as
|
// If expression resolution itself was erronous, resolve as
|
||||||
// Unknown and note error.
|
// Unknown and note error.
|
||||||
let res = state.or_else(res, TypeKind::Vague(Vague::Unknown), expression.1);
|
let res = state.or_else(res, TypeKind::Vague(Unknown), expression.1);
|
||||||
|
|
||||||
// Make sure the expression and variable type really is the same
|
// Make sure the expression and variable type really is the same
|
||||||
let res_t = state.or_else(
|
let res_t = state.or_else(
|
||||||
res.collapse_into(&var_t_resolved),
|
res.collapse_into(&var_t_resolved),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Unknown),
|
||||||
variable_reference.2 + expression.1,
|
variable_reference.2 + expression.1,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -143,7 +141,7 @@ impl Block {
|
|||||||
// Unable to infer variable type even from expression! Default it
|
// Unable to infer variable type even from expression! Default it
|
||||||
let res_t = state.or_else(
|
let res_t = state.or_else(
|
||||||
res_t.or_default(),
|
res_t.or_default(),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Unknown),
|
||||||
variable_reference.2,
|
variable_reference.2,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -189,14 +187,13 @@ impl Block {
|
|||||||
|
|
||||||
// If expression resolution itself was erronous, resolve as
|
// If expression resolution itself was erronous, resolve as
|
||||||
// Unknown.
|
// Unknown.
|
||||||
let expr_ty =
|
let expr_ty = state.or_else(res, TypeKind::Vague(Unknown), expression.1);
|
||||||
state.or_else(res, TypeKind::Vague(Vague::Unknown), expression.1);
|
|
||||||
|
|
||||||
// Make sure the expression and variable type to really
|
// Make sure the expression and variable type to really
|
||||||
// be the same
|
// be the same
|
||||||
let res_t = state.or_else(
|
let res_t = state.or_else(
|
||||||
expr_ty.collapse_into(&var.ty.resolve_hinted(&hints)),
|
expr_ty.collapse_into(&var.ty.resolve_hinted(&hints)),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Unknown),
|
||||||
variable_reference.meta + expression.1,
|
variable_reference.meta + expression.1,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -244,7 +241,7 @@ impl Block {
|
|||||||
let res = expr.typecheck(&mut state, &hints, hint.as_ref());
|
let res = expr.typecheck(&mut state, &hints, hint.as_ref());
|
||||||
return Ok((
|
return Ok((
|
||||||
ReturnKind::Hard,
|
ReturnKind::Hard,
|
||||||
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
state.or_else(res, TypeKind::Vague(Unknown), expr.1),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +254,7 @@ impl Block {
|
|||||||
let res = expr.typecheck(&mut state, &hints, ret_hint_t.as_ref());
|
let res = expr.typecheck(&mut state, &hints, ret_hint_t.as_ref());
|
||||||
Ok((
|
Ok((
|
||||||
*return_kind,
|
*return_kind,
|
||||||
state.or_else(res, TypeKind::Vague(Vague::Unknown), expr.1),
|
state.or_else(res, TypeKind::Vague(Unknown), expr.1),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok((ReturnKind::Soft, TypeKind::Void))
|
Ok((ReturnKind::Soft, TypeKind::Void))
|
||||||
@ -283,7 +280,7 @@ impl Expression {
|
|||||||
.map(|var| &var.ty)
|
.map(|var| &var.ty)
|
||||||
.cloned()
|
.cloned()
|
||||||
.ok_or(ErrorKind::VariableNotDefined(var_ref.1.clone())),
|
.ok_or(ErrorKind::VariableNotDefined(var_ref.1.clone())),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Unknown),
|
||||||
var_ref.2,
|
var_ref.2,
|
||||||
)
|
)
|
||||||
.resolve_hinted(hints);
|
.resolve_hinted(hints);
|
||||||
@ -291,7 +288,7 @@ impl Expression {
|
|||||||
// Update typing to be more accurate
|
// Update typing to be more accurate
|
||||||
var_ref.0 = state.or_else(
|
var_ref.0 = state.or_else(
|
||||||
var_ref.0.resolve_hinted(hints).collapse_into(&existing),
|
var_ref.0.resolve_hinted(hints).collapse_into(&existing),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Unknown),
|
||||||
var_ref.2,
|
var_ref.2,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -305,9 +302,9 @@ impl Expression {
|
|||||||
// TODO make sure lhs and rhs can actually do this binary
|
// TODO make sure lhs and rhs can actually do this binary
|
||||||
// operation once relevant
|
// operation once relevant
|
||||||
let lhs_res = lhs.typecheck(state, &hints, None);
|
let lhs_res = lhs.typecheck(state, &hints, None);
|
||||||
let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Vague::Unknown), lhs.1);
|
let lhs_type = state.or_else(lhs_res, TypeKind::Vague(Unknown), lhs.1);
|
||||||
let rhs_res = rhs.typecheck(state, &hints, Some(&lhs_type));
|
let rhs_res = rhs.typecheck(state, &hints, Some(&lhs_type));
|
||||||
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Vague::Unknown), rhs.1);
|
let rhs_type = state.or_else(rhs_res, TypeKind::Vague(Unknown), rhs.1);
|
||||||
|
|
||||||
if let Some(collapsed) = state.ok(rhs_type.collapse_into(&rhs_type), self.1) {
|
if let Some(collapsed) = state.ok(rhs_type.collapse_into(&rhs_type), self.1) {
|
||||||
// Try to coerce both sides again with collapsed type
|
// Try to coerce both sides again with collapsed type
|
||||||
@ -326,7 +323,7 @@ impl Expression {
|
|||||||
.cloned()
|
.cloned()
|
||||||
.ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()));
|
.ok_or(ErrorKind::FunctionNotDefined(function_call.name.clone()));
|
||||||
|
|
||||||
if let Some(f) = state.ok(true_function, self.1) {
|
if let Ok(f) = true_function {
|
||||||
let param_len_given = function_call.parameters.len();
|
let param_len_given = function_call.parameters.len();
|
||||||
let param_len_expected = f.params.len();
|
let param_len_expected = f.params.len();
|
||||||
|
|
||||||
@ -346,15 +343,14 @@ impl Expression {
|
|||||||
let true_params_iter = f
|
let true_params_iter = f
|
||||||
.params
|
.params
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(iter::repeat(TypeKind::Vague(Vague::Unknown)));
|
.chain(iter::repeat(TypeKind::Vague(Unknown)));
|
||||||
|
|
||||||
for (param, true_param_t) in
|
for (param, true_param_t) in
|
||||||
function_call.parameters.iter_mut().zip(true_params_iter)
|
function_call.parameters.iter_mut().zip(true_params_iter)
|
||||||
{
|
{
|
||||||
// Typecheck every param separately
|
// Typecheck every param separately
|
||||||
let param_res = param.typecheck(state, &hints, Some(&true_param_t));
|
let param_res = param.typecheck(state, &hints, Some(&true_param_t));
|
||||||
let param_t =
|
let param_t = state.or_else(param_res, TypeKind::Vague(Unknown), param.1);
|
||||||
state.or_else(param_res, TypeKind::Vague(Vague::Unknown), param.1);
|
|
||||||
state.ok(param_t.collapse_into(&true_param_t), param.1);
|
state.ok(param_t.collapse_into(&true_param_t), param.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,7 +368,7 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
||||||
let cond_res = cond.typecheck(state, &hints, Some(&TypeKind::Bool));
|
let cond_res = cond.typecheck(state, &hints, Some(&TypeKind::Bool));
|
||||||
let cond_t = state.or_else(cond_res, TypeKind::Vague(Vague::Unknown), cond.1);
|
let cond_t = state.or_else(cond_res, TypeKind::Vague(Unknown), cond.1);
|
||||||
state.ok(cond_t.collapse_into(&TypeKind::Bool), cond.1);
|
state.ok(cond_t.collapse_into(&TypeKind::Bool), cond.1);
|
||||||
|
|
||||||
// Typecheck then/else return types and make sure they are the
|
// Typecheck then/else return types and make sure they are the
|
||||||
@ -380,14 +376,14 @@ impl Expression {
|
|||||||
let then_res = lhs.typecheck(state, &hints, hint_t);
|
let then_res = lhs.typecheck(state, &hints, hint_t);
|
||||||
let (then_ret_kind, then_ret_t) = state.or_else(
|
let (then_ret_kind, then_ret_t) = state.or_else(
|
||||||
then_res,
|
then_res,
|
||||||
(ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)),
|
(ReturnKind::Soft, TypeKind::Vague(Unknown)),
|
||||||
lhs.meta,
|
lhs.meta,
|
||||||
);
|
);
|
||||||
let else_ret_t = if let Some(else_block) = rhs {
|
let else_ret_t = if let Some(else_block) = rhs {
|
||||||
let res = else_block.typecheck(state, &hints, hint_t);
|
let res = else_block.typecheck(state, &hints, hint_t);
|
||||||
let (else_ret_kind, else_ret_t) = state.or_else(
|
let (else_ret_kind, else_ret_t) = state.or_else(
|
||||||
res,
|
res,
|
||||||
(ReturnKind::Soft, TypeKind::Vague(Vague::Unknown)),
|
(ReturnKind::Soft, TypeKind::Vague(Unknown)),
|
||||||
else_block.meta,
|
else_block.meta,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -441,7 +437,7 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
let ty = state.or_else(
|
let ty = state.or_else(
|
||||||
elem_ty.resolve_hinted(hints).collapse_into(&inferred_ty),
|
elem_ty.resolve_hinted(hints).collapse_into(&inferred_ty),
|
||||||
TypeKind::Vague(Vague::Unknown),
|
TypeKind::Vague(Unknown),
|
||||||
self.1,
|
self.1,
|
||||||
);
|
);
|
||||||
*elem_ty = ty.clone();
|
*elem_ty = ty.clone();
|
||||||
@ -481,7 +477,7 @@ impl Expression {
|
|||||||
Err(errors) => {
|
Err(errors) => {
|
||||||
state.note_errors(errors, self.1);
|
state.note_errors(errors, self.1);
|
||||||
Ok(TypeKind::Array(
|
Ok(TypeKind::Array(
|
||||||
Box::new(TypeKind::Vague(Vague::Unknown)),
|
Box::new(TypeKind::Vague(Unknown)),
|
||||||
expressions.len() as u64,
|
expressions.len() as u64,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -536,7 +532,16 @@ impl Literal {
|
|||||||
(L::U64(_), TypeKind::U64) => self,
|
(L::U64(_), TypeKind::U64) => self,
|
||||||
(L::U128(_), TypeKind::U128) => self,
|
(L::U128(_), TypeKind::U128) => self,
|
||||||
(L::Bool(_), TypeKind::Bool) => self,
|
(L::Bool(_), TypeKind::Bool) => self,
|
||||||
(L::String(_), TypeKind::StringPtr) => self,
|
(L::String(val), TypeKind::String(len)) => {
|
||||||
|
if val.len() == *len {
|
||||||
|
L::String(val)
|
||||||
|
} else {
|
||||||
|
Err(ErrorKind::LiteralIncompatible(
|
||||||
|
L::String(val),
|
||||||
|
TypeKind::String(*len),
|
||||||
|
))?
|
||||||
|
}
|
||||||
|
}
|
||||||
// TODO make sure that v is actually able to fit in the
|
// TODO make sure that v is actually able to fit in the
|
||||||
// requested type
|
// requested type
|
||||||
(L::Vague(VagueL::Number(v)), TypeKind::I8) => L::I8(v as i8),
|
(L::Vague(VagueL::Number(v)), TypeKind::I8) => L::I8(v as i8),
|
||||||
@ -570,9 +575,9 @@ impl TypeKind {
|
|||||||
fn or_default(&self) -> Result<TypeKind, ErrorKind> {
|
fn or_default(&self) -> Result<TypeKind, ErrorKind> {
|
||||||
match self {
|
match self {
|
||||||
TypeKind::Vague(vague_type) => match &vague_type {
|
TypeKind::Vague(vague_type) => match &vague_type {
|
||||||
Vague::Unknown => Err(ErrorKind::TypeIsVague(*vague_type)),
|
Unknown => Err(ErrorKind::TypeIsVague(*vague_type)),
|
||||||
Vague::Number => Ok(TypeKind::I32),
|
Number => Ok(TypeKind::I32),
|
||||||
Vague::TypeRef(_) => panic!("Hinted default!"),
|
TypeRef(_) => panic!("Hinted default!"),
|
||||||
},
|
},
|
||||||
_ => Ok(self.clone()),
|
_ => Ok(self.clone()),
|
||||||
}
|
}
|
||||||
@ -580,7 +585,7 @@ impl TypeKind {
|
|||||||
|
|
||||||
fn resolve_hinted(&self, hints: &TypeRefs) -> TypeKind {
|
fn resolve_hinted(&self, hints: &TypeRefs) -> TypeKind {
|
||||||
let resolved = match self {
|
let resolved = match self {
|
||||||
TypeKind::Vague(Vague::TypeRef(idx)) => hints.retrieve_type(*idx).unwrap(),
|
TypeKind::Vague(TypeRef(idx)) => hints.retrieve_type(*idx).unwrap(),
|
||||||
_ => self.clone(),
|
_ => self.clone(),
|
||||||
};
|
};
|
||||||
match resolved {
|
match resolved {
|
||||||
@ -603,24 +608,22 @@ impl Collapsable for TypeKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(TypeKind::Vague(Vague::Number), other) | (other, TypeKind::Vague(Vague::Number)) => {
|
(TypeKind::Vague(Number), other) | (other, TypeKind::Vague(Number)) => match other {
|
||||||
match other {
|
TypeKind::Vague(Unknown) => Ok(TypeKind::Vague(Number)),
|
||||||
TypeKind::Vague(Vague::Unknown) => Ok(TypeKind::Vague(Vague::Number)),
|
TypeKind::Vague(Number) => Ok(TypeKind::Vague(Number)),
|
||||||
TypeKind::Vague(Vague::Number) => Ok(TypeKind::Vague(Vague::Number)),
|
TypeKind::I8
|
||||||
TypeKind::I8
|
| TypeKind::I16
|
||||||
| TypeKind::I16
|
| TypeKind::I32
|
||||||
| TypeKind::I32
|
| TypeKind::I64
|
||||||
| TypeKind::I64
|
| TypeKind::I128
|
||||||
| TypeKind::I128
|
| TypeKind::U8
|
||||||
| TypeKind::U8
|
| TypeKind::U16
|
||||||
| TypeKind::U16
|
| TypeKind::U32
|
||||||
| TypeKind::U32
|
| TypeKind::U64
|
||||||
| TypeKind::U64
|
| TypeKind::U128 => Ok(other.clone()),
|
||||||
| TypeKind::U128 => Ok(other.clone()),
|
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
|
||||||
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
|
},
|
||||||
}
|
(TypeKind::Vague(Unknown), other) | (other, TypeKind::Vague(Unknown)) => {
|
||||||
}
|
|
||||||
(TypeKind::Vague(Vague::Unknown), other) | (other, TypeKind::Vague(Vague::Unknown)) => {
|
|
||||||
Ok(other.clone())
|
Ok(other.clone())
|
||||||
}
|
}
|
||||||
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
|
_ => Err(ErrorKind::TypesIncompatible(self.clone(), other.clone())),
|
||||||
|
@ -31,7 +31,7 @@ impl<'t> Pass for TypeInference<'t> {
|
|||||||
|
|
||||||
fn module(&mut self, module: &mut Module, mut state: PassState<ErrorKind>) {
|
fn module(&mut self, module: &mut Module, mut state: PassState<ErrorKind>) {
|
||||||
for function in &mut module.functions {
|
for function in &mut module.functions {
|
||||||
let res = function.infer_types(&self.refs, &mut state.inner());
|
let res = function.infer_types(&self.refs, &mut state);
|
||||||
state.ok(res, function.block_meta());
|
state.ok(res, function.block_meta());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ impl<'scope> TypeRef<'scope> {
|
|||||||
match resolved {
|
match resolved {
|
||||||
TypeKind::Array(elem_ty, len) => {
|
TypeKind::Array(elem_ty, len) => {
|
||||||
let resolved_elem_ty = self.1.from_type(&elem_ty).unwrap().resolve_type();
|
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)
|
TypeKind::Array(Box::new(resolved_elem_ty), len)
|
||||||
}
|
}
|
||||||
_ => resolved,
|
_ => resolved,
|
||||||
|
@ -180,34 +180,3 @@ 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -205,7 +205,7 @@ impl std::iter::Sum for TokenRange {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Expected {} at Ln {}, Col {}, got {:?}", .0, (.2).1, (.2).0, .1)]
|
#[error("Expected {} at Ln {}, Col {}, got {:?}", .0, (.2).1, (.2).0, .1)]
|
||||||
Expected(String, Token, Position),
|
Expected(String, Token, Position),
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
|
|
||||||
import std::print;
|
|
||||||
|
|
||||||
fn main() -> u16 {
|
|
||||||
let hello = "hello world";
|
|
||||||
|
|
||||||
print(hello);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
@ -1,10 +0,0 @@
|
|||||||
|
|
||||||
extern fn puts(message: string) -> i32;
|
|
||||||
|
|
||||||
pub fn print(message: string) {
|
|
||||||
puts(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> u16 {
|
|
||||||
return 0;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user