let rec sast_to_castexpr mname env (typetag, sastexpr) = (get_tname typetag, c_expr_detail mname sastexpr env)
and sast_to_castexprlist mname env explist = List.map (sast_to_castexpr mname env) explist

(* Convert the sast expr_detail to cast_expr detail; convert names / types / etc *)
and c_expr_detail mname sastexp env = match sastexp with
    | Sast.This                                     -> Cast.This
    | Sast.Null                                     -> Cast.Null
    | Sast.Id(vname)                                -> Cast.Id(get_vname vname, snd (StringMap.find vname env))
    | Sast.NewObj(klass, args, BuiltIn(fuid))       -> Cast.NewObj(klass, fuid, sast_to_castexprlist mname env args)
    | Sast.NewObj(klass, args, FuncId(fuid))        -> Cast.NewObj(klass, to_fname fuid "init", sast_to_castexprlist mname env args)
    | Sast.NewObj(klass, args, ArrayAlloc(fuid))    -> Cast.NewArr(get_tname klass, to_aname fuid "array_alloc", sast_to_castexprlist mname env args)
    | Sast.Literal(lit)                             -> Cast.Literal(lit)
    | Sast.Assign(e1, e2)                           -> Cast.Assign(sast_to_castexpr mname env e1, sast_to_castexpr mname env e2)
    | Sast.Deref(e1, e2)                            -> Cast.Deref(sast_to_castexpr mname env e1, sast_to_castexpr mname env e2)
    | Sast.Field(e1, field)                         -> Cast.Field(sast_to_castexpr mname env e1, get_vname field)
    | Sast.Invoc(recv, fname, args, BuiltIn(fuid))  -> Cast.Invoc(sast_to_castexpr mname env recv, fuid, sast_to_castexprlist mname env args)
    | Sast.Invoc(recv, fname, args, FuncId(fuid))   -> Cast.Invoc(sast_to_castexpr mname env recv, to_fname fuid fname, sast_to_castexprlist mname env args)
    | Sast.Invoc(_, _, _, ArrayAlloc(_))            -> raise(Failure "Cannot allocate an array in an invocation, that is nonsensical.")
    | Sast.Unop(op, expr)                           -> Cast.Unop(op, sast_to_castexpr mname env expr)
    | Sast.Binop(e1, op, e2)                        -> Cast.Binop(sast_to_castexpr mname env e1, op, sast_to_castexpr mname env e2)
    | Sast.Refine(name, args, rtype, switch)        -> Cast.Refine(sast_to_castexprlist mname env args, opt_tname rtype, cast_switch mname name switch)
    | Sast.Refinable(name, switch)                  -> Cast.Refinable(cast_switch mname name switch)
    | Anonymous(_, _, _)                            -> raise(Failure("Anonymous objects should have been deanonymized."))