Basic variable implementation

This commit is contained in:
Michael Zhang 2022-04-05 23:32:37 -05:00
parent bcc2bf937f
commit daaf859f81
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
5 changed files with 99 additions and 27 deletions

4
examples/variables.e0 Normal file
View file

@ -0,0 +1,4 @@
fn main() -> int {
let x: int = 42;
return x;
}

View file

@ -1,23 +1,33 @@
use std::{collections::HashMap, marker::PhantomData};
use anyhow::Result; use anyhow::Result;
use inkwell::{ use inkwell::{
builder::Builder, builder::Builder,
context::Context, context::Context,
module::Module, module::Module,
types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicTypeEnum, FunctionType}, types::{BasicMetadataTypeEnum, BasicTypeEnum, FunctionType},
values::{ values::{AnyValueEnum, BasicValueEnum, PointerValue},
AnyValue, AnyValueEnum, BasicValue, BasicValueEnum, FunctionValue, IntValue,
},
}; };
use super::{Decl, Expr, Stmt, Type}; use super::{Decl, Expr, Stmt, Type};
impl Expr { impl Expr {
pub fn into_llvm<'ctx>( fn into_llvm<'ctx>(
&self, &self,
context: &'ctx Context, context: &'ctx Context,
builder: &Builder, builder: &Builder,
env: &Env<'_, 'ctx>,
) -> Result<BasicValueEnum<'ctx>> { ) -> Result<BasicValueEnum<'ctx>> {
match self { match self {
Expr::Var(name) => {
let (_, value) = match env.lookup(&name) {
Some(v) => v,
None => bail!("Unbound name {name:?}"),
};
Ok(BasicValueEnum::PointerValue(*value))
}
Expr::Int(n) => Ok(BasicValueEnum::IntValue( Expr::Int(n) => Ok(BasicValueEnum::IntValue(
context.i64_type().const_int(*n as u64, false), context.i64_type().const_int(*n as u64, false),
)), )),
@ -51,6 +61,65 @@ fn fn_type_basic<'ctx>(
} }
} }
type EnvValue<'a, 'ctx> = (&'a Type, PointerValue<'ctx>);
#[derive(Default)]
struct Env<'a, 'ctx> {
parent: Option<Box<Env<'a, 'ctx>>>,
local_type_map: HashMap<String, EnvValue<'a, 'ctx>>,
}
impl<'a, 'ctx> Env<'a, 'ctx> {
pub fn lookup(&self, name: impl AsRef<str>) -> Option<&EnvValue<'a, 'ctx>> {
match self.local_type_map.get(name.as_ref()) {
Some(v) => Some(v),
None => match &self.parent {
Some(p) => p.lookup(name),
None => None,
},
}
}
}
fn convert_lexical_block(
context: &Context,
builder: &Builder,
parent_env: Env,
stmts: impl AsRef<[Stmt]>,
) -> Result<()> {
let stmts = stmts.as_ref();
let mut scope_env = Env {
parent: Some(Box::new(parent_env)),
..Default::default()
};
for stmt in stmts.iter() {
match stmt {
Stmt::Let(name, ty, expr) => {
let llvm_ty = ty.into_llvm_basic_type(context);
let alloca = builder.build_alloca(llvm_ty, name);
let expr_val = expr.into_llvm(context, builder, &scope_env)?;
builder.build_store(alloca, expr_val);
scope_env.local_type_map.insert(name.clone(), (ty, alloca));
}
Stmt::Return(ret_val) => {
if let Some(ret_val) = ret_val {
let value = ret_val.into_llvm(context, builder, &scope_env)?;
builder.build_return(Some(&value));
} else {
builder.build_return(None);
}
println!("Emitted return.");
}
}
}
Ok(())
}
pub fn convert(context: &mut Context, program: Vec<Decl>) -> Result<Module> { pub fn convert(context: &mut Context, program: Vec<Decl>) -> Result<Module> {
let module = context.create_module("program"); let module = context.create_module("program");
let builder = context.create_builder(); let builder = context.create_builder();
@ -64,19 +133,8 @@ pub fn convert(context: &mut Context, program: Vec<Decl>) -> Result<Module> {
builder.position_at_end(entry_block); builder.position_at_end(entry_block);
for stmt in func.stmts.iter() { let env = Env::default();
match stmt { convert_lexical_block(context, &builder, env, &func.stmts)?;
Stmt::Return(ret_val) => {
if let Some(ret_val) = ret_val {
let value = ret_val.into_llvm(context, &builder)?;
builder.build_return(Some(&value));
} else {
builder.build_return(None);
}
println!("Emitted return.");
}
}
}
} }
Ok(module) Ok(module)

View file

@ -23,12 +23,14 @@ pub struct Func {
#[derive(Debug)] #[derive(Debug)]
pub enum Stmt { pub enum Stmt {
Let(String, Type, Expr),
Return(Option<Expr>), Return(Option<Expr>),
} }
#[derive(Debug)] #[derive(Debug)]
pub enum Expr { pub enum Expr {
Int(i64), Int(i64),
Var(String),
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -20,8 +20,13 @@ use crate::parser::ProgramParser;
struct Opt { struct Opt {
path: PathBuf, path: PathBuf,
#[clap(short = 'o', long = "out")] /// Path to output the bitcode to.
#[clap(short = 'o', long = "out", name = "bitcode-out")]
out_path: PathBuf, out_path: PathBuf,
/// Path to output the AST to, if at all.
#[clap(long = "emit-ast", name = "ast-out")]
emit_ast: Option<PathBuf>,
} }
fn main() -> Result<()> { fn main() -> Result<()> {

View file

@ -5,29 +5,32 @@ grammar;
pub Program: Vec<Decl> = Decl* => <>; pub Program: Vec<Decl> = Decl* => <>;
Decl: Decl = { Decl: Decl = {
Func => Decl::Func(<>), Func => Decl::Func(<>),
}; };
Func: Func = { Func: Func = {
"fn" <name:Ident> "(" ")" "->" <return_ty:Type> "{" <stmts:Stmt*> "}" => "fn" <name:Ident> "(" ")" "->" <return_ty:Type> "{" <stmts:Stmt*> "}" =>
Func { name, return_ty, stmts }, Func { name, return_ty, stmts },
}; };
Stmt: Stmt = { Stmt: Stmt = {
"return" <expr:Expr?> ";" => Stmt::Return(expr), "let" <name:Ident> ":" <ty:Type> "=" <expr:Expr> ";" =>
Stmt::Let(name, ty, expr),
"return" <expr:Expr?> ";" => Stmt::Return(expr),
}; };
Expr: Expr = { Expr: Expr = {
Expr1 => <>, Expr1 => <>,
}; };
Expr1: Expr = { Expr1: Expr = {
r"[0-9]+" => Expr::Int(<>.parse::<i64>().unwrap()), r"[0-9]+" => Expr::Int(<>.parse::<i64>().unwrap()),
"(" <expr:Expr> ")" => expr, Ident => Expr::Var(<>),
"(" <expr:Expr> ")" => expr,
}; };
Type: Type = { Type: Type = {
"int" => Type::Int, "int" => Type::Int,
}; };
Ident: String = r"([A-Za-z][A-Za-z0-9_]*)|(_[A-Za-z0-9_]+)" => <>.to_string(); Ident: String = r"([A-Za-z][A-Za-z0-9_]*)|(_[A-Za-z0-9_]+)" => <>.to_string();