Procházet zdrojové kódy

Function kind in AST (#8653)

* function kind

* carry "inline" flag

* print "inline function" Ast.Printer.s_expr_inner
Aleksandr Kuzmenko před 6 roky
rodič
revize
35869bf8ae

+ 1 - 1
src/context/display/documentSymbols.ml

@@ -22,7 +22,7 @@ let collect_module_symbols with_locals (pack,decls) =
 				add s Variable p;
 				add s Variable p;
 				expr parent e
 				expr parent e
 			) catches;
 			) catches;
-		| EFunction(Some (s,_),f) ->
+		| EFunction(FKNamed ((s,_),_),f) ->
 			add s Function p;
 			add s Function p;
 			func parent f
 			func parent f
 		| EBinop(OpIn,(EConst(Ident s),p),e2) ->
 		| EBinop(OpIn,(EConst(Ident s),p),e2) ->

+ 13 - 6
src/core/ast.ml

@@ -177,6 +177,11 @@ and func = {
 
 
 and placed_name = string * pos
 and placed_name = string * pos
 
 
+and function_kind =
+	| FKAnonymous
+	| FKNamed of placed_name * bool (* bool for `inline` *)
+	| FKArrow
+
 and display_kind =
 and display_kind =
 	| DKCall
 	| DKCall
 	| DKDot
 	| DKDot
@@ -196,7 +201,7 @@ and expr_def =
 	| ENew of placed_type_path * expr list
 	| ENew of placed_type_path * expr list
 	| EUnop of unop * unop_flag * expr
 	| EUnop of unop * unop_flag * expr
 	| EVars of (placed_name * bool * type_hint option * expr option) list
 	| EVars of (placed_name * bool * type_hint option * expr option) list
-	| EFunction of placed_name option * func
+	| EFunction of function_kind * func
 	| EBlock of expr list
 	| EBlock of expr list
 	| EFor of expr * expr
 	| EFor of expr * expr
 	| EIf of expr * expr * expr option
 	| EIf of expr * expr * expr option
@@ -628,7 +633,7 @@ let map_expr loop (e,p) =
 			let eo = opt loop eo in
 			let eo = opt loop eo in
 			n,b,t,eo
 			n,b,t,eo
 		) vl)
 		) vl)
-	| EFunction (n,f) -> EFunction (n,func f)
+	| EFunction (kind,f) -> EFunction (kind,func f)
 	| EBlock el -> EBlock (List.map loop el)
 	| EBlock el -> EBlock (List.map loop el)
 	| EFor (e1,e2) ->
 	| EFor (e1,e2) ->
 		let e1 = loop e1 in
 		let e1 = loop e1 in
@@ -734,8 +739,9 @@ module Printer = struct
 		| ENew (t,el) -> "new " ^ s_complex_type_path tabs t ^ "(" ^ s_expr_list tabs el ", " ^ ")"
 		| ENew (t,el) -> "new " ^ s_complex_type_path tabs t ^ "(" ^ s_expr_list tabs el ", " ^ ")"
 		| EUnop (op,Postfix,e) -> s_expr_inner tabs e ^ s_unop op
 		| EUnop (op,Postfix,e) -> s_expr_inner tabs e ^ s_unop op
 		| EUnop (op,Prefix,e) -> s_unop op ^ s_expr_inner tabs e
 		| EUnop (op,Prefix,e) -> s_unop op ^ s_expr_inner tabs e
-		| EFunction (Some (n,_),f) -> "function " ^ n ^ s_func tabs f
-		| EFunction (None,f) -> "function" ^ s_func tabs f
+		| EFunction (FKNamed((n,_),inline),f) -> (if inline then "inline " else "") ^ "function " ^ n ^ s_func tabs f
+		| EFunction (FKAnonymous,f) -> "function" ^ s_func tabs f
+		| EFunction (FKArrow,f) -> "function" ^ s_func ~is_arrow:true tabs f
 		| EVars vl -> "var " ^ String.concat ", " (List.map (s_var tabs) vl)
 		| EVars vl -> "var " ^ String.concat ", " (List.map (s_var tabs) vl)
 		| EBlock [] -> "{ }"
 		| EBlock [] -> "{ }"
 		| EBlock el -> s_block tabs el "{" "\n" "}"
 		| EBlock el -> s_block tabs el "{" "\n" "}"
@@ -805,10 +811,11 @@ module Printer = struct
 		match t with
 		match t with
 		| Some(t,_) -> pre ^ s_complex_type tabs t
 		| Some(t,_) -> pre ^ s_complex_type tabs t
 		| None -> ""
 		| None -> ""
-	and s_func tabs f =
+	and s_func ?(is_arrow=false) tabs f =
 		s_type_param_list tabs f.f_params ^
 		s_type_param_list tabs f.f_params ^
 		"(" ^ String.concat ", " (List.map (s_func_arg tabs) f.f_args) ^ ")" ^
 		"(" ^ String.concat ", " (List.map (s_func_arg tabs) f.f_args) ^ ")" ^
 		s_opt_type_hint tabs f.f_type ":" ^
 		s_opt_type_hint tabs f.f_type ":" ^
+		(if is_arrow then " -> " else "") ^
 		s_opt_expr tabs f.f_expr " "
 		s_opt_expr tabs f.f_expr " "
 	and s_type_param tabs t =
 	and s_type_param tabs t =
 		fst (t.tp_name) ^ s_type_param_list tabs t.tp_params ^
 		fst (t.tp_name) ^ s_type_param_list tabs t.tp_params ^
@@ -973,7 +980,7 @@ module Expr = struct
 					| Some e ->
 					| Some e ->
 						loop' (Printf.sprintf "%s      " tabs) e
 						loop' (Printf.sprintf "%s      " tabs) e
 				) vl
 				) vl
-			| EFunction(so,f) ->
+			| EFunction(_,f) ->
 				add "EFunction";
 				add "EFunction";
 				Option.may loop f.f_expr;
 				Option.may loop f.f_expr;
 			| EBlock el ->
 			| EBlock el ->

+ 1 - 1
src/core/type.ml

@@ -2892,7 +2892,7 @@ module TExprToExpr = struct
 		| TUnop (op,p,e) -> EUnop (op,p,convert_expr e)
 		| TUnop (op,p,e) -> EUnop (op,p,convert_expr e)
 		| TFunction f ->
 		| TFunction f ->
 			let arg (v,c) = (v.v_name,v.v_pos), false, v.v_meta, mk_type_hint v.v_type null_pos, (match c with None -> None | Some c -> Some (convert_expr c)) in
 			let arg (v,c) = (v.v_name,v.v_pos), false, v.v_meta, mk_type_hint v.v_type null_pos, (match c with None -> None | Some c -> Some (convert_expr c)) in
-			EFunction (None,{ f_params = []; f_args = List.map arg f.tf_args; f_type = mk_type_hint f.tf_type null_pos; f_expr = Some (convert_expr f.tf_expr) })
+			EFunction (FKAnonymous,{ f_params = []; f_args = List.map arg f.tf_args; f_type = mk_type_hint f.tf_type null_pos; f_expr = Some (convert_expr f.tf_expr) })
 		| TVar (v,eo) ->
 		| TVar (v,eo) ->
 			EVars ([(v.v_name,v.v_pos), v.v_final, mk_type_hint v.v_type v.v_pos, eopt eo])
 			EVars ([(v.v_name,v.v_pos), v.v_final, mk_type_hint v.v_type v.v_pos, eopt eo])
 		| TBlock el -> EBlock (List.map convert_expr el)
 		| TBlock el -> EBlock (List.map convert_expr el)

+ 1 - 0
src/macro/eval/evalEncode.ml

@@ -159,6 +159,7 @@ let encode_enum i pos index pl =
 		| IQuoteStatus -> key_haxe_macro_QuoteStatus
 		| IQuoteStatus -> key_haxe_macro_QuoteStatus
 		| IDisplayKind -> key_haxe_macro_DisplayKind
 		| IDisplayKind -> key_haxe_macro_DisplayKind
 		| IMessage -> key_haxe_macro_Message
 		| IMessage -> key_haxe_macro_Message
+		| IFunctionKind -> key_haxe_macro_FunctionKind
 	in
 	in
 	encode_enum_value key index (Array.of_list pl) pos
 	encode_enum_value key index (Array.of_list pl) pos
 
 

+ 1 - 0
src/macro/eval/evalHash.ml

@@ -105,6 +105,7 @@ let key_haxe_macro_ImportMode = hash "haxe.macro.ImportMode"
 let key_haxe_macro_QuoteStatus = hash "haxe.macro.QuoteStatus"
 let key_haxe_macro_QuoteStatus = hash "haxe.macro.QuoteStatus"
 let key_haxe_macro_DisplayKind = hash "haxe.macro.DisplayKind"
 let key_haxe_macro_DisplayKind = hash "haxe.macro.DisplayKind"
 let key_haxe_macro_Message = hash "haxe.macro.Message"
 let key_haxe_macro_Message = hash "haxe.macro.Message"
+let key_haxe_macro_FunctionKind = hash "haxe.macro.FunctionKind"
 let key_haxe_CallStack = hash "haxe.CallStack"
 let key_haxe_CallStack = hash "haxe.CallStack"
 let key___init__ = hash "__init__"
 let key___init__ = hash "__init__"
 let key_new = hash "new"
 let key_new = hash "new"

+ 21 - 4
src/macro/macroApi.ml

@@ -77,6 +77,7 @@ type enum_type =
 	| IImportMode
 	| IImportMode
 	| IDisplayKind
 	| IDisplayKind
 	| IMessage
 	| IMessage
+	| IFunctionKind
 
 
 (**
 (**
 	Our access to the interpreter from the macro api
 	Our access to the interpreter from the macro api
@@ -172,6 +173,7 @@ let enum_name = function
 	| IQuoteStatus -> "QuoteStatus"
 	| IQuoteStatus -> "QuoteStatus"
 	| IDisplayKind -> "DisplayKind"
 	| IDisplayKind -> "DisplayKind"
 	| IMessage -> "Message"
 	| IMessage -> "Message"
+	| IFunctionKind -> "FunctionKind"
 
 
 let all_enums =
 let all_enums =
 	let last = IImportMode in
 	let last = IImportMode in
@@ -438,8 +440,8 @@ and encode_expr e =
 						"expr",null loop eo;
 						"expr",null loop eo;
 					]
 					]
 				) vl)]
 				) vl)]
-			| EFunction (name,f) ->
-				11, [null encode_placed_name name; encode_fun f]
+			| EFunction (kind,f) ->
+				11, [encode_function_kind kind; encode_fun f]
 			| EBlock el ->
 			| EBlock el ->
 				12, [encode_array (List.map loop el)]
 				12, [encode_array (List.map loop el)]
 			| EFor (e,eloop) ->
 			| EFor (e,eloop) ->
@@ -504,6 +506,15 @@ and encode_null_expr e =
 	| Some e ->
 	| Some e ->
 		encode_expr e
 		encode_expr e
 
 
+and encode_function_kind kind =
+	match kind with
+	| FKAnonymous ->
+		encode_enum IFunctionKind 0 []
+	| FKNamed (name,inline) ->
+		encode_enum IFunctionKind 1 [encode_placed_name name; vbool inline]
+	| FKArrow ->
+		encode_enum IFunctionKind 2 []
+
 (* ---------------------------------------------------------------------- *)
 (* ---------------------------------------------------------------------- *)
 (* EXPR DECODING *)
 (* EXPR DECODING *)
 
 
@@ -699,6 +710,12 @@ and decode_display_kind v = match (decode_enum v) with
 	| 4, [outermost] -> DKPattern (decode_bool outermost)
 	| 4, [outermost] -> DKPattern (decode_bool outermost)
 	| _ -> raise Invalid_expr
 	| _ -> raise Invalid_expr
 
 
+and decode_function_kind kind = match decode_enum kind with
+	| 0, [] -> FKAnonymous
+	| 1, [name;inline] -> FKNamed ((decode_string name,Globals.null_pos), decode_bool inline)
+	| 2, [] -> FKArrow
+	| _ -> raise Invalid_expr
+
 and decode_expr v =
 and decode_expr v =
 	let rec loop v =
 	let rec loop v =
 		let p = decode_pos (field v "pos") in
 		let p = decode_pos (field v "pos") in
@@ -741,8 +758,8 @@ and decode_expr v =
 				let final = if vfinal == vnull then false else decode_bool vfinal in
 				let final = if vfinal == vnull then false else decode_bool vfinal in
 				((decode_placed_name (field v "name_pos") (field v "name")),final,opt decode_ctype (field v "type"),opt loop (field v "expr"))
 				((decode_placed_name (field v "name_pos") (field v "name")),final,opt decode_ctype (field v "type"),opt loop (field v "expr"))
 			) (decode_array vl))
 			) (decode_array vl))
-		| 11, [fname;f] ->
-			EFunction (opt (fun v -> decode_string v,Globals.null_pos) fname,decode_fun f)
+		| 11, [kind;f] ->
+			EFunction (decode_function_kind kind,decode_fun f)
 		| 12, [el] ->
 		| 12, [el] ->
 			EBlock (List.map loop (decode_array el))
 			EBlock (List.map loop (decode_array el))
 		| 13, [e1;e2] ->
 		| 13, [e1;e2] ->

+ 5 - 5
src/optimization/optimizer.ml

@@ -663,11 +663,11 @@ let optimize_completion_expr e args =
 			old();
 			old();
 			typing_side_effect := !told;
 			typing_side_effect := !told;
 			(EBlock (List.rev el),p)
 			(EBlock (List.rev el),p)
-		| EFunction (v,f) ->
-			(match v with
-			| None -> ()
-			| Some (name,_) ->
-				decl name None (Some e));
+		| EFunction (kind,f) ->
+			(match kind with
+			| FKNamed ((name,_),_) ->
+				decl name None (Some e)
+			| _ -> ());
 			let old = save() in
 			let old = save() in
 			List.iter (fun ((n,_),_,_,t,e) -> decl n (Option.map fst t) e) f.f_args;
 			List.iter (fun ((n,_),_,_,t,e) -> decl n (Option.map fst t) e) f.f_args;
 			let e = map e in
 			let e = map e in

+ 2 - 4
src/syntax/grammar.mly

@@ -1096,9 +1096,7 @@ and parse_function p1 inl = parser
 				f_args = al;
 				f_args = al;
 				f_expr = Some e;
 				f_expr = Some e;
 			} in
 			} in
-			let e = EFunction ((match name with None -> None | Some (name,pn) -> Some (name,pn)),f), punion p1 (pos e) in
-			if inl then make_meta Meta.Inline [] e p1
-			else e
+			EFunction ((match name with None -> FKAnonymous | Some (name,pn) -> FKNamed ((name,pn),inl)),f), punion p1 (pos e)
 		in
 		in
 		make (secure_expr s)
 		make (secure_expr s)
 
 
@@ -1110,7 +1108,7 @@ and arrow_function p1 al er s =
 	let make e =
 	let make e =
 		let p = pos e in
 		let p = pos e in
 		let return = (EMeta((Meta.ImplicitReturn, [], null_pos), (EReturn(Some e), p)), p) in
 		let return = (EMeta((Meta.ImplicitReturn, [], null_pos), (EReturn(Some e), p)), p) in
-		EFunction(None, { f_params = []; f_type = None; f_args = al; f_expr = Some return;  }), punion p1 p
+		EFunction(FKArrow, { f_params = []; f_type = None; f_args = al; f_expr = Some return;  }), punion p1 p
 	in
 	in
 	List.iter (fun (_,_,ml,_,_) ->	match ml with
 	List.iter (fun (_,_,ml,_,_) ->	match ml with
 		| (_,_,p) :: _ -> syntax_error (Custom "Metadata on arrow function arguments is not allowed") ~pos:(Some p) s ()
 		| (_,_,p) :: _ -> syntax_error (Custom "Metadata on arrow function arguments is not allowed") ~pos:(Some p) s ()

+ 7 - 14
src/syntax/reification.ml

@@ -280,21 +280,14 @@ let reify in_macro =
 				] in
 				] in
 				to_obj fields p
 				to_obj fields p
 			) vl p]
 			) vl p]
-		| EFunction (name,f) ->
-			let name = match name with
-				| None ->
-					to_null null_pos
-				| Some (name,pn) ->
-					if ExtString.String.starts_with name "inline_$" then begin
-						let real_name = (String.sub name 7 (String.length name - 7)) in
-						let e_name = to_string real_name pn in
-						let e_inline = to_string "inline_" p in
-						let e_add = (EBinop(OpAdd,e_inline,e_name),p) in
-						e_add
-					end else
-						to_string name pn
+		| EFunction (kind,f) ->
+			let kind, args = match kind with
+				| FKAnonymous -> "FAnonymous", []
+				| FKArrow -> "FArrow", []
+				| FKNamed ((name,pn),inline) -> "FNamed", [to_string name pn; to_bool inline pn]
 			in
 			in
-			expr "EFunction" [name; to_fun f p]
+			let kind = mk_enum "FunctionKind" kind args p in
+			expr "EFunction" [kind; to_fun f p]
 		| EBlock el ->
 		| EBlock el ->
 			expr "EBlock" [to_expr_array el p]
 			expr "EBlock" [to_expr_array el p]
 		| EFor (e1,e2) ->
 		| EFor (e1,e2) ->

+ 2 - 2
src/typing/typeload.ml

@@ -560,8 +560,8 @@ and init_meta_overloads ctx co cf =
 	let cf_meta = List.filter filter_meta cf.cf_meta in
 	let cf_meta = List.filter filter_meta cf.cf_meta in
 	cf.cf_meta <- List.filter (fun m ->
 	cf.cf_meta <- List.filter (fun m ->
 		match m with
 		match m with
-		| (Meta.Overload,[(EFunction (fname,f),p)],_)  ->
-			if fname <> None then error "Function name must not be part of @:overload" p;
+		| (Meta.Overload,[(EFunction (kind,f),p)],_)  ->
+			(match kind with FKNamed _ -> error "Function name must not be part of @:overload" p | _ -> ());
 			(match f.f_expr with Some (EBlock [], _) -> () | _ -> error "Overload must only declare an empty method body {}" p);
 			(match f.f_expr with Some (EBlock [], _) -> () | _ -> error "Overload must only declare an empty method body {}" p);
 			let old = ctx.type_params in
 			let old = ctx.type_params in
 			(match cf.cf_params with
 			(match cf.cf_params with

+ 4 - 5
src/typing/typer.ml

@@ -1992,7 +1992,8 @@ and type_map_declaration ctx e1 el with_type p =
 	let el = (mk (TVar (v,Some enew)) t_dynamic p) :: (List.rev el) in
 	let el = (mk (TVar (v,Some enew)) t_dynamic p) :: (List.rev el) in
 	mk (TBlock el) tmap p
 	mk (TBlock el) tmap p
 
 
-and type_local_function ctx name inline f with_type p =
+and type_local_function ctx kind f with_type p =
+	let name,inline = match kind with FKNamed (name,inline) -> Some name,inline | _ -> None,false in
 	let params = TypeloadFunction.type_function_params ctx f (match name with None -> "localfun" | Some (n,_) -> n) p in
 	let params = TypeloadFunction.type_function_params ctx f (match name with None -> "localfun" | Some (n,_) -> n) p in
 	if params <> [] then begin
 	if params <> [] then begin
 		if name = None then display_error ctx "Type parameters not supported in unnamed local functions" p;
 		if name = None then display_error ctx "Type parameters not supported in unnamed local functions" p;
@@ -2334,8 +2335,6 @@ and type_meta ?(mode=MGet) ctx m e1 with_type p =
 			| ENew (t,el) ->
 			| ENew (t,el) ->
 				let e = type_new ctx t el with_type true p in
 				let e = type_new ctx t el with_type true p in
 				{e with eexpr = TMeta((Meta.Inline,[],null_pos),e)}
 				{e with eexpr = TMeta((Meta.Inline,[],null_pos),e)}
-			| EFunction(Some(_) as name,e1) ->
-				type_local_function ctx name true e1 with_type p
 			| _ ->
 			| _ ->
 				display_error ctx "Call or function expected after inline keyword" p;
 				display_error ctx "Call or function expected after inline keyword" p;
 				e();
 				e();
@@ -2558,8 +2557,8 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
 		type_new ctx t el with_type false p
 		type_new ctx t el with_type false p
 	| EUnop (op,flag,e) ->
 	| EUnop (op,flag,e) ->
 		type_unop ctx op flag e p
 		type_unop ctx op flag e p
-	| EFunction (name,f) ->
-		type_local_function ctx name false f with_type p
+	| EFunction (kind,f) ->
+		type_local_function ctx kind f with_type p
 	| EUntyped e ->
 	| EUntyped e ->
 		let old = ctx.untyped in
 		let old = ctx.untyped in
 		ctx.untyped <- true;
 		ctx.untyped <- true;

+ 19 - 1
std/haxe/macro/Expr.hx

@@ -377,6 +377,24 @@ typedef ObjectField = {
 	var ?quotes:QuoteStatus;
 	var ?quotes:QuoteStatus;
 }
 }
 
 
+/**
+	Represents function kind in the AST
+**/
+enum FunctionKind {
+	/**
+		Anonymous function
+	**/
+	FAnonymous;
+	/**
+		Named function
+	**/
+	FNamed(name:String, inlined:Bool);
+	/**
+		Arrow function
+	**/
+	FArrow;
+}
+
 /**
 /**
 	Represents the kind of a node in the AST.
 	Represents the kind of a node in the AST.
 **/
 **/
@@ -447,7 +465,7 @@ enum ExprDef {
 	/**
 	/**
 		A function declaration.
 		A function declaration.
 	**/
 	**/
-	EFunction(name:Null<String>, f:Function);
+	EFunction(kind:FunctionKind, f:Function);
 
 
 	/**
 	/**
 		A block of expressions `{exprs}`.
 		A block of expressions `{exprs}`.

+ 2 - 2
std/haxe/macro/ExprTools.hx

@@ -187,7 +187,7 @@ class ExprTools {
 					for (c in cases)
 					for (c in cases)
 						ret.push({expr: opt(c.expr, f), guard: opt(c.guard, f), values: ExprArrayTools.map(c.values, f)});
 						ret.push({expr: opt(c.expr, f), guard: opt(c.guard, f), values: ExprArrayTools.map(c.values, f)});
 					ESwitch(f(e), ret, edef == null || edef.expr == null ? edef : f(edef));
 					ESwitch(f(e), ret, edef == null || edef.expr == null ? edef : f(edef));
-				case EFunction(name, func):
+				case EFunction(kind, func):
 					var ret = [];
 					var ret = [];
 					for (arg in func.args)
 					for (arg in func.args)
 						ret.push({
 						ret.push({
@@ -196,7 +196,7 @@ class ExprTools {
 							type: arg.type,
 							type: arg.type,
 							value: opt(arg.value, f)
 							value: opt(arg.value, f)
 						});
 						});
-					EFunction(name, {
+					EFunction(kind, {
 						args: ret,
 						args: ret,
 						ret: func.ret,
 						ret: func.ret,
 						params: func.params,
 						params: func.params,

+ 2 - 2
std/haxe/macro/Printer.hx

@@ -217,7 +217,7 @@ class Printer {
 			case ENew(tp, el): 'new ${printTypePath(tp)}(${printExprs(el, ", ")})';
 			case ENew(tp, el): 'new ${printTypePath(tp)}(${printExprs(el, ", ")})';
 			case EUnop(op, true, e1): printExpr(e1) + printUnop(op);
 			case EUnop(op, true, e1): printExpr(e1) + printUnop(op);
 			case EUnop(op, false, e1): printUnop(op) + printExpr(e1);
 			case EUnop(op, false, e1): printUnop(op) + printExpr(e1);
-			case EFunction(no, func) if (no != null): 'function $no' + printFunction(func);
+			case EFunction(FNamed(no,inlined), func): (inlined ? 'inline ' : '') + 'function $no' + printFunction(func);
 			case EFunction(_, func): "function" + printFunction(func);
 			case EFunction(_, func): "function" + printFunction(func);
 			case EVars(vl): "var " + vl.map(printVar).join(", ");
 			case EVars(vl): "var " + vl.map(printVar).join(", ");
 			case EBlock([]): '{ }';
 			case EBlock([]): '{ }';
@@ -438,7 +438,7 @@ class Printer {
 							loopI(v.expr);
 							loopI(v.expr);
 						}
 						}
 					}
 					}
-				case EFunction(name, f):
+				case EFunction(_, f):
 					add("EFunction");
 					add("EFunction");
 					if (f.expr != null) {
 					if (f.expr != null) {
 						loopI(f.expr);
 						loopI(f.expr);