From daaf859f81ec65001bdba4a78a6e36aeb1ba0e29 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Tue, 5 Apr 2022 23:32:37 -0500 Subject: [PATCH] Basic variable implementation --- examples/variables.e0 | 4 ++ src/ast/llvm.rs | 94 ++++++++++++++++++++++++++++++++++--------- src/ast/mod.rs | 2 + src/main.rs | 7 +++- src/parser.lalrpop | 19 +++++---- 5 files changed, 99 insertions(+), 27 deletions(-) create mode 100644 examples/variables.e0 diff --git a/examples/variables.e0 b/examples/variables.e0 new file mode 100644 index 0000000..7ed4bb5 --- /dev/null +++ b/examples/variables.e0 @@ -0,0 +1,4 @@ +fn main() -> int { + let x: int = 42; + return x; +} diff --git a/src/ast/llvm.rs b/src/ast/llvm.rs index 00e286a..f53c3ba 100644 --- a/src/ast/llvm.rs +++ b/src/ast/llvm.rs @@ -1,23 +1,33 @@ +use std::{collections::HashMap, marker::PhantomData}; + use anyhow::Result; use inkwell::{ builder::Builder, context::Context, module::Module, - types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicTypeEnum, FunctionType}, - values::{ - AnyValue, AnyValueEnum, BasicValue, BasicValueEnum, FunctionValue, IntValue, - }, + types::{BasicMetadataTypeEnum, BasicTypeEnum, FunctionType}, + values::{AnyValueEnum, BasicValueEnum, PointerValue}, }; use super::{Decl, Expr, Stmt, Type}; impl Expr { - pub fn into_llvm<'ctx>( + fn into_llvm<'ctx>( &self, context: &'ctx Context, builder: &Builder, + env: &Env<'_, 'ctx>, ) -> Result> { 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( 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>>, + local_type_map: HashMap>, +} + +impl<'a, 'ctx> Env<'a, 'ctx> { + pub fn lookup(&self, name: impl AsRef) -> 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) -> Result { let module = context.create_module("program"); let builder = context.create_builder(); @@ -64,19 +133,8 @@ pub fn convert(context: &mut Context, program: Vec) -> Result { builder.position_at_end(entry_block); - for stmt in func.stmts.iter() { - match stmt { - 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."); - } - } - } + let env = Env::default(); + convert_lexical_block(context, &builder, env, &func.stmts)?; } Ok(module) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 4a657da..053ae4a 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -23,12 +23,14 @@ pub struct Func { #[derive(Debug)] pub enum Stmt { + Let(String, Type, Expr), Return(Option), } #[derive(Debug)] pub enum Expr { Int(i64), + Var(String), } #[derive(Debug)] diff --git a/src/main.rs b/src/main.rs index 0efcbe3..2a6467e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,8 +20,13 @@ use crate::parser::ProgramParser; struct Opt { path: PathBuf, - #[clap(short = 'o', long = "out")] + /// Path to output the bitcode to. + #[clap(short = 'o', long = "out", name = "bitcode-out")] out_path: PathBuf, + + /// Path to output the AST to, if at all. + #[clap(long = "emit-ast", name = "ast-out")] + emit_ast: Option, } fn main() -> Result<()> { diff --git a/src/parser.lalrpop b/src/parser.lalrpop index cd7cdd2..2803230 100644 --- a/src/parser.lalrpop +++ b/src/parser.lalrpop @@ -5,29 +5,32 @@ grammar; pub Program: Vec = Decl* => <>; Decl: Decl = { - Func => Decl::Func(<>), + Func => Decl::Func(<>), }; Func: Func = { - "fn" "(" ")" "->" "{" "}" => - Func { name, return_ty, stmts }, + "fn" "(" ")" "->" "{" "}" => + Func { name, return_ty, stmts }, }; Stmt: Stmt = { - "return" ";" => Stmt::Return(expr), + "let" ":" "=" ";" => + Stmt::Let(name, ty, expr), + "return" ";" => Stmt::Return(expr), }; Expr: Expr = { - Expr1 => <>, + Expr1 => <>, }; Expr1: Expr = { - r"[0-9]+" => Expr::Int(<>.parse::().unwrap()), - "(" ")" => expr, + r"[0-9]+" => Expr::Int(<>.parse::().unwrap()), + Ident => Expr::Var(<>), + "(" ")" => expr, }; Type: Type = { - "int" => Type::Int, + "int" => Type::Int, }; Ident: String = r"([A-Za-z][A-Za-z0-9_]*)|(_[A-Za-z0-9_]+)" => <>.to_string();