Compare commits
2 Commits
615fec6e52
...
14e0dcbe15
Author | SHA1 | Date | |
---|---|---|---|
14e0dcbe15 | |||
85b2ebf04a |
@ -3,6 +3,8 @@
|
||||
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use llvm_sys::core::{LLVMBuildAlloca, LLVMBuildLoad2, LLVMBuildStore};
|
||||
|
||||
use crate::{
|
||||
BlockData, ConstValue, FunctionData, Instr, InstructionData, ModuleData, TerminatorKind, Type,
|
||||
util::match_types,
|
||||
@ -250,6 +252,29 @@ impl Builder {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Alloca(_, _) => Ok(()),
|
||||
Load(ptr, _) => {
|
||||
if let Ok(ty) = ptr.get_type(&self) {
|
||||
if let Type::Ptr(_) = ty {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
Store(ptr, _) => {
|
||||
if let Ok(ty) = ptr.get_type(&self) {
|
||||
if let Type::Ptr(_) = ty {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -298,7 +323,7 @@ impl InstructionValue {
|
||||
.function_data(&self.0.0)
|
||||
.params
|
||||
.get(*nth)
|
||||
.copied()
|
||||
.cloned()
|
||||
.ok_or(()),
|
||||
Constant(c) => Ok(c.get_type()),
|
||||
Add(lhs, rhs) => match_types(lhs, rhs, &builder),
|
||||
@ -308,6 +333,9 @@ impl InstructionValue {
|
||||
ICmp(_, _, _) => Ok(Type::Bool),
|
||||
FunctionCall(function_value, _) => Ok(builder.function_data(function_value).ret),
|
||||
Phi(values) => values.first().ok_or(()).and_then(|v| v.get_type(&builder)),
|
||||
Alloca(_, ty) => Ok(Type::Ptr(Box::new(ty.clone()))),
|
||||
Load(_, ty) => Ok(Type::Ptr(Box::new(ty.clone()))),
|
||||
Store(_, value) => value.get_type(builder),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -347,6 +375,7 @@ impl Type {
|
||||
Type::U128 => true,
|
||||
Type::Bool => true,
|
||||
Type::Void => false,
|
||||
Type::Ptr(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,6 +393,7 @@ impl Type {
|
||||
Type::U128 => false,
|
||||
Type::Bool => false,
|
||||
Type::Void => false,
|
||||
Type::Ptr(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -333,6 +333,22 @@ impl InstructionHolder {
|
||||
);
|
||||
phi
|
||||
}
|
||||
Alloca(name, ty) => LLVMBuildAlloca(
|
||||
module.builder_ref,
|
||||
ty.as_llvm(module.context_ref),
|
||||
into_cstring(name).as_ptr(),
|
||||
),
|
||||
Load(ptr, ty) => LLVMBuildLoad2(
|
||||
module.builder_ref,
|
||||
ty.as_llvm(module.context_ref),
|
||||
module.values.get(&ptr).unwrap().value_ref,
|
||||
c"load".as_ptr(),
|
||||
),
|
||||
Store(ptr, val) => LLVMBuildStore(
|
||||
module.builder_ref,
|
||||
module.values.get(&val).unwrap().value_ref,
|
||||
module.values.get(&ptr).unwrap().value_ref,
|
||||
),
|
||||
}
|
||||
};
|
||||
LLVMValue {
|
||||
@ -428,6 +444,7 @@ impl Type {
|
||||
I128 | U128 => LLVMInt128TypeInContext(context),
|
||||
Bool => LLVMInt1TypeInContext(context),
|
||||
Void => LLVMVoidType(),
|
||||
Ptr(ty) => LLVMPointerType(ty.as_llvm(context), 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,9 @@ impl Debug for Instr {
|
||||
Self::Phi(val) => fmt_call(f, &"Phi", &val),
|
||||
Self::ICmp(cmp, lhs, rhs) => fmt_binop(f, lhs, cmp, rhs),
|
||||
Self::FunctionCall(fun, params) => fmt_call(f, fun, params),
|
||||
Instr::Alloca(name, ty) => write!(f, "alloca<{:?}>({})", ty, name),
|
||||
Instr::Load(val, ty) => write!(f, "load<{:?}>({:?})", ty, val),
|
||||
Instr::Store(ptr, val) => write!(f, "store({:?} = {:?})", ptr, val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,13 +174,17 @@ pub enum Instr {
|
||||
And(InstructionValue, InstructionValue),
|
||||
Phi(Vec<InstructionValue>),
|
||||
|
||||
Alloca(String, Type),
|
||||
Load(InstructionValue, Type),
|
||||
Store(InstructionValue, InstructionValue),
|
||||
|
||||
/// Integer Comparison
|
||||
ICmp(CmpPredicate, InstructionValue, InstructionValue),
|
||||
|
||||
FunctionCall(FunctionValue, Vec<InstructionValue>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||
pub enum Type {
|
||||
I8,
|
||||
I16,
|
||||
@ -194,6 +198,7 @@ pub enum Type {
|
||||
U128,
|
||||
Bool,
|
||||
Void,
|
||||
Ptr(Box<Type>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
|
@ -1,9 +1,9 @@
|
||||
use reid::compile;
|
||||
|
||||
pub static ARITHMETIC: &str = include_str!("./reid/arithmetic.reid");
|
||||
pub static MUTABLE: &str = include_str!("./reid/mutable.reid");
|
||||
|
||||
fn main() {
|
||||
let text = match compile(ARITHMETIC) {
|
||||
let text = match compile(MUTABLE) {
|
||||
Ok(t) => t,
|
||||
Err(e) => panic!("{}", e),
|
||||
};
|
@ -1,13 +0,0 @@
|
||||
// Arithmetic, function calls and imports!
|
||||
|
||||
fn main() {
|
||||
let test = 9;
|
||||
let simpleAdd = 2 + 2;
|
||||
let simpleSub = 7 - 2; // 14
|
||||
|
||||
if simpleAdd < test {
|
||||
return 3;
|
||||
}
|
||||
|
||||
return arithmetic + simpleSub + boop;
|
||||
}
|
15
reid/examples/reid/mutable.reid
Normal file
15
reid/examples/reid/mutable.reid
Normal file
@ -0,0 +1,15 @@
|
||||
// Arithmetic, function calls and imports!
|
||||
|
||||
fn indirection() -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
fn main() -> u16 {
|
||||
let mut test = 5;
|
||||
|
||||
if indirection() {
|
||||
test = 11;
|
||||
}
|
||||
|
||||
return test;
|
||||
}
|
@ -92,7 +92,14 @@ pub struct IfExpression(
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LetStatement(pub String, pub Option<Type>, pub Expression, pub TokenRange);
|
||||
pub struct LetStatement(
|
||||
pub String,
|
||||
pub Option<Type>,
|
||||
/// Mutability
|
||||
pub bool,
|
||||
pub Expression,
|
||||
pub TokenRange,
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ImportStatement(pub Vec<String>, pub TokenRange);
|
||||
@ -125,7 +132,11 @@ pub struct Block(
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum BlockLevelStatement {
|
||||
Let(LetStatement),
|
||||
Import { _i: ImportStatement },
|
||||
/// Try to set a variable to a specified expression value
|
||||
Set(String, Expression, TokenRange),
|
||||
Import {
|
||||
_i: ImportStatement,
|
||||
},
|
||||
Expression(Expression),
|
||||
Return(ReturnType, Expression),
|
||||
}
|
||||
|
@ -223,6 +223,7 @@ impl Parse for IfExpression {
|
||||
impl Parse for LetStatement {
|
||||
fn parse(mut stream: TokenStream) -> Result<LetStatement, Error> {
|
||||
stream.expect(Token::LetKeyword)?;
|
||||
let mutability = stream.expect(Token::MutKeyword).is_ok();
|
||||
|
||||
if let Some(Token::Identifier(variable)) = stream.next() {
|
||||
stream.expect(Token::Equals)?;
|
||||
@ -232,6 +233,7 @@ impl Parse for LetStatement {
|
||||
Ok(LetStatement(
|
||||
variable,
|
||||
None, // TODO add possibility to name type
|
||||
mutability,
|
||||
expression,
|
||||
stream.get_range().unwrap(),
|
||||
))
|
||||
@ -331,7 +333,7 @@ impl Parse for Block {
|
||||
ReturnType::Hard => {
|
||||
return_stmt = Some((*r_type, e.clone()));
|
||||
break; // Return has to be the last statement
|
||||
// TODO: Make a mechanism that "can" parse even after this
|
||||
// TODO: Make a mechanism that "can" parse even after this
|
||||
}
|
||||
ReturnType::Soft => {
|
||||
return_stmt = Some((*r_type, e.clone()));
|
||||
@ -361,20 +363,40 @@ impl Parse for BlockLevelStatement {
|
||||
Stmt::Return(ReturnType::Hard, exp)
|
||||
}
|
||||
_ => {
|
||||
if let Ok(e) = stream.parse() {
|
||||
if stream.expect(Token::Semi).is_ok() {
|
||||
Stmt::Expression(e)
|
||||
} else {
|
||||
Stmt::Return(ReturnType::Soft, e)
|
||||
}
|
||||
if let Ok(SetStatement(ident, expr, range)) = stream.parse() {
|
||||
Stmt::Set(ident, expr, range)
|
||||
} else {
|
||||
Err(stream.expected_err("expression")?)?
|
||||
if let Ok(e) = stream.parse() {
|
||||
if stream.expect(Token::Semi).is_ok() {
|
||||
Stmt::Expression(e)
|
||||
} else {
|
||||
Stmt::Return(ReturnType::Soft, e)
|
||||
}
|
||||
} else {
|
||||
Err(stream.expected_err("expression")?)?
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SetStatement(String, Expression, TokenRange);
|
||||
|
||||
impl Parse for SetStatement {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||
if let Some(Token::Identifier(ident)) = stream.next() {
|
||||
stream.expect(Token::Equals)?;
|
||||
let expr = stream.parse()?;
|
||||
stream.expect(Token::Semi)?;
|
||||
Ok(Self(ident, expr, stream.get_range().unwrap()))
|
||||
} else {
|
||||
Err(stream.expected_err("identifier")?)?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for TopLevelStatement {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||
use TopLevelStatement as Stmt;
|
||||
|
@ -68,11 +68,23 @@ impl ast::Block {
|
||||
.map(|t| t.0.into())
|
||||
.unwrap_or(mir::TypeKind::Vague(mir::VagueType::Unknown)),
|
||||
s_let.0.clone(),
|
||||
s_let.3.into(),
|
||||
s_let.4.into(),
|
||||
),
|
||||
s_let.2.process(),
|
||||
s_let.2,
|
||||
s_let.3.process(),
|
||||
),
|
||||
s_let.3,
|
||||
s_let.4,
|
||||
),
|
||||
ast::BlockLevelStatement::Set(name, expression, range) => (
|
||||
StmtKind::Set(
|
||||
VariableReference(
|
||||
mir::TypeKind::Vague(mir::VagueType::Unknown),
|
||||
name.clone(),
|
||||
(*range).into(),
|
||||
),
|
||||
expression.process(),
|
||||
),
|
||||
*range,
|
||||
),
|
||||
ast::BlockLevelStatement::Import { _i } => todo!(),
|
||||
ast::BlockLevelStatement::Expression(e) => (StmtKind::Expression(e.process()), e.1),
|
||||
|
@ -1,11 +1,12 @@
|
||||
use std::{collections::HashMap, mem};
|
||||
|
||||
use llvm_sys::core::LLVMBuildStore;
|
||||
use reid_lib::{
|
||||
Block, CmpPredicate, ConstValue, Context, Function, Instr, Module, TerminatorKind as Term,
|
||||
Type, builder::InstructionValue,
|
||||
builder::InstructionValue, Block, CmpPredicate, ConstValue, Context, Function, Instr, Module,
|
||||
TerminatorKind as Term, Type,
|
||||
};
|
||||
|
||||
use crate::mir::{self, TypeKind, VariableReference, types::ReturnType};
|
||||
use crate::mir::{self, types::ReturnType, TypeKind, VariableReference};
|
||||
|
||||
/// Context that contains all of the given modules as complete codegenerated
|
||||
/// LLIR that can then be finally compiled into LLVM IR.
|
||||
@ -73,8 +74,14 @@ impl mir::Module {
|
||||
let mut entry = function.block("entry");
|
||||
|
||||
let mut stack_values = HashMap::new();
|
||||
for (i, (p_name, _)) in mir_function.parameters.iter().enumerate() {
|
||||
stack_values.insert(p_name.clone(), entry.build(Instr::Param(i)).unwrap());
|
||||
for (i, (p_name, p_ty)) in mir_function.parameters.iter().enumerate() {
|
||||
stack_values.insert(
|
||||
p_name.clone(),
|
||||
StackValue(
|
||||
StackValueKind::Immutable(entry.build(Instr::Param(i)).unwrap()),
|
||||
p_ty.get_type(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
let mut scope = Scope {
|
||||
@ -114,7 +121,16 @@ pub struct Scope<'ctx, 'a> {
|
||||
function: &'ctx Function<'ctx>,
|
||||
block: Block<'ctx>,
|
||||
functions: &'a HashMap<String, Function<'ctx>>,
|
||||
stack_values: HashMap<String, InstructionValue>,
|
||||
stack_values: HashMap<String, StackValue>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct StackValue(StackValueKind, Type);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum StackValueKind {
|
||||
Immutable(InstructionValue),
|
||||
Mutable(InstructionValue),
|
||||
}
|
||||
|
||||
impl<'ctx, 'a> Scope<'ctx, 'a> {
|
||||
@ -141,11 +157,33 @@ impl<'ctx, 'a> Scope<'ctx, 'a> {
|
||||
impl mir::Statement {
|
||||
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>) -> Option<InstructionValue> {
|
||||
match &self.0 {
|
||||
mir::StmtKind::Let(VariableReference(_, name, _), expression) => {
|
||||
mir::StmtKind::Let(VariableReference(ty, name, _), mutable, expression) => {
|
||||
let value = expression.codegen(scope).unwrap();
|
||||
scope.stack_values.insert(name.clone(), value);
|
||||
scope.stack_values.insert(
|
||||
name.clone(),
|
||||
StackValue(
|
||||
match mutable {
|
||||
true => StackValueKind::Mutable(value),
|
||||
false => StackValueKind::Immutable(value),
|
||||
},
|
||||
ty.get_type(),
|
||||
),
|
||||
);
|
||||
None
|
||||
}
|
||||
mir::StmtKind::Set(var, val) => {
|
||||
if let Some(StackValue(kind, ty)) = scope.stack_values.get(&var.1).cloned() {
|
||||
match kind {
|
||||
StackValueKind::Immutable(ptr) => {
|
||||
let expression = val.codegen(scope).unwrap();
|
||||
Some(scope.block.build(Instr::Store(ptr, expression)).unwrap())
|
||||
}
|
||||
StackValueKind::Mutable(_) => panic!(""),
|
||||
}
|
||||
} else {
|
||||
panic!("")
|
||||
}
|
||||
}
|
||||
// mir::StmtKind::If(if_expression) => if_expression.codegen(scope),
|
||||
mir::StmtKind::Import(_) => todo!(),
|
||||
mir::StmtKind::Expression(expression) => expression.codegen(scope),
|
||||
@ -218,7 +256,12 @@ impl mir::Expression {
|
||||
.stack_values
|
||||
.get(&varref.1)
|
||||
.expect("Variable reference not found?!");
|
||||
Some(v.clone())
|
||||
Some(match v.0 {
|
||||
StackValueKind::Immutable(val) => val.clone(),
|
||||
StackValueKind::Mutable(val) => {
|
||||
scope.block.build(Instr::Load(val, v.1.clone())).unwrap()
|
||||
}
|
||||
})
|
||||
}
|
||||
mir::ExprKind::Literal(lit) => Some(lit.as_const(&mut scope.block)),
|
||||
mir::ExprKind::BinOp(binop, lhs_exp, rhs_exp) => {
|
||||
|
@ -12,6 +12,8 @@ pub enum Token {
|
||||
// Keywords
|
||||
/// `let`
|
||||
LetKeyword,
|
||||
/// `mut`
|
||||
MutKeyword,
|
||||
/// `import`
|
||||
ImportKeyword,
|
||||
/// `return`
|
||||
@ -170,6 +172,7 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
|
||||
// Check for keywords
|
||||
let variant = match value.as_str() {
|
||||
"let" => Token::LetKeyword,
|
||||
"mut" => Token::MutKeyword,
|
||||
"import" => Token::ImportKeyword,
|
||||
"return" => Token::ReturnKeyword,
|
||||
"fn" => Token::FnKeyword,
|
||||
|
@ -94,7 +94,16 @@ impl Display for Statement {
|
||||
impl Display for StmtKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Let(var, block) => write!(f, "let {} = {}", var, block),
|
||||
Self::Let(var, mutable, block) => {
|
||||
write!(
|
||||
f,
|
||||
"let{} {} = {}",
|
||||
if *mutable { " mut" } else { "" },
|
||||
var,
|
||||
block
|
||||
)
|
||||
}
|
||||
Self::Set(var, expr) => write!(f, "{} = {}", var, expr),
|
||||
Self::Import(n) => write!(f, "import {}", n),
|
||||
Self::Expression(exp) => Display::fmt(exp, f),
|
||||
}
|
||||
|
@ -257,8 +257,9 @@ pub struct Statement(pub StmtKind, pub Metadata);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StmtKind {
|
||||
/// Variable name+type, evaluation
|
||||
Let(VariableReference, Expression),
|
||||
/// Variable name++mutability+type, evaluation
|
||||
Let(VariableReference, bool, Expression),
|
||||
Set(VariableReference, Expression),
|
||||
Import(Import),
|
||||
Expression(Expression),
|
||||
}
|
||||
|
@ -253,9 +253,10 @@ impl Block {
|
||||
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) => {
|
||||
StmtKind::Let(_, mutable, expression) => {
|
||||
expression.pass(pass, state, scope);
|
||||
}
|
||||
StmtKind::Set(variable_reference, expression) => {} // TODO
|
||||
StmtKind::Import(_) => todo!(),
|
||||
StmtKind::Expression(expression) => {
|
||||
expression.pass(pass, state, scope);
|
||||
@ -265,10 +266,11 @@ impl Statement {
|
||||
pass.stmt(self, PassState::from(state, scope));
|
||||
|
||||
match &mut self.0 {
|
||||
StmtKind::Let(variable_reference, _) => scope
|
||||
StmtKind::Let(variable_reference, mutable, _) => scope
|
||||
.variables
|
||||
.set(variable_reference.1.clone(), variable_reference.0)
|
||||
.ok(),
|
||||
StmtKind::Set(variable_reference, expression) => None, // TODO
|
||||
StmtKind::Import(_) => todo!(),
|
||||
StmtKind::Expression(_) => None,
|
||||
};
|
||||
|
@ -93,7 +93,8 @@ impl Block {
|
||||
|
||||
for statement in &mut self.statements {
|
||||
let ret = match &mut statement.0 {
|
||||
StmtKind::Let(variable_reference, expression) => {
|
||||
// TODO
|
||||
StmtKind::Let(variable_reference, mutable, expression) => {
|
||||
let res = expression.typecheck(&mut state, Some(variable_reference.0));
|
||||
|
||||
// If expression resolution itself was erronous, resolve as
|
||||
@ -125,6 +126,7 @@ impl Block {
|
||||
state.ok(res, variable_reference.2);
|
||||
None
|
||||
}
|
||||
StmtKind::Set(variable_reference, expression) => None, // TODO
|
||||
StmtKind::Import(_) => todo!(),
|
||||
StmtKind::Expression(expression) => {
|
||||
let res = expression.typecheck(&mut state, None);
|
||||
|
@ -26,8 +26,9 @@ impl ReturnType for Statement {
|
||||
use StmtKind::*;
|
||||
match &self.0 {
|
||||
Expression(e) => e.return_type(),
|
||||
Set(_, _) => todo!(),
|
||||
Import(_) => Err(ReturnTypeOther::Import(self.1.range)),
|
||||
Let(_, _) => Err(ReturnTypeOther::Let(self.1.range)),
|
||||
Let(_, _, _) => Err(ReturnTypeOther::Let(self.1.range)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user