Compare commits
4 Commits
95b3ffe8ef
...
2e99ec3a80
Author | SHA1 | Date | |
---|---|---|---|
2e99ec3a80 | |||
fb876e3ef5 | |||
cdbc4593a8 | |||
9b9fcd4ec4 |
@ -1,4 +1,4 @@
|
|||||||
use std::{cell::RefCell, marker::PhantomData, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BlockData, ConstValue, FunctionData, InstructionData, InstructionKind, ModuleData,
|
BlockData, ConstValue, FunctionData, InstructionData, InstructionKind, ModuleData,
|
||||||
@ -140,6 +140,7 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) unsafe fn module_data(&self, value: &ModuleValue) -> ModuleData {
|
pub(crate) unsafe fn module_data(&self, value: &ModuleValue) -> ModuleData {
|
||||||
unsafe { self.modules.borrow().get_unchecked(value.0).data.clone() }
|
unsafe { self.modules.borrow().get_unchecked(value.0).data.clone() }
|
||||||
}
|
}
|
||||||
@ -156,6 +157,7 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) unsafe fn block_data(&self, value: &BlockValue) -> BlockData {
|
pub(crate) unsafe fn block_data(&self, value: &BlockValue) -> BlockData {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.modules
|
self.modules
|
||||||
@ -235,7 +237,6 @@ impl Builder {
|
|||||||
impl InstructionValue {
|
impl InstructionValue {
|
||||||
pub fn get_type(&self, builder: &Builder) -> Result<Type, ()> {
|
pub fn get_type(&self, builder: &Builder) -> Result<Type, ()> {
|
||||||
use InstructionKind::*;
|
use InstructionKind::*;
|
||||||
use Type::*;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
match &builder.instr_data(self).kind {
|
match &builder.instr_data(self).kind {
|
||||||
Param(nth) => builder
|
Param(nth) => builder
|
||||||
@ -247,7 +248,7 @@ impl InstructionValue {
|
|||||||
Constant(c) => Ok(c.get_type()),
|
Constant(c) => Ok(c.get_type()),
|
||||||
Add(lhs, rhs) => match_types(lhs, rhs, &builder),
|
Add(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
Sub(lhs, rhs) => match_types(lhs, rhs, &builder),
|
Sub(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||||
ICmp(pred, lhs, rhs) => Ok(Type::Bool),
|
ICmp(_, _, _) => Ok(Type::Bool),
|
||||||
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
|
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
|
||||||
Phi(values) => values.first().ok_or(()).and_then(|v| v.get_type(&builder)),
|
Phi(values) => values.first().ok_or(()).and_then(|v| v.get_type(&builder)),
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{collections::HashMap, ffi::CString, hash::Hash, process::Termination, ptr::null_mut};
|
use std::{collections::HashMap, ffi::CString, ptr::null_mut};
|
||||||
|
|
||||||
use llvm_sys::{
|
use llvm_sys::{
|
||||||
LLVMIntPredicate,
|
LLVMIntPredicate,
|
||||||
@ -18,7 +18,7 @@ use llvm_sys::{
|
|||||||
use crate::util::{ErrorMessageHolder, from_cstring, into_cstring};
|
use crate::util::{ErrorMessageHolder, from_cstring, into_cstring};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
ConstValue, Context, Function, IntPredicate, Module, TerminatorKind, Type,
|
ConstValue, Context, IntPredicate, TerminatorKind, Type,
|
||||||
builder::{
|
builder::{
|
||||||
BlockHolder, BlockValue, Builder, FunctionHolder, FunctionValue, InstructionHolder,
|
BlockHolder, BlockValue, Builder, FunctionHolder, FunctionValue, InstructionHolder,
|
||||||
InstructionValue, ModuleHolder,
|
InstructionValue, ModuleHolder,
|
||||||
@ -54,6 +54,7 @@ pub struct LLVMModule<'a> {
|
|||||||
builder: &'a Builder,
|
builder: &'a Builder,
|
||||||
context_ref: LLVMContextRef,
|
context_ref: LLVMContextRef,
|
||||||
builder_ref: LLVMBuilderRef,
|
builder_ref: LLVMBuilderRef,
|
||||||
|
#[allow(dead_code)]
|
||||||
module_ref: LLVMModuleRef,
|
module_ref: LLVMModuleRef,
|
||||||
functions: HashMap<FunctionValue, LLVMFunction>,
|
functions: HashMap<FunctionValue, LLVMFunction>,
|
||||||
blocks: HashMap<BlockValue, LLVMBasicBlockRef>,
|
blocks: HashMap<BlockValue, LLVMBasicBlockRef>,
|
||||||
@ -67,7 +68,7 @@ pub struct LLVMFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct LLVMValue {
|
pub struct LLVMValue {
|
||||||
ty: Type,
|
_ty: Type,
|
||||||
value_ref: LLVMValueRef,
|
value_ref: LLVMValueRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,9 +245,9 @@ impl InstructionHolder {
|
|||||||
&self,
|
&self,
|
||||||
module: &LLVMModule,
|
module: &LLVMModule,
|
||||||
function: &LLVMFunction,
|
function: &LLVMFunction,
|
||||||
block: LLVMBasicBlockRef,
|
_block: LLVMBasicBlockRef,
|
||||||
) -> LLVMValue {
|
) -> LLVMValue {
|
||||||
let ty = self.value.get_type(module.builder).unwrap();
|
let _ty = self.value.get_type(module.builder).unwrap();
|
||||||
let val = unsafe {
|
let val = unsafe {
|
||||||
use super::InstructionKind::*;
|
use super::InstructionKind::*;
|
||||||
match &self.data.kind {
|
match &self.data.kind {
|
||||||
@ -267,7 +268,7 @@ impl InstructionHolder {
|
|||||||
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,
|
||||||
pred.as_llvm(ty.signed()),
|
pred.as_llvm(_ty.signed()),
|
||||||
lhs_val,
|
lhs_val,
|
||||||
rhs_val,
|
rhs_val,
|
||||||
c"icmp".as_ptr(),
|
c"icmp".as_ptr(),
|
||||||
@ -298,7 +299,7 @@ impl InstructionHolder {
|
|||||||
}
|
}
|
||||||
let phi = LLVMBuildPhi(
|
let phi = LLVMBuildPhi(
|
||||||
module.builder_ref,
|
module.builder_ref,
|
||||||
ty.as_llvm(module.context_ref),
|
_ty.as_llvm(module.context_ref),
|
||||||
c"phi".as_ptr(),
|
c"phi".as_ptr(),
|
||||||
);
|
);
|
||||||
LLVMAddIncoming(
|
LLVMAddIncoming(
|
||||||
@ -311,7 +312,10 @@ impl InstructionHolder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
LLVMValue { ty, value_ref: val }
|
LLVMValue {
|
||||||
|
_ty,
|
||||||
|
value_ref: val,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,10 +323,10 @@ impl TerminatorKind {
|
|||||||
fn compile(
|
fn compile(
|
||||||
&self,
|
&self,
|
||||||
module: &LLVMModule,
|
module: &LLVMModule,
|
||||||
function: &LLVMFunction,
|
_function: &LLVMFunction,
|
||||||
block: LLVMBasicBlockRef,
|
_block: LLVMBasicBlockRef,
|
||||||
) -> LLVMValue {
|
) -> LLVMValue {
|
||||||
let ty = self.get_type(module.builder).unwrap();
|
let _ty = self.get_type(module.builder).unwrap();
|
||||||
let val = unsafe {
|
let val = unsafe {
|
||||||
match self {
|
match self {
|
||||||
TerminatorKind::Ret(val) => {
|
TerminatorKind::Ret(val) => {
|
||||||
@ -341,7 +345,10 @@ impl TerminatorKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
LLVMValue { ty, value_ref: val }
|
LLVMValue {
|
||||||
|
_ty,
|
||||||
|
value_ref: val,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,57 +178,3 @@ pub enum TerminatorKind {
|
|||||||
Branch(BlockValue),
|
Branch(BlockValue),
|
||||||
CondBr(InstructionValue, BlockValue, BlockValue),
|
CondBr(InstructionValue, BlockValue, BlockValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test() {
|
|
||||||
use ConstValue::*;
|
|
||||||
use InstructionKind::*;
|
|
||||||
|
|
||||||
let context = Context::new();
|
|
||||||
|
|
||||||
let mut module = context.module("test");
|
|
||||||
|
|
||||||
let mut main = module.function("main", Type::I32, Vec::new());
|
|
||||||
let mut m_entry = main.block("entry");
|
|
||||||
|
|
||||||
let mut fibonacci = module.function("fibonacci", Type::I32, vec![Type::I32]);
|
|
||||||
|
|
||||||
let arg = m_entry.build(Constant(I32(5))).unwrap();
|
|
||||||
m_entry
|
|
||||||
.build(FunctionCall(fibonacci.value, vec![arg]))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut f_entry = fibonacci.block("entry");
|
|
||||||
|
|
||||||
let num_3 = f_entry.build(Constant(I32(3))).unwrap();
|
|
||||||
let param_n = f_entry.build(Param(0)).unwrap();
|
|
||||||
let cond = f_entry
|
|
||||||
.build(ICmp(IntPredicate::LessThan, param_n, num_3))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut then_b = fibonacci.block("then");
|
|
||||||
let mut else_b = fibonacci.block("else");
|
|
||||||
|
|
||||||
f_entry
|
|
||||||
.terminate(TerminatorKind::CondBr(cond, then_b.value, else_b.value))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let ret_const = then_b.build(Constant(I32(1))).unwrap();
|
|
||||||
then_b.terminate(TerminatorKind::Ret(ret_const)).unwrap();
|
|
||||||
|
|
||||||
let const_1 = else_b.build(Constant(I32(1))).unwrap();
|
|
||||||
let const_2 = else_b.build(Constant(I32(2))).unwrap();
|
|
||||||
let param_1 = else_b.build(Sub(param_n, const_1)).unwrap();
|
|
||||||
let param_2 = else_b.build(Sub(param_n, const_2)).unwrap();
|
|
||||||
let call_1 = else_b
|
|
||||||
.build(FunctionCall(fibonacci.value, vec![param_1]))
|
|
||||||
.unwrap();
|
|
||||||
let call_2 = else_b
|
|
||||||
.build(FunctionCall(fibonacci.value, vec![param_2]))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let add = else_b.build(Add(call_1, call_2)).unwrap();
|
|
||||||
|
|
||||||
else_b.terminate(TerminatorKind::Ret(add)).unwrap();
|
|
||||||
|
|
||||||
dbg!(context);
|
|
||||||
}
|
|
||||||
|
@ -13,7 +13,7 @@ pub enum TypeKind {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
I32(i32),
|
Number(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -53,13 +53,22 @@ impl BinaryOperator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FunctionCallExpression(pub String, pub Vec<Expression>, pub TokenRange);
|
pub struct FunctionCallExpression(
|
||||||
|
pub String,
|
||||||
|
pub Vec<Expression>,
|
||||||
|
#[allow(dead_code)] pub TokenRange,
|
||||||
|
);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct IfExpression(pub Expression, pub Block, pub Option<Block>, pub TokenRange);
|
pub struct IfExpression(
|
||||||
|
pub Expression,
|
||||||
|
pub Block,
|
||||||
|
pub Option<Block>,
|
||||||
|
#[allow(dead_code)] pub TokenRange,
|
||||||
|
);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LetStatement(pub String, pub Expression, pub TokenRange);
|
pub struct LetStatement(pub String, pub Option<Type>, pub Expression, pub TokenRange);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ImportStatement(Vec<String>, pub TokenRange);
|
pub struct ImportStatement(Vec<String>, pub TokenRange);
|
||||||
@ -72,6 +81,7 @@ pub struct FunctionSignature {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub args: Vec<(String, Type)>,
|
pub args: Vec<(String, Type)>,
|
||||||
pub return_type: Option<Type>,
|
pub return_type: Option<Type>,
|
||||||
|
#[allow(dead_code)]
|
||||||
pub range: TokenRange,
|
pub range: TokenRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +101,7 @@ pub struct Block(
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum BlockLevelStatement {
|
pub enum BlockLevelStatement {
|
||||||
Let(LetStatement),
|
Let(LetStatement),
|
||||||
Import(ImportStatement),
|
Import { _i: ImportStatement },
|
||||||
Expression(Expression),
|
Expression(Expression),
|
||||||
Return(ReturnType, Expression),
|
Return(ReturnType, Expression),
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ impl Parse for PrimaryExpression {
|
|||||||
Expression(Kind::VariableName(v.clone()), stream.get_range().unwrap())
|
Expression(Kind::VariableName(v.clone()), stream.get_range().unwrap())
|
||||||
}
|
}
|
||||||
Token::DecimalValue(v) => Expression(
|
Token::DecimalValue(v) => Expression(
|
||||||
Kind::Literal(Literal::I32(v.parse().unwrap())),
|
Kind::Literal(Literal::Number(v.parse().unwrap())),
|
||||||
stream.get_range().unwrap(),
|
stream.get_range().unwrap(),
|
||||||
),
|
),
|
||||||
Token::ParenOpen => {
|
Token::ParenOpen => {
|
||||||
@ -188,6 +188,7 @@ impl Parse for LetStatement {
|
|||||||
stream.expect(Token::Semi)?;
|
stream.expect(Token::Semi)?;
|
||||||
Ok(LetStatement(
|
Ok(LetStatement(
|
||||||
variable,
|
variable,
|
||||||
|
None, // TODO add possibility to name type
|
||||||
expression,
|
expression,
|
||||||
stream.get_range().unwrap(),
|
stream.get_range().unwrap(),
|
||||||
))
|
))
|
||||||
@ -307,7 +308,9 @@ impl Parse for BlockLevelStatement {
|
|||||||
use BlockLevelStatement as Stmt;
|
use BlockLevelStatement as Stmt;
|
||||||
Ok(match stream.peek() {
|
Ok(match stream.peek() {
|
||||||
Some(Token::LetKeyword) => Stmt::Let(stream.parse()?),
|
Some(Token::LetKeyword) => Stmt::Let(stream.parse()?),
|
||||||
Some(Token::ImportKeyword) => Stmt::Import(stream.parse()?),
|
Some(Token::ImportKeyword) => Stmt::Import {
|
||||||
|
_i: stream.parse()?,
|
||||||
|
},
|
||||||
Some(Token::ReturnKeyword) => {
|
Some(Token::ReturnKeyword) => {
|
||||||
stream.next();
|
stream.next();
|
||||||
let exp = stream.parse()?;
|
let exp = stream.parse()?;
|
||||||
|
@ -1,71 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self, TypeKind},
|
ast::{self},
|
||||||
mir::{self, StmtKind, VariableReference},
|
mir::{self, StmtKind, VariableReference},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum InferredType {
|
|
||||||
FromVariable(String),
|
|
||||||
FunctionReturn(String),
|
|
||||||
Static(mir::TypeKind),
|
|
||||||
OneOf(Vec<InferredType>),
|
|
||||||
Void,
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InferredType {
|
|
||||||
fn collapse(&self) -> mir::TypeKind {
|
|
||||||
match self {
|
|
||||||
InferredType::FromVariable(_) => mir::TypeKind::Vague(mir::VagueType::Unknown),
|
|
||||||
InferredType::FunctionReturn(_) => mir::TypeKind::Vague(mir::VagueType::Unknown),
|
|
||||||
InferredType::Static(type_kind) => type_kind.clone(),
|
|
||||||
InferredType::OneOf(inferred_types) => {
|
|
||||||
let list: Vec<mir::TypeKind> =
|
|
||||||
inferred_types.iter().map(|t| t.collapse()).collect();
|
|
||||||
if let Some(first) = list.first() {
|
|
||||||
if list.iter().all(|i| i == first) {
|
|
||||||
first.clone().into()
|
|
||||||
} else {
|
|
||||||
mir::TypeKind::Vague(mir::VagueType::Unknown)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mir::TypeKind::Void
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InferredType::Void => mir::TypeKind::Void,
|
|
||||||
InferredType::Unknown => mir::TypeKind::Vague(mir::VagueType::Unknown),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VirtualStorage<T> {
|
|
||||||
storage: HashMap<String, Vec<T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> VirtualStorage<T> {
|
|
||||||
fn set(&mut self, name: String, value: T) {
|
|
||||||
if let Some(list) = self.storage.get_mut(&name) {
|
|
||||||
list.push(value);
|
|
||||||
} else {
|
|
||||||
self.storage.insert(name, vec![value]);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self, name: &String) -> Option<&Vec<T>> {
|
|
||||||
self.storage.get(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for VirtualStorage<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
storage: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ast::Module {
|
impl ast::Module {
|
||||||
pub fn process(&self) -> mir::Module {
|
pub fn process(&self) -> mir::Module {
|
||||||
let mut imports = Vec::new();
|
let mut imports = Vec::new();
|
||||||
@ -115,19 +52,21 @@ impl ast::Block {
|
|||||||
|
|
||||||
for statement in &self.0 {
|
for statement in &self.0 {
|
||||||
let (kind, range) = match statement {
|
let (kind, range) = match statement {
|
||||||
ast::BlockLevelStatement::Let(s_let) => {
|
ast::BlockLevelStatement::Let(s_let) => (
|
||||||
let t = s_let.1.infer_return_type().collapse();
|
mir::StmtKind::Let(
|
||||||
let inferred = InferredType::Static(t.clone());
|
mir::VariableReference(
|
||||||
|
s_let
|
||||||
(
|
.1
|
||||||
mir::StmtKind::Let(
|
.map(|t| t.0.into())
|
||||||
mir::VariableReference(t, s_let.0.clone(), s_let.2.into()),
|
.unwrap_or(mir::TypeKind::Vague(mir::VagueType::Unknown)),
|
||||||
s_let.1.process(),
|
s_let.0.clone(),
|
||||||
|
s_let.3.into(),
|
||||||
),
|
),
|
||||||
s_let.2,
|
s_let.2.process(),
|
||||||
)
|
),
|
||||||
}
|
s_let.3,
|
||||||
ast::BlockLevelStatement::Import(_) => todo!(),
|
),
|
||||||
|
ast::BlockLevelStatement::Import { _i } => todo!(),
|
||||||
ast::BlockLevelStatement::Expression(e) => (StmtKind::Expression(e.process()), e.1),
|
ast::BlockLevelStatement::Expression(e) => (StmtKind::Expression(e.process()), e.1),
|
||||||
ast::BlockLevelStatement::Return(_, e) => (StmtKind::Expression(e.process()), e.1),
|
ast::BlockLevelStatement::Return(_, e) => (StmtKind::Expression(e.process()), e.1),
|
||||||
};
|
};
|
||||||
@ -147,13 +86,6 @@ impl ast::Block {
|
|||||||
meta: self.2.into(),
|
meta: self.2.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_return_type(&self) -> InferredType {
|
|
||||||
self.1
|
|
||||||
.as_ref()
|
|
||||||
.map(|(_, expr)| expr.infer_return_type())
|
|
||||||
.unwrap_or(InferredType::Void)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ast::ReturnType> for mir::ReturnKind {
|
impl From<ast::ReturnType> for mir::ReturnKind {
|
||||||
@ -201,26 +133,6 @@ impl ast::Expression {
|
|||||||
|
|
||||||
mir::Expression(kind, self.1.into())
|
mir::Expression(kind, self.1.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_return_type(&self) -> InferredType {
|
|
||||||
use ast::ExpressionKind::*;
|
|
||||||
match &self.0 {
|
|
||||||
VariableName(name) => InferredType::FromVariable(name.clone()),
|
|
||||||
Literal(lit) => InferredType::Static(lit.mir().as_type()),
|
|
||||||
Binop(_, lhs, rhs) => {
|
|
||||||
InferredType::OneOf(vec![lhs.infer_return_type(), rhs.infer_return_type()])
|
|
||||||
}
|
|
||||||
FunctionCall(fncall) => InferredType::FunctionReturn(fncall.0.clone()),
|
|
||||||
BlockExpr(block) => block.infer_return_type(),
|
|
||||||
IfExpr(exp) => {
|
|
||||||
let mut types = vec![exp.1.infer_return_type()];
|
|
||||||
if let Some(e) = &exp.2 {
|
|
||||||
types.push(e.infer_return_type())
|
|
||||||
}
|
|
||||||
InferredType::OneOf(types)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ast::BinaryOperator {
|
impl ast::BinaryOperator {
|
||||||
@ -240,7 +152,7 @@ impl ast::BinaryOperator {
|
|||||||
impl ast::Literal {
|
impl ast::Literal {
|
||||||
fn mir(&self) -> mir::Literal {
|
fn mir(&self) -> mir::Literal {
|
||||||
match *self {
|
match *self {
|
||||||
ast::Literal::I32(v) => mir::Literal::I32(v),
|
ast::Literal::Number(v) => mir::Literal::Vague(mir::VagueLiteral::Number(v)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
use std::{collections::HashMap, mem, ops::Deref};
|
use std::{collections::HashMap, mem};
|
||||||
|
|
||||||
use reid_lib::{
|
use reid_lib::{
|
||||||
builder::{FunctionValue, InstructionValue},
|
builder::InstructionValue, Block, ConstValue, Context, Function, InstructionKind, IntPredicate,
|
||||||
Block, ConstValue, Context, Function, InstructionKind, IntPredicate, Module, TerminatorKind,
|
Module, TerminatorKind, Type,
|
||||||
Type,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::mir::{self, types::ReturnType, TypeKind, VariableReference};
|
use crate::mir::{self, types::ReturnType, TypeKind, VariableReference};
|
||||||
@ -40,7 +39,7 @@ impl mir::Module {
|
|||||||
let mut entry = function.block("entry");
|
let mut entry = function.block("entry");
|
||||||
|
|
||||||
let mut stack_values = HashMap::new();
|
let mut stack_values = HashMap::new();
|
||||||
for (i, (p_name, p_type)) in mir_function.parameters.iter().enumerate() {
|
for (i, (p_name, _)) in mir_function.parameters.iter().enumerate() {
|
||||||
stack_values.insert(
|
stack_values.insert(
|
||||||
p_name.clone(),
|
p_name.clone(),
|
||||||
entry.build(InstructionKind::Param(i)).unwrap(),
|
entry.build(InstructionKind::Param(i)).unwrap(),
|
||||||
@ -297,6 +296,7 @@ impl mir::Literal {
|
|||||||
InstructionKind::Constant(match *self {
|
InstructionKind::Constant(match *self {
|
||||||
mir::Literal::I32(val) => ConstValue::I32(val),
|
mir::Literal::I32(val) => ConstValue::I32(val),
|
||||||
mir::Literal::I16(val) => ConstValue::I16(val),
|
mir::Literal::I16(val) => ConstValue::I16(val),
|
||||||
|
mir::Literal::Vague(_) => panic!("Got vague literal!"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ pub fn compile(source: &str) -> Result<String, ReidError> {
|
|||||||
dbg!(&mir_module);
|
dbg!(&mir_module);
|
||||||
|
|
||||||
let state = mir_module.typecheck();
|
let state = mir_module.typecheck();
|
||||||
|
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));
|
||||||
|
@ -51,6 +51,8 @@ pub enum TypeKind {
|
|||||||
pub enum VagueType {
|
pub enum VagueType {
|
||||||
#[error("Unknown")]
|
#[error("Unknown")]
|
||||||
Unknown,
|
Unknown,
|
||||||
|
#[error("Number")]
|
||||||
|
Number,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeKind {
|
impl TypeKind {
|
||||||
@ -88,6 +90,12 @@ impl TypeKind {
|
|||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
I32(i32),
|
I32(i32),
|
||||||
I16(i16),
|
I16(i16),
|
||||||
|
Vague(VagueLiteral),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum VagueLiteral {
|
||||||
|
Number(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Literal {
|
impl Literal {
|
||||||
@ -95,6 +103,7 @@ impl Literal {
|
|||||||
match self {
|
match self {
|
||||||
Literal::I32(_) => TypeKind::I32,
|
Literal::I32(_) => TypeKind::I32,
|
||||||
Literal::I16(_) => TypeKind::I16,
|
Literal::I16(_) => TypeKind::I16,
|
||||||
|
Literal::Vague(VagueLiteral::Number(_)) => TypeKind::Vague(VagueType::Number),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,6 +113,8 @@ impl State {
|
|||||||
pub struct Scope {
|
pub struct Scope {
|
||||||
function_returns: TypeStorage<ScopeFunction>,
|
function_returns: TypeStorage<ScopeFunction>,
|
||||||
variables: TypeStorage<TypeKind>,
|
variables: TypeStorage<TypeKind>,
|
||||||
|
/// Hard Return type of this scope, if inside a function
|
||||||
|
return_type_hint: Option<TypeKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -126,6 +128,7 @@ impl Scope {
|
|||||||
Scope {
|
Scope {
|
||||||
function_returns: self.function_returns.clone(),
|
function_returns: self.function_returns.clone(),
|
||||||
variables: self.variables.clone(),
|
variables: self.variables.clone(),
|
||||||
|
return_type_hint: self.return_type_hint,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,7 +178,10 @@ impl FunctionDefinition {
|
|||||||
|
|
||||||
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, _) => block.typecheck(state, scope),
|
FunctionDefinitionKind::Local(block, _) => {
|
||||||
|
scope.return_type_hint = Some(self.return_type);
|
||||||
|
block.typecheck(state, scope, Some(return_type))
|
||||||
|
}
|
||||||
FunctionDefinitionKind::Extern => Ok(Vague(Unknown)),
|
FunctionDefinitionKind::Extern => Ok(Vague(Unknown)),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -188,13 +194,18 @@ impl FunctionDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
fn typecheck(&mut self, state: &mut State, scope: &mut Scope) -> Result<TypeKind, ErrorKind> {
|
fn typecheck(
|
||||||
|
&mut self,
|
||||||
|
state: &mut State,
|
||||||
|
scope: &mut Scope,
|
||||||
|
hint_t: Option<TypeKind>,
|
||||||
|
) -> Result<TypeKind, ErrorKind> {
|
||||||
let mut scope = scope.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(state, &mut scope);
|
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.
|
||||||
@ -224,14 +235,18 @@ impl Block {
|
|||||||
}
|
}
|
||||||
StmtKind::Import(_) => todo!(),
|
StmtKind::Import(_) => todo!(),
|
||||||
StmtKind::Expression(expression) => {
|
StmtKind::Expression(expression) => {
|
||||||
let res = expression.typecheck(state, &mut scope);
|
let res = expression.typecheck(state, &mut scope, hint_t);
|
||||||
state.ok(res, expression.1);
|
state.ok(res, expression.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((_, expr)) = &mut self.return_expression {
|
if let Some((return_kind, expr)) = &mut self.return_expression {
|
||||||
let res = expr.typecheck(state, &mut scope);
|
let ret_hint_t = match return_kind {
|
||||||
|
ReturnKind::Hard => scope.return_type_hint,
|
||||||
|
ReturnKind::Soft => 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)
|
||||||
@ -240,7 +255,12 @@ impl Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
fn typecheck(&mut self, state: &mut State, scope: &mut Scope) -> Result<TypeKind, ErrorKind> {
|
fn typecheck(
|
||||||
|
&mut self,
|
||||||
|
state: &mut State,
|
||||||
|
scope: &mut Scope,
|
||||||
|
hint_t: Option<TypeKind>,
|
||||||
|
) -> Result<TypeKind, ErrorKind> {
|
||||||
match &mut self.0 {
|
match &mut self.0 {
|
||||||
ExprKind::Variable(var_ref) => {
|
ExprKind::Variable(var_ref) => {
|
||||||
let existing = state.or_else(
|
let existing = state.or_else(
|
||||||
@ -262,15 +282,19 @@ impl Expression {
|
|||||||
|
|
||||||
Ok(var_ref.0)
|
Ok(var_ref.0)
|
||||||
}
|
}
|
||||||
ExprKind::Literal(literal) => Ok(literal.as_type()),
|
ExprKind::Literal(literal) => {
|
||||||
|
*literal = literal.try_coerce(hint_t)?;
|
||||||
|
Ok(literal.as_type())
|
||||||
|
}
|
||||||
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, scope);
|
let lhs_res = lhs.typecheck(state, scope, None); // TODO
|
||||||
let rhs_res = rhs.typecheck(state, scope);
|
|
||||||
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, 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);
|
||||||
lhs_type.binop_type(&op, &rhs_type)
|
let res = lhs_type.binop_type(&op, &rhs_type)?;
|
||||||
|
Ok(res)
|
||||||
}
|
}
|
||||||
ExprKind::FunctionCall(function_call) => {
|
ExprKind::FunctionCall(function_call) => {
|
||||||
let true_function = scope
|
let true_function = scope
|
||||||
@ -289,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, scope);
|
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);
|
||||||
}
|
}
|
||||||
@ -306,21 +330,39 @@ 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, scope);
|
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, scope);
|
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, scope);
|
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, scope),
|
ExprKind::Block(block) => block.typecheck(state, scope, hint_t),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Literal {
|
||||||
|
fn try_coerce(self, hint: Option<TypeKind>) -> Result<Self, ErrorKind> {
|
||||||
|
if let Some(hint) = hint {
|
||||||
|
use Literal as L;
|
||||||
|
use VagueLiteral as VagueL;
|
||||||
|
Ok(match (self, hint) {
|
||||||
|
(L::I32(_), I32) => self,
|
||||||
|
(L::I16(_), I16) => self,
|
||||||
|
(L::Vague(VagueL::Number(v)), I32) => L::I32(v as i32),
|
||||||
|
(L::Vague(VagueL::Number(v)), I16) => L::I16(v as i16),
|
||||||
|
_ => Err(ErrorKind::TypesIncompatible(self.as_type(), hint))?,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,7 @@ impl<'a, 'b> TokenStream<'a, 'b> {
|
|||||||
/// Parse the next item with Parse-trait, also mapping it with the given
|
/// Parse the next item with Parse-trait, also mapping it with the given
|
||||||
/// function. The token-stream is only consumed, if the inner function
|
/// function. The token-stream is only consumed, if the inner function
|
||||||
/// retuns an Ok.
|
/// retuns an Ok.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn parse_map<T: Parse + std::fmt::Debug, F, O>(&mut self, inner: F) -> Result<O, Error>
|
pub fn parse_map<T: Parse + std::fmt::Debug, F, O>(&mut self, inner: F) -> Result<O, Error>
|
||||||
where
|
where
|
||||||
F: Fn(T) -> Result<O, Error>,
|
F: Fn(T) -> Result<O, Error>,
|
||||||
|
Loading…
Reference in New Issue
Block a user