aboutsummaryrefslogtreecommitdiff
path: root/src/boot/me/semant.ml
diff options
context:
space:
mode:
authorGraydon Hoare <[email protected]>2010-06-23 21:03:09 -0700
committerGraydon Hoare <[email protected]>2010-06-23 21:03:09 -0700
commitd6b7c96c3eb29b9244ece0c046d3f372ff432d04 (patch)
treeb425187e232966063ffc2f0d14c04a55d8f004ef /src/boot/me/semant.ml
parentInitial git commit. (diff)
downloadrust-d6b7c96c3eb29b9244ece0c046d3f372ff432d04.tar.xz
rust-d6b7c96c3eb29b9244ece0c046d3f372ff432d04.zip
Populate tree.
Diffstat (limited to 'src/boot/me/semant.ml')
-rw-r--r--src/boot/me/semant.ml1969
1 files changed, 1969 insertions, 0 deletions
diff --git a/src/boot/me/semant.ml b/src/boot/me/semant.ml
new file mode 100644
index 00000000..b5000ff3
--- /dev/null
+++ b/src/boot/me/semant.ml
@@ -0,0 +1,1969 @@
+
+open Common;;
+
+type slots_table = (Ast.slot_key,node_id) Hashtbl.t
+type items_table = (Ast.ident,node_id) Hashtbl.t
+type block_slots_table = (node_id,slots_table) Hashtbl.t
+type block_items_table = (node_id,items_table) Hashtbl.t
+;;
+
+
+type code = {
+ code_fixup: fixup;
+ code_quads: Il.quads;
+ code_vregs_and_spill: (int * fixup) option;
+}
+;;
+
+type glue =
+ GLUE_activate
+ | GLUE_yield
+ | GLUE_exit_main_task
+ | GLUE_exit_task
+ | GLUE_mark of Ast.ty
+ | GLUE_drop of Ast.ty
+ | GLUE_free of Ast.ty
+ | GLUE_copy of Ast.ty (* One-level copy. *)
+ | GLUE_clone of Ast.ty (* Deep copy. *)
+ | GLUE_compare of Ast.ty
+ | GLUE_hash of Ast.ty
+ | GLUE_write of Ast.ty
+ | GLUE_read of Ast.ty
+ | GLUE_unwind
+ | GLUE_get_next_pc
+ | GLUE_mark_frame of node_id (* node is the frame *)
+ | GLUE_drop_frame of node_id (* node is the frame *)
+ | GLUE_reloc_frame of node_id (* node is the frame *)
+ | GLUE_fn_binding of node_id (* node is the 'bind' stmt *)
+ | GLUE_obj_drop of node_id (* node is the obj *)
+ | GLUE_loop_body of node_id (* node is the 'for each' body block *)
+ | GLUE_forward of (Ast.ident * Ast.ty_obj * Ast.ty_obj)
+;;
+
+type data =
+ DATA_str of string
+ | DATA_name of Ast.name
+ | DATA_tydesc of Ast.ty
+ | DATA_frame_glue_fns of node_id
+ | DATA_obj_vtbl of node_id
+ | DATA_forwarding_vtbl of (Ast.ty_obj * Ast.ty_obj)
+ | DATA_crate
+;;
+
+type defn =
+ DEFN_slot of Ast.slot
+ | DEFN_item of Ast.mod_item_decl
+ | DEFN_ty_param of Ast.ty_param
+ | DEFN_obj_fn of (node_id * Ast.fn)
+ | DEFN_obj_drop of node_id
+ | DEFN_loop_body of node_id
+;;
+
+type glue_code = (glue, code) Hashtbl.t;;
+type item_code = (node_id, code) Hashtbl.t;;
+type file_code = (node_id, item_code) Hashtbl.t;;
+type data_frags = (data, (fixup * Asm.frag)) Hashtbl.t;;
+
+let string_of_name (n:Ast.name) : string =
+ Ast.fmt_to_str Ast.fmt_name n
+;;
+
+(* The only need for a carg is to uniquely identify a constraint-arg
+ * in a scope-independent fashion. So we just look up the node that's
+ * used as the base of any such arg and glue it on the front of the
+ * symbolic name.
+ *)
+
+type constr_key_arg = Constr_arg_node of (node_id * Ast.carg_path)
+ | Constr_arg_lit of Ast.lit
+type constr_key =
+ Constr_pred of (node_id * constr_key_arg array)
+ | Constr_init of node_id
+
+type ctxt =
+ { ctxt_sess: Session.sess;
+ ctxt_frame_args: (node_id,node_id list) Hashtbl.t;
+ ctxt_frame_blocks: (node_id,node_id list) Hashtbl.t;
+ ctxt_block_slots: block_slots_table;
+ ctxt_block_items: block_items_table;
+ ctxt_slot_is_arg: (node_id,unit) Hashtbl.t;
+ ctxt_slot_keys: (node_id,Ast.slot_key) Hashtbl.t;
+ ctxt_all_item_names: (node_id,Ast.name) Hashtbl.t;
+ ctxt_all_item_types: (node_id,Ast.ty) Hashtbl.t;
+ ctxt_all_lval_types: (node_id,Ast.ty) Hashtbl.t;
+ ctxt_all_cast_types: (node_id,Ast.ty) Hashtbl.t;
+ ctxt_all_type_items: (node_id,Ast.ty) Hashtbl.t;
+ ctxt_all_stmts: (node_id,Ast.stmt) Hashtbl.t;
+ ctxt_item_files: (node_id,filename) Hashtbl.t;
+ ctxt_all_lvals: (node_id,Ast.lval) Hashtbl.t;
+
+ (* definition id --> definition *)
+ ctxt_all_defns: (node_id,defn) Hashtbl.t;
+
+ (* reference id --> definition id *)
+ ctxt_lval_to_referent: (node_id,node_id) Hashtbl.t;
+
+ ctxt_required_items: (node_id, (required_lib * nabi_conv)) Hashtbl.t;
+ ctxt_required_syms: (node_id, string) Hashtbl.t;
+
+ (* Layout-y stuff. *)
+ ctxt_slot_aliased: (node_id,unit) Hashtbl.t;
+ ctxt_slot_is_obj_state: (node_id,unit) Hashtbl.t;
+ ctxt_slot_vregs: (node_id,((int option) ref)) Hashtbl.t;
+ ctxt_slot_offsets: (node_id,size) Hashtbl.t;
+ ctxt_frame_sizes: (node_id,size) Hashtbl.t;
+ ctxt_call_sizes: (node_id,size) Hashtbl.t;
+ ctxt_block_is_loop_body: (node_id,unit) Hashtbl.t;
+ ctxt_stmt_loop_depths: (node_id,int) Hashtbl.t;
+ ctxt_slot_loop_depths: (node_id,int) Hashtbl.t;
+
+ (* Typestate-y stuff. *)
+ ctxt_constrs: (constr_id,constr_key) Hashtbl.t;
+ ctxt_constr_ids: (constr_key,constr_id) Hashtbl.t;
+ ctxt_preconditions: (node_id,Bits.t) Hashtbl.t;
+ ctxt_postconditions: (node_id,Bits.t) Hashtbl.t;
+ ctxt_prestates: (node_id,Bits.t) Hashtbl.t;
+ ctxt_poststates: (node_id,Bits.t) Hashtbl.t;
+ ctxt_call_lval_params: (node_id,Ast.ty array) Hashtbl.t;
+ ctxt_copy_stmt_is_init: (node_id,unit) Hashtbl.t;
+ ctxt_post_stmt_slot_drops: (node_id,node_id list) Hashtbl.t;
+
+ (* Translation-y stuff. *)
+ ctxt_fn_fixups: (node_id,fixup) Hashtbl.t;
+ ctxt_block_fixups: (node_id,fixup) Hashtbl.t;
+ ctxt_file_fixups: (node_id,fixup) Hashtbl.t;
+ ctxt_spill_fixups: (node_id,fixup) Hashtbl.t;
+ ctxt_abi: Abi.abi;
+ ctxt_activate_fixup: fixup;
+ ctxt_yield_fixup: fixup;
+ ctxt_unwind_fixup: fixup;
+ ctxt_exit_task_fixup: fixup;
+
+ ctxt_debug_aranges_fixup: fixup;
+ ctxt_debug_pubnames_fixup: fixup;
+ ctxt_debug_info_fixup: fixup;
+ ctxt_debug_abbrev_fixup: fixup;
+ ctxt_debug_line_fixup: fixup;
+ ctxt_debug_frame_fixup: fixup;
+
+ ctxt_image_base_fixup: fixup;
+ ctxt_crate_fixup: fixup;
+
+ ctxt_file_code: file_code;
+ ctxt_all_item_code: item_code;
+ ctxt_glue_code: glue_code;
+ ctxt_data: data_frags;
+
+ ctxt_native_required:
+ (required_lib,((string,fixup) Hashtbl.t)) Hashtbl.t;
+ ctxt_native_provided:
+ (segment,((string, fixup) Hashtbl.t)) Hashtbl.t;
+
+ ctxt_required_rust_sym_num: (node_id, int) Hashtbl.t;
+ ctxt_required_c_sym_num: ((required_lib * string), int) Hashtbl.t;
+ ctxt_required_lib_num: (required_lib, int) Hashtbl.t;
+
+ ctxt_main_fn_fixup: fixup option;
+ ctxt_main_name: string option;
+ }
+;;
+
+let new_ctxt sess abi crate =
+ { ctxt_sess = sess;
+ ctxt_frame_args = Hashtbl.create 0;
+ ctxt_frame_blocks = Hashtbl.create 0;
+ ctxt_block_slots = Hashtbl.create 0;
+ ctxt_block_items = Hashtbl.create 0;
+ ctxt_slot_is_arg = Hashtbl.create 0;
+ ctxt_slot_keys = Hashtbl.create 0;
+ ctxt_all_item_names = Hashtbl.create 0;
+ ctxt_all_item_types = Hashtbl.create 0;
+ ctxt_all_lval_types = Hashtbl.create 0;
+ ctxt_all_cast_types = Hashtbl.create 0;
+ ctxt_all_type_items = Hashtbl.create 0;
+ ctxt_all_stmts = Hashtbl.create 0;
+ ctxt_item_files = crate.Ast.crate_files;
+ ctxt_all_lvals = Hashtbl.create 0;
+ ctxt_all_defns = Hashtbl.create 0;
+ ctxt_lval_to_referent = Hashtbl.create 0;
+ ctxt_required_items = crate.Ast.crate_required;
+ ctxt_required_syms = crate.Ast.crate_required_syms;
+
+ ctxt_constrs = Hashtbl.create 0;
+ ctxt_constr_ids = Hashtbl.create 0;
+ ctxt_preconditions = Hashtbl.create 0;
+ ctxt_postconditions = Hashtbl.create 0;
+ ctxt_prestates = Hashtbl.create 0;
+ ctxt_poststates = Hashtbl.create 0;
+ ctxt_copy_stmt_is_init = Hashtbl.create 0;
+ ctxt_post_stmt_slot_drops = Hashtbl.create 0;
+ ctxt_call_lval_params = Hashtbl.create 0;
+
+ ctxt_slot_aliased = Hashtbl.create 0;
+ ctxt_slot_is_obj_state = Hashtbl.create 0;
+ ctxt_slot_vregs = Hashtbl.create 0;
+ ctxt_slot_offsets = Hashtbl.create 0;
+ ctxt_frame_sizes = Hashtbl.create 0;
+ ctxt_call_sizes = Hashtbl.create 0;
+
+ ctxt_block_is_loop_body = Hashtbl.create 0;
+ ctxt_slot_loop_depths = Hashtbl.create 0;
+ ctxt_stmt_loop_depths = Hashtbl.create 0;
+
+ ctxt_fn_fixups = Hashtbl.create 0;
+ ctxt_block_fixups = Hashtbl.create 0;
+ ctxt_file_fixups = Hashtbl.create 0;
+ ctxt_spill_fixups = Hashtbl.create 0;
+ ctxt_abi = abi;
+ ctxt_activate_fixup = new_fixup "activate glue";
+ ctxt_yield_fixup = new_fixup "yield glue";
+ ctxt_unwind_fixup = new_fixup "unwind glue";
+ ctxt_exit_task_fixup = new_fixup "exit-task glue";
+
+ ctxt_debug_aranges_fixup = new_fixup "debug_aranges section";
+ ctxt_debug_pubnames_fixup = new_fixup "debug_pubnames section";
+ ctxt_debug_info_fixup = new_fixup "debug_info section";
+ ctxt_debug_abbrev_fixup = new_fixup "debug_abbrev section";
+ ctxt_debug_line_fixup = new_fixup "debug_line section";
+ ctxt_debug_frame_fixup = new_fixup "debug_frame section";
+
+ ctxt_image_base_fixup = new_fixup "loaded image base";
+ ctxt_crate_fixup = new_fixup "root crate structure";
+ ctxt_file_code = Hashtbl.create 0;
+ ctxt_all_item_code = Hashtbl.create 0;
+ ctxt_glue_code = Hashtbl.create 0;
+ ctxt_data = Hashtbl.create 0;
+
+ ctxt_native_required = Hashtbl.create 0;
+ ctxt_native_provided = Hashtbl.create 0;
+
+ ctxt_required_rust_sym_num = Hashtbl.create 0;
+ ctxt_required_c_sym_num = Hashtbl.create 0;
+ ctxt_required_lib_num = Hashtbl.create 0;
+
+ ctxt_main_fn_fixup =
+ (match crate.Ast.crate_main with
+ None -> None
+ | Some n -> Some (new_fixup (string_of_name n)));
+
+ ctxt_main_name =
+ (match crate.Ast.crate_main with
+ None -> None
+ | Some n -> Some (string_of_name n));
+ }
+;;
+
+let report_err cx ido str =
+ let sess = cx.ctxt_sess in
+ let spano = match ido with
+ None -> None
+ | Some id -> (Session.get_span sess id)
+ in
+ match spano with
+ None ->
+ Session.fail sess "Error: %s\n%!" str
+ | Some span ->
+ Session.fail sess "%s:E:Error: %s\n%!"
+ (Session.string_of_span span) str
+;;
+
+let bugi (cx:ctxt) (i:node_id) =
+ let k s =
+ report_err cx (Some i) s;
+ failwith s
+ in Printf.ksprintf k
+;;
+
+(* Convenience accessors. *)
+
+(* resolve an lval reference id to the id of its definition *)
+let lval_to_referent (cx:ctxt) (id:node_id) : node_id =
+ if Hashtbl.mem cx.ctxt_lval_to_referent id
+ then Hashtbl.find cx.ctxt_lval_to_referent id
+ else bug () "unresolved lval"
+;;
+
+(* resolve an lval reference id to its definition *)
+let resolve_lval_id (cx:ctxt) (id:node_id) : defn =
+ Hashtbl.find cx.ctxt_all_defns (lval_to_referent cx id)
+;;
+
+let referent_is_slot (cx:ctxt) (id:node_id) : bool =
+ match Hashtbl.find cx.ctxt_all_defns id with
+ DEFN_slot _ -> true
+ | _ -> false
+;;
+
+let referent_is_item (cx:ctxt) (id:node_id) : bool =
+ match Hashtbl.find cx.ctxt_all_defns id with
+ DEFN_item _ -> true
+ | _ -> false
+;;
+
+(* coerce an lval definition id to a slot *)
+let referent_to_slot (cx:ctxt) (id:node_id) : Ast.slot =
+ match Hashtbl.find cx.ctxt_all_defns id with
+ DEFN_slot slot -> slot
+ | _ -> bugi cx id "unknown slot"
+;;
+
+(* coerce an lval reference id to its definition slot *)
+let lval_to_slot (cx:ctxt) (id:node_id) : Ast.slot =
+ match resolve_lval_id cx id with
+ DEFN_slot slot -> slot
+ | _ -> bugi cx id "unknown slot"
+;;
+
+let get_stmt_depth (cx:ctxt) (id:node_id) : int =
+ Hashtbl.find cx.ctxt_stmt_loop_depths id
+;;
+
+let get_slot_depth (cx:ctxt) (id:node_id) : int =
+ Hashtbl.find cx.ctxt_slot_loop_depths id
+;;
+
+let get_fn_fixup (cx:ctxt) (id:node_id) : fixup =
+ if Hashtbl.mem cx.ctxt_fn_fixups id
+ then Hashtbl.find cx.ctxt_fn_fixups id
+ else bugi cx id "fn without fixup"
+;;
+
+let get_framesz (cx:ctxt) (id:node_id) : size =
+ if Hashtbl.mem cx.ctxt_frame_sizes id
+ then Hashtbl.find cx.ctxt_frame_sizes id
+ else bugi cx id "missing framesz"
+;;
+
+let get_callsz (cx:ctxt) (id:node_id) : size =
+ if Hashtbl.mem cx.ctxt_call_sizes id
+ then Hashtbl.find cx.ctxt_call_sizes id
+ else bugi cx id "missing callsz"
+;;
+
+let rec n_item_ty_params (cx:ctxt) (id:node_id) : int =
+ match Hashtbl.find cx.ctxt_all_defns id with
+ DEFN_item i -> Array.length i.Ast.decl_params
+ | DEFN_obj_fn (oid,_) -> n_item_ty_params cx oid
+ | DEFN_obj_drop oid -> n_item_ty_params cx oid
+ | DEFN_loop_body fid -> n_item_ty_params cx fid
+ | _ -> bugi cx id "n_item_ty_params on non-item"
+;;
+
+let item_is_obj_fn (cx:ctxt) (id:node_id) : bool =
+ match Hashtbl.find cx.ctxt_all_defns id with
+ DEFN_obj_fn _
+ | DEFN_obj_drop _ -> true
+ | _ -> false
+;;
+
+let get_spill (cx:ctxt) (id:node_id) : fixup =
+ if Hashtbl.mem cx.ctxt_spill_fixups id
+ then Hashtbl.find cx.ctxt_spill_fixups id
+ else bugi cx id "missing spill fixup"
+;;
+
+let require_native (cx:ctxt) (lib:required_lib) (name:string) : fixup =
+ let lib_tab = (htab_search_or_add cx.ctxt_native_required lib
+ (fun _ -> Hashtbl.create 0))
+ in
+ htab_search_or_add lib_tab name
+ (fun _ -> new_fixup ("require: " ^ name))
+;;
+
+let provide_native (cx:ctxt) (seg:segment) (name:string) : fixup =
+ let seg_tab = (htab_search_or_add cx.ctxt_native_provided seg
+ (fun _ -> Hashtbl.create 0))
+ in
+ htab_search_or_add seg_tab name
+ (fun _ -> new_fixup ("provide: " ^ name))
+;;
+
+let provide_existing_native
+ (cx:ctxt)
+ (seg:segment)
+ (name:string)
+ (fix:fixup)
+ : unit =
+ let seg_tab = (htab_search_or_add cx.ctxt_native_provided seg
+ (fun _ -> Hashtbl.create 0))
+ in
+ htab_put seg_tab name fix
+;;
+
+let slot_ty (s:Ast.slot) : Ast.ty =
+ match s.Ast.slot_ty with
+ Some t -> t
+ | None -> bug () "untyped slot"
+;;
+
+let defn_is_slot (d:defn) : bool =
+ match d with
+ DEFN_slot _ -> true
+ | _ -> false
+;;
+
+let defn_is_item (d:defn) : bool =
+ match d with
+ DEFN_item _ -> true
+ | _ -> false
+;;
+
+let slot_is_obj_state (cx:ctxt) (sid:node_id) : bool =
+ Hashtbl.mem cx.ctxt_slot_is_obj_state sid
+;;
+
+
+(* determines whether d defines a statically-known value *)
+let defn_is_static (d:defn) : bool =
+ not (defn_is_slot d)
+;;
+
+let defn_is_callable (d:defn) : bool =
+ match d with
+ DEFN_slot { Ast.slot_ty = Some Ast.TY_fn _ }
+ | DEFN_item { Ast.decl_item = (Ast.MOD_ITEM_fn _ ) } -> true
+ | _ -> false
+;;
+
+(* Constraint manipulation. *)
+
+let rec apply_names_to_carg_path
+ (names:(Ast.name_base option) array)
+ (cp:Ast.carg_path)
+ : Ast.carg_path =
+ match cp with
+ Ast.CARG_ext (Ast.CARG_base Ast.BASE_formal,
+ Ast.COMP_idx i) ->
+ begin
+ match names.(i) with
+ Some nb ->
+ Ast.CARG_base (Ast.BASE_named nb)
+ | None -> bug () "Indexing off non-named carg"
+ end
+ | Ast.CARG_ext (cp', e) ->
+ Ast.CARG_ext (apply_names_to_carg_path names cp', e)
+ | _ -> cp
+;;
+
+let apply_names_to_carg
+ (names:(Ast.name_base option) array)
+ (carg:Ast.carg)
+ : Ast.carg =
+ match carg with
+ Ast.CARG_path cp ->
+ Ast.CARG_path (apply_names_to_carg_path names cp)
+ | Ast.CARG_lit _ -> carg
+;;
+
+let apply_names_to_constr
+ (names:(Ast.name_base option) array)
+ (constr:Ast.constr)
+ : Ast.constr =
+ { constr with
+ Ast.constr_args =
+ Array.map (apply_names_to_carg names) constr.Ast.constr_args }
+;;
+
+let atoms_to_names (atoms:Ast.atom array)
+ : (Ast.name_base option) array =
+ Array.map
+ begin
+ fun atom ->
+ match atom with
+ Ast.ATOM_lval (Ast.LVAL_base nbi) -> Some nbi.node
+ | _ -> None
+ end
+ atoms
+;;
+
+let rec lval_base_id (lv:Ast.lval) : node_id =
+ match lv with
+ Ast.LVAL_base nbi -> nbi.id
+ | Ast.LVAL_ext (lv, _) -> lval_base_id lv
+;;
+
+let rec lval_base_slot (cx:ctxt) (lv:Ast.lval) : node_id option =
+ match lv with
+ Ast.LVAL_base nbi ->
+ let referent = lval_to_referent cx nbi.id in
+ if referent_is_slot cx referent
+ then Some referent
+ else None
+ | Ast.LVAL_ext (lv, _) -> lval_base_slot cx lv
+;;
+
+let rec lval_slots (cx:ctxt) (lv:Ast.lval) : node_id array =
+ match lv with
+ Ast.LVAL_base nbi ->
+ let referent = lval_to_referent cx nbi.id in
+ if referent_is_slot cx referent
+ then [| referent |]
+ else [| |]
+ | Ast.LVAL_ext (lv, Ast.COMP_named _) -> lval_slots cx lv
+ | Ast.LVAL_ext (lv, Ast.COMP_atom a) ->
+ Array.append (lval_slots cx lv) (atom_slots cx a)
+
+and atom_slots (cx:ctxt) (a:Ast.atom) : node_id array =
+ match a with
+ Ast.ATOM_literal _ -> [| |]
+ | Ast.ATOM_lval lv -> lval_slots cx lv
+;;
+
+let lval_option_slots (cx:ctxt) (lv:Ast.lval option) : node_id array =
+ match lv with
+ None -> [| |]
+ | Some lv -> lval_slots cx lv
+;;
+
+let resolve_lval (cx:ctxt) (lv:Ast.lval) : defn =
+ resolve_lval_id cx (lval_base_id lv)
+;;
+
+let atoms_slots (cx:ctxt) (az:Ast.atom array) : node_id array =
+ Array.concat (List.map (atom_slots cx) (Array.to_list az))
+;;
+
+let tup_inputs_slots (cx:ctxt) (az:Ast.tup_input array) : node_id array =
+ Array.concat (List.map
+ (fun (_,_,a) -> atom_slots cx a)
+ (Array.to_list az))
+;;
+
+let rec_inputs_slots (cx:ctxt)
+ (inputs:Ast.rec_input array) : node_id array =
+ Array.concat (List.map
+ (fun (_, _, _, atom) -> atom_slots cx atom)
+ (Array.to_list inputs))
+;;
+
+let expr_slots (cx:ctxt) (e:Ast.expr) : node_id array =
+ match e with
+ Ast.EXPR_binary (_, a, b) ->
+ Array.append (atom_slots cx a) (atom_slots cx b)
+ | Ast.EXPR_unary (_, u) -> atom_slots cx u
+ | Ast.EXPR_atom a -> atom_slots cx a
+;;
+
+
+(* Type extraction. *)
+
+let interior_slot_full mut ty : Ast.slot =
+ { Ast.slot_mode = Ast.MODE_interior;
+ Ast.slot_mutable = mut;
+ Ast.slot_ty = Some ty }
+;;
+
+let exterior_slot_full mut ty : Ast.slot =
+ { Ast.slot_mode = Ast.MODE_exterior;
+ Ast.slot_mutable = mut;
+ Ast.slot_ty = Some ty }
+;;
+
+let interior_slot ty : Ast.slot = interior_slot_full false ty
+;;
+
+let exterior_slot ty : Ast.slot = exterior_slot_full false ty
+;;
+
+
+(* General folds of Ast.ty. *)
+
+type ('ty, 'slot, 'slots, 'tag) ty_fold =
+ {
+ (* Functions that correspond to interior nodes in Ast.ty. *)
+ ty_fold_slot : (Ast.mode * bool * 'ty) -> 'slot;
+ ty_fold_slots : ('slot array) -> 'slots;
+ ty_fold_tags : (Ast.name, 'slots) Hashtbl.t -> 'tag;
+
+ (* Functions that correspond to the Ast.ty constructors. *)
+ ty_fold_any: unit -> 'ty;
+ ty_fold_nil : unit -> 'ty;
+ ty_fold_bool : unit -> 'ty;
+ ty_fold_mach : ty_mach -> 'ty;
+ ty_fold_int : unit -> 'ty;
+ ty_fold_uint : unit -> 'ty;
+ ty_fold_char : unit -> 'ty;
+ ty_fold_str : unit -> 'ty;
+ ty_fold_tup : 'slots -> 'ty;
+ ty_fold_vec : 'slot -> 'ty;
+ ty_fold_rec : (Ast.ident * 'slot) array -> 'ty;
+ ty_fold_tag : 'tag -> 'ty;
+ ty_fold_iso : (int * 'tag array) -> 'ty;
+ ty_fold_idx : int -> 'ty;
+ ty_fold_fn : (('slots * Ast.constrs * 'slot) * Ast.ty_fn_aux) -> 'ty;
+ ty_fold_obj : (Ast.effect
+ * (Ast.ident, (('slots * Ast.constrs * 'slot) *
+ Ast.ty_fn_aux)) Hashtbl.t) -> 'ty;
+ ty_fold_chan : 'ty -> 'ty;
+ ty_fold_port : 'ty -> 'ty;
+ ty_fold_task : unit -> 'ty;
+ ty_fold_native : opaque_id -> 'ty;
+ ty_fold_param : (int * Ast.effect) -> 'ty;
+ ty_fold_named : Ast.name -> 'ty;
+ ty_fold_type : unit -> 'ty;
+ ty_fold_constrained : ('ty * Ast.constrs) -> 'ty }
+;;
+
+let rec fold_ty (f:('ty, 'slot, 'slots, 'tag) ty_fold) (ty:Ast.ty) : 'ty =
+ let fold_slot (s:Ast.slot) : 'slot =
+ f.ty_fold_slot (s.Ast.slot_mode,
+ s.Ast.slot_mutable,
+ fold_ty f (slot_ty s))
+ in
+ let fold_slots (slots:Ast.slot array) : 'slots =
+ f.ty_fold_slots (Array.map fold_slot slots)
+ in
+ let fold_tags (ttag:Ast.ty_tag) : 'tag =
+ f.ty_fold_tags (htab_map ttag (fun k v -> (k, fold_slots v)))
+ in
+ let fold_sig tsig =
+ (fold_slots tsig.Ast.sig_input_slots,
+ tsig.Ast.sig_input_constrs,
+ fold_slot tsig.Ast.sig_output_slot)
+ in
+ let fold_obj fns =
+ htab_map fns (fun i (tsig, taux) -> (i, (fold_sig tsig, taux)))
+ in
+ match ty with
+ Ast.TY_any -> f.ty_fold_any ()
+ | Ast.TY_nil -> f.ty_fold_nil ()
+ | Ast.TY_bool -> f.ty_fold_bool ()
+ | Ast.TY_mach m -> f.ty_fold_mach m
+ | Ast.TY_int -> f.ty_fold_int ()
+ | Ast.TY_uint -> f.ty_fold_uint ()
+ | Ast.TY_char -> f.ty_fold_char ()
+ | Ast.TY_str -> f.ty_fold_str ()
+
+ | Ast.TY_tup t -> f.ty_fold_tup (fold_slots t)
+ | Ast.TY_vec s -> f.ty_fold_vec (fold_slot s)
+ | Ast.TY_rec r -> f.ty_fold_rec (Array.map (fun (k,v) -> (k,fold_slot v)) r)
+
+ | Ast.TY_tag tt -> f.ty_fold_tag (fold_tags tt)
+ | Ast.TY_iso ti -> f.ty_fold_iso (ti.Ast.iso_index,
+ (Array.map fold_tags ti.Ast.iso_group))
+ | Ast.TY_idx i -> f.ty_fold_idx i
+
+ | Ast.TY_fn (tsig,taux) -> f.ty_fold_fn (fold_sig tsig, taux)
+ | Ast.TY_chan t -> f.ty_fold_chan (fold_ty f t)
+ | Ast.TY_port t -> f.ty_fold_port (fold_ty f t)
+
+ | Ast.TY_obj (eff,t) -> f.ty_fold_obj (eff, (fold_obj t))
+ | Ast.TY_task -> f.ty_fold_task ()
+
+ | Ast.TY_native x -> f.ty_fold_native x
+ | Ast.TY_param x -> f.ty_fold_param x
+ | Ast.TY_named n -> f.ty_fold_named n
+ | Ast.TY_type -> f.ty_fold_type ()
+
+ | Ast.TY_constrained (t, constrs) ->
+ f.ty_fold_constrained (fold_ty f t, constrs)
+
+;;
+
+type 'a simple_ty_fold = ('a, 'a, 'a, 'a) ty_fold
+;;
+
+let ty_fold_default (default:'a) : 'a simple_ty_fold =
+ { ty_fold_slot = (fun _ -> default);
+ ty_fold_slots = (fun _ -> default);
+ ty_fold_tags = (fun _ -> default);
+ ty_fold_any = (fun _ -> default);
+ ty_fold_nil = (fun _ -> default);
+ ty_fold_bool = (fun _ -> default);
+ ty_fold_mach = (fun _ -> default);
+ ty_fold_int = (fun _ -> default);
+ ty_fold_uint = (fun _ -> default);
+ ty_fold_char = (fun _ -> default);
+ ty_fold_str = (fun _ -> default);
+ ty_fold_tup = (fun _ -> default);
+ ty_fold_vec = (fun _ -> default);
+ ty_fold_rec = (fun _ -> default);
+ ty_fold_tag = (fun _ -> default);
+ ty_fold_iso = (fun _ -> default);
+ ty_fold_idx = (fun _ -> default);
+ ty_fold_fn = (fun _ -> default);
+ ty_fold_obj = (fun _ -> default);
+ ty_fold_chan = (fun _ -> default);
+ ty_fold_port = (fun _ -> default);
+ ty_fold_task = (fun _ -> default);
+ ty_fold_native = (fun _ -> default);
+ ty_fold_param = (fun _ -> default);
+ ty_fold_named = (fun _ -> default);
+ ty_fold_type = (fun _ -> default);
+ ty_fold_constrained = (fun _ -> default) }
+;;
+
+let ty_fold_rebuild (id:Ast.ty -> Ast.ty)
+ : (Ast.ty, Ast.slot, Ast.slot array, Ast.ty_tag) ty_fold =
+ let rebuild_fn ((islots, constrs, oslot), aux) =
+ ({ Ast.sig_input_slots = islots;
+ Ast.sig_input_constrs = constrs;
+ Ast.sig_output_slot = oslot }, aux)
+ in
+ { ty_fold_slot = (fun (mode, mut, t) ->
+ { Ast.slot_mode = mode;
+ Ast.slot_mutable = mut;
+ Ast.slot_ty = Some t });
+ ty_fold_slots = (fun slots -> slots);
+ ty_fold_tags = (fun htab -> htab);
+ ty_fold_any = (fun _ -> id Ast.TY_any);
+ ty_fold_nil = (fun _ -> id Ast.TY_nil);
+ ty_fold_bool = (fun _ -> id Ast.TY_bool);
+ ty_fold_mach = (fun m -> id (Ast.TY_mach m));
+ ty_fold_int = (fun _ -> id Ast.TY_int);
+ ty_fold_uint = (fun _ -> id Ast.TY_uint);
+ ty_fold_char = (fun _ -> id Ast.TY_char);
+ ty_fold_str = (fun _ -> id Ast.TY_str);
+ ty_fold_tup = (fun slots -> id (Ast.TY_tup slots));
+ ty_fold_vec = (fun slot -> id (Ast.TY_vec slot));
+ ty_fold_rec = (fun entries -> id (Ast.TY_rec entries));
+ ty_fold_tag = (fun tag -> id (Ast.TY_tag tag));
+ ty_fold_iso = (fun (i, tags) -> id (Ast.TY_iso { Ast.iso_index = i;
+ Ast.iso_group = tags }));
+ ty_fold_idx = (fun i -> id (Ast.TY_idx i));
+ ty_fold_fn = (fun t -> id (Ast.TY_fn (rebuild_fn t)));
+ ty_fold_obj = (fun (eff,fns) ->
+ id (Ast.TY_obj
+ (eff, (htab_map fns
+ (fun id fn -> (id, rebuild_fn fn))))));
+ ty_fold_chan = (fun t -> id (Ast.TY_chan t));
+ ty_fold_port = (fun t -> id (Ast.TY_port t));
+ ty_fold_task = (fun _ -> id Ast.TY_task);
+ ty_fold_native = (fun oid -> id (Ast.TY_native oid));
+ ty_fold_param = (fun (i, mut) -> id (Ast.TY_param (i, mut)));
+ ty_fold_named = (fun n -> id (Ast.TY_named n));
+ ty_fold_type = (fun _ -> id (Ast.TY_type));
+ ty_fold_constrained = (fun (t, constrs) ->
+ id (Ast.TY_constrained (t, constrs))) }
+;;
+
+let rebuild_ty_under_params
+ (ty:Ast.ty)
+ (params:Ast.ty_param array)
+ (args:Ast.ty array)
+ (resolve_names:bool)
+ : Ast.ty =
+ if (Array.length params) <> (Array.length args)
+ then err None "mismatched type-params"
+ else
+ let nmap = Hashtbl.create (Array.length args) in
+ let pmap = Hashtbl.create (Array.length args) in
+ let _ =
+ Array.iteri
+ begin
+ fun i (ident, param) ->
+ htab_put pmap (Ast.TY_param param) args.(i);
+ if resolve_names
+ then
+ htab_put nmap ident args.(i)
+ end
+ params
+ in
+ let substituted = ref false in
+ let rec rebuild_ty t =
+ let base = ty_fold_rebuild (fun t -> t) in
+ let ty_fold_param (i, mut) =
+ let param = Ast.TY_param (i, mut) in
+ match htab_search pmap param with
+ None -> param
+ | Some arg -> (substituted := true; arg)
+ in
+ let ty_fold_named n =
+ let rec rebuild_name n =
+ match n with
+ Ast.NAME_base nb ->
+ Ast.NAME_base (rebuild_name_base nb)
+ | Ast.NAME_ext (n, nc) ->
+ Ast.NAME_ext (rebuild_name n,
+ rebuild_name_component nc)
+
+ and rebuild_name_base nb =
+ match nb with
+ Ast.BASE_ident i ->
+ Ast.BASE_ident i
+ | Ast.BASE_temp t ->
+ Ast.BASE_temp t
+ | Ast.BASE_app (i, tys) ->
+ Ast.BASE_app (i, rebuild_tys tys)
+
+ and rebuild_name_component nc =
+ match nc with
+ Ast.COMP_ident i ->
+ Ast.COMP_ident i
+ | Ast.COMP_app (i, tys) ->
+ Ast.COMP_app (i, rebuild_tys tys)
+ | Ast.COMP_idx i ->
+ Ast.COMP_idx i
+
+ and rebuild_tys tys =
+ Array.map (fun t -> rebuild_ty t) tys
+ in
+ let n = rebuild_name n in
+ match n with
+ Ast.NAME_base (Ast.BASE_ident id)
+ when resolve_names ->
+ begin
+ match htab_search nmap id with
+ None -> Ast.TY_named n
+ | Some arg -> (substituted := true; arg)
+ end
+ | _ -> Ast.TY_named n
+ in
+ let fold =
+ { base with
+ ty_fold_param = ty_fold_param;
+ ty_fold_named = ty_fold_named;
+ }
+ in
+ let t' = fold_ty fold t in
+ (*
+ * FIXME: "substituted" and "ty'" here are only required
+ * because the current type-equality-comparison code in Type
+ * uses <> and will judge some cases, such as rebuilt tags, as
+ * unequal simply due to the different hashtable order in the
+ * fold.
+ *)
+ if !substituted
+ then t'
+ else t
+ in
+ rebuild_ty ty
+;;
+
+let associative_binary_op_ty_fold
+ (default:'a)
+ (fn:'a -> 'a -> 'a)
+ : 'a simple_ty_fold =
+ let base = ty_fold_default default in
+ let reduce ls =
+ match ls with
+ [] -> default
+ | x::xs -> List.fold_left fn x xs
+ in
+ let reduce_fn ((islots, _, oslot), _) =
+ fn islots oslot
+ in
+ { base with
+ ty_fold_slots = (fun slots -> reduce (Array.to_list slots));
+ ty_fold_slot = (fun (_, _, a) -> a);
+ ty_fold_tags = (fun tab -> reduce (htab_vals tab));
+ ty_fold_tup = (fun a -> a);
+ ty_fold_vec = (fun a -> a);
+ ty_fold_rec = (fun sz ->
+ reduce (Array.to_list
+ (Array.map (fun (_, s) -> s) sz)));
+ ty_fold_tag = (fun a -> a);
+ ty_fold_iso = (fun (_,iso) -> reduce (Array.to_list iso));
+ ty_fold_fn = reduce_fn;
+ ty_fold_obj = (fun (_,fns) ->
+ reduce (List.map reduce_fn (htab_vals fns)));
+ ty_fold_chan = (fun a -> a);
+ ty_fold_port = (fun a -> a);
+ ty_fold_constrained = (fun (a, _) -> a) }
+
+let ty_fold_bool_and (default:bool) : bool simple_ty_fold =
+ associative_binary_op_ty_fold default (fun a b -> a & b)
+;;
+
+let ty_fold_bool_or (default:bool) : bool simple_ty_fold =
+ associative_binary_op_ty_fold default (fun a b -> a || b)
+;;
+
+let ty_fold_int_max (default:int) : int simple_ty_fold =
+ associative_binary_op_ty_fold default (fun a b -> max a b)
+;;
+
+let ty_fold_list_concat _ : ('a list) simple_ty_fold =
+ associative_binary_op_ty_fold [] (fun a b -> a @ b)
+;;
+
+let type_is_structured (t:Ast.ty) : bool =
+ let fold = ty_fold_bool_or false in
+ let fold = { fold with
+ ty_fold_tup = (fun _ -> true);
+ ty_fold_vec = (fun _ -> true);
+ ty_fold_rec = (fun _ -> true);
+ ty_fold_tag = (fun _ -> true);
+ ty_fold_iso = (fun _ -> true);
+ ty_fold_idx = (fun _ -> true);
+ ty_fold_fn = (fun _ -> true);
+ ty_fold_obj = (fun _ -> true) }
+ in
+ fold_ty fold t
+;;
+
+(* Effect analysis. *)
+let effect_le x y =
+ match (x,y) with
+ (Ast.UNSAFE, _) -> true
+ | (Ast.STATE, Ast.PURE) -> true
+ | (Ast.STATE, Ast.IO) -> true
+ | (Ast.STATE, Ast.STATE) -> true
+ | (Ast.IO, Ast.PURE) -> true
+ | (Ast.IO, Ast.IO) -> true
+ | (Ast.PURE, Ast.PURE) -> true
+ | _ -> false
+;;
+
+let lower_effect_of x y =
+ if effect_le x y then x else y
+;;
+
+let type_effect (t:Ast.ty) : Ast.effect =
+ let fold_slot ((*mode*)_, mut, eff) =
+ if mut
+ then lower_effect_of Ast.STATE eff
+ else eff
+ in
+ let fold = associative_binary_op_ty_fold Ast.PURE lower_effect_of in
+ let fold = { fold with ty_fold_slot = fold_slot } in
+ fold_ty fold t
+;;
+
+let type_has_state (t:Ast.ty) : bool =
+ effect_le (type_effect t) Ast.STATE
+;;
+
+
+(* Various type analyses. *)
+
+let is_prim_type (t:Ast.ty) : bool =
+ match t with
+ Ast.TY_int
+ | Ast.TY_uint
+ | Ast.TY_char
+ | Ast.TY_mach _
+ | Ast.TY_bool -> true
+ | _ -> false
+;;
+
+let type_contains_chan (t:Ast.ty) : bool =
+ let fold_chan _ = true in
+ let fold = ty_fold_bool_or false in
+ let fold = { fold with ty_fold_chan = fold_chan } in
+ fold_ty fold t
+;;
+
+
+let type_is_unsigned_2s_complement t =
+ match t with
+ Ast.TY_mach TY_u8
+ | Ast.TY_mach TY_u16
+ | Ast.TY_mach TY_u32
+ | Ast.TY_mach TY_u64
+ | Ast.TY_char
+ | Ast.TY_uint
+ | Ast.TY_bool -> true
+ | _ -> false
+;;
+
+
+let type_is_signed_2s_complement t =
+ match t with
+ Ast.TY_mach TY_i8
+ | Ast.TY_mach TY_i16
+ | Ast.TY_mach TY_i32
+ | Ast.TY_mach TY_i64
+ | Ast.TY_int -> true
+ | _ -> false
+;;
+
+
+let type_is_2s_complement t =
+ (type_is_unsigned_2s_complement t)
+ || (type_is_signed_2s_complement t)
+;;
+
+let n_used_type_params t =
+ let fold_param (i,_) = i+1 in
+ let fold = ty_fold_int_max 0 in
+ let fold = { fold with ty_fold_param = fold_param } in
+ fold_ty fold t
+;;
+
+
+
+let check_concrete params thing =
+ if Array.length params = 0
+ then thing
+ else bug () "unhandled parametric binding"
+;;
+
+
+let project_type_to_slot
+ (base_ty:Ast.ty)
+ (comp:Ast.lval_component)
+ : Ast.slot =
+ match (base_ty, comp) with
+ (Ast.TY_rec elts, Ast.COMP_named (Ast.COMP_ident id)) ->
+ begin
+ match atab_search elts id with
+ Some slot -> slot
+ | None -> err None "unknown record-member '%s'" id
+ end
+
+ | (Ast.TY_tup elts, Ast.COMP_named (Ast.COMP_idx i)) ->
+ if 0 <= i && i < (Array.length elts)
+ then elts.(i)
+ else err None "out-of-range tuple index %d" i
+
+ | (Ast.TY_vec slot, Ast.COMP_atom _) ->
+ slot
+
+ | (Ast.TY_str, Ast.COMP_atom _) ->
+ interior_slot (Ast.TY_mach TY_u8)
+
+ | (Ast.TY_obj (_, fns), Ast.COMP_named (Ast.COMP_ident id)) ->
+ interior_slot (Ast.TY_fn (Hashtbl.find fns id))
+
+ | (_,_) ->
+ bug ()
+ "unhandled form of lval-ext in Semant."
+ "project_slot: %a indexed by %a"
+ Ast.sprintf_ty base_ty Ast.sprintf_lval_component comp
+;;
+
+
+(* NB: this will fail if lval is not a slot. *)
+let rec lval_slot (cx:ctxt) (lval:Ast.lval) : Ast.slot =
+ match lval with
+ Ast.LVAL_base nb -> lval_to_slot cx nb.id
+ | Ast.LVAL_ext (base, comp) ->
+ let base_ty = slot_ty (lval_slot cx base) in
+ project_type_to_slot base_ty comp
+;;
+
+let exports_permit (view:Ast.mod_view) (ident:Ast.ident) : bool =
+ (Hashtbl.mem view.Ast.view_exports Ast.EXPORT_all_decls) ||
+ (Hashtbl.mem view.Ast.view_exports (Ast.EXPORT_ident ident))
+;;
+
+(* NB: this will fail if lval is not an item. *)
+let rec lval_item (cx:ctxt) (lval:Ast.lval) : Ast.mod_item =
+ match lval with
+ Ast.LVAL_base nb ->
+ begin
+ let referent = lval_to_referent cx nb.id in
+ match htab_search cx.ctxt_all_defns referent with
+ Some (DEFN_item item) -> {node=item; id=referent}
+ | _ -> err (Some (lval_base_id lval))
+ "lval does not name an item"
+ end
+ | Ast.LVAL_ext (base, comp) ->
+ let base_item = lval_item cx base in
+ match base_item.node.Ast.decl_item with
+ Ast.MOD_ITEM_mod (view, items) ->
+ begin
+ let i, args =
+ match comp with
+ Ast.COMP_named (Ast.COMP_ident i) -> (i, [||])
+ | Ast.COMP_named (Ast.COMP_app (i, args)) -> (i, args)
+ | _ ->
+ bug ()
+ "unhandled lval-component '%a' in Semant.lval_item"
+ Ast.sprintf_lval_component comp
+ in
+ match htab_search items i with
+ | Some sub when exports_permit view i ->
+ assert
+ ((Array.length sub.node.Ast.decl_params) =
+ (Array.length args));
+ check_concrete base_item.node.Ast.decl_params sub
+ | _ -> err (Some (lval_base_id lval))
+ "unknown module item '%s'" i
+ end
+ | _ -> err (Some (lval_base_id lval))
+ "lval base %a does not name a module" Ast.sprintf_lval base
+;;
+
+let lval_is_slot (cx:ctxt) (lval:Ast.lval) : bool =
+ match resolve_lval cx lval with
+ DEFN_slot _ -> true
+ | _ -> false
+;;
+
+let lval_is_item (cx:ctxt) (lval:Ast.lval) : bool =
+ match resolve_lval cx lval with
+ DEFN_item _ -> true
+ | _ -> false
+;;
+
+let lval_is_direct_fn (cx:ctxt) (lval:Ast.lval) : bool =
+ let defn = resolve_lval cx lval in
+ (defn_is_static defn) && (defn_is_callable defn)
+;;
+
+let lval_is_direct_mod (cx:ctxt) (lval:Ast.lval) : bool =
+ let defn = resolve_lval cx lval in
+ if not (defn_is_static defn)
+ then false
+ else
+ match defn with
+ DEFN_item { Ast.decl_item = Ast.MOD_ITEM_mod _ } -> true
+ | _ -> false
+;;
+
+let lval_is_static (cx:ctxt) (lval:Ast.lval) : bool =
+ defn_is_static (resolve_lval cx lval)
+;;
+
+let lval_is_callable (cx:ctxt) (lval:Ast.lval) : bool =
+ defn_is_callable (resolve_lval cx lval)
+;;
+
+let lval_is_obj_vtbl (cx:ctxt) (lval:Ast.lval) : bool =
+ if lval_is_slot cx lval
+ then
+ match lval with
+ Ast.LVAL_ext (base, _) ->
+ begin
+ match slot_ty (lval_slot cx base) with
+ Ast.TY_obj _ -> true
+ | _ -> false
+ end
+ | _ -> false
+ else false
+;;
+
+let rec lval_ty (cx:ctxt) (lval:Ast.lval) : Ast.ty =
+ let base_id = lval_base_id lval in
+ Hashtbl.find cx.ctxt_all_lval_types base_id
+;;
+
+let rec atom_type (cx:ctxt) (at:Ast.atom) : Ast.ty =
+ match at with
+ Ast.ATOM_literal {node=(Ast.LIT_int _); id=_} -> Ast.TY_int
+ | Ast.ATOM_literal {node=(Ast.LIT_uint _); id=_} -> Ast.TY_uint
+ | Ast.ATOM_literal {node=(Ast.LIT_bool _); id=_} -> Ast.TY_bool
+ | Ast.ATOM_literal {node=(Ast.LIT_char _); id=_} -> Ast.TY_char
+ | Ast.ATOM_literal {node=(Ast.LIT_nil); id=_} -> Ast.TY_nil
+ | Ast.ATOM_literal {node=(Ast.LIT_mach (m,_,_)); id=_} -> Ast.TY_mach m
+ | Ast.ATOM_lval lv -> lval_ty cx lv
+;;
+
+let expr_type (cx:ctxt) (e:Ast.expr) : Ast.ty =
+ match e with
+ Ast.EXPR_binary (op, a, _) ->
+ begin
+ match op with
+ Ast.BINOP_eq | Ast.BINOP_ne | Ast.BINOP_lt | Ast.BINOP_le
+ | Ast.BINOP_ge | Ast.BINOP_gt -> Ast.TY_bool
+ | _ -> atom_type cx a
+ end
+ | Ast.EXPR_unary (Ast.UNOP_not, _) -> Ast.TY_bool
+ | Ast.EXPR_unary (_, a) -> atom_type cx a
+ | Ast.EXPR_atom a -> atom_type cx a
+;;
+
+(* Mappings between mod items and their respective types. *)
+
+let arg_slots (slots:Ast.header_slots) : Ast.slot array =
+ Array.map (fun (sid,_) -> sid.node) slots
+;;
+
+let tup_slots (slots:Ast.header_tup) : Ast.slot array =
+ Array.map (fun sid -> sid.node) slots
+;;
+
+let ty_fn_of_fn (fn:Ast.fn) : Ast.ty_fn =
+ ({ Ast.sig_input_slots = arg_slots fn.Ast.fn_input_slots;
+ Ast.sig_input_constrs = fn.Ast.fn_input_constrs;
+ Ast.sig_output_slot = fn.Ast.fn_output_slot.node },
+ fn.Ast.fn_aux )
+;;
+
+let ty_obj_of_obj (obj:Ast.obj) : Ast.ty_obj =
+ (obj.Ast.obj_effect,
+ htab_map obj.Ast.obj_fns (fun i f -> (i, ty_fn_of_fn f.node)))
+;;
+
+let ty_of_mod_item ((*inside*)_:bool) (item:Ast.mod_item) : Ast.ty =
+ match item.node.Ast.decl_item with
+ Ast.MOD_ITEM_type _ -> Ast.TY_type
+ | Ast.MOD_ITEM_fn f -> (Ast.TY_fn (ty_fn_of_fn f))
+ | Ast.MOD_ITEM_mod _ -> bug () "Semant.ty_of_mod_item on mod"
+ | Ast.MOD_ITEM_obj ob ->
+ let taux = { Ast.fn_effect = Ast.PURE;
+ Ast.fn_is_iter = false }
+ in
+ let tobj = Ast.TY_obj (ty_obj_of_obj ob) in
+ let tsig = { Ast.sig_input_slots = arg_slots ob.Ast.obj_state;
+ Ast.sig_input_constrs = ob.Ast.obj_constrs;
+ Ast.sig_output_slot = interior_slot tobj }
+ in
+ (Ast.TY_fn (tsig, taux))
+
+ | Ast.MOD_ITEM_tag (htup, ttag, _) ->
+ let taux = { Ast.fn_effect = Ast.PURE;
+ Ast.fn_is_iter = false }
+ in
+ let tsig = { Ast.sig_input_slots = tup_slots htup;
+ Ast.sig_input_constrs = [| |];
+ Ast.sig_output_slot = interior_slot (Ast.TY_tag ttag) }
+ in
+ (Ast.TY_fn (tsig, taux))
+;;
+
+(* Scopes and the visitor that builds them. *)
+
+type scope =
+ SCOPE_block of node_id
+ | SCOPE_mod_item of Ast.mod_item
+ | SCOPE_obj_fn of (Ast.fn identified)
+ | SCOPE_crate of Ast.crate
+;;
+
+let id_of_scope (sco:scope) : node_id =
+ match sco with
+ SCOPE_block id -> id
+ | SCOPE_mod_item i -> i.id
+ | SCOPE_obj_fn f -> f.id
+ | SCOPE_crate c -> c.id
+;;
+
+let scope_stack_managing_visitor
+ (scopes:(scope list) ref)
+ (inner:Walk.visitor)
+ : Walk.visitor =
+ let push s =
+ scopes := s :: (!scopes)
+ in
+ let pop _ =
+ scopes := List.tl (!scopes)
+ in
+ let visit_block_pre b =
+ push (SCOPE_block b.id);
+ inner.Walk.visit_block_pre b
+ in
+ let visit_block_post b =
+ inner.Walk.visit_block_post b;
+ pop();
+ in
+ let visit_mod_item_pre n p i =
+ push (SCOPE_mod_item i);
+ inner.Walk.visit_mod_item_pre n p i
+ in
+ let visit_mod_item_post n p i =
+ inner.Walk.visit_mod_item_post n p i;
+ pop();
+ in
+ let visit_obj_fn_pre obj ident fn =
+ push (SCOPE_obj_fn fn);
+ inner.Walk.visit_obj_fn_pre obj ident fn
+ in
+ let visit_obj_fn_post obj ident fn =
+ inner.Walk.visit_obj_fn_post obj ident fn;
+ pop();
+ in
+ let visit_crate_pre c =
+ push (SCOPE_crate c);
+ inner.Walk.visit_crate_pre c
+ in
+ let visit_crate_post c =
+ inner.Walk.visit_crate_post c;
+ pop()
+ in
+ { inner with
+ Walk.visit_block_pre = visit_block_pre;
+ Walk.visit_block_post = visit_block_post;
+ Walk.visit_mod_item_pre = visit_mod_item_pre;
+ Walk.visit_mod_item_post = visit_mod_item_post;
+ Walk.visit_obj_fn_pre = visit_obj_fn_pre;
+ Walk.visit_obj_fn_post = visit_obj_fn_post;
+ Walk.visit_crate_pre = visit_crate_pre;
+ Walk.visit_crate_post = visit_crate_post; }
+;;
+
+(* Generic lookup, used for slots, items, types, etc. *)
+
+type resolved = ((scope list * node_id) option) ;;
+
+let get_item (cx:ctxt) (node:node_id) : Ast.mod_item_decl =
+ match htab_search cx.ctxt_all_defns node with
+ Some (DEFN_item item) -> item
+ | Some _ -> err (Some node) "defn is not an item"
+ | None -> bug () "missing defn"
+;;
+
+let get_slot (cx:ctxt) (node:node_id) : Ast.slot =
+ match htab_search cx.ctxt_all_defns node with
+ Some (DEFN_slot slot) -> slot
+ | Some _ -> err (Some node) "defn is not a slot"
+ | None -> bug () "missing defn"
+;;
+
+let get_mod_item
+ (cx:ctxt)
+ (node:node_id)
+ : (Ast.mod_view * Ast.mod_items) =
+ match get_item cx node with
+ { Ast.decl_item = Ast.MOD_ITEM_mod md } -> md
+ | _ -> err (Some node) "defn is not a mod"
+;;
+
+let get_name_comp_ident
+ (comp:Ast.name_component)
+ : Ast.ident =
+ match comp with
+ Ast.COMP_ident i -> i
+ | Ast.COMP_app (i, _) -> i
+ | Ast.COMP_idx i -> string_of_int i
+;;
+
+let get_name_base_ident
+ (comp:Ast.name_base)
+ : Ast.ident =
+ match comp with
+ Ast.BASE_ident i -> i
+ | Ast.BASE_app (i, _) -> i
+ | Ast.BASE_temp _ ->
+ bug () "get_name_base_ident on BASE_temp"
+;;
+
+let rec project_ident_from_items
+ (cx:ctxt)
+ (scopes:scope list)
+ ((view:Ast.mod_view),(items:Ast.mod_items))
+ (ident:Ast.ident)
+ (inside:bool)
+ : resolved =
+ if not (inside || (exports_permit view ident))
+ then None
+ else
+ match htab_search items ident with
+ Some i -> Some (scopes, i.id)
+ | None ->
+ match htab_search view.Ast.view_imports ident with
+ None -> None
+ | Some name -> lookup_by_name cx scopes name
+
+and project_name_comp_from_resolved
+ (cx:ctxt)
+ (mod_res:resolved)
+ (ext:Ast.name_component)
+ : resolved =
+ match mod_res with
+ None -> None
+ | Some (scopes, id) ->
+ let scope = (SCOPE_mod_item {id=id; node=get_item cx id}) in
+ let scopes = scope :: scopes in
+ let ident = get_name_comp_ident ext in
+ let md = get_mod_item cx id in
+ project_ident_from_items cx scopes md ident false
+
+and lookup_by_name
+ (cx:ctxt)
+ (scopes:scope list)
+ (name:Ast.name)
+ : resolved =
+ assert (Ast.sane_name name);
+ match name with
+ Ast.NAME_base nb ->
+ let ident = get_name_base_ident nb in
+ lookup_by_ident cx scopes ident
+ | Ast.NAME_ext (name, ext) ->
+ let base_res = lookup_by_name cx scopes name in
+ project_name_comp_from_resolved cx base_res ext
+
+and lookup_by_ident
+ (cx:ctxt)
+ (scopes:scope list)
+ (ident:Ast.ident)
+ : resolved =
+ let check_slots scopes islots =
+ arr_search islots
+ (fun _ (sloti,ident') ->
+ if ident = ident'
+ then Some (scopes, sloti.id)
+ else None)
+ in
+ let check_params scopes params =
+ arr_search params
+ (fun _ {node=(i,_); id=id} ->
+ if i = ident then Some (scopes, id) else None)
+ in
+ let passed_capture_scope = ref false in
+ let would_capture r =
+ match r with
+ None -> None
+ | Some _ ->
+ if !passed_capture_scope
+ then err None "attempted dynamic environment-capture"
+ else r
+ in
+ let check_scope scopes scope =
+ match scope with
+ SCOPE_block block_id ->
+ let block_slots = Hashtbl.find cx.ctxt_block_slots block_id in
+ let block_items = Hashtbl.find cx.ctxt_block_items block_id in
+ begin
+ match htab_search block_slots (Ast.KEY_ident ident) with
+ Some id -> would_capture (Some (scopes, id))
+ | None ->
+ match htab_search block_items ident with
+ Some id -> Some (scopes, id)
+ | None -> None
+ end
+
+ | SCOPE_crate crate ->
+ project_ident_from_items
+ cx scopes crate.node.Ast.crate_items ident true
+
+ | SCOPE_obj_fn fn ->
+ would_capture (check_slots scopes fn.node.Ast.fn_input_slots)
+
+ | SCOPE_mod_item item ->
+ begin
+ let item_match =
+ match item.node.Ast.decl_item with
+ Ast.MOD_ITEM_fn f ->
+ check_slots scopes f.Ast.fn_input_slots
+
+ | Ast.MOD_ITEM_obj obj ->
+ begin
+ match htab_search obj.Ast.obj_fns ident with
+ Some fn -> Some (scopes, fn.id)
+ | None -> check_slots scopes obj.Ast.obj_state
+ end
+
+ | Ast.MOD_ITEM_mod md ->
+ project_ident_from_items cx scopes md ident true
+
+ | _ -> None
+ in
+ match item_match with
+ Some _ -> item_match
+ | None ->
+ would_capture
+ (check_params scopes item.node.Ast.decl_params)
+ end
+ in
+ let rec search scopes =
+ match scopes with
+ [] -> None
+ | scope::rest ->
+ match check_scope scopes scope with
+ None ->
+ begin
+ let is_ty_item i =
+ match i.node.Ast.decl_item with
+ Ast.MOD_ITEM_type _ -> true
+ | _ -> false
+ in
+ match scope with
+ SCOPE_block _
+ | SCOPE_obj_fn _ ->
+ search rest
+
+ | SCOPE_mod_item item when is_ty_item item ->
+ search rest
+
+ | _ ->
+ passed_capture_scope := true;
+ search rest
+ end
+ | x -> x
+ in
+ search scopes
+;;
+
+let lookup_by_temp
+ (cx:ctxt)
+ (scopes:scope list)
+ (temp:temp_id)
+ : ((scope list * node_id) option) =
+ let passed_item_scope = ref false in
+ let check_scope scope =
+ if !passed_item_scope
+ then None
+ else
+ match scope with
+ SCOPE_block block_id ->
+ let block_slots = Hashtbl.find cx.ctxt_block_slots block_id in
+ htab_search block_slots (Ast.KEY_temp temp)
+ | _ ->
+ passed_item_scope := true;
+ None
+ in
+ list_search_ctxt scopes check_scope
+;;
+
+let lookup
+ (cx:ctxt)
+ (scopes:scope list)
+ (key:Ast.slot_key)
+ : ((scope list * node_id) option) =
+ match key with
+ Ast.KEY_temp temp -> lookup_by_temp cx scopes temp
+ | Ast.KEY_ident ident -> lookup_by_ident cx scopes ident
+;;
+
+
+let run_passes
+ (cx:ctxt)
+ (name:string)
+ (path:Ast.name_component Stack.t)
+ (passes:Walk.visitor array)
+ (log:string->unit)
+ (crate:Ast.crate)
+ : unit =
+ let do_pass i pass =
+ let logger s = log (Printf.sprintf "pass %d: %s" i s) in
+ Walk.walk_crate
+ (Walk.path_managing_visitor path
+ (Walk.mod_item_logging_visitor logger path pass))
+ crate
+ in
+ let sess = cx.ctxt_sess in
+ if sess.Session.sess_failed
+ then ()
+ else
+ try
+ Session.time_inner name sess
+ (fun _ -> Array.iteri do_pass passes)
+ with
+ Semant_err (ido, str) -> report_err cx ido str
+;;
+
+(* Rust type -> IL type conversion. *)
+
+let word_sty (abi:Abi.abi) : Il.scalar_ty =
+ Il.ValTy abi.Abi.abi_word_bits
+;;
+
+let word_rty (abi:Abi.abi) : Il.referent_ty =
+ Il.ScalarTy (word_sty abi)
+;;
+
+let tydesc_rty (abi:Abi.abi) : Il.referent_ty =
+ (*
+ * NB: must match corresponding tydesc structure
+ * in trans and offsets in ABI exactly.
+ *)
+ Il.StructTy
+ [|
+ word_rty abi; (* Abi.tydesc_field_first_param *)
+ word_rty abi; (* Abi.tydesc_field_size *)
+ word_rty abi; (* Abi.tydesc_field_align *)
+ Il.ScalarTy (Il.AddrTy Il.CodeTy); (* Abi.tydesc_field_copy_glue *)
+ Il.ScalarTy (Il.AddrTy Il.CodeTy); (* Abi.tydesc_field_drop_glue *)
+ Il.ScalarTy (Il.AddrTy Il.CodeTy); (* Abi.tydesc_field_free_glue *)
+ Il.ScalarTy (Il.AddrTy Il.CodeTy); (* Abi.tydesc_field_mark_glue *)
+ Il.ScalarTy (Il.AddrTy Il.CodeTy); (* Abi.tydesc_field_obj_drop_glue *)
+ |]
+;;
+
+let obj_closure_rty (abi:Abi.abi) : Il.referent_ty =
+ Il.StructTy [| word_rty abi;
+ Il.ScalarTy (Il.AddrTy (tydesc_rty abi));
+ word_rty abi (* A lie: it's opaque, but this permits
+ * GEP'ing to it. *)
+ |]
+;;
+
+let rec referent_type (abi:Abi.abi) (t:Ast.ty) : Il.referent_ty =
+ let s t = Il.ScalarTy t in
+ let v b = Il.ValTy b in
+ let p t = Il.AddrTy t in
+ let sv b = s (v b) in
+ let sp t = s (p t) in
+
+ let word = word_rty abi in
+ let ptr = sp Il.OpaqueTy in
+ let rc_ptr = sp (Il.StructTy [| word; Il.OpaqueTy |]) in
+ let codeptr = sp Il.CodeTy in
+ let tup ttup = Il.StructTy (Array.map (slot_referent_type abi) ttup) in
+ let tag ttag =
+ let union =
+ Il.UnionTy
+ (Array.map
+ (fun key -> tup (Hashtbl.find ttag key))
+ (sorted_htab_keys ttag))
+ in
+ let discriminant = word in
+ Il.StructTy [| discriminant; union |]
+ in
+
+ match t with
+ Ast.TY_any -> Il.StructTy [| word; ptr |]
+ | Ast.TY_nil -> Il.NilTy
+ | Ast.TY_int
+ | Ast.TY_uint -> word
+
+ | Ast.TY_bool -> sv Il.Bits8
+
+ | Ast.TY_mach (TY_u8)
+ | Ast.TY_mach (TY_i8) -> sv Il.Bits8
+
+ | Ast.TY_mach (TY_u16)
+ | Ast.TY_mach (TY_i16) -> sv Il.Bits16
+
+ | Ast.TY_mach (TY_u32)
+ | Ast.TY_mach (TY_i32)
+ | Ast.TY_mach (TY_f32)
+ | Ast.TY_char -> sv Il.Bits32
+
+ | Ast.TY_mach (TY_u64)
+ | Ast.TY_mach (TY_i64)
+ | Ast.TY_mach (TY_f64) -> sv Il.Bits64
+
+ | Ast.TY_str -> sp (Il.StructTy [| word; word; word; ptr |])
+ | Ast.TY_vec _ -> sp (Il.StructTy [| word; word; word; ptr |])
+ | Ast.TY_tup tt -> tup tt
+ | Ast.TY_rec tr -> tup (Array.map snd tr)
+
+ | Ast.TY_fn _ ->
+ let fn_closure_ptr = sp (Il.StructTy [| word; Il.OpaqueTy |]) in
+ Il.StructTy [| codeptr; fn_closure_ptr |]
+
+ | Ast.TY_obj _ ->
+ let obj_closure_ptr = sp (obj_closure_rty abi) in
+ Il.StructTy [| ptr; obj_closure_ptr |]
+
+ | Ast.TY_tag ttag -> tag ttag
+ | Ast.TY_iso tiso -> tag tiso.Ast.iso_group.(tiso.Ast.iso_index)
+
+ | Ast.TY_idx _ -> word (* A lie, but permits GEP'ing to it. *)
+
+ | Ast.TY_chan _
+ | Ast.TY_port _
+ | Ast.TY_task -> rc_ptr
+
+ | Ast.TY_type -> sp (tydesc_rty abi)
+
+ | Ast.TY_native _ -> ptr
+
+ | Ast.TY_param (i, _) -> Il.ParamTy i
+
+ | Ast.TY_named _ -> bug () "named type in referent_type"
+ | Ast.TY_constrained (t, _) -> referent_type abi t
+
+and slot_referent_type (abi:Abi.abi) (sl:Ast.slot) : Il.referent_ty =
+ let s t = Il.ScalarTy t in
+ let v b = Il.ValTy b in
+ let p t = Il.AddrTy t in
+ let sv b = s (v b) in
+ let sp t = s (p t) in
+
+ let word = sv abi.Abi.abi_word_bits in
+
+ let rty = referent_type abi (slot_ty sl) in
+ match sl.Ast.slot_mode with
+ Ast.MODE_exterior _ -> sp (Il.StructTy [| word; rty |])
+ | Ast.MODE_interior _ -> rty
+ | Ast.MODE_alias _ -> sp rty
+;;
+
+let task_rty (abi:Abi.abi) : Il.referent_ty =
+ Il.StructTy
+ begin
+ Array.init
+ Abi.n_visible_task_fields
+ (fun _ -> word_rty abi)
+ end
+;;
+
+let call_args_referent_type_full
+ (abi:Abi.abi)
+ (out_slot:Ast.slot)
+ (n_ty_params:int)
+ (in_slots:Ast.slot array)
+ (iterator_arg_rtys:Il.referent_ty array)
+ (indirect_arg_rtys:Il.referent_ty array)
+ : Il.referent_ty =
+ let out_slot_rty = slot_referent_type abi out_slot in
+ let out_ptr_rty = Il.ScalarTy (Il.AddrTy out_slot_rty) in
+ let task_ptr_rty = Il.ScalarTy (Il.AddrTy (task_rty abi)) in
+ let ty_param_rtys =
+ let td = Il.ScalarTy (Il.AddrTy (tydesc_rty abi)) in
+ Il.StructTy (Array.init n_ty_params (fun _ -> td))
+ in
+ let arg_rtys = Il.StructTy (Array.map (slot_referent_type abi) in_slots) in
+ (*
+ * NB: must match corresponding calltup structure in trans and
+ * member indices in ABI exactly.
+ *)
+ Il.StructTy
+ [|
+ out_ptr_rty; (* Abi.calltup_elt_out_ptr *)
+ task_ptr_rty; (* Abi.calltup_elt_task_ptr *)
+ ty_param_rtys; (* Abi.calltup_elt_ty_params *)
+ arg_rtys; (* Abi.calltup_elt_args *)
+ Il.StructTy iterator_arg_rtys; (* Abi.calltup_elt_iterator_args *)
+ Il.StructTy indirect_arg_rtys (* Abi.calltup_elt_indirect_args *)
+ |]
+;;
+
+let call_args_referent_type
+ (cx:ctxt)
+ (n_ty_params:int)
+ (callee_ty:Ast.ty)
+ (closure:Il.referent_ty option)
+ : Il.referent_ty =
+ let indirect_arg_rtys =
+ match closure with
+ None -> [| |]
+ | Some c ->
+ [|
+ (* Abi.indirect_args_elt_closure *)
+ Il.ScalarTy (Il.AddrTy c)
+ |]
+ in
+ let iterator_arg_rtys _ =
+ [|
+ (* Abi.iterator_args_elt_loop_size *)
+ Il.ScalarTy (Il.ValTy cx.ctxt_abi.Abi.abi_word_bits);
+ (* Abi.iterator_args_elt_loop_info_ptr *)
+ Il.ScalarTy (Il.AddrTy Il.OpaqueTy)
+ |]
+ in
+ match callee_ty with
+ Ast.TY_fn (tsig, taux) ->
+ call_args_referent_type_full
+ cx.ctxt_abi
+ tsig.Ast.sig_output_slot
+ n_ty_params
+ tsig.Ast.sig_input_slots
+ (if taux.Ast.fn_is_iter then (iterator_arg_rtys()) else [||])
+ indirect_arg_rtys
+
+ | _ -> bug cx "Semant.call_args_referent_type on non-callable type"
+;;
+
+let indirect_call_args_referent_type
+ (cx:ctxt)
+ (n_ty_params:int)
+ (callee_ty:Ast.ty)
+ (closure:Il.referent_ty)
+ : Il.referent_ty =
+ call_args_referent_type cx n_ty_params callee_ty (Some closure)
+;;
+
+let direct_call_args_referent_type
+ (cx:ctxt)
+ (callee_node:node_id)
+ : Il.referent_ty =
+ let ity = Hashtbl.find cx.ctxt_all_item_types callee_node in
+ let n_ty_params =
+ if item_is_obj_fn cx callee_node
+ then 0
+ else n_item_ty_params cx callee_node
+ in
+ call_args_referent_type cx n_ty_params ity None
+;;
+
+let ty_sz (abi:Abi.abi) (t:Ast.ty) : int64 =
+ force_sz (Il.referent_ty_size abi.Abi.abi_word_bits (referent_type abi t))
+;;
+
+let ty_align (abi:Abi.abi) (t:Ast.ty) : int64 =
+ force_sz (Il.referent_ty_align abi.Abi.abi_word_bits (referent_type abi t))
+;;
+
+let slot_sz (abi:Abi.abi) (s:Ast.slot) : int64 =
+ force_sz (Il.referent_ty_size abi.Abi.abi_word_bits
+ (slot_referent_type abi s))
+;;
+
+let word_slot (abi:Abi.abi) : Ast.slot =
+ interior_slot (Ast.TY_mach abi.Abi.abi_word_ty)
+;;
+
+let read_alias_slot (ty:Ast.ty) : Ast.slot =
+ { Ast.slot_mode = Ast.MODE_alias;
+ Ast.slot_mutable = false;
+ Ast.slot_ty = Some ty }
+;;
+
+let word_write_alias_slot (abi:Abi.abi) : Ast.slot =
+ { Ast.slot_mode = Ast.MODE_alias;
+ Ast.slot_mutable = true;
+ Ast.slot_ty = Some (Ast.TY_mach abi.Abi.abi_word_ty) }
+;;
+
+let mk_ty_fn_or_iter
+ (out_slot:Ast.slot)
+ (arg_slots:Ast.slot array)
+ (is_iter:bool)
+ : Ast.ty =
+ (* In some cases we don't care what aux or constrs are. *)
+ let taux = { Ast.fn_effect = Ast.PURE;
+ Ast.fn_is_iter = is_iter; }
+ in
+ let tsig = { Ast.sig_input_slots = arg_slots;
+ Ast.sig_input_constrs = [| |];
+ Ast.sig_output_slot = out_slot; }
+ in
+ Ast.TY_fn (tsig, taux)
+;;
+
+let mk_ty_fn
+ (out_slot:Ast.slot)
+ (arg_slots:Ast.slot array)
+ : Ast.ty =
+ mk_ty_fn_or_iter out_slot arg_slots false
+;;
+
+let mk_simple_ty_fn
+ (arg_slots:Ast.slot array)
+ : Ast.ty =
+ (* In some cases we don't care what the output slot is. *)
+ let out_slot = interior_slot Ast.TY_nil in
+ mk_ty_fn out_slot arg_slots
+;;
+
+let mk_simple_ty_iter
+ (arg_slots:Ast.slot array)
+ : Ast.ty =
+ (* In some cases we don't care what the output slot is. *)
+ let out_slot = interior_slot Ast.TY_nil in
+ mk_ty_fn_or_iter out_slot arg_slots true
+;;
+
+
+(* name mangling support. *)
+
+let item_name (cx:ctxt) (id:node_id) : Ast.name =
+ Hashtbl.find cx.ctxt_all_item_names id
+;;
+
+let item_str (cx:ctxt) (id:node_id) : string =
+ string_of_name (item_name cx id)
+;;
+
+let ty_str (ty:Ast.ty) : string =
+ let base = associative_binary_op_ty_fold "" (fun a b -> a ^ b) in
+ let fold_slot (mode,mut,ty) =
+ (if mut then "m" else "")
+ ^ (match mode with
+ Ast.MODE_exterior -> "e"
+ | Ast.MODE_alias -> "a"
+ | Ast.MODE_interior -> "")
+ ^ ty
+ in
+ let num n = (string_of_int n) ^ "$" in
+ let len a = num (Array.length a) in
+ let join az = Array.fold_left (fun a b -> a ^ b) "" az in
+ let fold_slots slots =
+ "t"
+ ^ (len slots)
+ ^ (join slots)
+ in
+ let fold_rec entries =
+ "r"
+ ^ (len entries)
+ ^ (Array.fold_left
+ (fun str (ident, s) -> str ^ "$" ^ ident ^ "$" ^ s)
+ "" entries)
+ in
+ let fold_tags tags =
+ "g"
+ ^ (num (Hashtbl.length tags))
+ ^ (Array.fold_left
+ (fun str key -> str ^ (string_of_name key) ^ (Hashtbl.find tags key))
+ "" (sorted_htab_keys tags))
+ in
+ let fold_iso (n, tags) =
+ "G"
+ ^ (num n)
+ ^ (len tags)
+ ^ (join tags)
+ in
+ let fold_mach m =
+ match m with
+ TY_u8 -> "U0"
+ | TY_u16 -> "U1"
+ | TY_u32 -> "U2"
+ | TY_u64 -> "U3"
+ | TY_i8 -> "I0"
+ | TY_i16 -> "I1"
+ | TY_i32 -> "I2"
+ | TY_i64 -> "I3"
+ | TY_f32 -> "F2"
+ | TY_f64 -> "F3"
+ in
+ let fold =
+ { base with
+ (* Structural types. *)
+ ty_fold_slot = fold_slot;
+ ty_fold_slots = fold_slots;
+ ty_fold_tags = fold_tags;
+ ty_fold_rec = fold_rec;
+ ty_fold_nil = (fun _ -> "n");
+ ty_fold_bool = (fun _ -> "b");
+ ty_fold_mach = fold_mach;
+ ty_fold_int = (fun _ -> "i");
+ ty_fold_uint = (fun _ -> "u");
+ ty_fold_char = (fun _ -> "c");
+ ty_fold_obj = (fun _ -> "o");
+ ty_fold_str = (fun _ -> "s");
+ ty_fold_vec = (fun s -> "v" ^ s);
+ ty_fold_iso = fold_iso;
+ ty_fold_idx = (fun i -> "x" ^ (string_of_int i));
+ (* FIXME: encode constrs, aux as well. *)
+ ty_fold_fn = (fun ((ins,_,out),_) -> "f" ^ ins ^ out);
+
+ (* Built-in special types. *)
+ ty_fold_any = (fun _ -> "A");
+ ty_fold_chan = (fun t -> "H" ^ t);
+ ty_fold_port = (fun t -> "R" ^ t);
+ ty_fold_task = (fun _ -> "T");
+ ty_fold_native = (fun _ -> "N");
+ ty_fold_param = (fun _ -> "P");
+ ty_fold_type = (fun _ -> "Y");
+
+ (* FIXME: encode obj types. *)
+ (* FIXME: encode opaque and param numbers. *)
+ ty_fold_named = (fun _ -> bug () "string-encoding named type");
+ (* FIXME: encode constrs as well. *)
+ ty_fold_constrained = (fun (t,_)-> t) }
+ in
+ fold_ty fold ty
+;;
+
+let glue_str (cx:ctxt) (g:glue) : string =
+ match g with
+ GLUE_activate -> "glue$activate"
+ | GLUE_yield -> "glue$yield"
+ | GLUE_exit_main_task -> "glue$exit_main_task"
+ | GLUE_exit_task -> "glue$exit_task"
+ | GLUE_mark ty -> "glue$mark$" ^ (ty_str ty)
+ | GLUE_drop ty -> "glue$drop$" ^ (ty_str ty)
+ | GLUE_free ty -> "glue$free$" ^ (ty_str ty)
+ | GLUE_copy ty -> "glue$copy$" ^ (ty_str ty)
+ | GLUE_clone ty -> "glue$clone$" ^ (ty_str ty)
+ | GLUE_compare ty -> "glue$compare$" ^ (ty_str ty)
+ | GLUE_hash ty -> "glue$hash$" ^ (ty_str ty)
+ | GLUE_write ty -> "glue$write$" ^ (ty_str ty)
+ | GLUE_read ty -> "glue$read$" ^ (ty_str ty)
+ | GLUE_unwind -> "glue$unwind"
+ | GLUE_get_next_pc -> "glue$get_next_pc"
+ | GLUE_mark_frame i -> "glue$mark_frame$" ^ (item_str cx i)
+ | GLUE_drop_frame i -> "glue$drop_frame$" ^ (item_str cx i)
+ | GLUE_reloc_frame i -> "glue$reloc_frame$" ^ (item_str cx i)
+ (*
+ * FIXME: the node_id here isn't an item, it's a statement;
+ * lookup bind target and encode bound arg tuple type.
+ *)
+ | GLUE_fn_binding i
+ -> "glue$fn_binding$" ^ (string_of_int (int_of_node i))
+ | GLUE_obj_drop oid
+ -> (item_str cx oid) ^ ".drop"
+ | GLUE_loop_body i
+ -> "glue$loop_body$" ^ (string_of_int (int_of_node i))
+ | GLUE_forward (id, oty1, oty2)
+ -> "glue$forward$"
+ ^ id
+ ^ "$" ^ (ty_str (Ast.TY_obj oty1))
+ ^ "$" ^ (ty_str (Ast.TY_obj oty2))
+;;
+
+
+(*
+ * Local Variables:
+ * fill-column: 78;
+ * indent-tabs-mode: nil
+ * buffer-file-coding-system: utf-8-unix
+ * compile-command: "make -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
+ * End:
+ *)