Skip to content

Commit

Permalink
support metadata in var declaration syntax
Browse files Browse the repository at this point in the history
closes #9618
  • Loading branch information
RealyUniqueName committed Jun 22, 2020
1 parent 6f1123b commit e344635
Show file tree
Hide file tree
Showing 18 changed files with 61 additions and 41 deletions.
6 changes: 3 additions & 3 deletions src/context/display/display.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/context/display/documentSymbols.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/context/display/syntaxExplorer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 9 additions & 7 deletions src/core/ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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

This comment has been minimized.

Copy link
@Simn

Simn Jun 22, 2020

Member

Feel free to turn this monster tuple into a record type next time you're bored. :D

| EFunction of function_kind * func
| EBlock of expr list
| EFor of expr * expr
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 ^ "\""
Expand Down Expand Up @@ -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 ^ "):") ^
Expand Down Expand Up @@ -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 -> ()
Expand Down
2 changes: 1 addition & 1 deletion src/core/tOther.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/macro/eval/evalDebugMisc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 5 additions & 2 deletions src/macro/macroApi.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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) ->
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 4 additions & 4 deletions src/optimization/optimizer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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 ->
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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
Expand Down
24 changes: 13 additions & 11 deletions src/syntax/grammar.mly
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/syntax/reification.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion src/typing/macroContext.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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 () ->
Expand Down
2 changes: 1 addition & 1 deletion src/typing/matcher.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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) ->
Expand Down
6 changes: 3 additions & 3 deletions src/typing/typeloadFields.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/typing/typeloadModule.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/typing/typer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions std/haxe/macro/Expr.hx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down
9 changes: 7 additions & 2 deletions std/haxe/macro/Printer.hx
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions tests/unit/src/unit/TestMacro.hx
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down

0 comments on commit e344635

Please sign in to comment.