Select Git revision
Forked from
Per Lindgren / D7050E
Source project has a limited visibility.
crust.rs 20.71 KiB
use crust::{
ast::{Expr, Func, Op, Span, SpanExpr},
parse::{parse_block, parse_expr},
};
use inkwell::{
builder::Builder,
context::Context,
execution_engine::{ExecutionEngine, JitFunction},
module::Module,
passes::PassManager,
types::BasicTypeEnum,
values::{
BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue,
},
FloatPredicate, OptimizationLevel,
};
use std::collections::HashMap;
use std::error::Error;
type ExprFunc = unsafe extern "C" fn() -> i32;
fn main() -> Result<(), Box<dyn Error>> {
let context = Context::create();
let mut module = context.create_module("expr");
let builder = context.create_builder();
let fpm = PassManager::create(&module);
fpm.initialize();
let execution_engine =
module.create_jit_execution_engine(OptimizationLevel::None)?;
// match parse_block(Span::new(
// "
// {
// return = 2 + 3;
// }
// ",
// ))
match parse_expr(Span::new("2 + 3")) {
Ok((_, expr)) => {
println!("{:?}", &expr);
let u32_type = context.i32_type();
let fn_type = u32_type.fn_type(&[], false);
let function = module.add_function("expr", fn_type, None);
let basic_block = context.append_basic_block(&function, "entry");
builder.position_at_end(&basic_block);
let mut compiler = Compiler {
context: &context,
builder: &builder,
module: &module,
//&fpm,
};
let res = compiler.compile_expr(&expr);
builder.build_return(Some(&res));
let fun_expr: JitFunction<ExprFunc> =
unsafe { execution_engine.get_function("expr").ok().unwrap() };
unsafe {
println!("{}", fun_expr.call());
}
}
_ => panic!(),
}
println!("module: {}", module.print_to_string());
Ok(())
}
pub struct Compiler<'a> {
pub context: &'a Context,
pub builder: &'a Builder,
// pub fpm: &'a PassManager<FunctionValue>,
pub module: &'a Module,
// pub function: &'a Func<'a>,
// variables: HashMap<String, PointerValue>,
// fn_value_opt: Option<FunctionValue>,
}
impl<'a> Compiler<'a> {
fn compile_expr(&self, expr: &SpanExpr) -> IntValue {
match expr.1.clone() {
Expr::Num(i) => self.context.i32_type().const_int(i as u64, false),
Expr::BinOp(op, l, r) => {
let lv = self.compile_expr(&l);
let rv = self.compile_expr(&r);
match op {
Op::Add => self.builder.build_int_add(lv, rv, "sum")
,
// Op::Sub => lv - rv,
// Op::Mul => lv * rv,
// Op::Div => lv / rv,
// Op::Pow => lv.pow(rv as u32),
_ => unimplemented!(),
}
}
// Expr::UnaryOp(op, e) => {
// let e = eval_expr(&e);
// match op {
// Op::Add => e,
// Op::Sub => -e,
// _ => unimplemented!(),
// }
// }
_ => unimplemented!(),
}
}
}
// fn main() {
// let p = parse_prog(Span::new(
// "
// fn main() -> i32
// {
// let a : i32 = 1 + 2;
// a = a + 1;
// return a
// }
// ",
// ));
// println!("{:?}", &p);
// }
// // ======================================================================================
// // COMPILER =============================================================================
// // ======================================================================================
// /// Defines the `Expr` compiler.
// pub struct Compiler<'a> {
// pub context: &'a Context,
// pub builder: &'a Builder,
// pub fpm: &'a PassManager<FunctionValue>,
// pub module: &'a Module,
// pub function: &'a Func<'a>,
// variables: HashMap<String, PointerValue>,
// fn_value_opt: Option<FunctionValue>,
// }
// impl<'a> Compiler<'a> {
// /// Gets a defined function given its name.
// #[inline]
// fn get_function(&self, name: &str) -> Option<FunctionValue> {
// self.module.get_function(name)
// }
// /// Returns the `FunctionValue` representing the function being compiled.
// #[inline]
// fn fn_value(&self) -> FunctionValue {
// self.fn_value_opt.unwrap()
// }
// /// Creates a new stack allocation instruction in the entry block of the function.
// fn create_entry_block_alloca(&self, name: &str) -> PointerValue {
// let builder = self.context.create_builder();
// let entry = self.fn_value().get_first_basic_block().unwrap();
// match entry.get_first_instruction() {
// Some(first_instr) => builder.position_before(&first_instr),
// None => builder.position_at_end(&entry),
// }
// builder.build_alloca(self.context.f64_type(), name)
// }
// /// Compiles the specified `Expr` into an LLVM `FloatValue`.
// fn compile_expr(
// &mut self,
// expr: &Expr,
// ) -> Result<FloatValue, &'static str> {
// match *expr {
// // Expr::Num(nb) => Ok(self.context.i32_type().const_int(nb, true)),
// // Expr::Variable(ref name) => {
// // match self.variables.get(name.as_str()) {
// // Some(var) => Ok(self
// // .builder
// // .build_load(*var, name.as_str())
// // .into_float_value()),
// // None => Err("Could not find a matching variable."),
// // }
// // }
// // Expr::VarIn {
// // ref variables,
// // ref body,
// // } => {
// // let mut old_bindings = Vec::new();
// // for &(ref var_name, ref initializer) in variables {
// // let var_name = var_name.as_str();
// // let initial_val = match *initializer {
// // Some(ref init) => self.compile_expr(init)?,
// // None => self.context.f64_type().const_float(0.),
// // };
// // let alloca = self.create_entry_block_alloca(var_name);
// // self.builder.build_store(alloca, initial_val);
// // if let Some(old_binding) = self.variables.remove(var_name) {
// // old_bindings.push(old_binding);
// // }
// // self.variables.insert(var_name.to_string(), alloca);
// // }
// // let body = self.compile_expr(body)?;
// // for binding in old_bindings {
// // self.variables.insert(
// // binding.get_name().to_str().unwrap().to_string(),
// // binding,
// // );
// // }
// // Ok(body)
// // }
// // Expr::Binary {
// // op,
// // ref left,
// // ref right,
// // } => {
// // if op == '=' {
// // // handle assignement
// // let var_name = match *left.borrow() {
// // Expr::Variable(ref var_name) => var_name,
// // _ => {
// // return Err("Expected variable as left-hand operator of assignement.");
// // }
// // };
// // let var_val = self.compile_expr(right)?;
// // let var = self
// // .variables
// // .get(var_name.as_str())
// // .ok_or("Undefined variable.")?;
// // self.builder.build_store(*var, var_val);
// // Ok(var_val)
// // } else {
// // let lhs = self.compile_expr(left)?;
// // let rhs = self.compile_expr(right)?;
// // match op {
// // '+' => {
// // Ok(self.builder.build_float_add(lhs, rhs, "tmpadd"))
// // }
// // '-' => {
// // Ok(self.builder.build_float_sub(lhs, rhs, "tmpsub"))
// // }
// // '*' => {
// // Ok(self.builder.build_float_mul(lhs, rhs, "tmpmul"))
// // }
// // '/' => {
// // Ok(self.builder.build_float_div(lhs, rhs, "tmpdiv"))
// // }
// // '<' => Ok({
// // let cmp = self.builder.build_float_compare(
// // FloatPredicate::ULT,
// // lhs,
// // rhs,
// // "tmpcmp",
// // );
// // self.builder.build_unsigned_int_to_float(
// // cmp,
// // self.context.f64_type(),
// // "tmpbool",
// // )
// // }),
// // '>' => Ok({
// // let cmp = self.builder.build_float_compare(
// // FloatPredicate::ULT,
// // rhs,
// // lhs,
// // "tmpcmp",
// // );
// // self.builder.build_unsigned_int_to_float(
// // cmp,
// // self.context.f64_type(),
// // "tmpbool",
// // )
// // }),
// // custom => {
// // let mut name = String::from("binary");
// // name.push(custom);
// // match self.get_function(name.as_str()) {
// // Some(fun) => {
// // match self
// // .builder
// // .build_call(
// // fun,
// // &[lhs.into(), rhs.into()],
// // "tmpbin",
// // )
// // .try_as_basic_value()
// // .left()
// // {
// // Some(value) => {
// // Ok(value.into_float_value())
// // }
// // None => Err("Invalid call produced."),
// // }
// // }
// // None => Err("Undefined binary operator."),
// // }
// // }
// // }
// // }
// // }
// // Expr::Call {
// // ref fn_name,
// // ref args,
// // } => match self.get_function(fn_name.as_str()) {
// // Some(fun) => {
// // let mut compiled_args = Vec::with_capacity(args.len());
// // for arg in args {
// // compiled_args.push(self.compile_expr(arg)?);
// // }
// // let argsv: Vec<BasicValueEnum> = compiled_args
// // .iter()
// // .by_ref()
// // .map(|&val| val.into())
// // .collect();
// // match self
// // .builder
// // .build_call(fun, argsv.as_slice(), "tmp")
// // .try_as_basic_value()
// // .left()
// // {
// // Some(value) => Ok(value.into_float_value()),
// // None => Err("Invalid call produced."),
// // }
// // }
// // None => Err("Unknown function."),
// // },
// // Expr::Conditional {
// // ref cond,
// // ref consequence,
// // ref alternative,
// // } => {
// // let parent = self.fn_value();
// // let zero_const = self.context.f64_type().const_float(0.0);
// // // create condition by comparing without 0.0 and returning an int
// // let cond = self.compile_expr(cond)?;
// // let cond = self.builder.build_float_compare(
// // FloatPredicate::ONE,
// // cond,
// // zero_const,
// // "ifcond",
// // );
// // // build branch
// // let then_bb = self.context.append_basic_block(&parent, "then");
// // let else_bb = self.context.append_basic_block(&parent, "else");
// // let cont_bb =
// // self.context.append_basic_block(&parent, "ifcont");
// // self.builder
// // .build_conditional_branch(cond, &then_bb, &else_bb);
// // // build then block
// // self.builder.position_at_end(&then_bb);
// // let then_val = self.compile_expr(consequence)?;
// // self.builder.build_unconditional_branch(&cont_bb);
// // let then_bb = self.builder.get_insert_block().unwrap();
// // // build else block
// // self.builder.position_at_end(&else_bb);
// // let else_val = self.compile_expr(alternative)?;
// // self.builder.build_unconditional_branch(&cont_bb);
// // let else_bb = self.builder.get_insert_block().unwrap();
// // // emit merge block
// // self.builder.position_at_end(&cont_bb);
// // let phi =
// // self.builder.build_phi(self.context.f64_type(), "iftmp");
// // phi.add_incoming(&[
// // (&then_val, &then_bb),
// // (&else_val, &else_bb),
// // ]);
// // Ok(phi.as_basic_value().into_float_value())
// // }
// // Expr::For {
// // ref var_name,
// // ref start,
// // ref end,
// // ref step,
// // ref body,
// // } => {
// // let parent = self.fn_value();
// // let start_alloca = self.create_entry_block_alloca(var_name);
// // let start = self.compile_expr(start)?;
// // self.builder.build_store(start_alloca, start);
// // // go from current block to loop block
// // let loop_bb = self.context.append_basic_block(&parent, "loop");
// // self.builder.build_unconditional_branch(&loop_bb);
// // self.builder.position_at_end(&loop_bb);
// // let old_val = self.variables.remove(var_name.as_str());
// // self.variables.insert(var_name.to_owned(), start_alloca);
// // // emit body
// // self.compile_expr(body)?;
// // // emit step
// // let step = match *step {
// // Some(ref step) => self.compile_expr(step)?,
// // None => self.context.f64_type().const_float(1.0),
// // };
// // // compile end condition
// // let end_cond = self.compile_expr(end)?;
// // let curr_var = self.builder.build_load(start_alloca, var_name);
// // let next_var = self.builder.build_float_add(
// // curr_var.into_float_value(),
// // step,
// // "nextvar",
// // );
// // self.builder.build_store(start_alloca, next_var);
// // let end_cond = self.builder.build_float_compare(
// // FloatPredicate::ONE,
// // end_cond,
// // self.context.f64_type().const_float(0.0),
// // "loopcond",
// // );
// // let after_bb =
// // self.context.append_basic_block(&parent, "afterloop");
// // self.builder
// // .build_conditional_branch(end_cond, &loop_bb, &after_bb);
// // self.builder.position_at_end(&after_bb);
// // self.variables.remove(var_name);
// // if let Some(val) = old_val {
// // self.variables.insert(var_name.to_owned(), val);
// // }
// // Ok(self.context.f64_type().const_float(0.0))
// // }
// _ => unimplemented!(),
// }
// }
// /// Compiles the specified `Prototype` into an extern LLVM `FunctionValue`.
// fn compile_prototype(
// &self,
// sig: &Sig,
// ) -> Result<FunctionValue, &'static str> {
// let ret_type = sig.2;
// let args_types = std::iter::repeat(ret_type)
// .take(sig.1.len())
// .map(|f| f.into())
// .collect::<Vec<BasicTypeEnum>>();
// let args_types = args_types.as_slice();
// let fn_type = self.context.f64_type().fn_type(args_types, false);
// let fn_val = self.module.add_function(sig.0.as_str(), fn_type, None);
// // set arguments names
// for (i, arg) in fn_val.get_param_iter().enumerate() {
// arg.into_float_value().set_name(proto.args[i].as_str());
// }
// // finally return built prototype
// Ok(fn_val)
// }
// /// Compiles the specified `Function` into an LLVM `FunctionValue`.
// fn compile_fn(&mut self) -> Result<FunctionValue, &'static str> {
// let sig = &self.function.sig;
// let function = self.compile_sig(sig)?;
// // got external function, returning only compiled prototype
// // if self.function.body.is_none() {
// // return Ok(function);
// // }
// let entry = self.context.append_basic_block(&function, "entry");
// self.builder.position_at_end(&entry);
// // update fn field
// self.fn_value_opt = Some(function);
// // build variables map
// self.variables.reserve(proto.args.len());
// for (i, arg) in function.get_param_iter().enumerate() {
// let arg_name = proto.args[i].as_str();
// let alloca = self.create_entry_block_alloca(arg_name);
// self.builder.build_store(alloca, arg);
// self.variables.insert(proto.args[i].clone(), alloca);
// }
// // compile body
// let body = self.compile_expr(self.function.body.as_ref().unwrap())?;
// self.builder.build_return(Some(&body));
// // return the whole thing after verification and optimization
// if function.verify(true) {
// self.fpm.run_on(&function);
// Ok(function)
// } else {
// unsafe {
// function.delete();
// }
// Err("Invalid generated function.")
// }
// }
// /// Compiles the specified `Function` in the given `Context` and using the specified `Builder`, `PassManager`, and `Module`.
// pub fn compile(
// context: &'a Context,
// builder: &'a Builder,
// pass_manager: &'a PassManager<FunctionValue>,
// module: &'a Module,
// function: &Function,
// ) -> Result<FunctionValue, &'static str> {
// let mut compiler = Compiler {
// context: context,
// builder: builder,
// fpm: pass_manager,
// module: module,
// function: function,
// fn_value_opt: None,
// variables: HashMap::new(),
// };
// compiler.compile_fn()
// }
// }