big progress

This commit is contained in:
Edgar 2023-05-19 19:55:57 +02:00
parent 04c3fdcd07
commit 1208f25975
No known key found for this signature in database
GPG key ID: 70ADAE8F35904387
6 changed files with 200 additions and 36 deletions

View file

@ -1,5 +1,9 @@
fn main(x: i32) -> i32 {
fn main(x: i64) -> i64 { let y = 0;
let x = 2 + 3; if x == 5 {
return x; y = 2 * x;
} else {
y = 3 * x;
}
return y;
} }

View file

@ -5,6 +5,10 @@ pub enum OpCode {
Mul, Mul,
Div, Div,
Rem, Rem,
And,
Or,
Eq,
Ne,
} }
impl OpCode { impl OpCode {
@ -15,6 +19,10 @@ impl OpCode {
OpCode::Mul => "muli", OpCode::Mul => "muli",
OpCode::Div => "divi", OpCode::Div => "divi",
OpCode::Rem => "remi", OpCode::Rem => "remi",
OpCode::And => "and",
OpCode::Or => "or",
OpCode::Eq => "eq",
OpCode::Ne => "ne",
} }
} }
} }
@ -82,6 +90,11 @@ pub enum Statement {
name: String, name: String,
value: Box<Expression>, value: Box<Expression>,
}, },
If {
condition: Box<Expression>,
body: Vec<Statement>,
else_body: Option<Vec<Statement>>,
},
Return(Option<Box<Expression>>), Return(Option<Box<Expression>>),
Function(Function), Function(Function),
} }

View file

@ -1,5 +1,5 @@
use std::{ use std::{
collections::HashMap, collections::{HashMap, HashSet},
path::{Path, PathBuf}, path::{Path, PathBuf},
todo, todo,
}; };
@ -12,6 +12,7 @@ use inkwell::{
module::Module, module::Module,
types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum}, types::{BasicMetadataTypeEnum, BasicType, BasicTypeEnum},
values::{BasicMetadataValueEnum, BasicValue, BasicValueEnum}, values::{BasicMetadataValueEnum, BasicValue, BasicValueEnum},
IntPredicate,
}; };
use itertools::{Either, Itertools}; use itertools::{Either, Itertools};
@ -40,6 +41,12 @@ pub struct CodeGen<'ctx> {
ast: ast::Program, ast: ast::Program,
} }
#[derive(Debug, Clone)]
struct BlockInfo<'a> {
pub blocks: Vec<BasicBlock<'a>>,
pub current_block: usize,
}
impl<'ctx> CodeGen<'ctx> { impl<'ctx> CodeGen<'ctx> {
pub fn new( pub fn new(
context: &'ctx Context, context: &'ctx Context,
@ -70,6 +77,7 @@ impl<'ctx> CodeGen<'ctx> {
match &statement { match &statement {
Statement::Variable { .. } => unreachable!(), Statement::Variable { .. } => unreachable!(),
Statement::Return(_) => unreachable!(), Statement::Return(_) => unreachable!(),
Statement::If { .. } => unreachable!(),
Statement::Function(function) => { Statement::Function(function) => {
functions.push(function); functions.push(function);
self.compile_function_signature(function)?; self.compile_function_signature(function)?;
@ -130,25 +138,27 @@ impl<'ctx> CodeGen<'ctx> {
self.builder.position_at_end(entry_block); self.builder.position_at_end(entry_block);
let mut variables: HashMap<String, BasicValueEnum<'ctx>> = HashMap::new(); let mut variables: HashMap<String, (BasicValueEnum<'ctx>, usize)> = HashMap::new();
for (i, param) in function.params.iter().enumerate() { for (i, param) in function.params.iter().enumerate() {
let id = param.ident.clone(); let id = param.ident.clone();
variables.insert( variables.insert(
id.clone(), id.clone(),
(
func.get_nth_param(i.try_into().unwrap()) func.get_nth_param(i.try_into().unwrap())
.expect("parameter"), .expect("parameter"),
0,
),
); );
} }
// todo: check function has return?
let mut has_return = false; let mut has_return = false;
for statement in &function.body { for statement in &function.body {
if let Statement::Return(_) = statement { if let Statement::Return(_) = statement {
has_return = true has_return = true
} }
self.compile_statement(&entry_block, statement, &mut variables)?; self.compile_statement(statement, &mut variables)?;
} }
if !has_return { if !has_return {
@ -160,29 +170,124 @@ impl<'ctx> CodeGen<'ctx> {
fn compile_statement( fn compile_statement(
&self, &self,
block: &BasicBlock,
statement: &Statement, statement: &Statement,
variables: &mut HashMap<String, BasicValueEnum<'ctx>>, // value, assignments
variables: &mut HashMap<String, (BasicValueEnum<'ctx>, usize)>,
) -> Result<()> { ) -> Result<()> {
match statement { match statement {
// Variable assignment // Variable assignment
Statement::Variable { name, value } => { Statement::Variable { name, value } => {
let result = self let result = self
.compile_expression(block, value, variables)? .compile_expression(value, variables)?
.expect("should have result"); .expect("should have result");
variables.insert(name.clone(), result); let accesses = if let Some(x) = variables.get(name) {
x.1 + 1
} else {
0
};
variables.insert(name.clone(), (result, accesses));
} }
Statement::Return(ret) => { Statement::Return(ret) => {
if let Some(ret) = ret { if let Some(ret) = ret {
let result = self let result = self
.compile_expression(block, ret, variables)? .compile_expression(ret, variables)?
.expect("should have result"); .expect("should have result");
self.builder.build_return(Some(&result)); self.builder.build_return(Some(&result));
} else { } else {
self.builder.build_return(None); self.builder.build_return(None);
} }
} }
Statement::If {
condition,
body,
else_body,
} => {
let condition = self
.compile_expression(condition, variables)?
.expect("should produce a value");
let func = self
.builder
.get_insert_block()
.unwrap()
.get_parent()
.expect("parent should exist");
let mut if_block = self.context.append_basic_block(func, "if");
let mut else_block = self.context.append_basic_block(func, "else");
let merge_block = self.context.append_basic_block(func, "merge");
self.builder.build_conditional_branch(
condition.into_int_value(),
if_block,
if let Some(else_body) = else_body {
else_block
} else {
merge_block
},
);
let mut variables_if = variables.clone();
self.builder.position_at_end(if_block);
for s in body {
self.compile_statement(s, &mut variables_if);
}
// should we set the builder at the end of the if_block again?
self.builder.build_unconditional_branch(merge_block);
if_block = self.builder.get_insert_block().unwrap(); // update for phi
let mut variables_else = variables.clone();
if let Some(else_body) = else_body {
self.builder.position_at_end(else_block);
for s in else_body {
self.compile_statement(s, &mut variables_else);
}
// should we set the builder at the end of the if_block again?
self.builder.build_unconditional_branch(merge_block);
else_block = self.builder.get_insert_block().unwrap(); // update for phi
}
self.builder.position_at_end(merge_block);
let mut processed_vars = HashMap::new();
for (name, (value, acc)) in variables_if {
if variables.contains_key(&name) {
let (old_val, old_acc) = variables.get(&name).unwrap();
if acc > *old_acc {
let phi = self
.builder
.build_phi(old_val.get_type(), &format!("{name}_phi"));
phi.add_incoming(&[(&value, if_block)]);
processed_vars.insert(name, (value, phi));
}
}
}
if else_body.is_some() {
for (name, (value, acc)) in variables_else {
if variables.contains_key(&name) {
let (old_val, old_acc) = variables.get(&name).unwrap();
if acc > *old_acc {
if let Some((_, phi)) = processed_vars.get(&name) {
phi.add_incoming(&[(&value, else_block)]);
} else {
let phi = self
.builder
.build_phi(old_val.get_type(), &format!("{name}_phi"));
phi.add_incoming(&[(&value, else_block)]);
processed_vars.insert(name, (value, phi));
}
}
}
}
}
for (name, (_, phi)) in processed_vars {
variables.insert(name, (phi.as_basic_value(), 0));
}
}
Statement::Function(_function) => unreachable!(), Statement::Function(_function) => unreachable!(),
}; };
@ -191,28 +296,24 @@ impl<'ctx> CodeGen<'ctx> {
pub fn compile_expression( pub fn compile_expression(
&self, &self,
block: &BasicBlock,
expr: &Expression, expr: &Expression,
variables: &mut HashMap<String, BasicValueEnum<'ctx>>, variables: &mut HashMap<String, (BasicValueEnum<'ctx>, usize)>,
) -> Result<Option<BasicValueEnum<'ctx>>> { ) -> Result<Option<BasicValueEnum<'ctx>>> {
Ok(match expr { Ok(match expr {
Expression::Variable(term) => Some(self.compile_variable(term, variables)?), Expression::Variable(term) => Some(self.compile_variable(term, variables)?),
Expression::Literal(term) => Some(self.compile_literal(term)?), Expression::Literal(term) => Some(self.compile_literal(term)?),
Expression::Call { function, args } => { Expression::Call { function, args } => self.compile_call(function, args, variables)?,
self.compile_call(block, function, args, variables)?
}
Expression::BinaryOp(lhs, op, rhs) => { Expression::BinaryOp(lhs, op, rhs) => {
Some(self.compile_binary_op(block, lhs, op, rhs, variables)?) Some(self.compile_binary_op(lhs, op, rhs, variables)?)
} }
}) })
} }
pub fn compile_call( pub fn compile_call(
&self, &self,
block: &BasicBlock,
func_name: &str, func_name: &str,
args: &[Box<Expression>], args: &[Box<Expression>],
variables: &mut HashMap<String, BasicValueEnum<'ctx>>, variables: &mut HashMap<String, (BasicValueEnum<'ctx>, usize)>,
) -> Result<Option<BasicValueEnum<'ctx>>> { ) -> Result<Option<BasicValueEnum<'ctx>>> {
let function = self.module.get_function(func_name).expect("should exist"); let function = self.module.get_function(func_name).expect("should exist");
@ -220,7 +321,7 @@ impl<'ctx> CodeGen<'ctx> {
for arg in args { for arg in args {
let res = self let res = self
.compile_expression(block, arg, variables)? .compile_expression(arg, variables)?
.expect("should have result"); .expect("should have result");
value_args.push(res.into()); value_args.push(res.into());
} }
@ -238,18 +339,17 @@ impl<'ctx> CodeGen<'ctx> {
pub fn compile_binary_op( pub fn compile_binary_op(
&self, &self,
block: &BasicBlock,
lhs: &Expression, lhs: &Expression,
op: &OpCode, op: &OpCode,
rhs: &Expression, rhs: &Expression,
variables: &mut HashMap<String, BasicValueEnum<'ctx>>, variables: &mut HashMap<String, (BasicValueEnum<'ctx>, usize)>,
) -> Result<BasicValueEnum<'ctx>> { ) -> Result<BasicValueEnum<'ctx>> {
let lhs = self let lhs = self
.compile_expression(block, lhs, variables)? .compile_expression(lhs, variables)?
.expect("should have result") .expect("should have result")
.into_int_value(); .into_int_value();
let rhs = self let rhs = self
.compile_expression(block, rhs, variables)? .compile_expression(rhs, variables)?
.expect("should have result") .expect("should have result")
.into_int_value(); .into_int_value();
@ -259,6 +359,14 @@ impl<'ctx> CodeGen<'ctx> {
OpCode::Mul => self.builder.build_int_mul(lhs, rhs, "mul"), OpCode::Mul => self.builder.build_int_mul(lhs, rhs, "mul"),
OpCode::Div => self.builder.build_int_signed_div(lhs, rhs, "div"), OpCode::Div => self.builder.build_int_signed_div(lhs, rhs, "div"),
OpCode::Rem => self.builder.build_int_signed_rem(lhs, rhs, "rem"), OpCode::Rem => self.builder.build_int_signed_rem(lhs, rhs, "rem"),
OpCode::And => self.builder.build_and(lhs, rhs, "and"),
OpCode::Or => self.builder.build_or(lhs, rhs, "or"),
OpCode::Eq => self
.builder
.build_int_compare(IntPredicate::EQ, lhs, rhs, "eq"),
OpCode::Ne => self
.builder
.build_int_compare(IntPredicate::NE, lhs, rhs, "eq"),
}; };
Ok(result.as_basic_value_enum()) Ok(result.as_basic_value_enum())
@ -288,9 +396,9 @@ impl<'ctx> CodeGen<'ctx> {
pub fn compile_variable( pub fn compile_variable(
&self, &self,
variable: &str, variable: &str,
variables: &mut HashMap<String, BasicValueEnum<'ctx>>, variables: &mut HashMap<String, (BasicValueEnum<'ctx>, usize)>,
) -> Result<BasicValueEnum<'ctx>> { ) -> Result<BasicValueEnum<'ctx>> {
let var = *variables.get(variable).expect("value"); let var = *variables.get(variable).expect("value");
Ok(var) Ok(var.0)
} }
} }

View file

@ -14,6 +14,9 @@ extern {
enum Token { enum Token {
"let" => Token::KeywordLet, "let" => Token::KeywordLet,
"print" => Token::KeywordPrint, "print" => Token::KeywordPrint,
"struct" => Token::KeywordStruct,
"if" => Token::KeywordIf,
"else" => Token::KeywordElse,
"identifier" => Token::Identifier(<String>), "identifier" => Token::Identifier(<String>),
"int" => Token::Integer(<String>), "int" => Token::Integer(<String>),
"return" => Token::KeywordReturn, "return" => Token::KeywordReturn,
@ -32,6 +35,10 @@ extern {
"*" => Token::OperatorMul, "*" => Token::OperatorMul,
"/" => Token::OperatorDiv, "/" => Token::OperatorDiv,
"%" => Token::OperatorRem, "%" => Token::OperatorRem,
"&&" => Token::OperatorAnd,
"||" => Token::OperatorOr,
"==" => Token::OperatorEq,
"!=" => Token::OperatorNe,
} }
} }
@ -66,15 +73,30 @@ Statement: ast::Statement = {
BasicStatement: ast::Statement = { BasicStatement: ast::Statement = {
"let" <i:"identifier"> "=" <e:Expr> ";" => ast::Statement::Variable { name: i, value: e}, "let" <i:"identifier"> "=" <e:Expr> ";" => ast::Statement::Variable { name: i, value: e},
<i:"identifier"> "=" <e:Expr> ";" => ast::Statement::Variable { name: i, value: e}, <i:"identifier"> "=" <e:Expr> ";" => ast::Statement::Variable { name: i, value: e},
"if" <cond:Expr> "{" <s:Statements> "}" <e:ElseExpr?> => ast::Statement::If { condition: cond, body: s, else_body: e},
"return" <e:Expr?> ";" => ast::Statement::Return(e), "return" <e:Expr?> ";" => ast::Statement::Return(e),
}; };
ExprOp: ast::OpCode = { ElseExpr: Vec<ast::Statement> = {
"else" "{" <s:Statements> "}" => s
}
Level0_Op: ast::OpCode = {
"&&" => ast::OpCode::And,
"||" => ast::OpCode::Or,
}
Level1_Op: ast::OpCode = {
"==" => ast::OpCode::Eq,
"!=" => ast::OpCode::Ne,
}
Level2_Op: ast::OpCode = {
"+" => ast::OpCode::Add, "+" => ast::OpCode::Add,
"-" => ast::OpCode::Sub, "-" => ast::OpCode::Sub,
}; };
FactorOp: ast::OpCode = { Level3_Op: ast::OpCode = {
"*" => ast::OpCode::Mul, "*" => ast::OpCode::Mul,
"/" => ast::OpCode::Div, "/" => ast::OpCode::Div,
"%" => ast::OpCode::Rem, "%" => ast::OpCode::Rem,
@ -85,18 +107,20 @@ Tier<Op,NextTier>: Box<ast::Expression> = {
NextTier NextTier
}; };
Expr = Tier<ExprOp, Factor>; Expr = Tier<Level0_Op, Expr2>;
Factor = Tier<FactorOp, Term>; Expr2 = Tier<Level1_Op, Expr3>;
Expr3 = Tier<Level2_Op, Expr4>;
Expr4 = Tier<Level3_Op, Term>;
// Terms: variables, literals, calls // Terms: variables, literals, calls
Term: Box<ast::Expression> = { Term: Box<ast::Expression> = {
<i:"identifier"> => Box::new(ast::Expression::Variable(i)), <i:"identifier"> => Box::new(ast::Expression::Variable(i)),
<n:Num> => Box::new(ast::Expression::Literal(n)), <n:Number> => Box::new(ast::Expression::Literal(n)),
<i:"identifier"> "(" <values:Comma<Term>> ")" => Box::new(ast::Expression::Call { function: i, args: values}), <i:"identifier"> "(" <values:Comma<Term>> ")" => Box::new(ast::Expression::Call { function: i, args: values}),
"(" <Term> ")" "(" <Term> ")"
}; };
Num: ast::LiteralValue = <n:"int"> => ast::LiteralValue::Integer { bits: None, signed: true, value: n.to_string()}; Number: ast::LiteralValue = <n:"int"> => ast::LiteralValue::Integer { bits: None, signed: true, value: n.to_string()};
// Function handling // Function handling
Param: ast::Parameter = { Param: ast::Parameter = {

View file

@ -121,6 +121,7 @@ fn main() -> Result<()> {
// return Ok(()); // return Ok(());
//} //}
println!("{:#?}", ast);
let context = Context::create(); let context = Context::create();
let codegen = codegen::CodeGen::new(&context, &file_name, program, ast)?; let codegen = codegen::CodeGen::new(&context, &file_name, program, ast)?;
codegen.compile_ast()?; codegen.compile_ast()?;

View file

@ -13,6 +13,12 @@ pub enum Token {
KeywordFn, KeywordFn,
#[token("return")] #[token("return")]
KeywordReturn, KeywordReturn,
#[token("struct")]
KeywordStruct,
#[token("if")]
KeywordIf,
#[token("else")]
KeywordElse,
#[regex(r"_?\p{XID_Start}\p{XID_Continue}*", |lex| lex.slice().parse().ok())] #[regex(r"_?\p{XID_Start}\p{XID_Continue}*", |lex| lex.slice().parse().ok())]
Identifier(String), Identifier(String),
@ -48,6 +54,14 @@ pub enum Token {
OperatorDiv, OperatorDiv,
#[token("%")] #[token("%")]
OperatorRem, OperatorRem,
#[token("&&")]
OperatorAnd,
#[token("||")]
OperatorOr,
#[token("==")]
OperatorEq,
#[token("!=")]
OperatorNe,
} }
impl fmt::Display for Token { impl fmt::Display for Token {