Ver Fonte

support metadata in var declaration syntax
closes #9618

Aleksandr Kuzmenko há 5 anos atrás
pai
commit
e344635380

+ 3 - 3
src/context/display/display.ml

@@ -72,7 +72,7 @@ module ExprPreprocessing = struct
 			match fst e with
 			| EVars vl when is_annotated (pos e) && is_completion ->
 				let rec loop2 acc mark vl = match vl with
-					| ((s,pn),final,tho,eo) as v :: vl ->
+					| ((s,pn),final,tho,eo,ml) as v :: vl ->
 						if mark then
 							loop2 (v :: acc) mark vl
 						else if is_annotated pn then
@@ -96,7 +96,7 @@ module ExprPreprocessing = struct
 								in
 								let p = {p0 with pmax = (pos e).pmin} in
 								let e = if is_annotated p then annotate_marked e else e in
-								loop2 (((s,pn),final,tho,(Some e)) :: acc) mark vl
+								loop2 (((s,pn),final,tho,(Some e),ml) :: acc) mark vl
 						end
 					| [] ->
 						List.rev acc,mark
@@ -196,7 +196,7 @@ module ExprPreprocessing = struct
 				raise Exit
 			| EVars vl when is_annotated (pos e) ->
 				(* We only want to mark EVars if we're on a var name. *)
-				if List.exists (fun ((_,pn),_,_,_) -> is_annotated pn) vl then
+				if List.exists (fun ((_,pn),_,_,_,_) -> is_annotated pn) vl then
 					annotate_marked e
 				else
 					raise Exit

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

@@ -12,7 +12,7 @@ let collect_module_symbols mname with_locals (pack,decls) =
 		let add name kind location = add name kind location parent in
 		begin match e with
 		| EVars vl ->
-			List.iter (fun ((s,p),_,_,eo) ->
+			List.iter (fun ((s,p),_,_,eo,_) ->
 				add s Variable p false;
 				expr_opt parent eo
 			) vl

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

@@ -60,7 +60,7 @@ let find_in_syntax symbols (pack,decls) =
 			expr e1;
 			check KAnyField s;
 		| EVars vl ->
-			List.iter (fun (_,_,tho,eo) ->
+			List.iter (fun (_,_,tho,eo,_) ->
 				Option.may type_hint tho;
 				expr_opt eo
 			) vl;

+ 9 - 7
src/core/ast.ml

@@ -205,7 +205,7 @@ and expr_def =
 	| ECall of expr * expr list
 	| ENew of placed_type_path * expr list
 	| 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 * metadata) list
 	| EFunction of function_kind * func
 	| EBlock of expr list
 	| EFor of expr * expr
@@ -666,10 +666,10 @@ let map_expr loop (e,p) =
 		ENew (t,el)
 	| EUnop (op,f,e) -> EUnop (op,f,loop e)
 	| EVars vl ->
-		EVars (List.map (fun (n,b,t,eo) ->
+		EVars (List.map (fun (n,b,t,eo,ml) ->
 			let t = opt type_hint t in
 			let eo = opt loop eo in
-			n,b,t,eo
+			n,b,t,eo,ml
 		) vl)
 	| EFunction (kind,f) -> EFunction (kind,func f)
 	| EBlock el -> EBlock (List.map loop el)
@@ -750,7 +750,7 @@ let iter_expr loop (e,p) =
 	| EFunction(_,f) ->
 		List.iter (fun (_,_,_,_,eo) -> opt eo) f.f_args;
 		opt f.f_expr
-	| EVars vl -> List.iter (fun (_,_,_,eo) -> opt eo) vl
+	| EVars vl -> List.iter (fun (_,_,_,eo,_) -> opt eo) vl
 
 let s_object_key_name name =  function
 	| DoubleQuotes -> "\"" ^ StringHelper.s_escape name ^ "\""
@@ -885,8 +885,10 @@ module Printer = struct
 		if List.length tl > 0 then "<" ^ String.concat ", " (List.map (s_type_param tabs) tl) ^ ">" else ""
 	and s_func_arg tabs ((n,_),o,_,t,e) =
 		if o then "?" else "" ^ n ^ s_opt_type_hint tabs t ":" ^ s_opt_expr tabs e " = "
-	and s_var tabs ((n,_),_,t,e) =
-		n ^ (s_opt_type_hint tabs t ":") ^ s_opt_expr tabs e " = "
+	and s_var tabs ((n,_),_,t,e,ml) =
+		let s = n ^ (s_opt_type_hint tabs t ":") ^ s_opt_expr tabs e " = " in
+		if ml = [] then s
+		else (String.concat " " (List.map (s_metadata tabs) ml)) ^ " " ^ s
 	and s_case tabs (el,e1,e2,_) =
 		"case " ^ s_expr_list tabs el ", " ^
 		(match e1 with None -> ":" | Some e -> " if (" ^ s_expr_inner tabs e ^ "):") ^
@@ -1032,7 +1034,7 @@ module Expr = struct
 				loop e1
 			| EVars vl ->
 				add "EVars";
-				List.iter (fun ((n,p),_,cto,eo) ->
+				List.iter (fun ((n,p),_,cto,eo,_) ->
 					add (Printf.sprintf "%s  %s%s" tabs n (match cto with None -> "" | Some (ct,_) -> ":" ^ Printer.s_complex_type "" ct));
 					match eo with
 					| None -> ()

+ 1 - 1
src/core/tOther.ml

@@ -103,7 +103,7 @@ module TExprToExpr = struct
 			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 (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) ->
-			EVars ([(v.v_name,v.v_pos), has_var_flag v VFinal, mk_type_hint v.v_type v.v_pos, eopt eo])
+			EVars ([(v.v_name,v.v_pos), has_var_flag v VFinal, mk_type_hint v.v_type v.v_pos, eopt eo, v.v_meta])
 		| TBlock el -> EBlock (List.map convert_expr el)
 		| TFor (v,it,e) ->
 			let ein = (EBinop (OpIn,(EConst (Ident v.v_name),it.epos),convert_expr it),it.epos) in

+ 1 - 1
src/macro/eval/evalDebugMisc.ml

@@ -329,7 +329,7 @@ let rec expr_to_value ctx env e =
 			let v1 = loop e1 in
 			throw v1 (pos e)
 		| EVars vl ->
-			List.iter (fun ((n,_),_,_,eo) ->
+			List.iter (fun ((n,_),_,_,eo,_) ->
 				match eo with
 				| Some e ->
 					env.env_extra_locals <- IntMap.add (hash n) (loop e) env.env_extra_locals

+ 5 - 2
src/macro/macroApi.ml

@@ -439,13 +439,14 @@ and encode_expr e =
 			| EUnop (op,flag,e) ->
 				9, [encode_unop op; vbool (match flag with Prefix -> false | Postfix -> true); loop e]
 			| EVars vl ->
-				10, [encode_array (List.map (fun (v,final,t,eo) ->
+				10, [encode_array (List.map (fun (v,final,t,eo,ml) ->
 					encode_obj [
 						"name",encode_placed_name v;
 						"name_pos",encode_pos (pos v);
 						"isFinal",vbool final;
 						"type",null encode_ctype t;
 						"expr",null loop eo;
+						"meta",encode_meta_content ml;
 					]
 				) vl)]
 			| EFunction (kind,f) ->
@@ -773,7 +774,9 @@ and decode_expr v =
 			EVars (List.map (fun v ->
 				let vfinal = field v "isFinal" 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"))
+				let vmeta = field v "meta" in
+				let meta = if vmeta == vnull then [] else decode_meta_content vmeta in
+				((decode_placed_name (field v "name_pos") (field v "name")),final,opt decode_ctype (field v "type"),opt loop (field v "expr"),meta)
 			) (decode_array vl))
 		| 11, [kind;f] ->
 			EFunction (decode_function_kind kind,decode_fun f)

+ 4 - 4
src/optimization/optimizer.ml

@@ -669,10 +669,10 @@ let optimize_completion_expr e args =
 				());
 			map e
 		| EVars vl ->
-			let vl = List.map (fun ((v,pv),final,t,e) ->
+			let vl = List.map (fun ((v,pv),final,t,e,ml) ->
 				let e = (match e with None -> None | Some e -> Some (loop e)) in
 				decl v (Option.map fst t) e;
-				((v,pv),final,t,e)
+				((v,pv),final,t,e,ml)
 			) vl in
 			(EVars vl,p)
 		| EBlock el ->
@@ -719,7 +719,7 @@ let optimize_completion_expr e args =
 						(fun (name, pos) ->
 							let etmp = (EConst (Ident "`tmp"),pos) in
 							decl name None (Some (EBlock [
-								(EVars [("`tmp",null_pos),false,None,None],p);
+								(EVars [("`tmp",null_pos),false,None,None,[]],p);
 								(EFor(header,(EBinop (OpAssign,etmp,(EConst (Ident name),p)),p)), p);
 								etmp
 							],p));
@@ -817,7 +817,7 @@ let optimize_completion_expr e args =
 							with Not_found ->
 								let e = subst_locals lc e in
 								let name = "`tmp_" ^ string_of_int id in
-								tmp_locals := ((name,null_pos),false,None,Some e) :: !tmp_locals;
+								tmp_locals := ((name,null_pos),false,None,Some e,[]) :: !tmp_locals;
 								tmp_hlocals := PMap.add id name !tmp_hlocals;
 								name
 							) in

+ 13 - 11
src/syntax/grammar.mly

@@ -1151,33 +1151,35 @@ and parse_array_decl p1 s =
 	in
 	EArrayDecl (List.rev el),punion p1 p2
 
-and parse_var_decl_head final = parser
-	| [< name, p = dollar_ident; t = popt parse_type_hint >] -> (name,final,t,p)
+and parse_var_decl_head final s =
+	let meta = parse_meta s in
+	match s with parser
+	| [< name, p = dollar_ident; t = popt parse_type_hint >] -> (meta,name,final,t,p)
 
 and parse_var_assignment = parser
 	| [< '(Binop OpAssign,p1); s >] ->
 		Some (secure_expr s)
 	| [< >] -> None
 
-and parse_var_assignment_resume final vl name pn t s =
+and parse_var_assignment_resume final vl name pn t meta s =
 	let eo = parse_var_assignment s in
-	((name,pn),final,t,eo)
+	((name,pn),final,t,eo,meta)
 
 and parse_var_decls_next final vl = parser
-	| [< '(Comma,p1); name,final,t,pn = parse_var_decl_head final; s >] ->
-		let v_decl = parse_var_assignment_resume final vl name pn t s in
+	| [< '(Comma,p1); meta,name,final,t,pn = parse_var_decl_head final; s >] ->
+		let v_decl = parse_var_assignment_resume final vl name pn t meta s in
 		parse_var_decls_next final (v_decl :: vl) s
 	| [< >] ->
 		vl
 
 and parse_var_decls final p1 = parser
-	| [< name,final,t,pn = parse_var_decl_head final; s >] ->
-		let v_decl = parse_var_assignment_resume final [] name pn t s in
+	| [< meta,name,final,t,pn = parse_var_decl_head final; s >] ->
+		let v_decl = parse_var_assignment_resume final [] name pn t meta s in
 		List.rev (parse_var_decls_next final [v_decl] s)
 	| [< s >] -> error (Custom "Missing variable identifier") p1
 
 and parse_var_decl final = parser
-	| [< name,final,t,pn = parse_var_decl_head final; v_decl = parse_var_assignment_resume final [] name pn t >] -> v_decl
+	| [< meta,name,final,t,pn = parse_var_decl_head final; v_decl = parse_var_assignment_resume final [] name pn t meta >] -> v_decl
 
 and inline_function = parser
 	| [< '(Kwd Inline,_); '(Kwd Function,p1) >] -> true, p1
@@ -1499,8 +1501,8 @@ and parse_guard = parser
 		e
 
 and expr_or_var = parser
-	| [< '(Kwd Var,p1); name,p2 = dollar_ident; >] -> EVars [(name,p2),false,None,None],punion p1 p2
-	| [< '(Kwd Final,p1); name,p2 = dollar_ident; >] -> EVars [(name,p2),true,None,None],punion p1 p2
+	| [< '(Kwd Var,p1); name,p2 = dollar_ident; >] -> EVars [(name,p2),false,None,None,[]],punion p1 p2
+	| [< '(Kwd Final,p1); name,p2 = dollar_ident; >] -> EVars [(name,p2),true,None,None,[]],punion p1 p2
 	| [< e = secure_expr >] -> e
 
 and parse_switch_cases eswitch cases = parser

+ 2 - 1
src/syntax/reification.ml

@@ -278,12 +278,13 @@ let reify in_macro =
 			) [] p in
 			expr "EUnop" [op;to_bool (flag = Postfix) p;loop e]
 		| EVars vl ->
-			expr "EVars" [to_array (fun ((n,pn),final,th,e) p ->
+			expr "EVars" [to_array (fun ((n,pn),final,th,e,ml) p ->
 				let fields = [
 					"name", to_string n pn;
 					"type", to_opt to_type_hint th p;
 					"expr", to_opt to_expr e p;
 					"isFinal",to_bool final p;
+					"meta",to_meta ml p;
 				] in
 				to_obj fields p
 			) vl p]

+ 1 - 1
src/typing/macroContext.ml

@@ -730,7 +730,7 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p =
 							else
 								List.map Interp.decode_field (Interp.decode_array v)
 						in
-						Some (EVars [("fields",null_pos),false,Some (CTAnonymous fields,p),None],p)
+						Some (EVars [("fields",null_pos),false,Some (CTAnonymous fields,p),None,[]],p)
 					)
 				| MMacroType ->
 					"ComplexType",(fun () ->

+ 1 - 1
src/typing/matcher.ml

@@ -336,7 +336,7 @@ module Pattern = struct
 						if i = "_" then PatAny
 						else handle_ident i (pos e)
 				end
-			| EVars([(s,p),final,None,None]) ->
+			| EVars([(s,p),final,None,None,[]]) ->
 				let v = add_local final s p in
 				PatVariable v
 			| ECall(e1,el) ->

+ 3 - 3
src/typing/typeloadFields.ml

@@ -226,7 +226,7 @@ let transform_abstract_field com this_t a_t a f =
 	| FProp _ when not stat ->
 		error "Member property accessors must be get/set or never" p;
 	| FFun fu when fst f.cff_name = "new" && not stat ->
-		let init p = (EVars [("this",null_pos),false,Some this_t,None],p) in
+		let init p = (EVars [("this",null_pos),false,Some this_t,None,[]],p) in
 		let cast e = (ECast(e,None)),pos e in
 		let ret p = (EReturn (Some (cast (EConst (Ident "this"),p))),p) in
 		let meta = (Meta.Impl,[],null_pos) :: (Meta.NoCompletion,[],null_pos) :: f.cff_meta in
@@ -419,7 +419,7 @@ let build_enum_abstract ctx c a fields p =
 		| _ ->
 			()
 	) fields;
-	EVars [("",null_pos),false,Some (CTAnonymous fields,p),None],p
+	EVars [("",null_pos),false,Some (CTAnonymous fields,p),None,[]],p
 
 let apply_macro ctx mode path el p =
 	let cpath, meth = (match List.rev (ExtString.String.nsplit path ".") with
@@ -664,7 +664,7 @@ let build_fields (ctx,cctx) c fields =
 	c.cl_build <- (fun() -> BuildMacro pending);
 	build_module_def ctx (TClassDecl c) c.cl_meta get_fields cctx.context_init (fun (e,p) ->
 		match e with
-		| EVars [_,_,Some (CTAnonymous f,p),None] ->
+		| EVars [_,_,Some (CTAnonymous f,p),None,_] ->
 			let f = List.map (fun f -> transform_field (ctx,cctx) c f fields p) f in
 			fields := f
 		| _ -> error "Class build macro must return a single variable with anonymous fields" p

+ 1 - 1
src/typing/typeloadModule.ml

@@ -736,7 +736,7 @@ let init_module_type ctx context_init (decl,p) =
 		in
 		TypeloadFields.build_module_def ctx (TEnumDecl e) e.e_meta get_constructs context_init (fun (e,p) ->
 			match e with
-			| EVars [_,_,Some (CTAnonymous fields,p),None] ->
+			| EVars [_,_,Some (CTAnonymous fields,p),None,_] ->
 				constructs := List.map (fun f ->
 					let args, params, t = (match f.cff_kind with
 					| FVar (t,None) -> [], [], t

+ 2 - 1
src/typing/typer.ml

@@ -1443,7 +1443,7 @@ and type_array_access ctx e1 e2 p mode =
 	Calls.array_access ctx e1 e2 mode p
 
 and type_vars ctx vl p =
-	let vl = List.map (fun ((v,pv),final,t,e) ->
+	let vl = List.map (fun ((v,pv),final,t,e,ml) ->
 		try
 			let t = Typeload.load_type_hint ctx p t in
 			let e = (match e with
@@ -1454,6 +1454,7 @@ and type_vars ctx vl p =
 					Some e
 			) in
 			let v = add_local_with_origin ctx TVOLocalVariable v t pv in
+			v.v_meta <- ml;
 			if final then add_var_flag v VFinal;
 			if ctx.in_display && DisplayPosition.display_position#enclosed_in pv then
 				DisplayEmitter.display_variable ctx v pv;

+ 5 - 0
std/haxe/macro/Expr.hx

@@ -315,6 +315,11 @@ typedef Var = {
 		Whether or not the variable can be assigned to.
 	**/
 	var ?isFinal:Bool;
+
+	/**
+		Metadata associatied with the variable, if available.
+	**/
+	var ?meta:Metadata;
 }
 
 /**

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

@@ -208,8 +208,13 @@ class Printer {
 			+ opt(func.expr, printExpr, " ");
 	}
 
-	public function printVar(v:Var)
-		return v.name + opt(v.type, printComplexType, ":") + opt(v.expr, printExpr, " = ");
+	public function printVar(v:Var) {
+		var s = v.name + opt(v.type, printComplexType, ":") + opt(v.expr, printExpr, " = ");
+		return switch v.meta {
+			case null|[]: s;
+			case meta: meta.map(printMetadata).join(" ") + " " + s;
+		}
+	}
 
 	public function printObjectFieldKey(of:ObjectField) {
 		return switch (of.quotes) {

+ 1 - 0
tests/unit/src/unit/TestMacro.hx

@@ -38,6 +38,7 @@ class TestMacro extends Test {
 		parseAndPrint("var a:A");
 		parseAndPrint("var a = b");
 		parseAndPrint("var a:A = b");
+		parseAndPrint("var @:a(b) c:D = e");
 		parseAndPrint("function() { }");
 		parseAndPrint("for (a in b) { }");
 		parseAndPrint("if (a) b");