Sfoglia il codice sorgente

allowed member macros functions (called as static)

Nicolas Cannasse 14 anni fa
parent
commit
430a0684ab
4 ha cambiato i file con 130 aggiunte e 4 eliminazioni
  1. 1 0
      doc/CHANGES.txt
  2. 100 0
      interp.ml
  3. 13 3
      typeload.ml
  4. 16 1
      typer.ml

+ 1 - 0
doc/CHANGES.txt

@@ -11,6 +11,7 @@
 	all : added haxe.Int32 isNeg,isZero,ucompare, fixed overflows for js/flash8/php
 	all : bugfix when optimizing inlined immediate function call
 	all : fixed "using" on macro function
+	all : allowed member macros functions (called as static)
 
 2011-01-30: 2.07
 	all : fixed completion support with --remap

+ 100 - 0
interp.ml

@@ -3112,6 +3112,106 @@ let rec make_const e =
 	| _ ->
 		raise Exit
 
+(* ---------------------------------------------------------------------- *)
+(* TEXPR-TO-AST-EXPR *)
+
+open Ast
+
+let rec make_ast e =
+	let mk_path (pack,name) p =
+		match List.rev pack with
+		| [] -> (EConst (Type name),p)
+		| pl ->
+			let rec loop = function
+				| [] -> assert false
+				| [n] -> (EConst (Ident n),p)
+				| n :: l -> (EField (loop l, n),p)
+			in
+			(EType (loop pl,name),p)
+	in
+	let mk_const = function
+		| TInt i -> Int (Int32.to_string i)
+		| TFloat s -> Float s
+		| TString s -> String s
+		| TBool b -> Ident (if b then "true" else "false")
+		| TNull -> Ident "null"
+		| TThis -> Ident "this"
+		| TSuper -> Ident "super"
+	in
+	let tpath p pl =
+		CTPath {
+			tpackage = fst p;
+			tname = snd p;
+			tparams = List.map (fun t -> TPType t) pl;
+			tsub = None;
+		}
+	in
+	let rec mk_type = function
+		| TMono r ->
+			(match !r with
+			| None -> tpath ([],"Unknown") []
+			| Some t -> mk_type t)
+		| TEnum (e,pl) ->
+			tpath e.e_path (List.map mk_type pl)
+		| TInst (c,pl) ->
+			tpath c.cl_path (List.map mk_type pl)
+		| TType (t,pl) ->
+			tpath t.t_path (List.map mk_type pl)
+		| TFun (args,ret) ->
+			CTFunction (List.map (fun (_,_,t) -> mk_type t) args, mk_type ret)			
+		| TAnon a ->
+			CTAnonymous (PMap.foldi (fun _ f acc -> 
+				(f.cf_name,None,AFVar (mk_type f.cf_type), e.epos) :: acc
+			) a.a_fields [])
+		| (TDynamic t2) as t ->
+			tpath ([],"Dynamic") (if t == t_dynamic then [] else [mk_type t2])
+		| TLazy f ->
+			mk_type ((!f)())
+	in
+	let mk_ot t =
+		match follow t with
+		| TMono _ -> None
+		| _ -> Some (mk_type t)
+	in
+	let eopt = function None -> None | Some e -> Some (make_ast e) in
+	((match e.eexpr with
+	| TConst c ->
+		EConst (mk_const c)
+	| TLocal s -> EConst (Ident s)
+	| TEnumField (en,f) -> EField (mk_path en.e_path e.epos,f)
+	| TArray (e1,e2) -> EArray (make_ast e1,make_ast e2)
+	| TBinop (op,e1,e2) -> EBinop (op, make_ast e1, make_ast e2)
+	| TField (e,f) | TClosure (e,f) -> EField (make_ast e, f)
+	| TTypeExpr t -> fst (mk_path (t_path t) e.epos)
+	| TParenthesis e -> EParenthesis (make_ast e)
+	| TObjectDecl fl -> EObjectDecl (List.map (fun (f,e) -> f, make_ast e) fl)
+	| TArrayDecl el -> EArrayDecl (List.map make_ast el)
+	| TCall (e,el) -> ECall (make_ast e,List.map make_ast el)
+	| TNew (c,pl,el) -> ENew ((match mk_type (TInst (c,pl)) with CTPath p -> p | _ -> assert false),List.map make_ast el)
+	| TUnop (op,p,e) -> EUnop (op,p,make_ast e)
+	| TFunction f -> 
+		let arg (n,c,t) = n, false, mk_ot t, (match c with None -> None | Some c -> Some (EConst (mk_const c),e.epos)) in
+		EFunction (None,{ f_args = List.map arg f.tf_args; f_type = mk_ot f.tf_type; f_expr = make_ast f.tf_expr })
+	| TVars vl ->
+		EVars (List.map (fun (n,t,e) -> n, mk_ot t, eopt e) vl)
+	| TBlock el -> EBlock (List.map make_ast el)
+	| TFor (n,t,it,e) -> EFor (n,make_ast it,make_ast e)
+	| TIf (e,e1,e2) -> EIf (make_ast e,make_ast e1,eopt e2)
+	| TWhile (e1,e2,flag) -> EWhile (make_ast e1, make_ast e2, flag)
+	| TSwitch (e,cases,def) -> ESwitch (make_ast e,List.map (fun (vl,e) -> List.map make_ast vl, make_ast e) cases,eopt def)
+	| TMatch (e,en,cases,def) ->
+		let scases (idx,args,e) =
+			assert false
+		in
+		ESwitch (make_ast e,List.map scases cases,eopt def)
+	| TTry (e,catches) -> ETry (make_ast e,List.map (fun (n,t,e) -> n, mk_type t, make_ast e) catches)
+	| TReturn e -> EReturn (eopt e)
+	| TBreak -> EBreak
+	| TContinue -> EContinue
+	| TThrow e -> EThrow (make_ast e)
+	| TCast (e,t) -> ECast (make_ast e,(match t with None -> None | Some t -> Some (mk_type (match t with TClassDecl c -> TInst (c,[]) | TEnumDecl e -> TEnum (e,[]) | TTypeDecl t -> TType (t,[]))))))
+	,e.epos)
+
 ;;
 enc_array_ref := enc_array;
 encode_type_ref := encode_type;

+ 13 - 3
typeload.ml

@@ -821,7 +821,9 @@ let init_class ctx c p herits fields =
 				if not (is_full_type cf.cf_type) then cf.cf_type <- TLazy r;
 				(fun() -> ())
 			end
-		end else begin
+		end else if macro && not ctx.in_macro then
+			(fun () -> ())
+		else begin
 			cf.cf_type <- TLazy r;
 			(fun () -> ignore(!r()))
 		end
@@ -917,7 +919,15 @@ let init_class ctx c p herits fields =
 			let params = !params in
 			if inline && c.cl_interface then error "You can't declare inline methods in interfaces" p;
 			let is_macro = (is_macro && stat) || has_meta ":macro" f.cff_meta in
-			if is_macro && not stat then error "Only static methods can be macros" p;
+			let f, stat, fd = if not is_macro || stat then 
+				f, stat, fd
+			else if ctx.in_macro then
+				(* non-static macros methods are turned into static when we are running the macro *)
+				{ f with cff_access = AStatic :: f.cff_access }, true, fd
+			else
+				(* remove display of first argument which will contain the "this" expression *)
+				f, stat, { fd with f_args = match fd.f_args with [] -> [] | _ :: l -> l }
+			in
 			let fd = if not is_macro then
 				fd
 			else if ctx.in_macro then
@@ -935,7 +945,7 @@ let init_class ctx c p herits fields =
 					| _ -> tdyn
 				in
 				{
-					f_type = tdyn;
+					f_type = (match fd.f_type with Some (CTPath t) -> to_dyn t | _ -> tdyn);
 					f_args = List.map (fun (a,o,t,_) -> a,o,(match t with Some (CTPath t) -> to_dyn t | _ -> tdyn),None) fd.f_args;
 					f_expr = (EBlock [],p)
 				}

+ 16 - 1
typer.ml

@@ -1715,7 +1715,22 @@ and type_call ctx e el p =
 				(match ctx.g.do_macro ctx c.cl_path f.cf_name el p with
 				| None -> type_expr ctx (EConst (Ident "null"),p)
 				| Some e -> type_expr ctx e)
-			| _ -> assert false)
+			| _ ->
+				(* member-macro call : since we will make a static call, let's found the actual class and not its subclass *)
+				(match follow ethis.etype with
+				| TInst (c,_) ->					
+					let rec loop c =
+						if PMap.mem f.cf_name c.cl_fields then
+							match ctx.g.do_macro ctx c.cl_path f.cf_name (Interp.make_ast ethis :: el) p with
+							| None -> type_expr ctx (EConst (Ident "null"),p)
+							| Some e -> type_expr ctx e
+						else
+							match c.cl_super with
+							| None -> assert false
+							| Some (csup,_) -> loop csup
+					in
+					loop c
+				| _ -> assert false))
 		| AKNo _ | AKSet _ as acc ->
 			ignore(acc_get ctx acc p);
 			assert false