let rec expr_to_cstr (exptype, expr_detail) = exprdetail_to_cstr expr_detail

and exprdetail_to_cstr castexpr_detail =
    let generate_deref obj index =
        let arrtype = fst obj in
        Format.sprintf "((struct %s*)(%s))[INTEGER_OF((%s))]" arrtype (expr_to_cstr obj) (expr_to_cstr index) in

    let generate_field obj field =
        let exptype = fst obj in
        Format.sprintf "(%s)->%s.%s" (expr_to_cstr obj) (GenCast.from_tname exptype) field in

    let generate_invocation recvr fname args =
        let this = Format.sprintf "((struct %s*)(%s))" (fst recvr) (expr_to_cstr recvr) in
        let vals = List.map expr_to_cstr args in
        Format.sprintf "%s(%s)" fname (String.concat ", " (this::vals)) in

    let generate_vreference vname = function
        | Sast.Local -> vname
        | Sast.Instance(klass) -> Format.sprintf "(this->%s).%s" klass vname in

    let generate_allocation klass fname args =
        let vals = List.map expr_to_cstr args in
        let alloc = Format.sprintf "MAKE_NEW(%s)" klass in
        Format.sprintf "%s(%s)" fname (String.concat ", " (alloc::vals)) in

    let generate_array_alloc _ fname args =
        let vals = List.map expr_to_cstr args in
        Format.sprintf "%s(%s)" fname (String.concat ", " vals) in

    let generate_refine args ret = function
        | Sast.Switch(_, _, dispatch) ->
          let vals = List.map expr_to_cstr args in
          Format.sprintf "%s(%s)" dispatch (String.concat ", " ("this"::vals))
        | _ -> raise(Failure("Wrong switch applied to refine -- compiler error.")) in

    let generate_refinable = function
        | Sast.Test(_, _, dispatchby) -> Format.sprintf "%s(this)" dispatchby
        | _ -> raise(Failure("Wrong switch applied to refinable -- compiler error.")) in

    match castexpr_detail with
    | This                               -> "this" (* There is no way this is right with implicit object passing *)
    | Null                               -> "NULL"
    | Id(vname, varkind)                 -> generate_vreference vname varkind
    | NewObj(classname, fname, args)     -> generate_allocation classname fname args
    | NewArr(arrtype, fname, args)       -> generate_array_alloc arrtype fname args
    | Literal(lit)                       -> lit_to_str lit
    | Assign((vtype, _) as memory, data) -> Format.sprintf "%s = ((struct %s*)(%s))" (expr_to_cstr memory) vtype (expr_to_cstr data)
    | Deref(carray, index)               -> generate_deref carray index
    | Field(obj, fieldname)              -> generate_field obj fieldname
    | Invoc(recvr, fname, args)          -> generate_invocation recvr fname args
    | Unop(op, expr)                     -> stringify_unop op (expr_to_cstr expr) (fst expr)
    | Binop(lop, op, rop)                -> stringify_binop op (expr_to_cstr lop) (expr_to_cstr rop) ((fst lop), (fst rop))
    | Refine(args, ret, switch)          -> generate_refine args ret switch
    | Refinable(switch)                  -> generate_refinable switch

and vdecl_to_cstr (vtype, vname) = Format.sprintf "struct %s*%s" vtype vname