123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620 |
- (*
- The Haxe Compiler
- Copyright (C) 2005-2019 Haxe Foundation
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *)
- open Ast
- open Type
- open Common
- open Error
- open Globals
- (* -------------------------------------------------------------------------- *)
- (* TOOLS *)
- let rec has_properties c =
- List.exists (fun f ->
- match f.cf_kind with
- | Var { v_read = AccCall } -> true
- | Var { v_write = AccCall } -> true
- | _ when Meta.has Meta.Accessor f.cf_meta -> true
- | _ -> false
- ) c.cl_ordered_fields || (match c.cl_super with Some (c,_) -> has_properties c | _ -> false)
- let get_properties fields =
- List.fold_left (fun acc f ->
- if Meta.has Meta.Accessor f.cf_meta then
- (f.cf_name, f.cf_name) :: acc
- else
- let acc = (match f.cf_kind with
- | Var { v_read = AccCall } -> ("get_" ^ f.cf_name , "get_" ^ f.cf_name) :: acc
- | _ -> acc) in
- match f.cf_kind with
- | Var { v_write = AccCall } -> ("set_" ^ f.cf_name , "set_" ^ f.cf_name) :: acc
- | _ -> acc
- ) [] fields
- let add_property_field com c =
- let p = c.cl_pos in
- let props = get_properties (c.cl_ordered_statics @ c.cl_ordered_fields) in
- match props with
- | [] -> ()
- | _ ->
- let fields,values = List.fold_left (fun (fields,values) (n,v) ->
- let cf = mk_field n com.basic.tstring p null_pos in
- PMap.add n cf fields,((n,null_pos,NoQuotes),Texpr.Builder.make_string com.basic v p) :: values
- ) (PMap.empty,[]) props in
- let t = mk_anon fields in
- let e = mk (TObjectDecl values) t p in
- let cf = mk_field "__properties__" t p null_pos in
- cf.cf_expr <- Some e;
- c.cl_statics <- PMap.add cf.cf_name cf c.cl_statics;
- c.cl_ordered_statics <- cf :: c.cl_ordered_statics
- let escape_res_name name allow_dirs =
- ExtString.String.replace_chars (fun chr ->
- if (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z') || (chr >= '0' && chr <= '9') || chr = '_' || chr = '.' then
- Char.escaped chr
- else if chr = '/' && allow_dirs then
- "/"
- else
- "-x" ^ (string_of_int (Char.code chr))) name
- let update_cache_dependencies t =
- let rec check_t m t = match t with
- | TInst(c,tl) ->
- add_dependency m c.cl_module;
- List.iter (check_t m) tl;
- | TEnum(en,tl) ->
- add_dependency m en.e_module;
- List.iter (check_t m) tl;
- | TType(t,tl) ->
- add_dependency m t.t_module;
- List.iter (check_t m) tl;
- | TAbstract(a,tl) ->
- add_dependency m a.a_module;
- List.iter (check_t m) tl;
- | TFun(targs,tret) ->
- List.iter (fun (_,_,t) -> check_t m t) targs;
- check_t m tret;
- | TAnon an ->
- PMap.iter (fun _ cf -> check_field m cf) an.a_fields
- | TMono r ->
- (match !r with
- | Some t -> check_t m t
- | _ -> ())
- | TLazy f ->
- check_t m (lazy_type f)
- | TDynamic t ->
- if t == t_dynamic then
- ()
- else
- check_t m t
- and check_field m cf =
- check_t m cf.cf_type
- in
- match t with
- | TClassDecl c ->
- List.iter (check_field c.cl_module) c.cl_ordered_statics;
- List.iter (check_field c.cl_module) c.cl_ordered_fields;
- (match c.cl_constructor with None -> () | Some cf -> check_field c.cl_module cf);
- | _ ->
- ()
- (* -------------------------------------------------------------------------- *)
- (* FIX OVERRIDES *)
- (*
- on some platforms which doesn't support type parameters, we must have the
- exact same type for overridden/implemented function as the original one
- *)
- let rec find_field com c f =
- try
- (match c.cl_super with
- | None ->
- raise Not_found
- | Some ( {cl_path = (["cpp"],"FastIterator")}, _ ) ->
- raise Not_found (* This is a strongly typed 'extern' and the usual rules don't apply *)
- | Some (c,_) ->
- find_field com c f)
- with Not_found -> try
- if com.platform = Cpp || com.platform = Hl then (* uses delegation for interfaces *)
- raise Not_found;
- let rec loop = function
- | [] ->
- raise Not_found
- | (c,_) :: l ->
- try
- find_field com c f
- with
- Not_found -> loop l
- in
- loop c.cl_implements
- with Not_found ->
- let f = PMap.find f.cf_name c.cl_fields in
- (match f.cf_kind with Var { v_read = AccRequire _ } -> raise Not_found | _ -> ());
- f
- let fix_override com c f fd =
- let f2 = (try Some (find_field com c f) with Not_found -> None) in
- match f2,fd with
- | Some (f2), Some(fd) ->
- let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> assert false) in
- let changed_args = ref [] in
- let prefix = "_tmp_" in
- let nargs = List.map2 (fun ((v,ct) as cur) (_,_,t2) ->
- try
- type_eq EqStrict (monomorphs c.cl_params (monomorphs f.cf_params v.v_type)) t2;
- (* Flash generates type parameters with a single constraint as that constraint type, so we
- have to detect this case and change the variable (issue #2712). *)
- begin match follow v.v_type with
- | TInst({cl_kind = KTypeParameter [tc]} as cp,_) when com.platform = Flash ->
- if List.mem_assoc (snd cp.cl_path) c.cl_params then raise (Unify_error [])
- | _ ->
- ()
- end;
- cur
- with Unify_error _ ->
- let v2 = alloc_var VGenerated (prefix ^ v.v_name) t2 v.v_pos in
- changed_args := (v,v2) :: !changed_args;
- v2,ct
- ) fd.tf_args targs in
- let fd2 = {
- tf_args = nargs;
- tf_type = tret;
- tf_expr = (match List.rev !changed_args with
- | [] -> fd.tf_expr
- | args ->
- let e = fd.tf_expr in
- let el = (match e.eexpr with TBlock el -> el | _ -> [e]) in
- let p = (match el with [] -> e.epos | e :: _ -> e.epos) in
- let el_v = List.map (fun (v,v2) ->
- mk (TVar (v,Some (mk (TCast (mk (TLocal v2) v2.v_type p,None)) v.v_type p))) com.basic.tvoid p
- ) args in
- { e with eexpr = TBlock (el_v @ el) }
- );
- } in
- (* as3 does not allow wider visibility, so the base method has to be made public *)
- if Common.defined com Define.As3 && has_class_field_flag f CfPublic then add_class_field_flag f2 CfPublic;
- let targs = List.map (fun(v,c) -> (v.v_name, Option.is_some c, v.v_type)) nargs in
- let fde = (match f.cf_expr with None -> assert false | Some e -> e) in
- f.cf_expr <- Some { fde with eexpr = TFunction fd2 };
- f.cf_type <- TFun(targs,tret);
- | Some(f2), None when c.cl_interface ->
- let targs, tret = (match follow f2.cf_type with TFun (args,ret) -> args, ret | _ -> assert false) in
- f.cf_type <- TFun(targs,tret)
- | _ ->
- ()
- let fix_overrides com t =
- match t with
- | TClassDecl c ->
- (* overrides can be removed from interfaces *)
- if c.cl_interface then
- c.cl_ordered_fields <- List.filter (fun f ->
- try
- if find_field com c f == f then raise Not_found;
- c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
- false;
- with Not_found ->
- true
- ) c.cl_ordered_fields;
- List.iter (fun f ->
- match f.cf_expr, f.cf_kind with
- | Some { eexpr = TFunction fd }, Method (MethNormal | MethInline) ->
- fix_override com c f (Some fd)
- | None, Method (MethNormal | MethInline) when c.cl_interface ->
- fix_override com c f None
- | _ ->
- ()
- ) c.cl_ordered_fields
- | _ ->
- ()
- (*
- PHP does not allow abstract classes extending other abstract classes to override any fields, so these duplicates
- must be removed from the child interface
- *)
- let fix_abstract_inheritance com t =
- match t with
- | TClassDecl c when c.cl_interface ->
- c.cl_ordered_fields <- List.filter (fun f ->
- let b = try (find_field com c f) == f
- with Not_found -> false in
- if not b then c.cl_fields <- PMap.remove f.cf_name c.cl_fields;
- b;
- ) c.cl_ordered_fields
- | _ -> ()
- (* -------------------------------------------------------------------------- *)
- (* MISC FEATURES *)
- let rec is_volatile t =
- match t with
- | TMono r ->
- (match !r with
- | Some t -> is_volatile t
- | _ -> false)
- | TLazy f ->
- is_volatile (lazy_type f)
- | TType (t,tl) ->
- (match t.t_path with
- | _ -> is_volatile (apply_params t.t_params tl t.t_type))
- | _ ->
- false
- let bytes_serialize data =
- let b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" in
- let tbl = Array.init (String.length b64) (fun i -> String.get b64 i) in
- Bytes.unsafe_to_string (Base64.str_encode ~tbl data)
- module Dump = struct
- (*
- Make a dump of the full typed AST of all types
- *)
- let create_dumpfile acc l =
- let ch = Path.create_file false ".dump" acc l in
- let buf = Buffer.create 0 in
- buf, (fun () ->
- output_string ch (Buffer.contents buf);
- close_out ch)
- let create_dumpfile_from_path com path =
- let buf,close = create_dumpfile [] ("dump" :: (platform_name_macro com) :: fst path @ [snd path]) in
- buf,close
- let dump_types com s_expr =
- let s_type = s_type (Type.print_context()) in
- let params tl = match tl with [] -> "" | l -> Printf.sprintf "<%s>" (String.concat "," (List.map (fun (n,t) -> n ^ " : " ^ s_type t) l)) in
- List.iter (fun mt ->
- let path = Type.t_path mt in
- let buf,close = create_dumpfile_from_path com path in
- let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
- let s_metas ml tabs =
- let args el =
- match el with
- | [] -> ""
- | el -> Printf.sprintf "(%s)" (String.concat ", " (List.map (fun e -> Ast.s_expr e) el)) in
- match ml with
- | [] -> ""
- | ml -> String.concat " " (List.map (fun me -> match me with (m,el,_) -> "@" ^ Meta.to_string m ^ args el) ml) ^ "\n" ^ tabs in
- (match mt with
- | Type.TClassDecl c ->
- let s_cf_expr f =
- match f.cf_expr with
- | None -> ""
- | Some e -> Printf.sprintf "%s" (s_expr s_type e) in
- let is_inline_var v : bool = v = Var { v_read = AccInline; v_write = AccNever } in
- let rec print_field stat f =
- print "\n\t%s%s%s%s%s %s%s"
- (s_metas f.cf_meta "\t")
- (if (has_class_field_flag f CfPublic && not (c.cl_extern || c.cl_interface)) then "public " else "")
- (if stat then "static " else "")
- (match f.cf_kind with
- | Var v when (is_inline_var f.cf_kind) -> "inline "
- | Var v -> ""
- | Method m ->
- match m with
- | MethNormal -> ""
- | MethDynamic -> "dynamic "
- | MethInline -> "inline "
- | MethMacro -> "macro ")
- (match f.cf_kind with Var v -> "var" | Method m -> "function")
- (f.cf_name ^ match f.cf_kind with
- | Var { v_read = AccNormal; v_write = AccNormal } -> ""
- | Var v when (is_inline_var f.cf_kind) -> ""
- | Var v -> "(" ^ s_access true v.v_read ^ "," ^ s_access false v.v_write ^ ")"
- | _ -> "")
- (params f.cf_params);
- (match f.cf_kind with
- | Var v -> print ":%s%s;" (s_type f.cf_type)
- (match f.cf_expr with
- | None -> ""
- | Some e -> " = " ^ (s_cf_expr f));
- | Method m -> if (c.cl_extern || c.cl_interface) then (
- match f.cf_type with
- | TFun(al,t) -> print "(%s):%s;" (String.concat ", " (
- List.map (fun (n,o,t) -> n ^ ":" ^ (s_type t)) al))
- (s_type t)
- | _ -> ()
- ) else print "%s" (s_cf_expr f));
- print "\n";
- List.iter (fun f -> print_field stat f) f.cf_overloads
- in
- print "%s%s%s%s %s%s" (s_metas c.cl_meta "") (if c.cl_private then "private " else "") (if c.cl_extern then "extern " else "") (if c.cl_interface then "interface" else "class") (s_type_path path) (params c.cl_params);
- (match c.cl_super with None -> () | Some (c,pl) -> print " extends %s" (s_type (TInst (c,pl))));
- List.iter (fun (c,pl) -> print " implements %s" (s_type (TInst (c,pl)))) c.cl_implements;
- (match c.cl_array_access with None -> () | Some t -> print " implements ArrayAccess<%s>" (s_type t));
- print " {\n";
- (match c.cl_constructor with
- | None -> ()
- | Some f -> print_field false f);
- List.iter (print_field false) c.cl_ordered_fields;
- List.iter (print_field true) c.cl_ordered_statics;
- (match c.cl_init with
- | None -> ()
- | Some e ->
- print "\n\tstatic function __init__() ";
- print "%s" (s_expr s_type e);
- print "\n");
- print "}";
- | Type.TEnumDecl e ->
- print "%s%s%senum %s%s {\n" (s_metas e.e_meta "") (if e.e_private then "private " else "") (if e.e_extern then "extern " else "") (s_type_path path) (params e.e_params);
- List.iter (fun n ->
- let f = PMap.find n e.e_constrs in
- print "\t%s%s;\n" f.ef_name (
- match f.ef_type with
- | TFun (al,t) -> Printf.sprintf "(%s)" (String.concat ", "
- (List.map (fun (n,o,t) -> (if o then "?" else "") ^ n ^ ":" ^ (s_type t)) al))
- | _ -> "")
- ) e.e_names;
- print "}"
- | Type.TTypeDecl t ->
- print "%s%stypedef %s%s = %s" (s_metas t.t_meta "") (if t.t_private then "private " else "") (s_type_path path) (params t.t_params) (s_type t.t_type);
- | Type.TAbstractDecl a ->
- print "%s%sabstract %s%s%s%s {}" (s_metas a.a_meta "") (if a.a_private then "private " else "") (s_type_path path) (params a.a_params)
- (String.concat " " (List.map (fun t -> " from " ^ s_type t) a.a_from))
- (String.concat " " (List.map (fun t -> " to " ^ s_type t) a.a_to));
- );
- close();
- ) com.types
- let dump_record com =
- List.iter (fun mt ->
- let buf,close = create_dumpfile_from_path com (t_path mt) in
- let s = match mt with
- | TClassDecl c -> Printer.s_tclass "" c
- | TEnumDecl en -> Printer.s_tenum "" en
- | TTypeDecl t -> Printer.s_tdef "" t
- | TAbstractDecl a -> Printer.s_tabstract "" a
- in
- Buffer.add_string buf s;
- close();
- ) com.types
- let dump_position com =
- List.iter (fun mt ->
- match mt with
- | TClassDecl c ->
- let buf,close = create_dumpfile_from_path com (t_path mt) in
- Printf.bprintf buf "%s\n" (s_type_path c.cl_path);
- let field cf =
- Printf.bprintf buf "\t%s\n" cf.cf_name;
- begin match cf.cf_expr with
- | None -> ()
- | Some e ->
- Printf.bprintf buf "%s\n" (Texpr.dump_with_pos "\t" e);
- end
- in
- Option.may field c.cl_constructor;
- List.iter field c.cl_ordered_statics;
- List.iter field c.cl_ordered_fields;
- close();
- | _ ->
- ()
- ) com.types
- let dump_types com =
- match Common.defined_value_safe com Define.Dump with
- | "pretty" -> dump_types com (Type.s_expr_pretty false "\t" true)
- | "legacy" -> dump_types com Type.s_expr
- | "record" -> dump_record com
- | "position" -> dump_position com
- | _ -> dump_types com (Type.s_expr_ast (not (Common.defined com Define.DumpIgnoreVarIds)) "\t")
- let dump_dependencies ?(target_override=None) com =
- let target_name = match target_override with
- | None -> platform_name_macro com
- | Some s -> s
- in
- let buf,close = create_dumpfile [] ["dump";target_name;".dependencies"] in
- let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
- let dep = Hashtbl.create 0 in
- List.iter (fun m ->
- print "%s:\n" m.m_extra.m_file;
- PMap.iter (fun _ m2 ->
- print "\t%s\n" (m2.m_extra.m_file);
- let l = try Hashtbl.find dep m2.m_extra.m_file with Not_found -> [] in
- Hashtbl.replace dep m2.m_extra.m_file (m :: l)
- ) m.m_extra.m_deps;
- ) com.Common.modules;
- close();
- let buf,close = create_dumpfile [] ["dump";target_name;".dependants"] in
- let print fmt = Printf.kprintf (fun s -> Buffer.add_string buf s) fmt in
- Hashtbl.iter (fun n ml ->
- print "%s:\n" n;
- List.iter (fun m ->
- print "\t%s\n" (m.m_extra.m_file);
- ) ml;
- ) dep;
- close()
- end
- (*
- Build a default safe-cast expression :
- { var $t = <e>; if( Std.is($t,<t>) ) $t else throw "Class cast error"; }
- *)
- let default_cast ?(vtmp="$t") com e texpr t p =
- let api = com.basic in
- let mk_texpr = function
- | TClassDecl c -> TAnon { a_fields = PMap.empty; a_status = ref (Statics c) }
- | TEnumDecl e -> TAnon { a_fields = PMap.empty; a_status = ref (EnumStatics e) }
- | TAbstractDecl a -> TAnon { a_fields = PMap.empty; a_status = ref (AbstractStatics a) }
- | TTypeDecl _ -> assert false
- in
- let vtmp = alloc_var VGenerated vtmp e.etype e.epos in
- let var = mk (TVar (vtmp,Some e)) api.tvoid p in
- let vexpr = mk (TLocal vtmp) e.etype p in
- let texpr = mk (TTypeExpr texpr) (mk_texpr texpr) p in
- let std = (try List.find (fun t -> t_path t = ([],"Std")) com.types with Not_found -> assert false) in
- let fis = (try
- let c = (match std with TClassDecl c -> c | _ -> assert false) in
- FStatic (c, PMap.find "is" c.cl_statics)
- with Not_found ->
- assert false
- ) in
- let std = mk (TTypeExpr std) (mk_texpr std) p in
- let is = mk (TField (std,fis)) (tfun [t_dynamic;t_dynamic] api.tbool) p in
- let is = mk (TCall (is,[vexpr;texpr])) api.tbool p in
- let enull = Texpr.Builder.make_null vexpr.etype p in
- let eop = Texpr.Builder.binop OpEq vexpr enull api.tbool p in
- let echeck = Texpr.Builder.binop OpBoolOr is eop api.tbool p in
- let exc = mk (TThrow (mk (TConst (TString "Class cast error")) api.tstring p)) t p in
- let check = mk (TIf (Texpr.Builder.mk_parent echeck,mk (TCast (vexpr,None)) t p,Some exc)) t p in
- mk (TBlock [var;check;vexpr]) t p
- module UnificationCallback = struct
- let tf_stack = new_rec_stack()
- let check_call_params f el tl =
- let rec loop acc el tl = match el,tl with
- | e :: el, (n,_,t) :: tl ->
- loop ((f e t) :: acc) el tl
- | [], [] ->
- acc
- | [],_ ->
- acc
- | e :: el, [] ->
- loop (e :: acc) el []
- in
- List.rev (loop [] el tl)
- let check_call f el t = match follow t with
- | TFun(args,_) ->
- check_call_params f el args
- | _ ->
- List.map (fun e -> f e t_dynamic) el
- let rec run ff e =
- let f e t =
- if not (type_iseq e.etype t) then
- ff e t
- else
- e
- in
- let check e = match e.eexpr with
- | TBinop((OpAssign | OpAssignOp _),e1,e2) ->
- assert false; (* this trigger #4347, to be fixed before enabling
- let e2 = f e2 e1.etype in
- {e with eexpr = TBinop(op,e1,e2)} *)
- | TVar(v,Some ev) ->
- let eo = Some (f ev v.v_type) in
- { e with eexpr = TVar(v,eo) }
- | TCall(e1,el) ->
- let el = check_call f el e1.etype in
- {e with eexpr = TCall(e1,el)}
- | TNew(c,tl,el) ->
- begin try
- let tcf,_ = get_constructor (fun cf -> apply_params c.cl_params tl cf.cf_type) c in
- let el = check_call f el tcf in
- {e with eexpr = TNew(c,tl,el)}
- with Not_found ->
- e
- end
- | TArrayDecl el ->
- begin match follow e.etype with
- | TInst({cl_path=[],"Array"},[t]) -> {e with eexpr = TArrayDecl(List.map (fun e -> f e t) el)}
- | _ -> e
- end
- | TObjectDecl fl ->
- begin match follow e.etype with
- | TAnon an ->
- let fl = List.map (fun ((n,p,qs),e) ->
- let e = try
- let t = (PMap.find n an.a_fields).cf_type in
- f e t
- with Not_found ->
- e
- in
- (n,p,qs),e
- ) fl in
- { e with eexpr = TObjectDecl fl }
- | _ -> e
- end
- | TReturn (Some e1) ->
- begin match tf_stack.rec_stack with
- | tf :: _ -> { e with eexpr = TReturn (Some (f e1 tf.tf_type))}
- | _ -> e
- end
- | _ ->
- e
- in
- match e.eexpr with
- | TFunction tf ->
- rec_stack_loop tf_stack tf (fun() -> {e with eexpr = TFunction({tf with tf_expr = run f tf.tf_expr})}) ()
- | _ ->
- check (Type.map_expr (run ff) e)
- end;;
- let interpolate_code com code tl f_string f_expr p =
- let exprs = Array.of_list tl in
- let i = ref 0 in
- let err msg =
- let pos = { p with pmin = p.pmin + !i } in
- com.error msg pos
- in
- let regex = Str.regexp "[{}]" in
- let rec loop m = match m with
- | [] ->
- ()
- | Str.Text txt :: tl ->
- i := !i + String.length txt;
- f_string txt;
- loop tl
- | Str.Delim a :: Str.Delim b :: tl when a = b ->
- i := !i + 2;
- f_string a;
- loop tl
- | Str.Delim "{" :: Str.Text n :: Str.Delim "}" :: tl ->
- begin try
- let expr = Array.get exprs (int_of_string n) in
- f_expr expr;
- with
- | Failure _ ->
- f_string ("{" ^ n ^ "}");
- | Invalid_argument _ ->
- err ("Out-of-bounds special parameter: " ^ n)
- end;
- i := !i + 2 + String.length n;
- loop tl
- | Str.Delim x :: tl ->
- f_string x;
- incr i;
- loop tl
- in
- loop (Str.full_split regex code)
- let map_source_header com f =
- match Common.defined_value_safe com Define.SourceHeader with
- | "" -> ()
- | s -> f s
- (* Static extensions for classes *)
- module ExtClass = struct
- let add_cl_init c e = match c.cl_init with
- | None -> c.cl_init <- Some e
- | Some e' -> c.cl_init <- Some (concat e' e)
- let add_static_init c cf e p =
- let ethis = Texpr.Builder.make_static_this c p in
- let ef1 = mk (TField(ethis,FStatic(c,cf))) cf.cf_type p in
- let e_assign = mk (TBinop(OpAssign,ef1,e)) e.etype p in
- add_cl_init c e_assign
- end
|