<commit_before>#![feature(rustc_private)]
extern crate llvm_sys as llvm;
extern crate libc;
use std::ptr;
use std::ffi;

use self::llvm::prelude::{LLVMContextRef, LLVMModuleRef, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef};
use self::llvm::core::*;

use std::collections::{HashMap};
use std::mem;

use syntax::ast::{Block, Expr, Decl, TType, OptionalTypeExprTupleList};
use syntax::ptr::{B};
//FIXME this import is for integration testing purposes
use syntax::parse::*;//{Parser};
use syntax::parse::parser::{Parser};

macro_rules! c_str_ptr {
    ($s:expr) => {
        ffi::CString::new($s).unwrap().as_ptr()
    };
}

pub struct Context{
    context : LLVMContextRef,
    module : LLVMModuleRef,
    builder : LLVMBuilderRef,
    sym_tab : HashMap<String, LLVMValueRef>,
    bb_stack : Vec<*mut llvm::LLVMBasicBlock>
}

impl Context{
    fn new(module_name : &str) -> Self{
        unsafe{
            let llvm_context =  LLVMContextCreate();
            let llvm_module = LLVMModuleCreateWithNameInContext(c_str_ptr!(module_name),
                                                                llvm_context);
            let builder = LLVMCreateBuilderInContext(llvm_context);
            let sym_tab = HashMap::new();
            let bb_stack = Vec::new();

            Context {
                context : llvm_context,
                module : llvm_module,
                builder : builder,
                sym_tab : sym_tab,
                bb_stack : bb_stack
            }
        }
    }

    pub fn dump(&self){
        unsafe{
            LLVMDumpModule(self.module);
        }
    }
}

impl Drop for Context{
    fn drop(&mut self){
        unsafe{
            LLVMDisposeBuilder(self.builder);
            LLVMDisposeModule(self.module);
            LLVMContextDispose(self.context);
        }
    }
}

//TODO move these in a seperate file
type IRBuildingResult = Result<LLVMValueRef, String>;

trait IRBuilder{
    fn codegen(&self, ctxt : &mut Context) -> IRBuildingResult;
}

fn std_functions_call_factory(fn_name : &str,
                              args : &OptionalTypeExprTupleList,
                              ctxt : &mut Context) -> Option<LLVMValueRef>{
    unsafe{
        match fn_name {
            "print" =>{
                debug_assert!(args.is_some(), "No args passed to print()");
                let lst = args.as_ref().unwrap();
                debug_assert!(lst.len() == 1, "One arg should be passed to print()");
                debug_assert!(lst[0].0 == TType::TString);
                let str_arg = match &*lst[0].1 {
                    &Expr::StringExpr(ref value) => c_str_ptr!(&*(value.clone())),
                    _ => panic!("Expected a string expr")
                };

                let print_ty = LLVMIntTypeInContext(ctxt.context, 32);
                let mut pf_type_args_vec = Vec::new();
                pf_type_args_vec.push(LLVMPointerType(LLVMIntTypeInContext(ctxt.context, 8),
                                                      0));
                let proto = LLVMFunctionType(print_ty, pf_type_args_vec.as_mut_ptr(), 1, 1);
                let print_function = LLVMAddFunction(ctxt.module,
                                                     c_str_ptr!("printf"),
                                                     proto);
                let gstr = LLVMBuildGlobalStringPtr(ctxt.builder,
                                                    str_arg,
                                                    c_str_ptr!(".str"));
                let mut pf_args = Vec::new();
                pf_args.push(gstr);

                Some(LLVMBuildCall(ctxt.builder,
                                   print_function,
                                   pf_args.as_mut_ptr(),
                                   1,
                                   c_str_ptr!("call")))
            },
            _ => {None}
        }
    }
}

fn get_llvm_type_for_ttype(ty : &TType, ctxt : &mut Context) -> LLVMTypeRef{
    unsafe{
        match ty {
            &TType::TVoid => LLVMVoidTypeInContext(ctxt.context),
            &TType::TInt32 => LLVMIntTypeInContext(ctxt.context, 32),
            _ => panic!("Other TTypes not mapped yet to the corresponding LLVM types")
        }
    }
}

impl IRBuilder for Expr{
    fn codegen(&self, ctxt : &mut Context) -> IRBuildingResult{
        macro_rules! build_binary_instrs{
            ($fun : ident, $e1:ident, $e2:ident, $s : expr) => {{
                let ev1 = try!($e1.codegen(ctxt));
                let ev2 = try!($e2.codegen(ctxt));
                Ok($fun(ctxt.builder, ev1, ev2, $s.as_ptr() as *const i8))
            }}
        }
        unsafe{
            match self{
                &Expr::NumExpr(ref i) => {
                    let ty = LLVMIntTypeInContext(ctxt.context, 32);
                    Ok(LLVMConstInt(ty, *i as u64, 0))
                },
                &Expr::AddExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFAdd, e1, e2, "add_tmp")
                },
                &Expr::SubExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFSub, e1, e2, "sub_tmp")
                },
                &Expr::MulExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFMul, e1, e2, "mul_tmp")
                },
                &Expr::DivExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFDiv, e1, e2, "div_tmp")
                },
                &Expr::IfThenElseExpr(ref conditional_expr, ref then_expr, ref else_expr) => {
                    let cond_code = try!(conditional_expr.codegen(ctxt));
                    let zero = LLVMConstInt(LLVMIntTypeInContext(ctxt.context, 32), 0u64, 0);
                    let if_cond = LLVMBuildICmp(ctxt.builder, llvm::LLVMIntPredicate::LLVMIntNE, cond_code, zero, c_str_ptr!("ifcond"));
                    let bb = LLVMGetInsertBlock(ctxt.builder);
                    let function = LLVMGetBasicBlockParent(bb);
                    let then_block = LLVMAppendBasicBlockInContext(ctxt.context, function, c_str_ptr!("thencond"));
                    let else_block = LLVMAppendBasicBlockInContext(ctxt.context, function, c_str_ptr!("elsecond"));
                    let ifcont_block = LLVMAppendBasicBlockInContext(ctxt.context, function, c_str_ptr!("ifcont"));
                    LLVMBuildCondBr(ctxt.builder, if_cond, then_block, else_block);

                    LLVMPositionBuilderAtEnd(ctxt.builder, then_block);
                    let then_code = try!(then_expr.codegen(ctxt));
                    LLVMBuildBr(ctxt.builder, ifcont_block);
                    let then_end = LLVMGetInsertBlock(ctxt.builder);

                    LLVMPositionBuilderAtEnd(ctxt.builder, else_block);
                    let else_code = try!(else_expr.codegen(ctxt));
                    LLVMBuildBr(ctxt.builder, ifcont_block);
                    let else_end = LLVMGetInsertBlock(ctxt.builder);

                    LLVMPositionBuilderAtEnd(ctxt.builder, ifcont_block);

                    let phi_node = LLVMBuildPhi(ctxt.builder, LLVMIntTypeInContext(ctxt.context, 32), c_str_ptr!("ifphi"));
                    LLVMAddIncoming(phi_node, vec![then_code].as_mut_ptr(), vec![then_end].as_mut_ptr(), 1);
                    LLVMAddIncoming(phi_node, vec![else_code].as_mut_ptr(), vec![else_end].as_mut_ptr(), 1);
                    Ok(phi_node)

                },
                &Expr::CallExpr(ref fn_name, ref optional_args) => {
                    //FIXME instead of directly passing to the factory
                    //fn_name can be checked in a map that records names of std functions
                    match std_functions_call_factory(&*fn_name, optional_args, ctxt) {
                        Some(call) => Ok(call),
                        _ => {
                            //user defined function call
                            let mut pf_args = Vec::new();
                            //FIXME pass args if present in the call
                            if optional_args.is_some() {

                            }
                            //pf_args.push(gstr);
                            let _fn = ctxt.sym_tab[&*fn_name];
                            Ok(LLVMBuildCall(ctxt.builder,
                                            _fn,
                                            pf_args.as_mut_ptr(),
                                            0,
                                            c_str_ptr!("")))
                        }
                    }
                },
                &Expr::LetExpr(ref decls, ref expr) => {
                    debug_assert!(!decls.is_empty(), "Declarations in a let block can't be empty");
                    debug_assert!(expr.is_some(), "Expr in a let block can't be empty");
                    for decl in &*decls {
                        match decl {
                            &Decl::FunDec(ref name, ref params, ref ty, ref body, ref body_ty) => {
                                let llvm_ty = get_llvm_type_for_ttype(ty, ctxt);
                                let proto = LLVMFunctionType(llvm_ty, ptr::null_mut(), 0, 0);
                                let function = LLVMAddFunction(ctxt.module,
                                                               c_str_ptr!(&(*name.clone())),
                                                               proto);
                                let bb = LLVMAppendBasicBlockInContext(ctxt.context,
                                                                       function,
                                                                       c_str_ptr!("entry"));
                                ctxt.sym_tab.insert(name.clone(), function);
                                LLVMPositionBuilderAtEnd(ctxt.builder, bb);
                                //trans_expr(body, &mut ctxt);
                                let value_ref = try!(body.codegen(ctxt));
                                if *ty == TType::TVoid{
                                    LLVMBuildRetVoid(ctxt.builder);
                                }
                                else{
                                    LLVMBuildRet(ctxt.builder, value_ref);
                                }
                            },
                            _ => panic!("More decl types should be covered")
                        }

                    }
                    //trans_expr(&*expr.unwrap(), &mut ctxt);
                    //FIXME should the previous bb be popped here?
                    let bb = ctxt.bb_stack.pop().unwrap();
                    LLVMPositionBuilderAtEnd(ctxt.builder, bb);
                    let e = &expr.as_ref().unwrap();
                    let v = try!(e.codegen(ctxt));
                    Ok(v)
                }
                t => Err(format!("error: {:?}", t))
            }
        }
    }
}

pub fn translate(expr : &Expr) -> Option<Context>{
    let mut ctxt = Context::new("main_mod");
    unsafe{
        //build outer embedding main() fn
        let ty = LLVMIntTypeInContext(ctxt.context, 32);
        let proto = LLVMFunctionType(ty, ptr::null_mut(), 0, 0);
        let function = LLVMAddFunction(ctxt.module,
                                       c_str_ptr!("main"),
                                       proto);
        let bb = LLVMAppendBasicBlockInContext(ctxt.context,
                                               function,
                                               c_str_ptr!("entry"));
        LLVMPositionBuilderAtEnd(ctxt.builder, bb);
        ctxt.bb_stack.push(bb);
        trans_expr(expr, &mut ctxt);
        LLVMBuildRet(ctxt.builder,
                     LLVMConstInt(LLVMIntTypeInContext(ctxt.context, 32), 0 as u64, 0));

        //add translated code as part of the block
    }
    Some(ctxt)
}

fn trans_expr(expr: &Expr, ctxt : &mut Context){
    let result = expr.codegen(ctxt); //ctxt is already &mut
    match result {
        Ok(_) => {},
        Err(msg) => panic!(msg)
    }
}

//#[test]
fn test_translate_std_print_call() {
    let ctxt = translate(&Expr::CallExpr("print".to_string(),
                                  Some(vec![(TType::TString,
                                             B(Expr::StringExpr("abhi".to_string())))])));
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

//#[test]
fn test_prsr_bcknd_intgrtion_prnt_call() {
    let mut p = Parser::new("print(\"Grrrr!\n\")".to_string());
    p.start_lexer();
    let tup = p.expr();
    let (ty, b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    // let ctxt = translate();&Expr::CallExpr("print".to_string(),
    //                               Some(vec![(TType::TString,
    //                                          B(Expr::StringExpr("abhi".to_string())))])));
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

#[test]
fn test_translate_add_expr(){
    let mut p = Parser::new(String::from("let function foo() : int = 1+3 in foo() end"));
    p.start_lexer();
    let tup = p.expr();
    let (_ , b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    ctxt.unwrap().dump();
}
#[test]
fn test_prsr_bcknd_intgrtion_let_blk() {
    let mut p = Parser::new("let function foo() = print(\"Grrrr!\n\") in foo() end".to_string());
    p.start_lexer();
    let tup = p.expr();
    let (ty, b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

#[test]
fn test_prsr_bcknd_intgrtion_if_then_expr() {
    let mut p = Parser::new("let function foo() :int = if 1+1 then 1 else 5 in foo() end".to_string());
    p.start_lexer();
    let tup = p.expr();
    let (ty, b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

//#[test]
//fn test_prsr_bcknd_intgrtion_for_expr() {
//    let mut p = Parser::new("let function foo() = for i:= 1 to 1 do 1 in foo() end".to_string());
//    p.start_lexer();
//    let tup = p.expr();
//    let (ty, b_expr) = tup.unwrap();
//    let ctxt = translate(&*b_expr);
//    assert_eq!(ctxt.is_some(), true);
//    ctxt.unwrap().dump();
//}
<commit_msg>Add exe generation to translate<commit_after>#![feature(rustc_private)]
extern crate llvm_sys as llvm;
extern crate libc;
use std::ptr;
use std::ffi;

use self::llvm::prelude::{LLVMContextRef, LLVMModuleRef, LLVMBuilderRef, LLVMValueRef, LLVMTypeRef};
use self::llvm::core::*;
use self::llvm::target::*;
use self::llvm::target_machine::*;

use std::collections::{HashMap};
use std::mem;
use std::process::Command;

use syntax::ast::{Block, Expr, Decl, TType, OptionalTypeExprTupleList};
use syntax::ptr::{B};
//FIXME this import is for integration testing purposes
use syntax::parse::*;//{Parser};
use syntax::parse::parser::{Parser};

macro_rules! c_str_ptr {
    ($s:expr) => {
        ffi::CString::new($s).unwrap().as_ptr()
    };
}

macro_rules! c_str_mut_ptr {
    ($s:expr) => {
        ffi::CString::new($s).unwrap().into_raw()
    };
}

pub struct Context{
    context : LLVMContextRef,
    module : LLVMModuleRef,
    builder : LLVMBuilderRef,
    sym_tab : HashMap<String, LLVMValueRef>,
    bb_stack : Vec<*mut llvm::LLVMBasicBlock>
}

impl Context{
    fn new(module_name : &str) -> Self{
        unsafe{
            let llvm_context =  LLVMContextCreate();
            let llvm_module = LLVMModuleCreateWithNameInContext(c_str_ptr!(module_name),
                                                                llvm_context);
            let builder = LLVMCreateBuilderInContext(llvm_context);
            let sym_tab = HashMap::new();
            let bb_stack = Vec::new();

            Context {
                context : llvm_context,
                module : llvm_module,
                builder : builder,
                sym_tab : sym_tab,
                bb_stack : bb_stack
            }
        }
    }

    pub fn dump(&self){
        unsafe{
            LLVMDumpModule(self.module);
        }
    }
}

impl Drop for Context{
    fn drop(&mut self){
        unsafe{
            LLVMDisposeBuilder(self.builder);
            LLVMDisposeModule(self.module);
            LLVMContextDispose(self.context);
        }
    }
}

//TODO move these in a seperate file
type IRBuildingResult = Result<LLVMValueRef, String>;

trait IRBuilder{
    fn codegen(&self, ctxt : &mut Context) -> IRBuildingResult;
}

fn std_functions_call_factory(fn_name : &str,
                              args : &OptionalTypeExprTupleList,
                              ctxt : &mut Context) -> Option<LLVMValueRef>{
    unsafe{
        match fn_name {
            "print" =>{
                debug_assert!(args.is_some(), "No args passed to print()");
                let lst = args.as_ref().unwrap();
                debug_assert!(lst.len() == 1, "One arg should be passed to print()");
                debug_assert!(lst[0].0 == TType::TString);
                let str_arg = match &*lst[0].1 {
                    &Expr::StringExpr(ref value) => c_str_ptr!(&*(value.clone())),
                    _ => panic!("Expected a string expr")
                };

                let print_ty = LLVMIntTypeInContext(ctxt.context, 32);
                let mut pf_type_args_vec = Vec::new();
                pf_type_args_vec.push(LLVMPointerType(LLVMIntTypeInContext(ctxt.context, 8),
                                                      0));
                let proto = LLVMFunctionType(print_ty, pf_type_args_vec.as_mut_ptr(), 1, 1);
                let print_function = LLVMAddFunction(ctxt.module,
                                                     c_str_ptr!("printf"),
                                                     proto);
                let gstr = LLVMBuildGlobalStringPtr(ctxt.builder,
                                                    str_arg,
                                                    c_str_ptr!(".str"));
                let mut pf_args = Vec::new();
                pf_args.push(gstr);

                Some(LLVMBuildCall(ctxt.builder,
                                   print_function,
                                   pf_args.as_mut_ptr(),
                                   1,
                                   c_str_ptr!("call")))
            },
            _ => {None}
        }
    }
}

fn get_llvm_type_for_ttype(ty : &TType, ctxt : &mut Context) -> LLVMTypeRef{
    unsafe{
        match ty {
            &TType::TVoid => LLVMVoidTypeInContext(ctxt.context),
            &TType::TInt32 => LLVMIntTypeInContext(ctxt.context, 32),
            _ => panic!("Other TTypes not mapped yet to the corresponding LLVM types")
        }
    }
}

impl IRBuilder for Expr{
    fn codegen(&self, ctxt : &mut Context) -> IRBuildingResult{
        macro_rules! build_binary_instrs{
            ($fun : ident, $e1:ident, $e2:ident, $s : expr) => {{
                let ev1 = try!($e1.codegen(ctxt));
                let ev2 = try!($e2.codegen(ctxt));
                Ok($fun(ctxt.builder, ev1, ev2, $s.as_ptr() as *const i8))
            }}
        }
        unsafe{
            match self{
                &Expr::NumExpr(ref i) => {
                    let ty = LLVMIntTypeInContext(ctxt.context, 32);
                    Ok(LLVMConstInt(ty, *i as u64, 0))
                },
                &Expr::AddExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFAdd, e1, e2, "add_tmp")
                },
                &Expr::SubExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFSub, e1, e2, "sub_tmp")
                },
                &Expr::MulExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFMul, e1, e2, "mul_tmp")
                },
                &Expr::DivExpr(ref e1, ref e2) => {
                    build_binary_instrs!(LLVMBuildFDiv, e1, e2, "div_tmp")
                },
                &Expr::IfThenElseExpr(ref conditional_expr, ref then_expr, ref else_expr) => {
                    let cond_code = try!(conditional_expr.codegen(ctxt));
                    let zero = LLVMConstInt(LLVMIntTypeInContext(ctxt.context, 32), 0u64, 0);
                    let if_cond = LLVMBuildICmp(ctxt.builder, llvm::LLVMIntPredicate::LLVMIntNE, cond_code, zero, c_str_ptr!("ifcond"));
                    let bb = LLVMGetInsertBlock(ctxt.builder);
                    let function = LLVMGetBasicBlockParent(bb);
                    let then_block = LLVMAppendBasicBlockInContext(ctxt.context, function, c_str_ptr!("thencond"));
                    let else_block = LLVMAppendBasicBlockInContext(ctxt.context, function, c_str_ptr!("elsecond"));
                    let ifcont_block = LLVMAppendBasicBlockInContext(ctxt.context, function, c_str_ptr!("ifcont"));
                    LLVMBuildCondBr(ctxt.builder, if_cond, then_block, else_block);

                    LLVMPositionBuilderAtEnd(ctxt.builder, then_block);
                    let then_code = try!(then_expr.codegen(ctxt));
                    LLVMBuildBr(ctxt.builder, ifcont_block);
                    let then_end = LLVMGetInsertBlock(ctxt.builder);

                    LLVMPositionBuilderAtEnd(ctxt.builder, else_block);
                    let else_code = try!(else_expr.codegen(ctxt));
                    LLVMBuildBr(ctxt.builder, ifcont_block);
                    let else_end = LLVMGetInsertBlock(ctxt.builder);

                    LLVMPositionBuilderAtEnd(ctxt.builder, ifcont_block);

                    let phi_node = LLVMBuildPhi(ctxt.builder, LLVMIntTypeInContext(ctxt.context, 32), c_str_ptr!("ifphi"));
                    LLVMAddIncoming(phi_node, vec![then_code].as_mut_ptr(), vec![then_end].as_mut_ptr(), 1);
                    LLVMAddIncoming(phi_node, vec![else_code].as_mut_ptr(), vec![else_end].as_mut_ptr(), 1);
                    Ok(phi_node)

                },
                &Expr::CallExpr(ref fn_name, ref optional_args) => {
                    //FIXME instead of directly passing to the factory
                    //fn_name can be checked in a map that records names of std functions
                    match std_functions_call_factory(&*fn_name, optional_args, ctxt) {
                        Some(call) => Ok(call),
                        _ => {
                            //user defined function call
                            let mut pf_args = Vec::new();
                            //FIXME pass args if present in the call
                            if optional_args.is_some() {

                            }
                            //pf_args.push(gstr);
                            let _fn = ctxt.sym_tab[&*fn_name];
                            Ok(LLVMBuildCall(ctxt.builder,
                                            _fn,
                                            pf_args.as_mut_ptr(),
                                            0,
                                            c_str_ptr!("")))
                        }
                    }
                },
                &Expr::LetExpr(ref decls, ref expr) => {
                    debug_assert!(!decls.is_empty(), "Declarations in a let block can't be empty");
                    debug_assert!(expr.is_some(), "Expr in a let block can't be empty");
                    for decl in &*decls {
                        match decl {
                            &Decl::FunDec(ref name, ref params, ref ty, ref body, ref body_ty) => {
                                let llvm_ty = get_llvm_type_for_ttype(ty, ctxt);
                                let proto = LLVMFunctionType(llvm_ty, ptr::null_mut(), 0, 0);
                                let function = LLVMAddFunction(ctxt.module,
                                                               c_str_ptr!(&(*name.clone())),
                                                               proto);
                                let bb = LLVMAppendBasicBlockInContext(ctxt.context,
                                                                       function,
                                                                       c_str_ptr!("entry"));
                                ctxt.sym_tab.insert(name.clone(), function);
                                LLVMPositionBuilderAtEnd(ctxt.builder, bb);
                                //trans_expr(body, &mut ctxt);
                                let value_ref = try!(body.codegen(ctxt));
                                if *ty == TType::TVoid{
                                    LLVMBuildRetVoid(ctxt.builder);
                                }
                                else{
                                    LLVMBuildRet(ctxt.builder, value_ref);
                                }
                            },
                            _ => panic!("More decl types should be covered")
                        }

                    }
                    //trans_expr(&*expr.unwrap(), &mut ctxt);
                    //FIXME should the previous bb be popped here?
                    let bb = ctxt.bb_stack.pop().unwrap();
                    LLVMPositionBuilderAtEnd(ctxt.builder, bb);
                    let e = &expr.as_ref().unwrap();
                    let v = try!(e.codegen(ctxt));
                    Ok(v)
                }
                t => Err(format!("error: {:?}", t))
            }
        }
    }
}

pub fn translate(expr : &Expr) -> Option<Context>{
    let mut ctxt = Context::new("main_mod");
    unsafe{
        let r = LLVM_InitializeNativeTarget();
        assert_eq!(r, 0);
        LLVM_InitializeNativeAsmPrinter();
        //build outer embedding main() fn
        let ty = LLVMIntTypeInContext(ctxt.context, 32);
        let proto = LLVMFunctionType(ty, ptr::null_mut(), 0, 0);
        let function = LLVMAddFunction(ctxt.module,
                                       c_str_ptr!("main"),
                                       proto);
        let bb = LLVMAppendBasicBlockInContext(ctxt.context,
                                               function,
                                               c_str_ptr!("entry"));
        LLVMPositionBuilderAtEnd(ctxt.builder, bb);
        ctxt.bb_stack.push(bb);
        trans_expr(expr, &mut ctxt);

        //exit function
        let exit_ty = LLVMVoidTypeInContext(ctxt.context);
        let mut exit_type_args_vec = Vec::new();
        exit_type_args_vec.push(LLVMIntTypeInContext(ctxt.context, 32));
        let exit_proto = LLVMFunctionType(exit_ty, exit_type_args_vec.as_mut_ptr(), 1, 0);
        let exit_function = LLVMAddFunction(ctxt.module,
                                                      ffi::CString::new("exit").unwrap().as_ptr(),
                                                      exit_proto);
        let mut exit_args = Vec::new();
        exit_args.push(LLVMConstInt(LLVMIntTypeInContext(ctxt.context, 32), 0 as u64, 0));
        LLVMBuildCall(ctxt.builder,
                                  exit_function,
                                  exit_args.as_mut_ptr(),
                                  1,
                                  ffi::CString::new("call").unwrap().as_ptr());
        LLVMBuildRet(ctxt.builder,
                     LLVMConstInt(LLVMIntTypeInContext(ctxt.context, 32), 0 as u64, 0));

        //add translated code as part of the block
        let target_ref = LLVMGetFirstTarget();
        let target_mc = LLVMCreateTargetMachine(target_ref,
                                                LLVMGetDefaultTargetTriple(),
                                                c_str_ptr!("i386"),
                                                c_str_ptr!(""),
                                                LLVMCodeGenOptLevel::LLVMCodeGenLevelDefault,
                                                LLVMRelocMode::LLVMRelocDefault,
                                                LLVMCodeModel::LLVMCodeModelDefault );
        assert!(target_mc != ptr::null_mut());
        LLVMTargetMachineEmitToFile(target_mc,
                                    ctxt.module,
                                    c_str_mut_ptr!("tmp.o"),
                                    LLVMCodeGenFileType::LLVMObjectFile,
                                    c_str_mut_ptr!("") as *mut *mut libc::c_char);

        let out = Command::new("ld")
            .arg("--dynamic-linker")
            .arg("/lib64/ld-linux-x86-64.so.2")
            .arg("tmp.o")
            .arg("-o")
            .arg("first")
            .arg("-lc")
            .arg("--entry")
            .arg("main")
            .output()
            .unwrap_or_else(|e|{
                panic!("failed to compile - {}", e);
            });
        println!("{}", String::from_utf8_lossy(&out.stdout));
        println!("{}", String::from_utf8_lossy(&out.stderr));
    }
    Some(ctxt)
}

fn trans_expr(expr: &Expr, ctxt : &mut Context){
    let result = expr.codegen(ctxt); //ctxt is already &mut
    match result {
        Ok(_) => {},
        Err(msg) => panic!(msg)
    }
}

//#[test]
fn test_translate_std_print_call() {
    let ctxt = translate(&Expr::CallExpr("print".to_string(),
                                  Some(vec![(TType::TString,
                                             B(Expr::StringExpr("abhi".to_string())))])));
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

//#[test]
fn test_prsr_bcknd_intgrtion_prnt_call() {
    let mut p = Parser::new("print(\"Grrrr!\n\")".to_string());
    p.start_lexer();
    let tup = p.expr();
    let (ty, b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    // let ctxt = translate();&Expr::CallExpr("print".to_string(),
    //                               Some(vec![(TType::TString,
    //                                          B(Expr::StringExpr("abhi".to_string())))])));
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

#[test]
fn test_translate_add_expr(){
    let mut p = Parser::new(String::from("let function foo() : int = 1+3 in foo() end"));
    p.start_lexer();
    let tup = p.expr();
    let (_ , b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    ctxt.unwrap().dump();
}
#[test]
fn test_prsr_bcknd_intgrtion_let_blk() {
    let mut p = Parser::new("let function foo() = print(\"Grrrr!\n\") in foo() end".to_string());
    p.start_lexer();
    let tup = p.expr();
    let (ty, b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

#[test]
fn test_prsr_bcknd_intgrtion_if_then_expr() {
    let mut p = Parser::new("let function foo() :int = if 1+1 then 1 else 5 in foo() end".to_string());
    p.start_lexer();
    let tup = p.expr();
    let (ty, b_expr) = tup.unwrap();
    let ctxt = translate(&*b_expr);
    assert_eq!(ctxt.is_some(), true);
    ctxt.unwrap().dump();
}

//#[test]
//fn test_prsr_bcknd_intgrtion_for_expr() {
//    let mut p = Parser::new("let function foo() = for i:= 1 to 1 do 1 in foo() end".to_string());
//    p.start_lexer();
//    let tup = p.expr();
//    let (ty, b_expr) = tup.unwrap();
//    let ctxt = translate(&*b_expr);
//    assert_eq!(ctxt.is_some(), true);
//    ctxt.unwrap().dump();
//}
<|endoftext|>


<commit_before>use futures::channel::mpsc;
use futures::executor::block_on;
use futures::future::{ready, FutureExt};
use futures::lock::Mutex;
use futures::stream::StreamExt;
use futures::task::{Context, SpawnExt};
use futures_test::future::FutureTestExt;
use futures_test::task::{new_count_waker, panic_context};
use std::sync::Arc;

#[test]
fn mutex_acquire_uncontested() {
    let mutex = Mutex::new(());
    for _ in 0..10 {
        assert!(mutex.lock().poll_unpin(&mut panic_context()).is_ready());
    }
}

#[test]
fn mutex_wakes_waiters() {
    let mutex = Mutex::new(());
    let (waker, counter) = new_count_waker();
    let lock = mutex.lock().poll_unpin(&mut panic_context());
    assert!(lock.is_ready());

    let mut cx = Context::from_waker(&waker);
    let mut waiter = mutex.lock();
    assert!(waiter.poll_unpin(&mut cx).is_pending());
    assert_eq!(counter, 0);

    drop(lock);

    assert_eq!(counter, 1);
    assert!(waiter.poll_unpin(&mut panic_context()).is_ready());
}

#[test]
fn mutex_contested() {
    let (tx, mut rx) = mpsc::unbounded();
    let pool = futures::executor::ThreadPool::builder()
        .pool_size(16)
        .create()
        .unwrap();

    let tx = Arc::new(tx);
    let mutex = Arc::new(Mutex::new(0));

    let num_tasks = 1000;
    for _ in 0..num_tasks {
        let tx = tx.clone();
        let mutex = mutex.clone();
        pool.spawn(async move {
            let mut lock = mutex.lock().await;
            ready(()).pending_once().await;
            *lock += 1;
            tx.unbounded_send(()).unwrap();
            drop(lock);
        })
        .unwrap();
    }

    block_on(async {
        for _ in 0..num_tasks {
            rx.next().await.unwrap();
        }
        let lock = mutex.lock().await;
        assert_eq!(num_tasks, *lock);
    })
}
<commit_msg>futures: tests/mutex.rs: Don't break w/o features<commit_after>#[cfg(all(feature = "alloc", feature = "std"))]
#[test]
fn mutex_acquire_uncontested() {
    use futures::future::FutureExt;
    use futures::lock::Mutex;
    use futures_test::task::panic_context;

    let mutex = Mutex::new(());
    for _ in 0..10 {
        assert!(mutex.lock().poll_unpin(&mut panic_context()).is_ready());
    }
}

#[cfg(all(feature = "alloc", feature = "std"))]
#[test]
fn mutex_wakes_waiters() {
    use futures::future::FutureExt;
    use futures::lock::Mutex;
    use futures::task::Context;
    use futures_test::task::{new_count_waker, panic_context};

    let mutex = Mutex::new(());
    let (waker, counter) = new_count_waker();
    let lock = mutex.lock().poll_unpin(&mut panic_context());
    assert!(lock.is_ready());

    let mut cx = Context::from_waker(&waker);
    let mut waiter = mutex.lock();
    assert!(waiter.poll_unpin(&mut cx).is_pending());
    assert_eq!(counter, 0);

    drop(lock);

    assert_eq!(counter, 1);
    assert!(waiter.poll_unpin(&mut panic_context()).is_ready());
}

#[cfg(feature = "thread-pool")]
#[test]
fn mutex_contested() {
    use futures::channel::mpsc;
    use futures::executor::block_on;
    use futures::future::ready;
    use futures::lock::Mutex;
    use futures::stream::StreamExt;
    use futures::task::SpawnExt;
    use futures_test::future::FutureTestExt;
    use std::sync::Arc;

    let (tx, mut rx) = mpsc::unbounded();
    let pool = futures::executor::ThreadPool::builder()
        .pool_size(16)
        .create()
        .unwrap();

    let tx = Arc::new(tx);
    let mutex = Arc::new(Mutex::new(0));

    let num_tasks = 1000;
    for _ in 0..num_tasks {
        let tx = tx.clone();
        let mutex = mutex.clone();
        pool.spawn(async move {
            let mut lock = mutex.lock().await;
            ready(()).pending_once().await;
            *lock += 1;
            tx.unbounded_send(()).unwrap();
            drop(lock);
        })
        .unwrap();
    }

    block_on(async {
        for _ in 0..num_tasks {
            rx.next().await.unwrap();
        }
        let lock = mutex.lock().await;
        assert_eq!(num_tasks, *lock);
    })
}
<|endoftext|>


<commit_before>//! Basic DOM data structures.

use std::collections::hashmap::{HashMap, HashSet};

pub type AttrMap = HashMap<String, String>;

#[deriving(Show)]
pub struct Node {
    // data common to all nodes:
    pub children: Vec<Node>,

    // data specific to each node type:
    pub node_type: NodeType,
}

#[deriving(Show)]
pub enum NodeType {
    Element(ElementData),
    Text(String),
}

#[deriving(Show)]
pub struct ElementData {
    pub tag_name: String,
    pub attributes: AttrMap,
}

// Constructor functions for convenience:

pub fn text(data: String) -> Node {
    Node { children: vec![], node_type: Text(data) }
}

pub fn elem(name: String, attrs: AttrMap, children: Vec<Node>) -> Node {
    Node {
        children: children,
        node_type: Element(ElementData {
            tag_name: name,
            attributes: attrs,
        })
    }
}

// Element methods

impl ElementData {
    pub fn get_attribute<'a>(&'a self, key: &str) -> Option<&'a String> {
        self.attributes.find_equiv(&key)
    }

    pub fn id<'a>(&'a self) -> Option<&'a String> {
        self.get_attribute("id")
    }

    pub fn classes<'a>(&'a self) -> HashSet<&'a str> {
        match self.get_attribute("class") {
            Some(classlist) => classlist.as_slice().split(' ').collect(),
            None => HashSet::new()
        }
    }
}
<commit_msg>Elide lifetimes<commit_after>//! Basic DOM data structures.

use std::collections::hashmap::{HashMap, HashSet};

pub type AttrMap = HashMap<String, String>;

#[deriving(Show)]
pub struct Node {
    // data common to all nodes:
    pub children: Vec<Node>,

    // data specific to each node type:
    pub node_type: NodeType,
}

#[deriving(Show)]
pub enum NodeType {
    Element(ElementData),
    Text(String),
}

#[deriving(Show)]
pub struct ElementData {
    pub tag_name: String,
    pub attributes: AttrMap,
}

// Constructor functions for convenience:

pub fn text(data: String) -> Node {
    Node { children: vec![], node_type: Text(data) }
}

pub fn elem(name: String, attrs: AttrMap, children: Vec<Node>) -> Node {
    Node {
        children: children,
        node_type: Element(ElementData {
            tag_name: name,
            attributes: attrs,
        })
    }
}

// Element methods

impl ElementData {
    pub fn get_attribute(&self, key: &str) -> Option<&String> {
        self.attributes.find_equiv(&key)
    }

    pub fn id(&self) -> Option<&String> {
        self.get_attribute("id")
    }

    pub fn classes(&self) -> HashSet<&str> {
        match self.get_attribute("class") {
            Some(classlist) => classlist.as_slice().split(' ').collect(),
            None => HashSet::new()
        }
    }
}
<|endoftext|>


<commit_before>use std::slice;

use goblin::elf;

use {Object, ObjectSection, SectionKind, Symbol, SymbolKind};

/// An ELF object file.
#[derive(Debug)]
pub struct ElfFile<'a> {
    elf: elf::Elf<'a>,
    data: &'a [u8],
}

/// An iterator of the sections of an `ElfFile`.
#[derive(Debug)]
pub struct ElfSectionIterator<'a> {
    file: &'a ElfFile<'a>,
    iter: slice::Iter<'a, elf::SectionHeader>,
}

/// A section of an `ElfFile`.
#[derive(Debug)]
pub struct ElfSection<'a> {
    file: &'a ElfFile<'a>,
    section: <slice::Iter<'a, elf::SectionHeader> as Iterator>::Item,
}

impl<'a> Object<'a> for ElfFile<'a> {
    type Section = ElfSection<'a>;
    type SectionIterator = ElfSectionIterator<'a>;

    fn parse(data: &'a [u8]) -> Result<Self, &'static str> {
        let elf = elf::Elf::parse(data).map_err(|_| "Could not parse ELF header")?;
        Ok(ElfFile { elf, data })
    }

    fn get_section(&self, section_name: &str) -> Option<&'a [u8]> {
        for header in &self.elf.section_headers {
            if let Some(Ok(name)) = self.elf.shdr_strtab.get(header.sh_name) {
                if name == section_name {
                    return Some(&self.data[header.sh_offset as usize..][..header.sh_size as usize]);
                }
            }
        }
        None
    }

    fn get_sections(&'a self) -> ElfSectionIterator<'a> {
        ElfSectionIterator {
            file: self,
            iter: self.elf.section_headers.iter(),
        }
    }

    fn get_symbols(&self) -> Vec<Symbol<'a>> {
        // Determine section kinds.
        // The section kinds are inherited by symbols in those sections.
        let mut section_kinds = Vec::new();
        for sh in &self.elf.section_headers {
            let kind = match sh.sh_type {
                elf::section_header::SHT_PROGBITS => {
                    if sh.sh_flags & u64::from(elf::section_header::SHF_EXECINSTR) != 0 {
                        SectionKind::Text
                    } else if sh.sh_flags & u64::from(elf::section_header::SHF_WRITE) != 0 {
                        SectionKind::Data
                    } else {
                        SectionKind::ReadOnlyData
                    }
                }
                elf::section_header::SHT_NOBITS => SectionKind::UninitializedData,
                _ => SectionKind::Unknown,
            };
            section_kinds.push(kind);
        }

        let mut symbols = Vec::new();
        // Skip undefined symbol index.
        for sym in self.elf.syms.iter().skip(1) {
            let kind = match elf::sym::st_type(sym.st_info) {
                elf::sym::STT_OBJECT => SymbolKind::Data,
                elf::sym::STT_FUNC => SymbolKind::Text,
                elf::sym::STT_SECTION => SymbolKind::Section,
                elf::sym::STT_FILE => SymbolKind::File,
                elf::sym::STT_COMMON => SymbolKind::Common,
                elf::sym::STT_TLS => SymbolKind::Tls,
                _ => SymbolKind::Unknown,
            };
            let global = elf::sym::st_bind(sym.st_info) != elf::sym::STB_LOCAL;
            let section_kind = if sym.st_shndx == elf::section_header::SHN_UNDEF as usize
                || sym.st_shndx >= section_kinds.len()
            {
                None
            } else {
                Some(section_kinds[sym.st_shndx])
            };
            let name = match self.elf.strtab.get(sym.st_name) {
                Some(Ok(name)) => name.as_bytes(),
                _ => continue,
            };
            symbols.push(Symbol {
                kind,
                section: sym.st_shndx,
                section_kind,
                global,
                name,
                address: sym.st_value,
                size: sym.st_size,
            });
        }
        symbols
    }

    #[inline]
    fn is_little_endian(&self) -> bool {
        self.elf.little_endian
    }
}

impl<'a> Iterator for ElfSectionIterator<'a> {
    type Item = ElfSection<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|section| {
            ElfSection {
                file: self.file,
                section,
            }
        })
    }
}

impl<'a> ObjectSection<'a> for ElfSection<'a> {
    #[inline]
    fn address(&self) -> u64 {
        self.section.sh_addr
    }

    #[inline]
    fn size(&self) -> u64 {
        self.section.sh_size
    }

    fn data(&self) -> &'a [u8] {
        &self.file.data[self.section.sh_offset as usize..][..self.section.sh_size as usize]
    }

    fn name(&self) -> Option<&str> {
        self.file
            .elf
            .shdr_strtab
            .get(self.section.sh_name)
            .and_then(|x| x.ok())
    }
}
<commit_msg>Return ELF symbols with invalid names<commit_after>use std::slice;

use goblin::elf;

use {Object, ObjectSection, SectionKind, Symbol, SymbolKind};

/// An ELF object file.
#[derive(Debug)]
pub struct ElfFile<'a> {
    elf: elf::Elf<'a>,
    data: &'a [u8],
}

/// An iterator of the sections of an `ElfFile`.
#[derive(Debug)]
pub struct ElfSectionIterator<'a> {
    file: &'a ElfFile<'a>,
    iter: slice::Iter<'a, elf::SectionHeader>,
}

/// A section of an `ElfFile`.
#[derive(Debug)]
pub struct ElfSection<'a> {
    file: &'a ElfFile<'a>,
    section: <slice::Iter<'a, elf::SectionHeader> as Iterator>::Item,
}

impl<'a> Object<'a> for ElfFile<'a> {
    type Section = ElfSection<'a>;
    type SectionIterator = ElfSectionIterator<'a>;

    fn parse(data: &'a [u8]) -> Result<Self, &'static str> {
        let elf = elf::Elf::parse(data).map_err(|_| "Could not parse ELF header")?;
        Ok(ElfFile { elf, data })
    }

    fn get_section(&self, section_name: &str) -> Option<&'a [u8]> {
        for header in &self.elf.section_headers {
            if let Some(Ok(name)) = self.elf.shdr_strtab.get(header.sh_name) {
                if name == section_name {
                    return Some(&self.data[header.sh_offset as usize..][..header.sh_size as usize]);
                }
            }
        }
        None
    }

    fn get_sections(&'a self) -> ElfSectionIterator<'a> {
        ElfSectionIterator {
            file: self,
            iter: self.elf.section_headers.iter(),
        }
    }

    fn get_symbols(&self) -> Vec<Symbol<'a>> {
        // Determine section kinds.
        // The section kinds are inherited by symbols in those sections.
        let mut section_kinds = Vec::new();
        for sh in &self.elf.section_headers {
            let kind = match sh.sh_type {
                elf::section_header::SHT_PROGBITS => {
                    if sh.sh_flags & u64::from(elf::section_header::SHF_EXECINSTR) != 0 {
                        SectionKind::Text
                    } else if sh.sh_flags & u64::from(elf::section_header::SHF_WRITE) != 0 {
                        SectionKind::Data
                    } else {
                        SectionKind::ReadOnlyData
                    }
                }
                elf::section_header::SHT_NOBITS => SectionKind::UninitializedData,
                _ => SectionKind::Unknown,
            };
            section_kinds.push(kind);
        }

        let mut symbols = Vec::new();
        // Skip undefined symbol index.
        for sym in self.elf.syms.iter().skip(1) {
            let kind = match elf::sym::st_type(sym.st_info) {
                elf::sym::STT_OBJECT => SymbolKind::Data,
                elf::sym::STT_FUNC => SymbolKind::Text,
                elf::sym::STT_SECTION => SymbolKind::Section,
                elf::sym::STT_FILE => SymbolKind::File,
                elf::sym::STT_COMMON => SymbolKind::Common,
                elf::sym::STT_TLS => SymbolKind::Tls,
                _ => SymbolKind::Unknown,
            };
            let global = elf::sym::st_bind(sym.st_info) != elf::sym::STB_LOCAL;
            let section_kind = if sym.st_shndx == elf::section_header::SHN_UNDEF as usize
                || sym.st_shndx >= section_kinds.len()
            {
                None
            } else {
                Some(section_kinds[sym.st_shndx])
            };
            let name = match self.elf.strtab.get(sym.st_name) {
                Some(Ok(name)) => name.as_bytes(),
                _ => &[],
            };
            symbols.push(Symbol {
                kind,
                section: sym.st_shndx,
                section_kind,
                global,
                name,
                address: sym.st_value,
                size: sym.st_size,
            });
        }
        symbols
    }

    #[inline]
    fn is_little_endian(&self) -> bool {
        self.elf.little_endian
    }
}

impl<'a> Iterator for ElfSectionIterator<'a> {
    type Item = ElfSection<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|section| {
            ElfSection {
                file: self.file,
                section,
            }
        })
    }
}

impl<'a> ObjectSection<'a> for ElfSection<'a> {
    #[inline]
    fn address(&self) -> u64 {
        self.section.sh_addr
    }

    #[inline]
    fn size(&self) -> u64 {
        self.section.sh_size
    }

    fn data(&self) -> &'a [u8] {
        &self.file.data[self.section.sh_offset as usize..][..self.section.sh_size as usize]
    }

    fn name(&self) -> Option<&str> {
        self.file
            .elf
            .shdr_strtab
            .get(self.section.sh_name)
            .and_then(|x| x.ok())
    }
}
<|endoftext|>


<commit_before>pub const OPCODES: [&'static str; 256] = [
     "NOP",
     "LD BC, 0x{1}{0}",
     "",
     "INC BC",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "JR 0x{0}",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "JR NZ, 0x{0}",
     "LD HL, 0x{1}{0}",
     "",
     "INC HL",
     "",
     "",
     "",
     "",
     "JR Z, 0x{0}",
     "",
     "LDI A, (HL)",
     "",
     "",
     "",
     "",
     "",
     "",
     "LD SP, (0x{1}{0})",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "LD A, 0x{0}",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "LD A, B",
     "",
     "",
     "",
     "LD A, H",
     "LD A, L",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "OR A, C",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "JP 0x{1}{0}",
     "",
     "PUSH BC",
     "",
     "",
     "",
     "RET",
     "",
     "",
     "",
     "CALL 0x{1}{0}",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "LD (0xFF00 + 0x{0}), A",
     "POP HL",
     "",
     "",
     "",
     "PUSH HL",
     "",
     "",
     "",
     "",
     "LD (0x{1}{0}), A",
     "",
     "",
     "",
     "",
     "",
     "LD A, (0xFF00 + 0x{0})",
     "POP AF",
     "",
     "DI",
     "",
     "PUSH AF",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "CP A, 0x{0}",
     "",
];

pub const CBOPCODES: [&'static str; 256] = [
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
];

<commit_msg>More opcode strings<commit_after>pub const OPCODES: [&'static str; 256] = [
     "NOP",
     "LD BC, 0x{1}{0}",
     "",
     "INC BC",
     "",
     "DEC B",
     "LD B, 0x{0}",
     "",
     "",
     "",
     "",
     "",
     "",
     "DEC C",
     "LD C 0x{0}",
     "",
     "",
     "LD DE, 0x{1}{0}",
     "LD (DE), A",
     "INC DE",
     "INC D",
     "",
     "",
     "",
     "JR 0x{0}",
     "",
     "LD A, (DE)",
     "",
     "INC E",
     "",
     "",
     "",
     "JR NZ, 0x{0}",
     "LD HL, 0x{1}{0}",
     "LDI (HL), A",
     "INC HL",
     "INC H",
     "",
     "LD H, {0}",
     "",
     "JR Z, 0x{0}",
     "",
     "LDI A, (HL)",
     "",
     "INC L",
     "DEC L",
     "",
     "",
     "",
     "LD SP, (0x{1}{0})",
     "LDD (HL), A",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "LD A, 0x{0}",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "LD B, (HL)",
     "LD B, A",
     "",
     "",
     "",
     "",
     "",
     "",
     "LD C, (HL)",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "LD D, (HL)",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "LD (HL), A",
     "LD A, B",
     "",
     "",
     "",
     "LD A, H",
     "LD A, L",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "XOR A, C",
     "",
     "",
     "",
     "",
     "XOR A, (HL)",
     "",
     "",
     "OR A, C",
     "",
     "",
     "",
     "",
     "",
     "OR A, A",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "POP BC",
     "",
     "JP 0x{1}{0}",
     "CALL NZ, 0x{1}{0}",
     "PUSH BC",
     "ADD A, 0x{0}",
     "",
     "",
     "RET",
     "",
     "",
     "",
     "CALL 0x{1}{0}",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "PUSH DE",
     "SUB A, 0x{0}",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "LD (0xFF00 + 0x{0}), A",
     "POP HL",
     "",
     "",
     "",
     "PUSH HL",
     "AND A, 0x{0}",
     "",
     "",
     "",
     "LD (0x{1}{0}), A",
     "",
     "",
     "",
     "",
     "",
     "LD A, (0xFF00 + 0x{0})",
     "POP AF",
     "",
     "DI",
     "",
     "PUSH AF",
     "",
     "",
     "",
     "",
     "LD A, (0x{1}{0})",
     "",
     "",
     "",
     "CP A, 0x{0}",
     "",
];

pub const CBOPCODES: [&'static str; 256] = [
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "SRL B",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
     "",
];

<|endoftext|>


<commit_before>use std::hashmap::HashMap;
use module::{Type, TypeVariable, TypeOperator, Expr, Identifier, Number, Apply, Lambda, Let, Case, Typed, Alternative, Module, Class, Instance, Binding, DataDefinition, Constructor, TypeDeclaration,
    Pattern, ConstructorPattern, NumberPattern, IdentifierPattern};
use Scope;

#[cfg(test)]
use parser::Parser;
#[cfg(test)]
use typecheck::{identifier, apply, number, lambda, let_};

#[deriving(Eq)]
pub enum Instruction {
    Add,
    Sub,
    Multiply,
    Divide,
    Remainder,
    Push(int),
    PushGlobal(int),
    PushInt(int),
    Mkap,
    Eval,
    Unwind,
    Update(int),
    Pop(int),
    Slide(uint),
    Split(uint),
    Pack(u16, u16),
    CaseJump(uint),
    Jump(uint)
}

enum Var {
    StackVariable(int),
    GlobalVariable(int),
    ConstructorVariable(u16, u16)
}

pub struct SuperCombinator {
    arity : int,
    instructions : ~[Instruction]
}
impl SuperCombinator {
    fn new() -> SuperCombinator {
        SuperCombinator { arity : 0, instructions : ~[] }
    }
}

pub struct Assembly {
    superCombinators: ~[(~str, SuperCombinator)]
}

impl Assembly {
    fn find(&self, name: &str) -> Option<Var> {
        let mut index = 0;
        for &(ref n, _) in self.superCombinators.iter() {
            if name == *n {
                return Some(GlobalVariable(index));
            }
            index += 1;
        }
        return None;
    }
}

pub struct Compiler {
    stackSize : int,
    globals : HashMap<~str, SuperCombinator>,
    variables: HashMap<~str, Var>,
    globalIndex : int
}

impl Compiler {
    pub fn new() -> Compiler {
        let mut variables = HashMap::new();
        variables.insert(~"[]", ConstructorVariable(0, 0));
        variables.insert(~":", ConstructorVariable(1, 2));
        Compiler { stackSize : 0, globals : HashMap::new(), globalIndex : 0, variables: variables }
    }

    pub fn compileModule(&mut self, module : &Module) -> Assembly {
        //TODO
        let mut superCombinators = ~[];
        for bind in module.bindings.iter() {
            self.variables.insert(bind.name.clone(), GlobalVariable(self.globalIndex));
            self.globalIndex += 1;
            let sc = self.compileBinding(bind.arity, &bind.expression);
            superCombinators.push((bind.name.clone(), sc));
        }
        Assembly { superCombinators: superCombinators }
    }
    fn compileBinding<'a>(&mut self, arity : int, expr : &Typed<Expr>) -> SuperCombinator {

        let mut comb = SuperCombinator::new();
        comb.arity = arity;
        let mut stack = CompilerNode { compiler: self, stack: Scope::new() };
        match &expr.expr {
            &Lambda(_, _) => {
                stack.compile(expr, &mut comb.instructions, false);
                comb.instructions.push(Update(0));
                comb.instructions.push(Pop(comb.arity));
                comb.instructions.push(Unwind);
            }
            _ => {
                stack.compile(expr, &mut comb.instructions, false);
                comb.instructions.push(Update(0));
                comb.instructions.push(Unwind);
            }
       }
       comb
    }
    pub fn compileExpression(&mut self, expr: &Typed<Expr>) -> ~[Instruction] {
        let mut stack = CompilerNode { compiler: self, stack: Scope::new() };
        let mut instructions = ~[];
        stack.compile(expr, &mut instructions, false);
        instructions
    }

}

struct CompilerNode<'a> {
    stack: Scope<'a, Var>,
    compiler: &'a mut Compiler
}

//CompilerNode are only used locally and the destructor are just to reduce the stack size
//so this should be safe(?)
#[unsafe_destructor]
impl <'a> Drop for CompilerNode<'a> {
    fn drop(&mut self) {
        self.compiler.stackSize -= self.stack.variables.len() as int;
    }
}

impl <'a> CompilerNode<'a> {

    fn find(&'a self, identifier : &str) -> Option<&'a Var> {
       match self.stack.find(identifier) {
            Some(var) => Some(var),
            None => self.compiler.variables.find_equiv(&identifier)
        }
    }

    fn newStackVar(&mut self, identifier : ~str) {
        self.stack.insert(identifier, StackVariable(self.compiler.stackSize));
        self.compiler.stackSize += 1;
    }

    fn child(&'a self) -> CompilerNode<'a> {
        CompilerNode { compiler: self.compiler, stack : self.stack.child() }
    }

    fn compile<'a>(&mut self, expr : &Typed<Expr>, instructions : &mut ~[Instruction], strict: bool) {
        match &expr.expr {
            &Identifier(ref name) => {
                match self.find(*name) {
                    None => fail!("Undefined variable " + *name),
                    Some(var) => {
                        match var {
                            &StackVariable(index) => instructions.push(Push(index)),
                            &GlobalVariable(index) => instructions.push(PushGlobal(index)),
                            &ConstructorVariable(tag, arity) => instructions.push(Pack(tag, arity))
                        }
                    }
                }
            }
            &Number(num) => instructions.push(PushInt(num)),
            &Apply(ref func, ref arg) => {
                if !self.primitive(*func, *arg, instructions) {
                    self.compile(*arg, instructions, false);
                    self.compile(*func, instructions, strict);
                    match &instructions[instructions.len() - 1] {
                        &Pack(_, _) => (),//The function was only the pack instruction so to do Mkap
                        _ => instructions.push(Mkap)
                    }
                    if strict {
                        instructions.push(Eval);
                    }
                }
            }
            &Lambda(ref varname, ref body) => {
                self.newStackVar(varname.clone());
                self.compile(*body, instructions, false);
            }
            &Let(ref bindings, ref body) => {
                for bind in bindings.iter() {
                    self.newStackVar(bind.name.clone());
                    self.compile(&bind.expression, instructions, false);
                }
                self.compile(*body, instructions, strict);
                instructions.push(Slide(bindings.len()));
            }
            &Case(ref body, ref alternatives) => {
                self.compile(*body, instructions, strict);
                self.newStackVar(~"");//Dummy variable for the case expression
                let mut branches = ~[];
                for alt in alternatives.iter() {
                    self.compile_pattern(&alt.pattern, &mut branches, instructions);
                }
                for i in range(0, alternatives.len()) {
                    let alt = &alternatives[i];

                    //Set the jump instruction to jump to this place
                    instructions[branches[i]] = Jump(instructions.len());

                    let mut childScope = self.child();
                    let num_vars = childScope.add_pattern_variables(&alt.pattern, instructions);
                    childScope.compile(&alt.expression, instructions, strict);
                    instructions.push(Slide(num_vars));

                    //Reuse branches for the next Jump
                    branches[i] = instructions.len();
                    instructions.push(Jump(0));
                }
                for branch in branches.iter() {
                    instructions[*branch] = Jump(instructions.len());
                }
                if strict {
                    instructions.push(Eval);
                }
            }
        }
    }

    fn primitive(&mut self, func: &Typed<Expr>, arg: &Typed<Expr>, instructions: &mut ~[Instruction]) -> bool {
        match &func.expr {
            &Apply(ref prim_func, ref arg2) => {
                match &prim_func.expr {
                    &Identifier(ref name) => {
                        let maybeOP = match *name {
                            ~"primIntAdd" => Some(Add),
                            ~"primIntSubtract" => Some(Sub),
                            ~"primIntMultiply" => Some(Multiply),
                            ~"primIntDivide" => Some(Divide),
                            ~"primIntRemainder" => Some(Remainder),
                            _ => None
                        };
                        match maybeOP {
                            Some(op) => {
                                self.compile(*arg2, instructions, true);
                                self.compile(arg, instructions, true);
                                instructions.push(op);
                                true
                            }
                            None => false
                        }
                    }
                    _ => false
                }
            }
            _ => false
        }
    }

    fn compile_pattern(&self, pattern: &Pattern, branches: &mut ~[uint], instructions: &mut ~[Instruction]) {
        //TODO this is unlikely to work with nested patterns currently
        match pattern {
            &ConstructorPattern(ref name, ref patterns) => {
                match self.find(*name) {
                    Some(&ConstructorVariable(tag, _)) => {
                        instructions.push(CaseJump(tag as uint));
                        branches.push(instructions.len());
                        instructions.push(Jump(0));//To be determined later
                    }
                    _ => fail!("Undefined constructor {}", *name)
                }
                for p in patterns.iter() {
                    self.compile_pattern(p, branches, instructions);
                }
            }
            _ => ()
        }
    }

    fn add_pattern_variables(&mut self, pattern: &Pattern, instructions: &mut ~[Instruction]) -> uint {
        match pattern {
            &ConstructorPattern(_, ref patterns) => {
                instructions.push(Split(patterns.len()));
                let mut vars = 0;
                for p in patterns.iter() {
                    vars += self.add_pattern_variables(p, instructions);
                }
                vars
            }
            &IdentifierPattern(ref ident) => {
                self.newStackVar(ident.clone());
                1
            }
            &NumberPattern(_) => 0
        }
    }
}

#[test]
fn test_add() {
    let e = apply(apply(identifier(~"primIntAdd"), number(1)), number(2));
    let mut comp = Compiler::new();
    let instr = comp.compileExpression(&e);

    assert_eq!(instr, ~[PushInt(1), PushInt(2), Add]);
}

#[test]
fn test_apply() {
    let file =
r"add x y = primIntAdd x y
main = add 2 3";
    let mut parser = Parser::new(file.chars());
    let module = parser.module();
    let mut comp = Compiler::new();
    let assembly = comp.compileModule(&module);

    assert_eq!(assembly.superCombinators[1].n1().instructions, ~[PushInt(3), PushInt(2), PushGlobal(0), Mkap, Mkap, Update(0), Unwind]);
}

#[test]
fn test_compile_constructor() {
    let file =
r"1 : []";
    let mut parser = Parser::new(file.chars());
    let expr = parser.expression_();
    let mut comp = Compiler::new();
    let instructions = comp.compileExpression(&expr);

    assert_eq!(instructions, ~[Pack(0, 0), PushInt(1), Pack(1, 2)]);
}

#[test]
fn test_compile_case() {
    let file =
r"case [1] of
    : x xs -> x
    [] -> 2";
    let mut parser = Parser::new(file.chars());
    let expr = parser.expression_();
    let mut comp = Compiler::new();
    let instructions = comp.compileExpression(&expr);

    assert_eq!(instructions, ~[Pack(0, 0), PushInt(1), Pack(1, 2),
        CaseJump(1), Jump(7),
        CaseJump(0), Jump(11),
        Split(2), Push(1), Slide(2), Jump(15),
        Split(0), PushInt(2), Slide(0), Jump(15)]);
}
<commit_msg>Bugfix: The compiler did not adjust the stack before compiling alternatives<commit_after>use std::hashmap::HashMap;
use module::{Type, TypeVariable, TypeOperator, Expr, Identifier, Number, Apply, Lambda, Let, Case, Typed, Alternative, Module, Class, Instance, Binding, DataDefinition, Constructor, TypeDeclaration,
    Pattern, ConstructorPattern, NumberPattern, IdentifierPattern};
use Scope;

#[cfg(test)]
use parser::Parser;
#[cfg(test)]
use typecheck::{identifier, apply, number, lambda, let_};

#[deriving(Eq)]
pub enum Instruction {
    Add,
    Sub,
    Multiply,
    Divide,
    Remainder,
    Push(int),
    PushGlobal(int),
    PushInt(int),
    Mkap,
    Eval,
    Unwind,
    Update(int),
    Pop(int),
    Slide(uint),
    Split(uint),
    Pack(u16, u16),
    CaseJump(uint),
    Jump(uint)
}

enum Var {
    StackVariable(int),
    GlobalVariable(int),
    ConstructorVariable(u16, u16)
}

pub struct SuperCombinator {
    arity : int,
    instructions : ~[Instruction]
}
impl SuperCombinator {
    fn new() -> SuperCombinator {
        SuperCombinator { arity : 0, instructions : ~[] }
    }
}

pub struct Assembly {
    superCombinators: ~[(~str, SuperCombinator)]
}

impl Assembly {
    fn find(&self, name: &str) -> Option<Var> {
        let mut index = 0;
        for &(ref n, _) in self.superCombinators.iter() {
            if name == *n {
                return Some(GlobalVariable(index));
            }
            index += 1;
        }
        return None;
    }
}

pub struct Compiler {
    stackSize : int,
    globals : HashMap<~str, SuperCombinator>,
    variables: HashMap<~str, Var>,
    globalIndex : int
}

impl Compiler {
    pub fn new() -> Compiler {
        let mut variables = HashMap::new();
        variables.insert(~"[]", ConstructorVariable(0, 0));
        variables.insert(~":", ConstructorVariable(1, 2));
        Compiler { stackSize : 0, globals : HashMap::new(), globalIndex : 0, variables: variables }
    }

    pub fn compileModule(&mut self, module : &Module) -> Assembly {
        //TODO
        let mut superCombinators = ~[];
        for bind in module.bindings.iter() {
            self.variables.insert(bind.name.clone(), GlobalVariable(self.globalIndex));
            self.globalIndex += 1;
            let sc = self.compileBinding(bind.arity, &bind.expression);
            superCombinators.push((bind.name.clone(), sc));
        }
        Assembly { superCombinators: superCombinators }
    }
    fn compileBinding<'a>(&mut self, arity : int, expr : &Typed<Expr>) -> SuperCombinator {

        let mut comb = SuperCombinator::new();
        comb.arity = arity;
        let mut stack = CompilerNode { compiler: self, stack: Scope::new() };
        match &expr.expr {
            &Lambda(_, _) => {
                stack.compile(expr, &mut comb.instructions, false);
                comb.instructions.push(Update(0));
                comb.instructions.push(Pop(comb.arity));
                comb.instructions.push(Unwind);
            }
            _ => {
                stack.compile(expr, &mut comb.instructions, false);
                comb.instructions.push(Update(0));
                comb.instructions.push(Unwind);
            }
       }
       comb
    }
    pub fn compileExpression(&mut self, expr: &Typed<Expr>) -> ~[Instruction] {
        let mut stack = CompilerNode { compiler: self, stack: Scope::new() };
        let mut instructions = ~[];
        stack.compile(expr, &mut instructions, false);
        instructions
    }

}

struct CompilerNode<'a> {
    stack: Scope<'a, Var>,
    compiler: &'a mut Compiler
}

//CompilerNode are only used locally and the destructor are just to reduce the stack size
//so this should be safe(?)
#[unsafe_destructor]
impl <'a> Drop for CompilerNode<'a> {
    fn drop(&mut self) {
        self.compiler.stackSize -= self.stack.variables.len() as int;
    }
}

impl <'a> CompilerNode<'a> {

    fn find(&'a self, identifier : &str) -> Option<&'a Var> {
       match self.stack.find(identifier) {
            Some(var) => Some(var),
            None => self.compiler.variables.find_equiv(&identifier)
        }
    }

    fn newStackVar(&mut self, identifier : ~str) {
        self.stack.insert(identifier, StackVariable(self.compiler.stackSize));
        self.compiler.stackSize += 1;
    }

    fn child(&'a self) -> CompilerNode<'a> {
        CompilerNode { compiler: self.compiler, stack : self.stack.child() }
    }

    fn compile<'a>(&mut self, expr : &Typed<Expr>, instructions : &mut ~[Instruction], strict: bool) {
        match &expr.expr {
            &Identifier(ref name) => {
                match self.find(*name) {
                    None => fail!("Undefined variable " + *name),
                    Some(var) => {
                        match var {
                            &StackVariable(index) => instructions.push(Push(index)),
                            &GlobalVariable(index) => instructions.push(PushGlobal(index)),
                            &ConstructorVariable(tag, arity) => instructions.push(Pack(tag, arity))
                        }
                    }
                }
            }
            &Number(num) => instructions.push(PushInt(num)),
            &Apply(ref func, ref arg) => {
                if !self.primitive(*func, *arg, instructions) {
                    self.compile(*arg, instructions, false);
                    self.compile(*func, instructions, strict);
                    match &instructions[instructions.len() - 1] {
                        &Pack(_, _) => (),//The function was only the pack instruction so to do Mkap
                        _ => instructions.push(Mkap)
                    }
                    if strict {
                        instructions.push(Eval);
                    }
                }
            }
            &Lambda(ref varname, ref body) => {
                self.newStackVar(varname.clone());
                self.compile(*body, instructions, false);
            }
            &Let(ref bindings, ref body) => {
                for bind in bindings.iter() {
                    self.newStackVar(bind.name.clone());
                    self.compile(&bind.expression, instructions, false);
                }
                self.compile(*body, instructions, strict);
                instructions.push(Slide(bindings.len()));
            }
            &Case(ref body, ref alternatives) => {
                self.compile(*body, instructions, strict);
                self.newStackVar(~"");//Dummy variable for the case expression
                let mut branches = ~[];
                for alt in alternatives.iter() {
                    self.compile_pattern(&alt.pattern, &mut branches, instructions);
                }
                self.compiler.stackSize -= 1;
                for i in range(0, alternatives.len()) {
                    let alt = &alternatives[i];

                    //Set the jump instruction to jump to this place
                    instructions[branches[i]] = Jump(instructions.len());

                    let mut childScope = self.child();
                    let num_vars = childScope.add_pattern_variables(&alt.pattern, instructions);
                    childScope.compile(&alt.expression, instructions, strict);
                    instructions.push(Slide(num_vars));

                    //Reuse branches for the next Jump
                    branches[i] = instructions.len();
                    instructions.push(Jump(0));
                }
                for branch in branches.iter() {
                    instructions[*branch] = Jump(instructions.len());
                }
                if strict {
                    instructions.push(Eval);
                }
            }
        }
    }

    fn primitive(&mut self, func: &Typed<Expr>, arg: &Typed<Expr>, instructions: &mut ~[Instruction]) -> bool {
        match &func.expr {
            &Apply(ref prim_func, ref arg2) => {
                match &prim_func.expr {
                    &Identifier(ref name) => {
                        let maybeOP = match *name {
                            ~"primIntAdd" => Some(Add),
                            ~"primIntSubtract" => Some(Sub),
                            ~"primIntMultiply" => Some(Multiply),
                            ~"primIntDivide" => Some(Divide),
                            ~"primIntRemainder" => Some(Remainder),
                            _ => None
                        };
                        match maybeOP {
                            Some(op) => {
                                self.compile(*arg2, instructions, true);
                                self.compile(arg, instructions, true);
                                instructions.push(op);
                                true
                            }
                            None => false
                        }
                    }
                    _ => false
                }
            }
            _ => false
        }
    }

    fn compile_pattern(&self, pattern: &Pattern, branches: &mut ~[uint], instructions: &mut ~[Instruction]) {
        //TODO this is unlikely to work with nested patterns currently
        match pattern {
            &ConstructorPattern(ref name, ref patterns) => {
                match self.find(*name) {
                    Some(&ConstructorVariable(tag, _)) => {
                        instructions.push(CaseJump(tag as uint));
                        branches.push(instructions.len());
                        instructions.push(Jump(0));//To be determined later
                    }
                    _ => fail!("Undefined constructor {}", *name)
                }
                for p in patterns.iter() {
                    self.compile_pattern(p, branches, instructions);
                }
            }
            _ => ()
        }
    }

    fn add_pattern_variables(&mut self, pattern: &Pattern, instructions: &mut ~[Instruction]) -> uint {
        match pattern {
            &ConstructorPattern(_, ref patterns) => {
                instructions.push(Split(patterns.len()));
                let mut vars = 0;
                for p in patterns.iter() {
                    vars += self.add_pattern_variables(p, instructions);
                }
                vars
            }
            &IdentifierPattern(ref ident) => {
                self.newStackVar(ident.clone());
                1
            }
            &NumberPattern(_) => 0
        }
    }
}

#[test]
fn test_add() {
    let e = apply(apply(identifier(~"primIntAdd"), number(1)), number(2));
    let mut comp = Compiler::new();
    let instr = comp.compileExpression(&e);

    assert_eq!(instr, ~[PushInt(1), PushInt(2), Add]);
}

#[test]
fn test_apply() {
    let file =
r"add x y = primIntAdd x y
main = add 2 3";
    let mut parser = Parser::new(file.chars());
    let module = parser.module();
    let mut comp = Compiler::new();
    let assembly = comp.compileModule(&module);

    assert_eq!(assembly.superCombinators[1].n1().instructions, ~[PushInt(3), PushInt(2), PushGlobal(0), Mkap, Mkap, Update(0), Unwind]);
}

#[test]
fn test_compile_constructor() {
    let file =
r"1 : []";
    let mut parser = Parser::new(file.chars());
    let expr = parser.expression_();
    let mut comp = Compiler::new();
    let instructions = comp.compileExpression(&expr);

    assert_eq!(instructions, ~[Pack(0, 0), PushInt(1), Pack(1, 2)]);
}

#[test]
fn test_compile_case() {
    let file =
r"case [1] of
    : x xs -> x
    [] -> 2";
    let mut parser = Parser::new(file.chars());
    let expr = parser.expression_();
    let mut comp = Compiler::new();
    let instructions = comp.compileExpression(&expr);

    assert_eq!(instructions, ~[Pack(0, 0), PushInt(1), Pack(1, 2),
        CaseJump(1), Jump(7),
        CaseJump(0), Jump(11),
        Split(2), Push(1), Slide(2), Jump(15),
        Split(0), PushInt(2), Slide(0), Jump(15)]);
}
<|endoftext|>


<commit_before><commit_msg>Remove fcs.rs for future.<commit_after><|endoftext|>