Compare commits
No commits in common. "46560d85410001b26fac3210d73ba0749d35ade7" and "2e99ec3a80d82a618f3ea7771a8434a7104215f0" have entirely different histories.
46560d8541
...
2e99ec3a80
@ -260,17 +260,9 @@ impl ConstValue {
|
|||||||
pub fn get_type(&self) -> Type {
|
pub fn get_type(&self) -> Type {
|
||||||
use Type::*;
|
use Type::*;
|
||||||
match self {
|
match self {
|
||||||
ConstValue::I8(_) => I8,
|
|
||||||
ConstValue::I16(_) => I16,
|
|
||||||
ConstValue::I32(_) => I32,
|
ConstValue::I32(_) => I32,
|
||||||
ConstValue::I64(_) => I64,
|
ConstValue::I16(_) => I16,
|
||||||
ConstValue::I128(_) => I128,
|
|
||||||
ConstValue::U8(_) => U8,
|
|
||||||
ConstValue::U16(_) => U16,
|
|
||||||
ConstValue::U32(_) => U32,
|
ConstValue::U32(_) => U32,
|
||||||
ConstValue::U64(_) => U64,
|
|
||||||
ConstValue::U128(_) => U128,
|
|
||||||
ConstValue::Bool(_) => Bool,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -278,16 +270,9 @@ impl ConstValue {
|
|||||||
impl Type {
|
impl Type {
|
||||||
pub fn comparable(&self) -> bool {
|
pub fn comparable(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Type::I8 => true,
|
|
||||||
Type::I16 => true,
|
|
||||||
Type::I32 => true,
|
Type::I32 => true,
|
||||||
Type::I64 => true,
|
Type::I16 => true,
|
||||||
Type::I128 => true,
|
|
||||||
Type::U8 => true,
|
|
||||||
Type::U16 => true,
|
|
||||||
Type::U32 => true,
|
Type::U32 => true,
|
||||||
Type::U64 => true,
|
|
||||||
Type::U128 => true,
|
|
||||||
Type::Bool => true,
|
Type::Bool => true,
|
||||||
Type::Void => false,
|
Type::Void => false,
|
||||||
}
|
}
|
||||||
@ -295,16 +280,9 @@ impl Type {
|
|||||||
|
|
||||||
pub fn signed(&self) -> bool {
|
pub fn signed(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Type::I8 => true,
|
|
||||||
Type::I16 => true,
|
|
||||||
Type::I32 => true,
|
Type::I32 => true,
|
||||||
Type::I64 => true,
|
Type::I16 => true,
|
||||||
Type::I128 => true,
|
|
||||||
Type::U8 => false,
|
|
||||||
Type::U16 => false,
|
|
||||||
Type::U32 => false,
|
Type::U32 => false,
|
||||||
Type::U64 => false,
|
|
||||||
Type::U128 => false,
|
|
||||||
Type::Bool => false,
|
Type::Bool => false,
|
||||||
Type::Void => false,
|
Type::Void => false,
|
||||||
}
|
}
|
||||||
|
@ -264,13 +264,12 @@ impl InstructionHolder {
|
|||||||
LLVMBuildSub(module.builder_ref, lhs_val, rhs_val, c"sub".as_ptr())
|
LLVMBuildSub(module.builder_ref, lhs_val, rhs_val, c"sub".as_ptr())
|
||||||
}
|
}
|
||||||
ICmp(pred, lhs, rhs) => {
|
ICmp(pred, lhs, rhs) => {
|
||||||
let lhs = module.values.get(&lhs).unwrap();
|
let lhs_val = module.values.get(&lhs).unwrap().value_ref;
|
||||||
let rhs_val = module.values.get(&rhs).unwrap().value_ref;
|
let rhs_val = module.values.get(&rhs).unwrap().value_ref;
|
||||||
LLVMBuildICmp(
|
LLVMBuildICmp(
|
||||||
module.builder_ref,
|
module.builder_ref,
|
||||||
// Signedness from LHS
|
pred.as_llvm(_ty.signed()),
|
||||||
pred.as_llvm(lhs._ty.signed()),
|
lhs_val,
|
||||||
lhs.value_ref,
|
|
||||||
rhs_val,
|
rhs_val,
|
||||||
c"icmp".as_ptr(),
|
c"icmp".as_ptr(),
|
||||||
)
|
)
|
||||||
@ -371,17 +370,9 @@ impl ConstValue {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let t = self.get_type().as_llvm(context);
|
let t = self.get_type().as_llvm(context);
|
||||||
match *self {
|
match *self {
|
||||||
ConstValue::Bool(val) => LLVMConstInt(t, val as u64, 1),
|
|
||||||
ConstValue::I8(val) => LLVMConstInt(t, val as u64, 1),
|
|
||||||
ConstValue::I16(val) => LLVMConstInt(t, val as u64, 1),
|
|
||||||
ConstValue::I32(val) => LLVMConstInt(t, val as u64, 1),
|
ConstValue::I32(val) => LLVMConstInt(t, val as u64, 1),
|
||||||
ConstValue::I64(val) => LLVMConstInt(t, val as u64, 1),
|
ConstValue::I16(val) => LLVMConstInt(t, val as u64, 1),
|
||||||
ConstValue::I128(val) => LLVMConstInt(t, val as u64, 1),
|
ConstValue::U32(val) => LLVMConstInt(t, val as u64, 0),
|
||||||
ConstValue::U8(val) => LLVMConstInt(t, val as u64, 1),
|
|
||||||
ConstValue::U16(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::U128(val) => LLVMConstInt(t, val as u64, 1),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -389,16 +380,13 @@ impl ConstValue {
|
|||||||
|
|
||||||
impl Type {
|
impl Type {
|
||||||
fn as_llvm(&self, context: LLVMContextRef) -> LLVMTypeRef {
|
fn as_llvm(&self, context: LLVMContextRef) -> LLVMTypeRef {
|
||||||
use Type::*;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
match self {
|
match self {
|
||||||
I8 | U8 => LLVMInt8TypeInContext(context),
|
Type::I32 => LLVMInt32TypeInContext(context),
|
||||||
I16 | U16 => LLVMInt16TypeInContext(context),
|
Type::I16 => LLVMInt16TypeInContext(context),
|
||||||
I32 | U32 => LLVMInt32TypeInContext(context),
|
Type::U32 => LLVMInt32TypeInContext(context),
|
||||||
I64 | U64 => LLVMInt64TypeInContext(context),
|
Type::Bool => LLVMInt1TypeInContext(context),
|
||||||
I128 | U128 => LLVMInt128TypeInContext(context),
|
Type::Void => LLVMVoidType(),
|
||||||
Bool => LLVMInt1TypeInContext(context),
|
|
||||||
Void => LLVMVoidType(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,33 +158,18 @@ pub enum InstructionKind {
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
I8,
|
|
||||||
I16,
|
|
||||||
I32,
|
I32,
|
||||||
I64,
|
I16,
|
||||||
I128,
|
|
||||||
U8,
|
|
||||||
U16,
|
|
||||||
U32,
|
U32,
|
||||||
U64,
|
|
||||||
U128,
|
|
||||||
Bool,
|
Bool,
|
||||||
Void,
|
Void,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum ConstValue {
|
pub enum ConstValue {
|
||||||
I8(i8),
|
|
||||||
I16(i16),
|
|
||||||
I32(i32),
|
I32(i32),
|
||||||
I64(i64),
|
I16(i16),
|
||||||
I128(i128),
|
|
||||||
U8(u8),
|
|
||||||
U16(u16),
|
|
||||||
U32(u32),
|
U32(u32),
|
||||||
U64(u64),
|
|
||||||
U128(u128),
|
|
||||||
Bool(bool),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Hash)]
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
// Main
|
// Main
|
||||||
fn main() -> u8 {
|
fn main() -> i32 {
|
||||||
let a = fibonacci(3);
|
let a = fibonacci(3);
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fibonacci
|
// Fibonacci
|
||||||
fn fibonacci(value: u8) -> u8 {
|
fn fibonacci(value: i32) -> i32 {
|
||||||
if value < 3 {
|
if value < 3 {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 5 + fibonacci(value - 2);
|
return fibonacci(value - 1) + fibonacci(value - 2);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use reid::mir::{self, *};
|
use reid::mir::*;
|
||||||
use reid_lib::Context;
|
use reid_lib::Context;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -152,22 +152,21 @@ fn main() {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mir_context = mir::Context {
|
println!("test1");
|
||||||
modules: vec![Module {
|
|
||||||
|
let module = Module {
|
||||||
name: "test module".to_owned(),
|
name: "test module".to_owned(),
|
||||||
imports: vec![],
|
imports: vec![],
|
||||||
functions: vec![fibonacci, main],
|
functions: vec![fibonacci, main],
|
||||||
}],
|
|
||||||
};
|
};
|
||||||
println!("test1");
|
|
||||||
|
|
||||||
let context = Context::new();
|
|
||||||
let codegen = mir_context.codegen(&context);
|
|
||||||
println!("test2");
|
println!("test2");
|
||||||
|
let context = Context::new();
|
||||||
|
let codegen_module = module.codegen(&context);
|
||||||
|
|
||||||
codegen.compile();
|
|
||||||
println!("test3");
|
println!("test3");
|
||||||
|
|
||||||
|
codegen_module.context.compile();
|
||||||
// match codegen_module.module.print_to_string() {
|
// match codegen_module.module.print_to_string() {
|
||||||
// Ok(v) => println!("{}", v),
|
// Ok(v) => println!("{}", v),
|
||||||
// Err(e) => println!("Err: {:?}", e),
|
// Err(e) => println!("Err: {:?}", e),
|
||||||
|
@ -8,17 +8,7 @@ pub struct Type(pub TypeKind, pub TokenRange);
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum TypeKind {
|
pub enum TypeKind {
|
||||||
Bool,
|
|
||||||
I8,
|
|
||||||
I16,
|
|
||||||
I32,
|
I32,
|
||||||
I64,
|
|
||||||
I128,
|
|
||||||
U8,
|
|
||||||
U16,
|
|
||||||
U32,
|
|
||||||
U64,
|
|
||||||
U128,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -15,17 +15,7 @@ impl Parse for Type {
|
|||||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||||
let kind = if let Some(Token::Identifier(ident)) = stream.next() {
|
let kind = if let Some(Token::Identifier(ident)) = stream.next() {
|
||||||
Ok(match &*ident {
|
Ok(match &*ident {
|
||||||
"bool" => TypeKind::Bool,
|
|
||||||
"i8" => TypeKind::I8,
|
|
||||||
"i16" => TypeKind::I16,
|
|
||||||
"i32" => TypeKind::I32,
|
"i32" => TypeKind::I32,
|
||||||
"i64" => TypeKind::I64,
|
|
||||||
"i128" => TypeKind::I128,
|
|
||||||
"u8" => TypeKind::U8,
|
|
||||||
"u16" => TypeKind::U16,
|
|
||||||
"u32" => TypeKind::U32,
|
|
||||||
"u64" => TypeKind::U64,
|
|
||||||
"u128" => TypeKind::U128,
|
|
||||||
_ => panic!("asd"),
|
_ => panic!("asd"),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -3,16 +3,8 @@ use crate::{
|
|||||||
mir::{self, StmtKind, VariableReference},
|
mir::{self, StmtKind, VariableReference},
|
||||||
};
|
};
|
||||||
|
|
||||||
impl mir::Context {
|
|
||||||
pub fn from(modules: Vec<ast::Module>) -> mir::Context {
|
|
||||||
mir::Context {
|
|
||||||
modules: modules.iter().map(|m| m.process()).collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ast::Module {
|
impl ast::Module {
|
||||||
fn process(&self) -> mir::Module {
|
pub 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();
|
||||||
|
|
||||||
@ -168,17 +160,7 @@ impl ast::Literal {
|
|||||||
impl From<ast::TypeKind> for mir::TypeKind {
|
impl From<ast::TypeKind> for mir::TypeKind {
|
||||||
fn from(value: ast::TypeKind) -> Self {
|
fn from(value: ast::TypeKind) -> Self {
|
||||||
match value {
|
match value {
|
||||||
ast::TypeKind::Bool => mir::TypeKind::Bool,
|
|
||||||
ast::TypeKind::I8 => mir::TypeKind::I8,
|
|
||||||
ast::TypeKind::I16 => mir::TypeKind::I16,
|
|
||||||
ast::TypeKind::I32 => mir::TypeKind::I32,
|
ast::TypeKind::I32 => mir::TypeKind::I32,
|
||||||
ast::TypeKind::I64 => mir::TypeKind::I64,
|
|
||||||
ast::TypeKind::I128 => mir::TypeKind::I128,
|
|
||||||
ast::TypeKind::U8 => mir::TypeKind::U8,
|
|
||||||
ast::TypeKind::U16 => mir::TypeKind::U16,
|
|
||||||
ast::TypeKind::U32 => mir::TypeKind::U32,
|
|
||||||
ast::TypeKind::U64 => mir::TypeKind::U64,
|
|
||||||
ast::TypeKind::U128 => mir::TypeKind::U128,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,42 +7,13 @@ use reid_lib::{
|
|||||||
|
|
||||||
use crate::mir::{self, types::ReturnType, TypeKind, VariableReference};
|
use crate::mir::{self, types::ReturnType, TypeKind, VariableReference};
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct CodegenContext<'ctx> {
|
|
||||||
pub modules: Vec<ModuleCodegen<'ctx>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'ctx> CodegenContext<'ctx> {
|
|
||||||
pub fn compile(&self) {
|
|
||||||
for module in &self.modules {
|
|
||||||
module.context.compile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl mir::Context {
|
|
||||||
pub fn codegen<'ctx>(&self, context: &'ctx Context) -> CodegenContext<'ctx> {
|
|
||||||
let mut modules = Vec::new();
|
|
||||||
for module in &self.modules {
|
|
||||||
modules.push(module.codegen(context));
|
|
||||||
}
|
|
||||||
CodegenContext { modules }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ModuleCodegen<'ctx> {
|
pub struct ModuleCodegen<'ctx> {
|
||||||
pub context: &'ctx Context,
|
pub context: &'ctx Context,
|
||||||
pub module: Module<'ctx>,
|
pub 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl mir::Module {
|
impl mir::Module {
|
||||||
fn codegen<'ctx>(&self, context: &'ctx Context) -> ModuleCodegen<'ctx> {
|
pub fn codegen<'ctx>(&self, context: &'ctx Context) -> ModuleCodegen<'ctx> {
|
||||||
let mut module = context.module(&self.name);
|
let mut module = context.module(&self.name);
|
||||||
|
|
||||||
let mut functions = HashMap::new();
|
let mut functions = HashMap::new();
|
||||||
@ -323,16 +294,8 @@ impl mir::Literal {
|
|||||||
|
|
||||||
pub fn as_const_kind(&self) -> InstructionKind {
|
pub fn as_const_kind(&self) -> InstructionKind {
|
||||||
InstructionKind::Constant(match *self {
|
InstructionKind::Constant(match *self {
|
||||||
mir::Literal::I8(val) => ConstValue::I8(val),
|
|
||||||
mir::Literal::I16(val) => ConstValue::I16(val),
|
|
||||||
mir::Literal::I32(val) => ConstValue::I32(val),
|
mir::Literal::I32(val) => ConstValue::I32(val),
|
||||||
mir::Literal::I64(val) => ConstValue::I64(val),
|
mir::Literal::I16(val) => ConstValue::I16(val),
|
||||||
mir::Literal::I128(val) => ConstValue::I128(val),
|
|
||||||
mir::Literal::U8(val) => ConstValue::U8(val),
|
|
||||||
mir::Literal::U16(val) => ConstValue::U16(val),
|
|
||||||
mir::Literal::U32(val) => ConstValue::U32(val),
|
|
||||||
mir::Literal::U64(val) => ConstValue::U64(val),
|
|
||||||
mir::Literal::U128(val) => ConstValue::U128(val),
|
|
||||||
mir::Literal::Vague(_) => panic!("Got vague literal!"),
|
mir::Literal::Vague(_) => panic!("Got vague literal!"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -341,16 +304,8 @@ impl mir::Literal {
|
|||||||
impl TypeKind {
|
impl TypeKind {
|
||||||
fn get_type(&self) -> Type {
|
fn get_type(&self) -> Type {
|
||||||
match &self {
|
match &self {
|
||||||
TypeKind::I8 => Type::I8,
|
|
||||||
TypeKind::I16 => Type::I16,
|
|
||||||
TypeKind::I32 => Type::I32,
|
TypeKind::I32 => Type::I32,
|
||||||
TypeKind::I64 => Type::I64,
|
TypeKind::I16 => Type::I16,
|
||||||
TypeKind::I128 => Type::I128,
|
|
||||||
TypeKind::U8 => Type::U8,
|
|
||||||
TypeKind::U16 => Type::U16,
|
|
||||||
TypeKind::U32 => Type::U32,
|
|
||||||
TypeKind::U64 => Type::U64,
|
|
||||||
TypeKind::U128 => Type::U128,
|
|
||||||
TypeKind::Bool => Type::Bool,
|
TypeKind::Bool => Type::Bool,
|
||||||
TypeKind::Void => panic!("Void not a supported type"),
|
TypeKind::Void => panic!("Void not a supported type"),
|
||||||
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
|
TypeKind::Vague(_) => panic!("Tried to compile a vague type!"),
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use mir::typecheck::TypeCheck;
|
|
||||||
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};
|
||||||
@ -23,7 +22,7 @@ pub enum ReidError {
|
|||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
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::typecheck::Error>),
|
||||||
// #[error(transparent)]
|
// #[error(transparent)]
|
||||||
// CodegenError(#[from] codegen::Error),
|
// CodegenError(#[from] codegen::Error),
|
||||||
}
|
}
|
||||||
@ -49,24 +48,24 @@ pub fn compile(source: &str) -> Result<String, ReidError> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
dbg!(&ast_module);
|
dbg!(&ast_module);
|
||||||
let mut mir_context = mir::Context::from(vec![ast_module]);
|
let mut mir_module = ast_module.process();
|
||||||
|
|
||||||
dbg!(&mir_context);
|
dbg!(&mir_module);
|
||||||
|
|
||||||
let state = mir_context.pass(&mut TypeCheck {});
|
let state = mir_module.typecheck();
|
||||||
dbg!(&mir_context);
|
dbg!(&mir_module);
|
||||||
dbg!(&state);
|
dbg!(&state);
|
||||||
if !state.errors.is_empty() {
|
if !state.errors.is_empty() {
|
||||||
return Err(ReidError::TypeCheckErrors(state.errors));
|
return Err(ReidError::TypeCheckErrors(state.errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg!(&mir_context);
|
dbg!(&mir_module);
|
||||||
|
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
let codegen_modules = mir_context.codegen(&mut context);
|
let codegen_module = mir_module.codegen(&mut context);
|
||||||
|
|
||||||
dbg!(&codegen_modules);
|
dbg!(&codegen_module.context);
|
||||||
codegen_modules.compile();
|
codegen_module.context.compile();
|
||||||
|
|
||||||
Ok(String::new())
|
Ok(String::new())
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
/// type-checked beforehand.
|
/// type-checked beforehand.
|
||||||
use crate::token_stream::TokenRange;
|
use crate::token_stream::TokenRange;
|
||||||
|
|
||||||
pub mod pass;
|
|
||||||
pub mod typecheck;
|
pub mod typecheck;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
@ -36,28 +35,12 @@ impl From<TokenRange> for Metadata {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
|
||||||
pub enum TypeKind {
|
pub enum TypeKind {
|
||||||
#[error("bool")]
|
|
||||||
Bool,
|
|
||||||
#[error("i8")]
|
|
||||||
I8,
|
|
||||||
#[error("i16")]
|
|
||||||
I16,
|
|
||||||
#[error("i32")]
|
#[error("i32")]
|
||||||
I32,
|
I32,
|
||||||
#[error("i64")]
|
#[error("i16")]
|
||||||
I64,
|
I16,
|
||||||
#[error("i128")]
|
#[error("bool")]
|
||||||
I128,
|
Bool,
|
||||||
#[error("u8")]
|
|
||||||
U8,
|
|
||||||
#[error("u16")]
|
|
||||||
U16,
|
|
||||||
#[error("u32")]
|
|
||||||
U32,
|
|
||||||
#[error("u64")]
|
|
||||||
U64,
|
|
||||||
#[error("u128")]
|
|
||||||
U128,
|
|
||||||
#[error("void")]
|
#[error("void")]
|
||||||
Void,
|
Void,
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
@ -87,33 +70,15 @@ impl TypeKind {
|
|||||||
match self {
|
match self {
|
||||||
TypeKind::Void => false,
|
TypeKind::Void => false,
|
||||||
TypeKind::Vague(_) => false,
|
TypeKind::Vague(_) => false,
|
||||||
TypeKind::Bool => false,
|
_ => true,
|
||||||
TypeKind::I8 => false,
|
|
||||||
TypeKind::I16 => false,
|
|
||||||
TypeKind::I32 => false,
|
|
||||||
TypeKind::I64 => false,
|
|
||||||
TypeKind::I128 => false,
|
|
||||||
TypeKind::U8 => false,
|
|
||||||
TypeKind::U16 => false,
|
|
||||||
TypeKind::U32 => false,
|
|
||||||
TypeKind::U64 => false,
|
|
||||||
TypeKind::U128 => false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_maths(&self) -> bool {
|
pub fn is_maths(&self) -> bool {
|
||||||
use TypeKind::*;
|
use TypeKind::*;
|
||||||
match &self {
|
match &self {
|
||||||
I8 => true,
|
|
||||||
I16 => true,
|
|
||||||
I32 => true,
|
I32 => true,
|
||||||
I64 => true,
|
I16 => true,
|
||||||
I128 => true,
|
|
||||||
U8 => true,
|
|
||||||
U16 => true,
|
|
||||||
U32 => true,
|
|
||||||
U64 => true,
|
|
||||||
U128 => true,
|
|
||||||
Bool => true,
|
Bool => true,
|
||||||
Vague(_) => false,
|
Vague(_) => false,
|
||||||
Void => false,
|
Void => false,
|
||||||
@ -123,16 +88,8 @@ impl TypeKind {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
I8(i8),
|
|
||||||
I16(i16),
|
|
||||||
I32(i32),
|
I32(i32),
|
||||||
I64(i64),
|
I16(i16),
|
||||||
I128(i128),
|
|
||||||
U8(u8),
|
|
||||||
U16(u16),
|
|
||||||
U32(u32),
|
|
||||||
U64(u64),
|
|
||||||
U128(u128),
|
|
||||||
Vague(VagueLiteral),
|
Vague(VagueLiteral),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,16 +101,8 @@ pub enum VagueLiteral {
|
|||||||
impl Literal {
|
impl Literal {
|
||||||
pub fn as_type(self: &Literal) -> TypeKind {
|
pub fn as_type(self: &Literal) -> TypeKind {
|
||||||
match self {
|
match self {
|
||||||
Literal::I8(_) => TypeKind::I8,
|
|
||||||
Literal::I16(_) => TypeKind::I16,
|
|
||||||
Literal::I32(_) => TypeKind::I32,
|
Literal::I32(_) => TypeKind::I32,
|
||||||
Literal::I64(_) => TypeKind::I64,
|
Literal::I16(_) => TypeKind::I16,
|
||||||
Literal::I128(_) => TypeKind::I128,
|
|
||||||
Literal::U8(_) => TypeKind::U8,
|
|
||||||
Literal::U16(_) => TypeKind::U16,
|
|
||||||
Literal::U32(_) => TypeKind::U32,
|
|
||||||
Literal::U64(_) => TypeKind::U64,
|
|
||||||
Literal::U128(_) => TypeKind::U128,
|
|
||||||
Literal::Vague(VagueLiteral::Number(_)) => TypeKind::Vague(VagueType::Number),
|
Literal::Vague(VagueLiteral::Number(_)) => TypeKind::Vague(VagueType::Number),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,8 +215,3 @@ pub struct Module {
|
|||||||
pub imports: Vec<Import>,
|
pub imports: Vec<Import>,
|
||||||
pub functions: Vec<FunctionDefinition>,
|
pub functions: Vec<FunctionDefinition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Context {
|
|
||||||
pub modules: Vec<Module>,
|
|
||||||
}
|
|
||||||
|
@ -1,279 +0,0 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use std::error::Error as STDError;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone)]
|
|
||||||
pub enum SimplePassError {
|
|
||||||
#[error("Function not defined: {0}")]
|
|
||||||
FunctionAlreadyDefined(String),
|
|
||||||
#[error("Variable not defined: {0}")]
|
|
||||||
VariableAlreadyDefined(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Error<TErr: STDError> {
|
|
||||||
metadata: Metadata,
|
|
||||||
kind: TErr,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<TErr: STDError> std::fmt::Display for Error<TErr> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "Error at {}: {}", self.metadata, self.kind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<TErr: STDError> STDError for Error<TErr> {
|
|
||||||
fn source(&self) -> Option<&(dyn STDError + 'static)> {
|
|
||||||
self.kind.source()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Storage<T: std::fmt::Debug>(HashMap<String, T>);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct State<TErr: STDError> {
|
|
||||||
pub errors: Vec<Error<TErr>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<TErr: STDError> State<TErr> {
|
|
||||||
fn new() -> State<TErr> {
|
|
||||||
State {
|
|
||||||
errors: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn or_else<U, T: Into<Metadata> + Clone + Copy>(
|
|
||||||
&mut self,
|
|
||||||
result: Result<U, TErr>,
|
|
||||||
default: U,
|
|
||||||
meta: T,
|
|
||||||
) -> U {
|
|
||||||
match result {
|
|
||||||
Ok(t) => t,
|
|
||||||
Err(e) => {
|
|
||||||
self.errors.push(Error {
|
|
||||||
metadata: meta.into(),
|
|
||||||
kind: e,
|
|
||||||
});
|
|
||||||
default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ok<T: Into<Metadata> + Clone + Copy, U>(
|
|
||||||
&mut self,
|
|
||||||
result: Result<U, TErr>,
|
|
||||||
meta: T,
|
|
||||||
) -> Option<U> {
|
|
||||||
match result {
|
|
||||||
Ok(v) => Some(v),
|
|
||||||
Err(e) => {
|
|
||||||
self.errors.push(Error {
|
|
||||||
metadata: meta.into(),
|
|
||||||
kind: e,
|
|
||||||
});
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: std::fmt::Debug> Default for Storage<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Clone + std::fmt::Debug> Storage<T> {
|
|
||||||
pub fn set(&mut self, key: String, value: T) -> Result<T, ()> {
|
|
||||||
if let Some(_) = self.0.get(&key) {
|
|
||||||
Err(())
|
|
||||||
} else {
|
|
||||||
self.0.insert(key, value.clone());
|
|
||||||
Ok(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, key: &String) -> Option<&T> {
|
|
||||||
self.0.get(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug)]
|
|
||||||
pub struct Scope {
|
|
||||||
pub function_returns: Storage<ScopeFunction>,
|
|
||||||
pub variables: Storage<TypeKind>,
|
|
||||||
/// Hard Return type of this scope, if inside a function
|
|
||||||
pub return_type_hint: Option<TypeKind>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct ScopeFunction {
|
|
||||||
pub ret: TypeKind,
|
|
||||||
pub params: Vec<TypeKind>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Scope {
|
|
||||||
pub fn inner(&self) -> Scope {
|
|
||||||
Scope {
|
|
||||||
function_returns: self.function_returns.clone(),
|
|
||||||
variables: self.variables.clone(),
|
|
||||||
return_type_hint: self.return_type_hint,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PassState<'st, 'sc, TError: STDError + Clone> {
|
|
||||||
state: &'st mut State<TError>,
|
|
||||||
pub scope: &'sc mut Scope,
|
|
||||||
inner: Vec<Scope>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'st, 'sc, TError: STDError + Clone> PassState<'st, 'sc, TError> {
|
|
||||||
fn from(state: &'st mut State<TError>, scope: &'sc mut Scope) -> Self {
|
|
||||||
PassState {
|
|
||||||
state,
|
|
||||||
scope,
|
|
||||||
inner: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn or_else<U, TMeta: Into<Metadata> + Clone + Copy>(
|
|
||||||
&mut self,
|
|
||||||
result: Result<U, TError>,
|
|
||||||
default: U,
|
|
||||||
meta: TMeta,
|
|
||||||
) -> U {
|
|
||||||
self.state.or_else(result, default, meta)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ok<TMeta: Into<Metadata> + Clone + Copy, U>(
|
|
||||||
&mut self,
|
|
||||||
result: Result<U, TError>,
|
|
||||||
meta: TMeta,
|
|
||||||
) -> Option<U> {
|
|
||||||
self.state.ok(result, meta)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inner(&mut self) -> PassState<TError> {
|
|
||||||
self.inner.push(self.scope.inner());
|
|
||||||
let scope = self.inner.last_mut().unwrap();
|
|
||||||
PassState {
|
|
||||||
state: self.state,
|
|
||||||
scope,
|
|
||||||
inner: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Pass {
|
|
||||||
type TError: STDError + Clone;
|
|
||||||
|
|
||||||
fn module(&mut self, _module: &mut Module, mut _state: PassState<Self::TError>) {}
|
|
||||||
fn function(
|
|
||||||
&mut self,
|
|
||||||
_function: &mut FunctionDefinition,
|
|
||||||
mut _state: PassState<Self::TError>,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
fn block(&mut self, _block: &mut Block, mut _state: PassState<Self::TError>) {}
|
|
||||||
fn stmt(&mut self, _stmt: &mut Statement, mut _state: PassState<Self::TError>) {}
|
|
||||||
fn expr(&mut self, _expr: &mut Expression, mut _state: PassState<Self::TError>) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
for module in &mut self.modules {
|
|
||||||
module.pass(pass, &mut state, &mut scope);
|
|
||||||
}
|
|
||||||
state
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Module {
|
|
||||||
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) {
|
|
||||||
for function in &self.functions {
|
|
||||||
scope
|
|
||||||
.function_returns
|
|
||||||
.set(
|
|
||||||
function.name.clone(),
|
|
||||||
ScopeFunction {
|
|
||||||
ret: function.return_type,
|
|
||||||
params: function.parameters.iter().map(|v| v.1).collect(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
pass.module(self, PassState::from(state, scope));
|
|
||||||
|
|
||||||
for function in &mut self.functions {
|
|
||||||
function.pass(pass, state, scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FunctionDefinition {
|
|
||||||
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) {
|
|
||||||
for param in &self.parameters {
|
|
||||||
scope.variables.set(param.0.clone(), param.1).ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
pass.function(self, PassState::from(state, scope));
|
|
||||||
|
|
||||||
match &mut self.kind {
|
|
||||||
FunctionDefinitionKind::Local(block, _) => {
|
|
||||||
scope.return_type_hint = Some(self.return_type);
|
|
||||||
block.pass(pass, state, scope);
|
|
||||||
}
|
|
||||||
FunctionDefinitionKind::Extern => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Block {
|
|
||||||
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) {
|
|
||||||
let mut scope = scope.inner();
|
|
||||||
|
|
||||||
for statement in &mut self.statements {
|
|
||||||
statement.pass(pass, state, &mut scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
pass.block(self, PassState::from(state, &mut scope));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Statement {
|
|
||||||
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) {
|
|
||||||
match &mut self.0 {
|
|
||||||
StmtKind::Let(_, expression) => {
|
|
||||||
expression.pass(pass, state, scope);
|
|
||||||
}
|
|
||||||
StmtKind::Import(_) => todo!(),
|
|
||||||
StmtKind::Expression(expression) => {
|
|
||||||
expression.pass(pass, state, scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pass.stmt(self, PassState::from(state, scope));
|
|
||||||
|
|
||||||
match &mut self.0 {
|
|
||||||
StmtKind::Let(variable_reference, _) => scope
|
|
||||||
.variables
|
|
||||||
.set(variable_reference.1.clone(), variable_reference.0)
|
|
||||||
.ok(),
|
|
||||||
StmtKind::Import(_) => todo!(),
|
|
||||||
StmtKind::Expression(_) => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Expression {
|
|
||||||
fn pass<T: Pass>(&mut self, pass: &mut T, state: &mut State<T::TError>, scope: &mut Scope) {
|
|
||||||
pass.expr(self, PassState::from(state, scope));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,27 @@
|
|||||||
use std::{convert::Infallible, iter};
|
use std::{collections::HashMap, convert::Infallible, iter};
|
||||||
|
|
||||||
/// This module contains code relevant to doing a type checking pass on the MIR.
|
/// This module contains code relevant to doing a type checking pass on the MIR.
|
||||||
use crate::{mir::*, util::try_all};
|
use crate::{mir::*, util::try_all};
|
||||||
use TypeKind::*;
|
use TypeKind::*;
|
||||||
use VagueType::*;
|
use VagueType::*;
|
||||||
|
|
||||||
use super::pass::{Pass, PassState, ScopeFunction};
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Error {
|
||||||
|
metadata: Metadata,
|
||||||
|
kind: ErrorKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Error at {}: {}", self.metadata, self.kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for Error {
|
||||||
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
self.kind.source()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(thiserror::Error, Debug, Clone)]
|
#[derive(thiserror::Error, Debug, Clone)]
|
||||||
pub enum ErrorKind {
|
pub enum ErrorKind {
|
||||||
@ -13,8 +29,6 @@ pub enum ErrorKind {
|
|||||||
Null,
|
Null,
|
||||||
#[error("Type is vague: {0}")]
|
#[error("Type is vague: {0}")]
|
||||||
TypeIsVague(VagueType),
|
TypeIsVague(VagueType),
|
||||||
#[error("Can not coerce {0} to vague type {1}")]
|
|
||||||
HintIsVague(TypeKind, VagueType),
|
|
||||||
#[error("Types {0} and {1} are incompatible")]
|
#[error("Types {0} and {1} are incompatible")]
|
||||||
TypesIncompatible(TypeKind, TypeKind),
|
TypesIncompatible(TypeKind, TypeKind),
|
||||||
#[error("Variable not defined: {0}")]
|
#[error("Variable not defined: {0}")]
|
||||||
@ -23,42 +37,150 @@ pub enum ErrorKind {
|
|||||||
FunctionNotDefined(String),
|
FunctionNotDefined(String),
|
||||||
#[error("Type is vague: {0}")]
|
#[error("Type is vague: {0}")]
|
||||||
ReturnTypeMismatch(TypeKind, TypeKind),
|
ReturnTypeMismatch(TypeKind, TypeKind),
|
||||||
#[error("Function not defined: {0}")]
|
|
||||||
FunctionAlreadyDefined(String),
|
|
||||||
#[error("Variable not defined: {0}")]
|
|
||||||
VariableAlreadyDefined(String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TypeCheck {}
|
#[derive(Clone)]
|
||||||
|
pub struct TypeStorage<T>(HashMap<String, T>);
|
||||||
|
|
||||||
impl Pass for TypeCheck {
|
impl<T> Default for TypeStorage<T> {
|
||||||
type TError = ErrorKind;
|
fn default() -> Self {
|
||||||
|
Self(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn module(&mut self, module: &mut Module, mut state: PassState<ErrorKind>) {
|
impl<T: Collapsable> TypeStorage<T> {
|
||||||
for function in &mut module.functions {
|
fn set(&mut self, key: String, value: T) -> Result<T, ErrorKind> {
|
||||||
let res = function.typecheck(&mut state);
|
if let Some(inner) = self.0.get(&key) {
|
||||||
|
match value.collapse_into(inner) {
|
||||||
|
Ok(collapsed) => {
|
||||||
|
self.0.insert(key, collapsed.clone());
|
||||||
|
Ok(collapsed)
|
||||||
|
}
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.0.insert(key, value.clone());
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(&self, key: &String) -> Option<&T> {
|
||||||
|
self.0.get(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct State {
|
||||||
|
pub errors: Vec<Error>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
fn new() -> State {
|
||||||
|
State {
|
||||||
|
errors: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn or_else<T: Into<Metadata> + Clone + Copy>(
|
||||||
|
&mut self,
|
||||||
|
result: Result<TypeKind, ErrorKind>,
|
||||||
|
default: TypeKind,
|
||||||
|
meta: T,
|
||||||
|
) -> TypeKind {
|
||||||
|
match result {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(e) => {
|
||||||
|
self.errors.push(Error {
|
||||||
|
metadata: meta.into(),
|
||||||
|
kind: e,
|
||||||
|
});
|
||||||
|
default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ok<T: Into<Metadata> + Clone + Copy, U>(&mut self, result: Result<U, ErrorKind>, meta: T) {
|
||||||
|
if let Err(e) = result {
|
||||||
|
self.errors.push(Error {
|
||||||
|
metadata: meta.into(),
|
||||||
|
kind: e,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct Scope {
|
||||||
|
function_returns: TypeStorage<ScopeFunction>,
|
||||||
|
variables: TypeStorage<TypeKind>,
|
||||||
|
/// Hard Return type of this scope, if inside a function
|
||||||
|
return_type_hint: Option<TypeKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ScopeFunction {
|
||||||
|
ret: TypeKind,
|
||||||
|
params: Vec<TypeKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Scope {
|
||||||
|
fn inner(&self) -> Scope {
|
||||||
|
Scope {
|
||||||
|
function_returns: self.function_returns.clone(),
|
||||||
|
variables: self.variables.clone(),
|
||||||
|
return_type_hint: self.return_type_hint,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Inferred {
|
||||||
|
Type(TypeKind),
|
||||||
|
Unresolved(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Module {
|
||||||
|
pub fn typecheck(&mut self) -> State {
|
||||||
|
let mut state = State::new();
|
||||||
|
let mut scope = Scope::default();
|
||||||
|
|
||||||
|
for function in &self.functions {
|
||||||
|
state.ok(
|
||||||
|
scope.function_returns.set(
|
||||||
|
function.name.clone(),
|
||||||
|
ScopeFunction {
|
||||||
|
ret: function.return_type,
|
||||||
|
params: function.parameters.iter().map(|v| v.1).collect(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
function.signature(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for function in &mut self.functions {
|
||||||
|
let res = function.typecheck(&mut state, &mut scope);
|
||||||
state.ok(res, function.block_meta());
|
state.ok(res, function.block_meta());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionDefinition {
|
impl FunctionDefinition {
|
||||||
fn typecheck(&mut self, state: &mut PassState<ErrorKind>) -> Result<TypeKind, ErrorKind> {
|
fn typecheck(&mut self, state: &mut State, scope: &mut Scope) -> Result<TypeKind, ErrorKind> {
|
||||||
for param in &self.parameters {
|
for param in &self.parameters {
|
||||||
let param_t = state.or_else(param.1.assert_known(), Vague(Unknown), self.signature());
|
let param_t = state.or_else(param.1.assert_known(), Vague(Unknown), self.signature());
|
||||||
let res = state
|
state.ok(
|
||||||
.scope
|
scope.variables.set(param.0.clone(), param_t),
|
||||||
.variables
|
self.signature(),
|
||||||
.set(param.0.clone(), param_t)
|
);
|
||||||
.or(Err(ErrorKind::VariableAlreadyDefined(param.0.clone())));
|
|
||||||
state.ok(res, self.signature());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let return_type = self.return_type.clone();
|
let return_type = self.return_type.clone();
|
||||||
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);
|
scope.return_type_hint = Some(self.return_type);
|
||||||
block.typecheck(state, Some(return_type))
|
block.typecheck(state, scope, Some(return_type))
|
||||||
}
|
}
|
||||||
FunctionDefinitionKind::Extern => Ok(Vague(Unknown)),
|
FunctionDefinitionKind::Extern => Ok(Vague(Unknown)),
|
||||||
};
|
};
|
||||||
@ -74,15 +196,16 @@ impl FunctionDefinition {
|
|||||||
impl Block {
|
impl Block {
|
||||||
fn typecheck(
|
fn typecheck(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut PassState<ErrorKind>,
|
state: &mut State,
|
||||||
|
scope: &mut Scope,
|
||||||
hint_t: Option<TypeKind>,
|
hint_t: Option<TypeKind>,
|
||||||
) -> Result<TypeKind, ErrorKind> {
|
) -> Result<TypeKind, ErrorKind> {
|
||||||
let mut state = state.inner();
|
let mut scope = scope.inner();
|
||||||
|
|
||||||
for statement in &mut self.statements {
|
for statement in &mut self.statements {
|
||||||
match &mut statement.0 {
|
match &mut statement.0 {
|
||||||
StmtKind::Let(variable_reference, expression) => {
|
StmtKind::Let(variable_reference, expression) => {
|
||||||
let res = expression.typecheck(&mut state, Some(variable_reference.0));
|
let res = expression.typecheck(state, &mut scope, Some(variable_reference.0));
|
||||||
|
|
||||||
// If expression resolution itself was erronous, resolve as
|
// If expression resolution itself was erronous, resolve as
|
||||||
// Unknown.
|
// Unknown.
|
||||||
@ -97,24 +220,22 @@ impl Block {
|
|||||||
|
|
||||||
// Make sure expression/variable type is NOT vague anymore
|
// Make sure expression/variable type is NOT vague anymore
|
||||||
let res_t =
|
let res_t =
|
||||||
state.or_else(res_t.or_default(), Vague(Unknown), variable_reference.2);
|
state.or_else(res_t.assert_known(), Vague(Unknown), variable_reference.2);
|
||||||
|
|
||||||
// Update typing to be more accurate
|
// Update typing to be more accurate
|
||||||
variable_reference.0 = res_t;
|
variable_reference.0 = res_t;
|
||||||
|
|
||||||
// Variable might already be defined, note error
|
// Variable might already be defined, note error
|
||||||
let res = state
|
state.ok(
|
||||||
.scope
|
scope
|
||||||
.variables
|
.variables
|
||||||
.set(variable_reference.1.clone(), variable_reference.0)
|
.set(variable_reference.1.clone(), variable_reference.0),
|
||||||
.or(Err(ErrorKind::VariableAlreadyDefined(
|
variable_reference.2,
|
||||||
variable_reference.1.clone(),
|
);
|
||||||
)));
|
|
||||||
state.ok(res, variable_reference.2);
|
|
||||||
}
|
}
|
||||||
StmtKind::Import(_) => todo!(),
|
StmtKind::Import(_) => todo!(),
|
||||||
StmtKind::Expression(expression) => {
|
StmtKind::Expression(expression) => {
|
||||||
let res = expression.typecheck(&mut state, None);
|
let res = expression.typecheck(state, &mut scope, hint_t);
|
||||||
state.ok(res, expression.1);
|
state.ok(res, expression.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,10 +243,10 @@ impl Block {
|
|||||||
|
|
||||||
if let Some((return_kind, expr)) = &mut self.return_expression {
|
if let Some((return_kind, expr)) = &mut self.return_expression {
|
||||||
let ret_hint_t = match return_kind {
|
let ret_hint_t = match return_kind {
|
||||||
ReturnKind::Hard => state.scope.return_type_hint,
|
ReturnKind::Hard => scope.return_type_hint,
|
||||||
ReturnKind::Soft => hint_t,
|
ReturnKind::Soft => hint_t,
|
||||||
};
|
};
|
||||||
let res = expr.typecheck(&mut state, ret_hint_t);
|
let res = expr.typecheck(state, &mut scope, ret_hint_t);
|
||||||
Ok(state.or_else(res, Vague(Unknown), expr.1))
|
Ok(state.or_else(res, Vague(Unknown), expr.1))
|
||||||
} else {
|
} else {
|
||||||
Ok(Void)
|
Ok(Void)
|
||||||
@ -136,16 +257,14 @@ impl Block {
|
|||||||
impl Expression {
|
impl Expression {
|
||||||
fn typecheck(
|
fn typecheck(
|
||||||
&mut self,
|
&mut self,
|
||||||
state: &mut PassState<ErrorKind>,
|
state: &mut State,
|
||||||
|
scope: &mut Scope,
|
||||||
hint_t: Option<TypeKind>,
|
hint_t: Option<TypeKind>,
|
||||||
) -> Result<TypeKind, ErrorKind> {
|
) -> Result<TypeKind, ErrorKind> {
|
||||||
match &mut self.0 {
|
match &mut self.0 {
|
||||||
ExprKind::Variable(var_ref) => {
|
ExprKind::Variable(var_ref) => {
|
||||||
dbg!(&state.scope);
|
|
||||||
|
|
||||||
let existing = state.or_else(
|
let existing = state.or_else(
|
||||||
state
|
scope
|
||||||
.scope
|
|
||||||
.variables
|
.variables
|
||||||
.get(&var_ref.1)
|
.get(&var_ref.1)
|
||||||
.copied()
|
.copied()
|
||||||
@ -170,23 +289,15 @@ impl Expression {
|
|||||||
ExprKind::BinOp(op, lhs, rhs) => {
|
ExprKind::BinOp(op, lhs, rhs) => {
|
||||||
// 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, None); // TODO
|
let lhs_res = lhs.typecheck(state, scope, None); // TODO
|
||||||
let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.1);
|
let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.1);
|
||||||
let rhs_res = rhs.typecheck(state, Some(lhs_type)); // TODO
|
let rhs_res = rhs.typecheck(state, scope, Some(lhs_type)); // TODO
|
||||||
let rhs_type = state.or_else(rhs_res, Vague(Unknown), rhs.1);
|
let rhs_type = state.or_else(rhs_res, 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
|
|
||||||
lhs.typecheck(state, Some(collapsed)).ok();
|
|
||||||
rhs.typecheck(state, Some(collapsed)).ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
let res = lhs_type.binop_type(&op, &rhs_type)?;
|
let res = lhs_type.binop_type(&op, &rhs_type)?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
ExprKind::FunctionCall(function_call) => {
|
ExprKind::FunctionCall(function_call) => {
|
||||||
let true_function = state
|
let true_function = scope
|
||||||
.scope
|
|
||||||
.function_returns
|
.function_returns
|
||||||
.get(&function_call.name)
|
.get(&function_call.name)
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -202,7 +313,7 @@ impl Expression {
|
|||||||
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)
|
||||||
{
|
{
|
||||||
let param_res = param.typecheck(state, Some(true_param_t));
|
let param_res = param.typecheck(state, scope, Some(true_param_t));
|
||||||
let param_t = state.or_else(param_res, Vague(Unknown), param.1);
|
let param_t = state.or_else(param_res, 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);
|
||||||
}
|
}
|
||||||
@ -219,21 +330,21 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
ExprKind::If(IfExpression(cond, lhs, rhs)) => {
|
||||||
// TODO make sure cond_res is Boolean here
|
// TODO make sure cond_res is Boolean here
|
||||||
let cond_res = cond.typecheck(state, Some(Bool));
|
let cond_res = cond.typecheck(state, scope, Some(Bool));
|
||||||
let cond_t = state.or_else(cond_res, Vague(Unknown), cond.1);
|
let cond_t = state.or_else(cond_res, Vague(Unknown), cond.1);
|
||||||
state.ok(cond_t.collapse_into(&Bool), cond.1);
|
state.ok(cond_t.collapse_into(&Bool), cond.1);
|
||||||
|
|
||||||
let lhs_res = lhs.typecheck(state, hint_t);
|
let lhs_res = lhs.typecheck(state, scope, hint_t);
|
||||||
let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.meta);
|
let lhs_type = state.or_else(lhs_res, Vague(Unknown), lhs.meta);
|
||||||
let rhs_type = if let Some(rhs) = rhs {
|
let rhs_type = if let Some(rhs) = rhs {
|
||||||
let res = rhs.typecheck(state, hint_t);
|
let res = rhs.typecheck(state, scope, hint_t);
|
||||||
state.or_else(res, Vague(Unknown), rhs.meta)
|
state.or_else(res, Vague(Unknown), rhs.meta)
|
||||||
} else {
|
} else {
|
||||||
Vague(Unknown)
|
Vague(Unknown)
|
||||||
};
|
};
|
||||||
lhs_type.collapse_into(&rhs_type)
|
lhs_type.collapse_into(&rhs_type)
|
||||||
}
|
}
|
||||||
ExprKind::Block(block) => block.typecheck(state, hint_t),
|
ExprKind::Block(block) => block.typecheck(state, scope, hint_t),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,29 +355,10 @@ impl Literal {
|
|||||||
use Literal as L;
|
use Literal as L;
|
||||||
use VagueLiteral as VagueL;
|
use VagueLiteral as VagueL;
|
||||||
Ok(match (self, hint) {
|
Ok(match (self, hint) {
|
||||||
(L::I8(_), I8) => self,
|
|
||||||
(L::I16(_), I16) => self,
|
|
||||||
(L::I32(_), I32) => self,
|
(L::I32(_), I32) => self,
|
||||||
(L::I64(_), I64) => self,
|
(L::I16(_), I16) => self,
|
||||||
(L::I128(_), I128) => self,
|
|
||||||
(L::U8(_), U8) => self,
|
|
||||||
(L::U16(_), U16) => self,
|
|
||||||
(L::U32(_), U32) => self,
|
|
||||||
(L::U64(_), U64) => self,
|
|
||||||
(L::U128(_), U128) => self,
|
|
||||||
(L::Vague(VagueL::Number(v)), I8) => L::I8(v as i8),
|
|
||||||
(L::Vague(VagueL::Number(v)), I16) => L::I16(v as i16),
|
|
||||||
(L::Vague(VagueL::Number(v)), I32) => L::I32(v as i32),
|
(L::Vague(VagueL::Number(v)), I32) => L::I32(v as i32),
|
||||||
(L::Vague(VagueL::Number(v)), I64) => L::I64(v as i64),
|
(L::Vague(VagueL::Number(v)), I16) => L::I16(v as i16),
|
||||||
(L::Vague(VagueL::Number(v)), I128) => L::I128(v as i128),
|
|
||||||
(L::Vague(VagueL::Number(v)), U8) => L::U8(v as u8),
|
|
||||||
(L::Vague(VagueL::Number(v)), U16) => L::U16(v as u16),
|
|
||||||
(L::Vague(VagueL::Number(v)), U32) => L::U32(v as u32),
|
|
||||||
(L::Vague(VagueL::Number(v)), U64) => L::U64(v as u64),
|
|
||||||
(L::Vague(VagueL::Number(v)), U128) => L::U128(v as u128),
|
|
||||||
// Default type for number literal if unable to find true type.
|
|
||||||
(L::Vague(VagueL::Number(v)), Vague(Number)) => L::I32(v as i32),
|
|
||||||
(_, Vague(_)) => self,
|
|
||||||
_ => Err(ErrorKind::TypesIncompatible(self.as_type(), hint))?,
|
_ => Err(ErrorKind::TypesIncompatible(self.as_type(), hint))?,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -276,24 +368,10 @@ impl Literal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TypeKind {
|
impl TypeKind {
|
||||||
/// Assert that a type is already known and not vague. Return said type or
|
|
||||||
/// error.
|
|
||||||
fn assert_known(&self) -> Result<TypeKind, ErrorKind> {
|
fn assert_known(&self) -> Result<TypeKind, ErrorKind> {
|
||||||
self.is_known().map_err(ErrorKind::TypeIsVague)
|
self.is_known().map_err(ErrorKind::TypeIsVague)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to collapse a type on itself producing a default type if one exists,
|
|
||||||
/// Error if not.
|
|
||||||
fn or_default(&self) -> Result<TypeKind, ErrorKind> {
|
|
||||||
match self {
|
|
||||||
Vague(vague_type) => match vague_type {
|
|
||||||
Unknown => Err(ErrorKind::TypeIsVague(*vague_type)),
|
|
||||||
Number => Ok(TypeKind::I32),
|
|
||||||
},
|
|
||||||
_ => Ok(*self),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn binop_type(&self, op: &BinaryOperator, other: &TypeKind) -> Result<TypeKind, ErrorKind> {
|
fn binop_type(&self, op: &BinaryOperator, other: &TypeKind) -> Result<TypeKind, ErrorKind> {
|
||||||
let res = self.collapse_into(other)?;
|
let res = self.collapse_into(other)?;
|
||||||
Ok(match op {
|
Ok(match op {
|
||||||
@ -323,12 +401,6 @@ impl Collapsable for TypeKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Vague(Number), other) | (other, Vague(Number)) => match other {
|
|
||||||
Vague(Unknown) => Ok(Vague(Number)),
|
|
||||||
Vague(Number) => Ok(Vague(Number)),
|
|
||||||
I8 | I16 | I32 | I64 | I128 | U8 | U16 | U32 | U64 | U128 => Ok(*other),
|
|
||||||
_ => Err(ErrorKind::TypesIncompatible(*self, *other)),
|
|
||||||
},
|
|
||||||
(Vague(Unknown), other) | (other, Vague(Unknown)) => Ok(other.clone()),
|
(Vague(Unknown), other) | (other, Vague(Unknown)) => Ok(other.clone()),
|
||||||
_ => Err(ErrorKind::TypesIncompatible(*self, *other)),
|
_ => Err(ErrorKind::TypesIncompatible(*self, *other)),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user