From d69cc69101c47a49b8915b3c0f16bc45ac84f6b2 Mon Sep 17 00:00:00 2001
From: Per Lindgren <per.lindgren@ltu.se>
Date: Thu, 3 Oct 2019 14:03:44 +0200
Subject: [PATCH] Code generation for expr (const and add)

---
 .vscode/tasks.json |  12 +++++
 examples/crust.rs  | 109 ++++++++++++++++++++++++++++++++++++---------
 2 files changed, 99 insertions(+), 22 deletions(-)

diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index b890df0..4d7ce4c 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -62,6 +62,18 @@
                 "kind": "build",
                 "isDefault": true
             }
+        },
+        {
+            "type": "shell",
+            "label": "cargo run --example crust",
+            "command": "cargo run --example crust",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
         }
     ]
 }
\ No newline at end of file
diff --git a/examples/crust.rs b/examples/crust.rs
index b9e8077..7f92b9a 100644
--- a/examples/crust.rs
+++ b/examples/crust.rs
@@ -1,7 +1,8 @@
 use crust::{
-    ast::{Expr, Func, Sig, Span},
+    ast::{Expr, Func, Op, Span, SpanExpr},
     parse::parse_expr,
 };
+
 use inkwell::{
     builder::Builder,
     context::Context,
@@ -9,7 +10,7 @@ use inkwell::{
     module::Module,
     passes::PassManager,
     types::BasicTypeEnum,
-    values::{BasicValueEnum, FloatValue, FunctionValue, PointerValue},
+    values::{BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue},
     FloatPredicate, OptimizationLevel,
 };
 use std::collections::HashMap;
@@ -18,7 +19,42 @@ use std::error::Error;
 
 type ExprFunc = unsafe extern "C" fn() -> i32;
 
+fn compile_expr(
+    expr: &SpanExpr,
+    context: &Context,
+    module: &Module,
+    builder: &Builder,
+) -> IntValue {
+    match expr.1.clone() {
+        Expr::Num(i) => context.i32_type().const_int(i as u64, false),
+
+        Expr::BinOp(op, l, r) => {
+            let lv = compile_expr(&l, context, module, builder);
+            let rv = compile_expr(&r, context, module, builder);
+            match op {
+                Op::Add => 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 jit_compile_sum(
+    expr: &SpanExpr,
     context: &Context,
     module: &Module,
     builder: &Builder,
@@ -32,14 +68,15 @@ fn jit_compile_sum(
 
     builder.position_at_end(&basic_block);
 
-    let x = context.i32_type().const_int(1, false);
-    let y = context.i32_type().const_int(2, false);
-    let z = context.i32_type().const_int(3, false);
+    // let x = context.i32_type().const_int(1, false);
+    // let y = context.i32_type().const_int(42, false);
+    // let z = context.i32_type().const_int(3, false);
 
-    let sum = builder.build_int_add(x, y, "sum");
-    let sum = builder.build_int_add(sum, z, "sum");
-
-    builder.build_return(Some(&sum));
+    // let sum = builder.build_int_add(x, y, "sum");
+    // let sum = builder.build_int_add(sum, z, "sum");
+    // builder.build_return(Some(&sum));
+    let res = compile_expr(expr, context, module, builder);
+    builder.build_return(Some(&res));
 
     unsafe { execution_engine.get_function("expr").ok() }
 }
@@ -48,27 +85,55 @@ fn main() -> Result<(), Box<dyn Error>> {
     let context = Context::create();
     let module = context.create_module("expr");
     let builder = context.create_builder();
-    let execution_engine =
-        module.create_jit_execution_engine(OptimizationLevel::None)?;
+    let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None)?;
 
-    let p = parse_expr(Span::new(
+    match parse_expr(Span::new(
         "
-        1 + 2 + 3
+        2 + 3
         ",
-    ));
-    println!("{:?}", &p);
-
-    let fun_expr =
-        jit_compile_sum(&context, &module, &builder, &execution_engine)
-            .ok_or("Unable to JIT compile `expr`")?;
-
-    unsafe {
-        println!("{}", fun_expr.call());
+    )) {
+        Ok((_, e)) => {
+            println!("{:?}", &e);
+            let fun_expr = jit_compile_sum(&e, &context, &module, &builder, &execution_engine)
+                .ok_or("Unable to JIT compile `expr`")?;
+
+            unsafe {
+                println!("{}", fun_expr.call());
+            }
+        }
+        _ => panic!(),
     }
 
     Ok(())
 }
 
+pub fn eval_expr(e: &SpanExpr) -> i32 {
+    match e.1.clone() {
+        Expr::Num(i) => i,
+        Expr::BinOp(op, l, r) => {
+            let lv = eval_expr(&l);
+            let rv = eval_expr(&r);
+            match op {
+                Op::Add => lv + rv,
+                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(
 //         "
-- 
GitLab