diff --git a/src/jit.rs b/src/jit.rs
index ee2846838252d474e63bbd81d94b0405cb0fec35..befa81981368d9be74a64c85e8ec2c1dbff64e12 100644
--- a/src/jit.rs
+++ b/src/jit.rs
@@ -112,53 +112,61 @@ impl JIT {
         // the_return: String,
         // stmts: Vec<Expr>,
     ) -> Result<(), String> {
-        //         // Our toy language currently only supports I64 values, though Cranelift
-        //         // supports other types.
-        //         let int = self.module.target_config().pointer_type();
+        // Our toy language currently only supports I64 values, though Cranelift
+        // supports other types.
 
-        //         for _p in &params {
-        //             self.ctx.func.signature.params.push(AbiParam::new(int));
-        //         }
+        // Per: ok let i32 be an I64 for now, does not really matter
+        let int = self.module.target_config().pointer_type();
 
-        //         // Our toy language currently only supports one return value, though
-        //         // Cranelift is designed to support more.
-        //         self.ctx.func.signature.returns.push(AbiParam::new(int));
-
-        //         // Create the builder to build a function.
-        //         let mut builder = FunctionBuilder::new(&mut self.ctx.func, &mut self.builder_context);
-
-        //         // Create the entry block, to start emitting code in.
-        //         let entry_block = builder.create_block();
+        println!("set params");
+        for _p in &f.params.0 {
+            println!("id {:?}", _p.id);
+            self.ctx.func.signature.params.push(AbiParam::new(int));
+        }
 
-        //         // Since this is the entry block, add block parameters corresponding to
-        //         // the function's parameters.
-        //         //
-        //         // TODO: Streamline the API here.
-        //         builder.append_block_params_for_function_params(entry_block);
-
-        //         // Tell the builder to emit code in this block.
-        //         builder.switch_to_block(entry_block);
-
-        //         // And, tell the builder that this block will have no further
-        //         // predecessors. Since it's the entry block, it won't have any
-        //         // predecessors.
-        //         builder.seal_block(entry_block);
-
-        //         // The toy language allows variables to be declared implicitly.
-        //         // Walk the AST and declare all implicitly-declared variables.
-        //         let variables =
-        //             declare_variables(int, &mut builder, &params, &the_return, &stmts, entry_block);
-
-        //         // Now translate the statements of the function body.
-        //         let mut trans = FunctionTranslator {
-        //             int,
-        //             builder,
-        //             variables,
-        //             module: &mut self.module,
-        //         };
-        //         for expr in stmts {
-        //             trans.translate_expr(expr);
-        //         }
+        println!("set return value");
+        // Our toy language currently only supports one return value, though
+        // Cranelift is designed to support more.
+        self.ctx.func.signature.returns.push(AbiParam::new(int));
+
+        // Create the builder to build a function.
+        let mut builder = FunctionBuilder::new(&mut self.ctx.func, &mut self.builder_context);
+
+        // Create the entry block, to start emitting code in.
+        let entry_block = builder.create_block();
+
+        // Since this is the entry block, add block parameters corresponding to
+        // the function's parameters.
+        //
+        // TODO: Streamline the API here.
+        builder.append_block_params_for_function_params(entry_block);
+
+        // Tell the builder to emit code in this block.
+        builder.switch_to_block(entry_block);
+
+        // And, tell the builder that this block will have no further
+        // predecessors. Since it's the entry block, it won't have any
+        // predecessors.
+        builder.seal_block(entry_block);
+
+        // The toy language allows variables to be declared implicitly.
+        // Walk the AST and declare all implicitly-declared variables.
+
+        // Per: Not sure how we deal with introducing variables on the fly
+        // let variables =
+        //     declare_variables(int, &mut builder, &params, &the_return, &stmts, entry_block);
+        let variables = HashMap::<Id, Variable>::new();
+
+        // Now translate the statements of the function body.
+        let mut trans = FunctionTranslator {
+            int,
+            builder,
+            variables,
+            module: &mut self.module,
+        };
+        for expr in stmts {
+            trans.translate_expr(expr);
+        }
 
         //         // Set up the return variable of the function. Above, we declared a
         //         // variable to hold the return value. Here, we just do a use of that
@@ -173,317 +181,315 @@ impl JIT {
         //         trans.builder.finalize();
         Ok(())
     }
-    // }
-
-    // /// A collection of state used for translating from toy-language AST nodes
-    // /// into Cranelift IR.
-    // struct FunctionTranslator<'a> {
-    //     int: types::Type,
-    //     builder: FunctionBuilder<'a>,
-    //     variables: HashMap<String, Variable>,
-    //     module: &'a mut Module<SimpleJITBackend>,
-    // }
-
-    // impl<'a> FunctionTranslator<'a> {
-    //     /// When you write out instructions in Cranelift, you get back `Value`s. You
-    //     /// can then use these references in other instructions.
-    //     fn translate_expr(&mut self, expr: Expr) -> Value {
-    //         match expr {
-    //             Expr::Literal(literal) => {
-    //                 let imm: i32 = literal.parse().unwrap();
-    //                 self.builder.ins().iconst(self.int, i64::from(imm))
-    //             }
-
-    //             Expr::Add(lhs, rhs) => {
-    //                 let lhs = self.translate_expr(*lhs);
-    //                 let rhs = self.translate_expr(*rhs);
-    //                 self.builder.ins().iadd(lhs, rhs)
-    //             }
-
-    //             Expr::Sub(lhs, rhs) => {
-    //                 let lhs = self.translate_expr(*lhs);
-    //                 let rhs = self.translate_expr(*rhs);
-    //                 self.builder.ins().isub(lhs, rhs)
-    //             }
-
-    //             Expr::Mul(lhs, rhs) => {
-    //                 let lhs = self.translate_expr(*lhs);
-    //                 let rhs = self.translate_expr(*rhs);
-    //                 self.builder.ins().imul(lhs, rhs)
-    //             }
-
-    //             Expr::Div(lhs, rhs) => {
-    //                 let lhs = self.translate_expr(*lhs);
-    //                 let rhs = self.translate_expr(*rhs);
-    //                 self.builder.ins().udiv(lhs, rhs)
-    //             }
-
-    //             Expr::Eq(lhs, rhs) => {
-    //                 let lhs = self.translate_expr(*lhs);
-    //                 let rhs = self.translate_expr(*rhs);
-    //                 let c = self.builder.ins().icmp(IntCC::Equal, lhs, rhs);
-    //                 self.builder.ins().bint(self.int, c)
-    //             }
-
-    //             Expr::Ne(lhs, rhs) => {
-    //                 let lhs = self.translate_expr(*lhs);
-    //                 let rhs = self.translate_expr(*rhs);
-    //                 let c = self.builder.ins().icmp(IntCC::NotEqual, lhs, rhs);
-    //                 self.builder.ins().bint(self.int, c)
-    //             }
-
-    //             Expr::Lt(lhs, rhs) => {
-    //                 let lhs = self.translate_expr(*lhs);
-    //                 let rhs = self.translate_expr(*rhs);
-    //                 let c = self.builder.ins().icmp(IntCC::SignedLessThan, lhs, rhs);
-    //                 self.builder.ins().bint(self.int, c)
-    //             }
-
-    //             Expr::Le(lhs, rhs) => {
-    //                 let lhs = self.translate_expr(*lhs);
-    //                 let rhs = self.translate_expr(*rhs);
-    //                 let c = self
-    //                     .builder
-    //                     .ins()
-    //                     .icmp(IntCC::SignedLessThanOrEqual, lhs, rhs);
-    //                 self.builder.ins().bint(self.int, c)
-    //             }
-
-    //             Expr::Gt(lhs, rhs) => {
-    //                 let lhs = self.translate_expr(*lhs);
-    //                 let rhs = self.translate_expr(*rhs);
-    //                 let c = self.builder.ins().icmp(IntCC::SignedGreaterThan, lhs, rhs);
-    //                 self.builder.ins().bint(self.int, c)
-    //             }
-
-    //             Expr::Ge(lhs, rhs) => {
-    //                 let lhs = self.translate_expr(*lhs);
-    //                 let rhs = self.translate_expr(*rhs);
-    //                 let c = self
-    //                     .builder
-    //                     .ins()
-    //                     .icmp(IntCC::SignedGreaterThanOrEqual, lhs, rhs);
-    //                 self.builder.ins().bint(self.int, c)
-    //             }
-
-    //             Expr::Call(name, args) => self.translate_call(name, args),
-
-    //             Expr::GlobalDataAddr(name) => self.translate_global_data_addr(name),
-
-    //             Expr::Identifier(name) => {
-    //                 // `use_var` is used to read the value of a variable.
-    //                 let variable = self.variables.get(&name).expect("variable not defined");
-    //                 self.builder.use_var(*variable)
-    //             }
-
-    //             Expr::Assign(name, expr) => {
-    //                 // `def_var` is used to write the value of a variable. Note that
-    //                 // variables can have multiple definitions. Cranelift will
-    //                 // convert them into SSA form for itself automatically.
-    //                 let new_value = self.translate_expr(*expr);
-    //                 let variable = self.variables.get(&name).unwrap();
-    //                 self.builder.def_var(*variable, new_value);
-    //                 new_value
-    //             }
-
-    //             Expr::IfElse(condition, then_body, else_body) => {
-    //                 let condition_value = self.translate_expr(*condition);
-
-    //                 let then_block = self.builder.create_block();
-    //                 let else_block = self.builder.create_block();
-    //                 let merge_block = self.builder.create_block();
-
-    //                 // If-else constructs in the toy language have a return value.
-    //                 // In traditional SSA form, this would produce a PHI between
-    //                 // the then and else bodies. Cranelift uses block parameters,
-    //                 // so set up a parameter in the merge block, and we'll pass
-    //                 // the return values to it from the branches.
-    //                 self.builder.append_block_param(merge_block, self.int);
-
-    //                 // Test the if condition and conditionally branch.
-    //                 self.builder.ins().brz(condition_value, else_block, &[]);
-    //                 // Fall through to then block.
-    //                 self.builder.ins().jump(then_block, &[]);
-
-    //                 self.builder.switch_to_block(then_block);
-    //                 self.builder.seal_block(then_block);
-    //                 let mut then_return = self.builder.ins().iconst(self.int, 0);
-    //                 for expr in then_body {
-    //                     then_return = self.translate_expr(expr);
-    //                 }
-
-    //                 // Jump to the merge block, passing it the block return value.
-    //                 self.builder.ins().jump(merge_block, &[then_return]);
-
-    //                 self.builder.switch_to_block(else_block);
-    //                 self.builder.seal_block(else_block);
-    //                 let mut else_return = self.builder.ins().iconst(self.int, 0);
-    //                 for expr in else_body {
-    //                     else_return = self.translate_expr(expr);
-    //                 }
-
-    //                 // Jump to the merge block, passing it the block return value.
-    //                 self.builder.ins().jump(merge_block, &[else_return]);
-
-    //                 // Switch to the merge block for subsequent statements.
-    //                 self.builder.switch_to_block(merge_block);
-
-    //                 // We've now seen all the predecessors of the merge block.
-    //                 self.builder.seal_block(merge_block);
-
-    //                 // Read the value of the if-else by reading the merge block
-    //                 // parameter.
-    //                 let phi = self.builder.block_params(merge_block)[0];
-
-    //                 phi
-    //             }
-
-    //             Expr::WhileLoop(condition, loop_body) => {
-    //                 let header_block = self.builder.create_block();
-    //                 let body_block = self.builder.create_block();
-    //                 let exit_block = self.builder.create_block();
-
-    //                 self.builder.ins().jump(header_block, &[]);
-    //                 self.builder.switch_to_block(header_block);
-
-    //                 let condition_value = self.translate_expr(*condition);
-    //                 self.builder.ins().brz(condition_value, exit_block, &[]);
-    //                 self.builder.ins().jump(body_block, &[]);
-
-    //                 self.builder.switch_to_block(body_block);
-    //                 self.builder.seal_block(body_block);
-
-    //                 for expr in loop_body {
-    //                     self.translate_expr(expr);
-    //                 }
-    //                 self.builder.ins().jump(header_block, &[]);
-
-    //                 self.builder.switch_to_block(exit_block);
-
-    //                 // We've reached the bottom of the loop, so there will be no
-    //                 // more backedges to the header to exits to the bottom.
-    //                 self.builder.seal_block(header_block);
-    //                 self.builder.seal_block(exit_block);
-
-    //                 // Just return 0 for now.
-    //                 self.builder.ins().iconst(self.int, 0)
-    //             }
-    //         }
-    //     }
+}
+/// A collection of state used for translating from toy-language AST nodes
+/// into Cranelift IR.
+struct FunctionTranslator<'a> {
+    int: types::Type,
+    builder: FunctionBuilder<'a>,
+    variables: HashMap<String, Variable>,
+    module: &'a mut Module<SimpleJITBackend>,
+}
 
-    //     fn translate_call(&mut self, name: String, args: Vec<Expr>) -> Value {
-    //         let mut sig = self.module.make_signature();
+impl<'a> FunctionTranslator<'a> {
+    /// When you write out instructions in Cranelift, you get back `Value`s. You
+    /// can then use these references in other instructions.
+    fn translate_expr(&mut self, expr: Expr) -> Value {
+        match expr {
+            Expr::Num(literal) => self.builder.ins().iconst(self.int, i64::from(literal)),
+            _ => unimplemented!(),
+        }
+    }
+}
 
-    //         // Add a parameter for each argument.
-    //         for _arg in &args {
-    //             sig.params.push(AbiParam::new(self.int));
-    //         }
+//             Expr::Add(lhs, rhs) => {
+//                 let lhs = self.translate_expr(*lhs);
+//                 let rhs = self.translate_expr(*rhs);
+//                 self.builder.ins().iadd(lhs, rhs)
+//             }
 
-    //         // For simplicity for now, just make all calls return a single I64.
-    //         sig.returns.push(AbiParam::new(self.int));
+//             Expr::Sub(lhs, rhs) => {
+//                 let lhs = self.translate_expr(*lhs);
+//                 let rhs = self.translate_expr(*rhs);
+//                 self.builder.ins().isub(lhs, rhs)
+//             }
 
-    //         // TODO: Streamline the API here?
-    //         let callee = self
-    //             .module
-    //             .declare_function(&name, Linkage::Import, &sig)
-    //             .expect("problem declaring function");
-    //         let local_callee = self
-    //             .module
-    //             .declare_func_in_func(callee, &mut self.builder.func);
-
-    //         let mut arg_values = Vec::new();
-    //         for arg in args {
-    //             arg_values.push(self.translate_expr(arg))
-    //         }
-    //         let call = self.builder.ins().call(local_callee, &arg_values);
-    //         self.builder.inst_results(call)[0]
-    //     }
+//             Expr::Mul(lhs, rhs) => {
+//                 let lhs = self.translate_expr(*lhs);
+//                 let rhs = self.translate_expr(*rhs);
+//                 self.builder.ins().imul(lhs, rhs)
+//             }
 
-    //     fn translate_global_data_addr(&mut self, name: String) -> Value {
-    //         let sym = self
-    //             .module
-    //             .declare_data(&name, Linkage::Export, true, false, None)
-    //             .expect("problem declaring data object");
-    //         let local_id = self
-    //             .module
-    //             .declare_data_in_func(sym, &mut self.builder.func);
+//             Expr::Div(lhs, rhs) => {
+//                 let lhs = self.translate_expr(*lhs);
+//                 let rhs = self.translate_expr(*rhs);
+//                 self.builder.ins().udiv(lhs, rhs)
+//             }
 
-    //         let pointer = self.module.target_config().pointer_type();
-    //         self.builder.ins().symbol_value(pointer, local_id)
-    //     }
-}
+//             Expr::Eq(lhs, rhs) => {
+//                 let lhs = self.translate_expr(*lhs);
+//                 let rhs = self.translate_expr(*rhs);
+//                 let c = self.builder.ins().icmp(IntCC::Equal, lhs, rhs);
+//                 self.builder.ins().bint(self.int, c)
+//             }
 
-// fn declare_variables(
-//     int: types::Type,
-//     builder: &mut FunctionBuilder,
-//     params: &[String],
-//     the_return: &str,
-//     stmts: &[Expr],
-//     entry_block: Block,
-// ) -> HashMap<String, Variable> {
-//     let mut variables = HashMap::new();
-//     let mut index = 0;
-
-//     for (i, name) in params.iter().enumerate() {
-//         // TODO: cranelift_frontend should really have an API to make it easy to set
-//         // up param variables.
-//         let val = builder.block_params(entry_block)[i];
-//         let var = declare_variable(int, builder, &mut variables, &mut index, name);
-//         builder.def_var(var, val);
-//     }
-//     let zero = builder.ins().iconst(int, 0);
-//     let return_variable = declare_variable(int, builder, &mut variables, &mut index, the_return);
-//     builder.def_var(return_variable, zero);
-//     for expr in stmts {
-//         declare_variables_in_stmt(int, builder, &mut variables, &mut index, expr);
-//     }
+//             Expr::Ne(lhs, rhs) => {
+//                 let lhs = self.translate_expr(*lhs);
+//                 let rhs = self.translate_expr(*rhs);
+//                 let c = self.builder.ins().icmp(IntCC::NotEqual, lhs, rhs);
+//                 self.builder.ins().bint(self.int, c)
+//             }
 
-//     variables
-// }
-
-// /// Recursively descend through the AST, translating all implicit
-// /// variable declarations.
-// fn declare_variables_in_stmt(
-//     int: types::Type,
-//     builder: &mut FunctionBuilder,
-//     variables: &mut HashMap<String, Variable>,
-//     index: &mut usize,
-//     expr: &Expr,
-// ) {
-//     match *expr {
-//         Expr::Assign(ref name, _) => {
-//             declare_variable(int, builder, variables, index, name);
-//         }
-//         Expr::IfElse(ref _condition, ref then_body, ref else_body) => {
-//             for stmt in then_body {
-//                 declare_variables_in_stmt(int, builder, variables, index, &stmt);
+//             Expr::Lt(lhs, rhs) => {
+//                 let lhs = self.translate_expr(*lhs);
+//                 let rhs = self.translate_expr(*rhs);
+//                 let c = self.builder.ins().icmp(IntCC::SignedLessThan, lhs, rhs);
+//                 self.builder.ins().bint(self.int, c)
 //             }
-//             for stmt in else_body {
-//                 declare_variables_in_stmt(int, builder, variables, index, &stmt);
+
+//             Expr::Le(lhs, rhs) => {
+//                 let lhs = self.translate_expr(*lhs);
+//                 let rhs = self.translate_expr(*rhs);
+//                 let c = self
+//                     .builder
+//                     .ins()
+//                     .icmp(IntCC::SignedLessThanOrEqual, lhs, rhs);
+//                 self.builder.ins().bint(self.int, c)
 //             }
-//         }
-//         Expr::WhileLoop(ref _condition, ref loop_body) => {
-//             for stmt in loop_body {
-//                 declare_variables_in_stmt(int, builder, variables, index, &stmt);
+
+//             Expr::Gt(lhs, rhs) => {
+//                 let lhs = self.translate_expr(*lhs);
+//                 let rhs = self.translate_expr(*rhs);
+//                 let c = self.builder.ins().icmp(IntCC::SignedGreaterThan, lhs, rhs);
+//                 self.builder.ins().bint(self.int, c)
 //             }
+
+//             Expr::Ge(lhs, rhs) => {
+//                 let lhs = self.translate_expr(*lhs);
+//                 let rhs = self.translate_expr(*rhs);
+//                 let c = self
+//                     .builder
+//                     .ins()
+//                     .icmp(IntCC::SignedGreaterThanOrEqual, lhs, rhs);
+//                 self.builder.ins().bint(self.int, c)
+//             }
+
+//             Expr::Call(name, args) => self.translate_call(name, args),
+
+//             Expr::GlobalDataAddr(name) => self.translate_global_data_addr(name),
+
+//             Expr::Identifier(name) => {
+//                 // `use_var` is used to read the value of a variable.
+//                 let variable = self.variables.get(&name).expect("variable not defined");
+//                 self.builder.use_var(*variable)
+//             }
+
+//             Expr::Assign(name, expr) => {
+//                 // `def_var` is used to write the value of a variable. Note that
+//                 // variables can have multiple definitions. Cranelift will
+//                 // convert them into SSA form for itself automatically.
+//                 let new_value = self.translate_expr(*expr);
+//                 let variable = self.variables.get(&name).unwrap();
+//                 self.builder.def_var(*variable, new_value);
+//                 new_value
+//             }
+
+//             Expr::IfElse(condition, then_body, else_body) => {
+//                 let condition_value = self.translate_expr(*condition);
+
+//                 let then_block = self.builder.create_block();
+//                 let else_block = self.builder.create_block();
+//                 let merge_block = self.builder.create_block();
+
+//                 // If-else constructs in the toy language have a return value.
+//                 // In traditional SSA form, this would produce a PHI between
+//                 // the then and else bodies. Cranelift uses block parameters,
+//                 // so set up a parameter in the merge block, and we'll pass
+//                 // the return values to it from the branches.
+//                 self.builder.append_block_param(merge_block, self.int);
+
+//                 // Test the if condition and conditionally branch.
+//                 self.builder.ins().brz(condition_value, else_block, &[]);
+//                 // Fall through to then block.
+//                 self.builder.ins().jump(then_block, &[]);
+
+//                 self.builder.switch_to_block(then_block);
+//                 self.builder.seal_block(then_block);
+//                 let mut then_return = self.builder.ins().iconst(self.int, 0);
+//                 for expr in then_body {
+//                     then_return = self.translate_expr(expr);
+//                 }
+
+//                 // Jump to the merge block, passing it the block return value.
+//                 self.builder.ins().jump(merge_block, &[then_return]);
+
+//                 self.builder.switch_to_block(else_block);
+//                 self.builder.seal_block(else_block);
+//                 let mut else_return = self.builder.ins().iconst(self.int, 0);
+//                 for expr in else_body {
+//                     else_return = self.translate_expr(expr);
+//                 }
+
+//                 // Jump to the merge block, passing it the block return value.
+//                 self.builder.ins().jump(merge_block, &[else_return]);
+
+//                 // Switch to the merge block for subsequent statements.
+//                 self.builder.switch_to_block(merge_block);
+
+//                 // We've now seen all the predecessors of the merge block.
+//                 self.builder.seal_block(merge_block);
+
+//                 // Read the value of the if-else by reading the merge block
+//                 // parameter.
+//                 let phi = self.builder.block_params(merge_block)[0];
+
+//                 phi
+//             }
+
+//             Expr::WhileLoop(condition, loop_body) => {
+//                 let header_block = self.builder.create_block();
+//                 let body_block = self.builder.create_block();
+//                 let exit_block = self.builder.create_block();
+
+//                 self.builder.ins().jump(header_block, &[]);
+//                 self.builder.switch_to_block(header_block);
+
+//                 let condition_value = self.translate_expr(*condition);
+//                 self.builder.ins().brz(condition_value, exit_block, &[]);
+//                 self.builder.ins().jump(body_block, &[]);
+
+//                 self.builder.switch_to_block(body_block);
+//                 self.builder.seal_block(body_block);
+
+//                 for expr in loop_body {
+//                     self.translate_expr(expr);
+//                 }
+//                 self.builder.ins().jump(header_block, &[]);
+
+//                 self.builder.switch_to_block(exit_block);
+
+//                 // We've reached the bottom of the loop, so there will be no
+//                 // more backedges to the header to exits to the bottom.
+//                 self.builder.seal_block(header_block);
+//                 self.builder.seal_block(exit_block);
+
+//                 // Just return 0 for now.
+//                 self.builder.ins().iconst(self.int, 0)
+//             }
+//         }
+
+//     fn translate_call(&mut self, name: String, args: Vec<Expr>) -> Value {
+//         let mut sig = self.module.make_signature();
+
+//         // Add a parameter for each argument.
+//         for _arg in &args {
+//             sig.params.push(AbiParam::new(self.int));
 //         }
-//         _ => (),
+
+//         // For simplicity for now, just make all calls return a single I64.
+//         sig.returns.push(AbiParam::new(self.int));
+
+//         // TODO: Streamline the API here?
+//         let callee = self
+//             .module
+//             .declare_function(&name, Linkage::Import, &sig)
+//             .expect("problem declaring function");
+//         let local_callee = self
+//             .module
+//             .declare_func_in_func(callee, &mut self.builder.func);
+
+//         let mut arg_values = Vec::new();
+//         for arg in args {
+//             arg_values.push(self.translate_expr(arg))
+//         }
+//         let call = self.builder.ins().call(local_callee, &arg_values);
+//         self.builder.inst_results(call)[0]
 //     }
-// }
-
-// /// Declare a single variable declaration.
-// fn declare_variable(
-//     int: types::Type,
-//     builder: &mut FunctionBuilder,
-//     variables: &mut HashMap<String, Variable>,
-//     index: &mut usize,
-//     name: &str,
-// ) -> Variable {
-//     let var = Variable::new(*index);
-//     if !variables.contains_key(name) {
-//         variables.insert(name.into(), var);
-//         builder.declare_var(var, int);
-//         *index += 1;
+
+//     fn translate_global_data_addr(&mut self, name: String) -> Value {
+//         let sym = self
+//             .module
+//             .declare_data(&name, Linkage::Export, true, false, None)
+//             .expect("problem declaring data object");
+//         let local_id = self
+//             .module
+//             .declare_data_in_func(sym, &mut self.builder.func);
+
+//         let pointer = self.module.target_config().pointer_type();
+//         self.builder.ins().symbol_value(pointer, local_id)
 //     }
-//     var
-// }
+
+fn declare_variables(
+    int: types::Type,
+    builder: &mut FunctionBuilder,
+    params: &[String],
+    the_return: &str,
+    stmts: &[Expr],
+    entry_block: Block,
+) -> HashMap<String, Variable> {
+    let mut variables = HashMap::new();
+    let mut index = 0;
+
+    for (i, name) in params.iter().enumerate() {
+        // TODO: cranelift_frontend should really have an API to make it easy to set
+        // up param variables.
+        let val = builder.block_params(entry_block)[i];
+        let var = declare_variable(int, builder, &mut variables, &mut index, name);
+        builder.def_var(var, val);
+    }
+    let zero = builder.ins().iconst(int, 0);
+    let return_variable = declare_variable(int, builder, &mut variables, &mut index, the_return);
+    builder.def_var(return_variable, zero);
+    for expr in stmts {
+        declare_variables_in_stmt(int, builder, &mut variables, &mut index, expr);
+    }
+
+    variables
+}
+
+/// Recursively descend through the AST, translating all implicit
+/// variable declarations.
+fn declare_variables_in_stmt(
+    int: types::Type,
+    builder: &mut FunctionBuilder,
+    variables: &mut HashMap<String, Variable>,
+    index: &mut usize,
+    expr: &Expr,
+) {
+    match *expr {
+        // Expr::Assign(ref name, _) => {
+        //     declare_variable(int, builder, variables, index, name);
+        // }
+        // Expr::IfElse(ref _condition, ref then_body, ref else_body) => {
+        //     for stmt in then_body {
+        //         declare_variables_in_stmt(int, builder, variables, index, &stmt);
+        //     }
+        //     for stmt in else_body {
+        //         declare_variables_in_stmt(int, builder, variables, index, &stmt);
+        //     }
+        // }
+        // Expr::WhileLoop(ref _condition, ref loop_body) => {
+        //     for stmt in loop_body {
+        //         declare_variables_in_stmt(int, builder, variables, index, &stmt);
+        //     }
+        // }
+        _ => (),
+    }
+}
+
+/// Declare a single variable declaration.
+fn declare_variable(
+    int: types::Type,
+    builder: &mut FunctionBuilder,
+    variables: &mut HashMap<String, Variable>,
+    index: &mut usize,
+    name: &str,
+) -> Variable {
+    let var = Variable::new(*index);
+    if !variables.contains_key(name) {
+        variables.insert(name.into(), var);
+        builder.declare_var(var, int);
+        *index += 1;
+    }
+    var
+}
diff --git a/src/main.rs b/src/main.rs
index cdfc465e43777a8efabb6be934718f2e492817b9..b2faf634ee983623eebb886b753ff9081f45481f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -22,7 +22,10 @@ pub fn read(file_name: &str) -> std::io::Result<String> {
 pub fn parse(file_name: &str) {
     let p = read(file_name).expect("File not found");
     let p = ProgramParser::new().parse(&p).unwrap();
-    println!("program {:?}", p);
+    println!("program {:?}", &p);
+
+    let mut jit = jit::JIT::new();
+    jit.compile(&p);
 }
 
 #[test]