瀏覽代碼

* add quoted status to EObjectDecl fields
* add quoted status and position to TObjectDecl fields
* remove awkward quoted status encoding
* unify Lexer.is_valid_identifier (we had that function 3 times...)
* add some tests for haxe.macro.Printer

closes #2642
closes #5424

Simon Krajewski 8 年之前
父節點
當前提交
9878c4fda7

+ 9 - 9
src/codegen/codegen.ml

@@ -124,7 +124,7 @@ let rec type_constant_value com (e,p) =
 	| EParenthesis e ->
 		type_constant_value com e
 	| EObjectDecl el ->
-		mk (TObjectDecl (List.map (fun ((n,_),e) -> n, type_constant_value com e) el)) (TAnon { a_fields = PMap.empty; a_status = ref Closed }) p
+		mk (TObjectDecl (List.map (fun (k,e) -> k,type_constant_value com e) el)) (TAnon { a_fields = PMap.empty; a_status = ref Closed }) p
 	| EArrayDecl el ->
 		mk (TArrayDecl (List.map (type_constant_value com) el)) (com.basic.tarray t_dynamic) p
 	| _ ->
@@ -160,7 +160,7 @@ let add_property_field com c =
 	| _ ->
 		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, ExprBuilder.make_string com v p) :: values
+			PMap.add n cf fields,((n,null_pos,NoQuotes),ExprBuilder.make_string com v p) :: values
 		) (PMap.empty,[]) props in
 		let t = mk_anon fields in
 		let e = mk (TObjectDecl values) t p in
@@ -205,19 +205,19 @@ let build_metadata com t =
 		mk (TObjectDecl (List.map (fun (f,el,p) ->
 			if Hashtbl.mem h f then error ("Duplicate metadata '" ^ f ^ "'") p;
 			Hashtbl.add h f ();
-			f, mk (match el with [] -> TConst TNull | _ -> TArrayDecl (List.map (type_constant_value com) el)) (api.tarray t_dynamic) p
+			(f,null_pos,NoQuotes), mk (match el with [] -> TConst TNull | _ -> TArrayDecl (List.map (type_constant_value com) el)) (api.tarray t_dynamic) p
 		) ml)) t_dynamic p
 	in
 	let make_meta l =
-		mk (TObjectDecl (List.map (fun (f,ml) -> f,make_meta_field ml) l)) t_dynamic p
+		mk (TObjectDecl (List.map (fun (f,ml) -> (f,null_pos,NoQuotes),make_meta_field ml) l)) t_dynamic p
 	in
 	if meta = [] && fields = [] && statics = [] then
 		None
 	else
 		let meta_obj = [] in
-		let meta_obj = (if fields = [] then meta_obj else ("fields",make_meta fields) :: meta_obj) in
-		let meta_obj = (if statics = [] then meta_obj else ("statics",make_meta statics) :: meta_obj) in
-		let meta_obj = (try ("obj", make_meta_field (List.assoc "" meta)) :: meta_obj with Not_found -> meta_obj) in
+		let meta_obj = (if fields = [] then meta_obj else (("fields",null_pos,NoQuotes),make_meta fields) :: meta_obj) in
+		let meta_obj = (if statics = [] then meta_obj else (("statics",null_pos,NoQuotes),make_meta statics) :: meta_obj) in
+		let meta_obj = (try (("obj",null_pos,NoQuotes), make_meta_field (List.assoc "" meta)) :: meta_obj with Not_found -> meta_obj) in
 		Some (mk (TObjectDecl meta_obj) t_dynamic p)
 
 let update_cache_dependencies t =
@@ -801,14 +801,14 @@ module UnificationCallback = struct
 			| TObjectDecl fl ->
 				begin match follow e.etype with
 					| TAnon an ->
-						let fl = List.map (fun (n,e) ->
+						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,e
+							(n,p,qs),e
 						) fl in
 						{ e with eexpr = TObjectDecl fl }
 					| _ -> e

+ 1 - 1
src/codegen/gencommon/reflectionCFs.ml

@@ -700,7 +700,7 @@ let implement_dynamic_object_ctor ctx cl =
 	let do_objdecl e objdecl =
 		let exprs_before = ref [] in
 		let rec change_exprs decl acc = match decl with
-			| (name,expr) :: tl ->
+			| ((name,_,_),expr) :: tl ->
 				if is_side_effects_free expr then
 					change_exprs tl ((name,expr) :: acc)
 				else begin

+ 23 - 5
src/core/ast.ml

@@ -137,6 +137,10 @@ type while_flag =
 	| NormalWhile
 	| DoWhile
 
+type quote_status =
+	| NoQuotes
+	| DoubleQuotes
+
 type type_path = {
 	tpackage : string list;
 	tname : string;
@@ -175,7 +179,7 @@ and expr_def =
 	| EBinop of binop * expr * expr
 	| EField of expr * string
 	| EParenthesis of expr
-	| EObjectDecl of (placed_name * expr) list
+	| EObjectDecl of ((string * pos * quote_status) * expr) list
 	| EArrayDecl of expr list
 	| ECall of expr * expr list
 	| ENew of placed_type_path * expr list
@@ -589,7 +593,7 @@ let map_expr loop (e,p) =
 		EBinop (op,e1,e2)
 	| EField (e,f) -> EField (loop e, f)
 	| EParenthesis e -> EParenthesis (loop e)
-	| EObjectDecl fl -> EObjectDecl (List.map (fun ((f,p),e) -> (f,p),loop e) fl)
+	| EObjectDecl fl -> EObjectDecl (List.map (fun (k,e) -> k,loop e) fl)
 	| EArrayDecl el -> EArrayDecl (List.map loop el)
 	| ECall (e,el) ->
 		let e = loop e in
@@ -687,6 +691,10 @@ let iter_expr loop (e,p) =
 		opt f.f_expr
 	| EVars vl -> List.iter (fun (_,_,eo) -> opt eo) vl
 
+let s_object_key_name name =  function
+	| DoubleQuotes -> "\"" ^ s_escape name ^ "\""
+	| NoQuotes -> name
+
 let s_expr e =
 	let rec s_expr_inner tabs (e,_) =
 		match e with
@@ -695,7 +703,7 @@ let s_expr e =
 		| EBinop (op,e1,e2) -> s_expr_inner tabs e1 ^ " " ^ s_binop op ^ " " ^ s_expr_inner tabs e2
 		| EField (e,f) -> s_expr_inner tabs e ^ "." ^ f
 		| EParenthesis e -> "(" ^ (s_expr_inner tabs e) ^ ")"
-		| EObjectDecl fl -> "{ " ^ (String.concat ", " (List.map (fun ((n,_),e) -> n ^ " : " ^ (s_expr_inner tabs e)) fl)) ^ " }"
+		| EObjectDecl fl -> "{ " ^ (String.concat ", " (List.map (fun ((n,_,qs),e) -> (s_object_key_name n qs) ^ " : " ^ (s_expr_inner tabs e)) fl)) ^ " }"
 		| EArrayDecl el -> "[" ^ s_expr_list tabs el ", " ^ "]"
 		| ECall (e,el) -> s_expr_inner tabs e ^ "(" ^ s_expr_list tabs el ", " ^ ")"
 		| ENew (t,el) -> "new " ^ s_complex_type_path tabs t ^ "(" ^ s_expr_list tabs el ", " ^ ")"
@@ -802,7 +810,7 @@ let s_expr e =
 let get_value_meta meta =
 	try
 		begin match Meta.get Meta.Value meta with
-			| (_,[EObjectDecl values,_],_) -> List.fold_left (fun acc ((s,_),e) -> PMap.add s e acc) PMap.empty values
+			| (_,[EObjectDecl values,_],_) -> List.fold_left (fun acc ((s,_,_),e) -> PMap.add s e acc) PMap.empty values
 			| _ -> raise Not_found
 		end
 	with Not_found ->
@@ -862,8 +870,18 @@ module Expr = struct
 
 	let field_assoc name fl =
 		let rec loop fl = match fl with
-			| ((name',_),e) :: fl -> if name' = name then e else loop fl
+			| ((name',_,_),e) :: fl -> if name' = name then e else loop fl
 			| [] -> raise Not_found
 		in
 		loop fl
+
+	let field_mem_assoc name fl =
+		let rec loop fl = match fl with
+			| ((name',_,_),e) :: fl -> if name' = name then raise Exit else loop fl
+			| [] -> false
+		in
+		try
+			loop fl
+		with Exit ->
+			true
 end

+ 0 - 2
src/core/meta.ml

@@ -130,7 +130,6 @@ type strict_meta =
 	| Public
 	| PublicFields
 	| Pure
-	| QuotedField
 	| ReadOnly
 	| RealPath
 	| Remove
@@ -323,7 +322,6 @@ let get_info = function
 	| Pos -> ":pos",("Sets the position of a reified expression",[HasParam "Position";UsedOn TExpr])
 	| Public -> ":public",("Marks a class field as being public",[UsedOn TClassField;UsedInternally])
 	| PublicFields -> ":publicFields",("Forces all class fields of inheriting classes to be public",[UsedOn TClass])
-	| QuotedField -> ":quotedField",("Used internally to mark structure fields which are quoted in syntax",[UsedInternally])
 	| PrivateAccess -> ":privateAccess",("Allow private access to anything for the annotated expression",[UsedOn TExpr])
 	| Protected -> ":protected",("Marks a class field as being protected",[UsedOn TClassField;Platforms [Cs;Java;Flash]])
 	| Property -> ":property",("Marks a property field to be compiled as a native C# property",[UsedOn TClassField;Platform Cs])

+ 5 - 5
src/core/type.ml

@@ -125,7 +125,7 @@ and texpr_expr =
 	| TField of texpr * tfield_access
 	| TTypeExpr of module_type
 	| TParenthesis of texpr
-	| TObjectDecl of (string * texpr) list
+	| TObjectDecl of ((string * pos * quote_status) * texpr) list
 	| TArrayDecl of texpr list
 	| TCall of texpr * texpr list
 	| TNew of tclass * tparams * texpr list
@@ -1061,7 +1061,7 @@ let rec s_expr s_type e =
 	| TParenthesis e ->
 		sprintf "Parenthesis %s" (loop e)
 	| TObjectDecl fl ->
-		sprintf "ObjectDecl {%s}" (slist (fun (f,e) -> sprintf "%s : %s" f (loop e)) fl)
+		sprintf "ObjectDecl {%s}" (slist (fun ((f,_,qs),e) -> sprintf "%s : %s" (s_object_key_name f qs) (loop e)) fl)
 	| TArrayDecl el ->
 		sprintf "ArrayDecl [%s]" (slist loop el)
 	| TCall (e,el) ->
@@ -1126,7 +1126,7 @@ let rec s_expr_pretty print_var_ids tabs top_level s_type e =
 	| TField (e1,s) -> sprintf "%s.%s" (loop e1) (field_name s)
 	| TTypeExpr mt -> (s_type_path (t_path mt))
 	| TParenthesis e1 -> sprintf "(%s)" (loop e1)
-	| TObjectDecl fl -> sprintf "{%s}" (clist (fun (f,e) -> sprintf "%s : %s" f (loop e)) fl)
+	| TObjectDecl fl -> sprintf "{%s}" (clist (fun ((f,_,qs),e) -> sprintf "%s : %s" (s_object_key_name f qs) (loop e)) fl)
 	| TArrayDecl el -> sprintf "[%s]" (clist loop el)
 	| TCall (e1,el) -> sprintf "%s(%s)" (loop e1) (clist loop el)
 	| TNew (c,pl,el) ->
@@ -1221,7 +1221,7 @@ let rec s_expr_ast print_var_ids tabs s_type e =
 		tag "Field" [loop e1; sfa]
 	| TTypeExpr mt -> module_type mt
 	| TParenthesis e1 -> tag "Parenthesis" [loop e1]
-	| TObjectDecl fl -> tag "ObjectDecl" (List.map (fun (s,e) -> sprintf "%s: %s" s (loop e)) fl)
+	| TObjectDecl fl -> tag "ObjectDecl" (List.map (fun ((s,_,qs),e) -> sprintf "%s: %s" (s_object_key_name s qs) (loop e)) fl)
 	| TArrayDecl el -> tag "ArrayDecl" (List.map loop el)
 	| TCall (e1,el) -> tag "Call" (loop e1 :: (List.map loop el))
 	| TNew (c,tl,el) -> tag "New" ((s_type (TInst(c,tl))) :: (List.map loop el))
@@ -2545,7 +2545,7 @@ module TExprToExpr = struct
 		| TField (e,f) -> EField (convert_expr e, field_name f)
 		| TTypeExpr t -> fst (mk_path (full_type_path t) e.epos)
 		| TParenthesis e -> EParenthesis (convert_expr e)
-		| TObjectDecl fl -> EObjectDecl (List.map (fun (f,e) -> (f,null_pos), convert_expr e) fl)
+		| TObjectDecl fl -> EObjectDecl (List.map (fun (k,e) -> k, convert_expr e) fl)
 		| TArrayDecl el -> EArrayDecl (List.map convert_expr el)
 		| TCall (e,el) -> ECall (convert_expr e,List.map convert_expr el)
 		| TNew (c,pl,el) -> ENew ((match (try convert_type (TInst (c,pl)) with Exit -> convert_type (TInst (c,[]))) with CTPath p -> p,null_pos | _ -> assert false),List.map convert_expr el)

+ 1 - 1
src/generators/genas3.ml

@@ -754,7 +754,7 @@ and gen_expr ctx e =
 		handle_break();
 	| TObjectDecl fields ->
 		spr ctx "{ ";
-		concat ctx ", " (fun (f,e) -> print ctx "%s : " (anon_field f); gen_value ctx e) fields;
+		concat ctx ", " (fun ((f,_,_),e) -> print ctx "%s : " (anon_field f); gen_value ctx e) fields;
 		spr ctx "}"
 	| TFor (v,it,e) ->
 		let handle_break = handle_break ctx e in

+ 10 - 10
src/generators/gencpp.ml

@@ -3006,14 +3006,14 @@ let retype_expression ctx request_type function_args function_type expression_tr
             CppBlock(cppExprs, List.rev !local_closures, !gc_stack ), TCppVoid
 
          | TObjectDecl (
-            ("fileName" , { eexpr = (TConst (TString file)) }) ::
-               ("lineNumber" , { eexpr = (TConst (TInt line)) }) ::
-                  ("className" , { eexpr = (TConst (TString class_name)) }) ::
-                     ("methodName", { eexpr = (TConst (TString meth)) }) :: [] ) ->
+            (("fileName",_,_) , { eexpr = (TConst (TString file)) }) ::
+               (("lineNumber",_,_) , { eexpr = (TConst (TInt line)) }) ::
+                  (("className",_,_) , { eexpr = (TConst (TString class_name)) }) ::
+                     (("methodName",_,_), { eexpr = (TConst (TString meth)) }) :: [] ) ->
               CppPosition(file,line,class_name,meth), TCppDynamic
 
          | TObjectDecl el ->
-            let retypedEls = List.map ( fun(v,e) -> v, retype TCppDynamic e) el in
+            let retypedEls = List.map ( fun((v,_,_),e) -> v, retype TCppDynamic e) el in
             (match return_type with
             | TCppVoid -> CppObjectDecl(retypedEls,false), TCppVoid
             | _ -> CppObjectDecl(retypedEls,false), TCppDynamic
@@ -7533,16 +7533,16 @@ class script_writer ctx filename asciiOut =
               this#checkCast return_type value false false;
          )
    | TObjectDecl (
-      ("fileName" , { eexpr = (TConst (TString file)) }) ::
-         ("lineNumber" , { eexpr = (TConst (TInt line)) }) ::
-            ("className" , { eexpr = (TConst (TString class_name)) }) ::
-               ("methodName", { eexpr = (TConst (TString meth)) }) :: [] ) ->
+      (("fileName",_,_) , { eexpr = (TConst (TString file)) }) ::
+         (("lineNumber",_,_) , { eexpr = (TConst (TInt line)) }) ::
+            (("className",_,_) , { eexpr = (TConst (TString class_name)) }) ::
+               (("methodName",_,_), { eexpr = (TConst (TString meth)) }) :: [] ) ->
             this#write ( (this#op IaPosInfo) ^ (this#stringText file) ^ (Printf.sprintf "%ld" line) ^ " " ^
                         (this#stringText class_name) ^ " " ^  (this#stringText meth))
 
    | TObjectDecl values ->this#write ( (this#op IaObjDef) ^ (string_of_int (List.length values)));
          this#write " ";
-         List.iter (fun (name,_) -> this#write (this#stringText name)  ) values;
+         List.iter (fun ((name,_,_),_) -> this#write (this#stringText name)  ) values;
          this#write "\n";
          List.iter (fun (_,e) -> this#gen_expression e ) values;
    | TTypeExpr type_expr ->

+ 3 - 3
src/generators/genhl.ml

@@ -2052,11 +2052,11 @@ and eval_expr ctx e =
 		unsafe_cast_to ctx r (to_type ctx e.etype) e.epos
 	| TObjectDecl fl ->
 		(match to_type ctx e.etype with
-		| HVirtual vp as t when Array.length vp.vfields = List.length fl && not (List.exists (fun (s,e) -> s = "toString" && is_to_string e.etype) fl)  ->
+		| HVirtual vp as t when Array.length vp.vfields = List.length fl && not (List.exists (fun ((s,_,_),e) -> s = "toString" && is_to_string e.etype) fl)  ->
 			let r = alloc_tmp ctx t in
 			op ctx (ONew r);
 			hold ctx r;
-			List.iter (fun (s,ev) ->
+			List.iter (fun ((s,_,_),ev) ->
 				let fidx = (try PMap.find s vp.vindex with Not_found -> assert false) in
 				let _, _, ft = vp.vfields.(fidx) in
 				let v = eval_to ctx ev ft in
@@ -2069,7 +2069,7 @@ and eval_expr ctx e =
 			op ctx (ONew r);
 			hold ctx r;
 			let a = (match follow e.etype with TAnon a -> Some a | t -> if t == t_dynamic then None else assert false) in
-			List.iter (fun (s,ev) ->
+			List.iter (fun ((s,_,_),ev) ->
 				let ft = (try (match a with None -> raise Not_found | Some a -> PMap.find s a.a_fields).cf_type with Not_found -> ev.etype) in
 				let v = eval_to ctx ev (to_type ctx ft) in
 				op ctx (ODynSet (r,alloc_string ctx s,v));

+ 5 - 5
src/generators/genjs.ml

@@ -436,8 +436,8 @@ let rec gen_call ctx e el in_value =
 			spr ctx "console.log(";
 			(match infos.eexpr with
 			| TObjectDecl (
-				("fileName" , { eexpr = (TConst (TString file)) }) ::
-				("lineNumber" , { eexpr = (TConst (TInt line)) }) :: _) ->
+				(("fileName",_,_) , { eexpr = (TConst (TString file)) }) ::
+				(("lineNumber",_,_) , { eexpr = (TConst (TInt line)) }) :: _) ->
 					print ctx "\"%s:%i:\"," file (Int32.to_int line)
 			| _ ->
 				());
@@ -654,9 +654,9 @@ and gen_expr ctx e =
 		ctx.in_loop <- old_in_loop
 	| TObjectDecl fields ->
 		spr ctx "{ ";
-		concat ctx ", " (fun (f,e) -> (match e.eexpr with
-			| TMeta((Meta.QuotedField,_,_),e) -> print ctx "\"%s\" : " (Ast.s_escape f);
-			| _ -> print ctx "%s : " (anon_field f));
+		concat ctx ", " (fun ((f,_,qs),e) -> (match qs with
+			| DoubleQuotes -> print ctx "\"%s\" : " (Ast.s_escape f);
+			| NoQuotes -> print ctx "%s : " (anon_field f));
 			gen_value ctx e
 		) fields;
 		spr ctx "}";

+ 4 - 4
src/generators/genlua.ml

@@ -389,7 +389,7 @@ let rec gen_call ctx e el =
                   if List.length(arr) > 0 then incr count;
               | { eexpr = TObjectDecl fields } ->
                   if (!count > 0 && List.length(fields) > 0) then spr ctx ",";
-                  concat ctx ", " (fun (f,e) ->
+                  concat ctx ", " (fun ((f,_,_),e) ->
                       print ctx "%s = " (anon_field f);
                       gen_value ctx e
                   ) fields;
@@ -624,7 +624,7 @@ and gen_expr ?(local=true) ctx e = begin
         spr ctx "(function(x) return x.";
         print ctx "%s" (field_name ef);
         spr ctx " end )({";
-        concat ctx ", " (fun (f,e) -> print ctx "%s = " (anon_field f); gen_value ctx e) fields;
+        concat ctx ", " (fun ((f,_,_),e) -> print ctx "%s = " (anon_field f); gen_value ctx e) fields;
         spr ctx "})";
     | TField ({eexpr = TLocal v}, f) when Meta.has Meta.MultiReturn v.v_meta ->
         (* field of a multireturn local var is actually just a local var *)
@@ -861,9 +861,9 @@ and gen_expr ?(local=true) ctx e = begin
         ctx.separator <- true
     | TObjectDecl fields ->
         spr ctx "_hx_o({__fields__={";
-        concat ctx "," (fun (f,e) -> print ctx "%s=" (anon_field f); spr ctx "true") fields;
+        concat ctx "," (fun ((f,_,_),e) -> print ctx "%s=" (anon_field f); spr ctx "true") fields;
         spr ctx "},";
-        concat ctx "," (fun (f,e) -> print ctx "%s=" (anon_field f); gen_anon_value ctx e) fields;
+        concat ctx "," (fun ((f,_,_),e) -> print ctx "%s=" (anon_field f); gen_anon_value ctx e) fields;
         spr ctx "})";
         ctx.separator <- true
     | TFor (v,it,e2) ->

+ 1 - 1
src/generators/genneko.ml

@@ -260,7 +260,7 @@ and gen_expr ctx e =
 		gen_expr ctx e
 	| TObjectDecl fl ->
 		let hasToString = ref false in
-		let fl = List.map (fun (f,e) -> if f = "toString" then hasToString := (match follow e.etype with TFun ([],_) -> true | _ -> false); f , gen_expr ctx e) fl in
+		let fl = List.map (fun ((f,_,_),e) -> if f = "toString" then hasToString := (match follow e.etype with TFun ([],_) -> true | _ -> false); f , gen_expr ctx e) fl in
 		(EObject (if !hasToString then ("__string",ident p "@default__string") :: fl else fl),p)
 	| TArrayDecl el ->
 		call p (field p (ident p "Array") "new1") [array p (List.map (gen_expr ctx) el); int p (List.length el)]

+ 2 - 2
src/generators/genphp7.ml

@@ -1688,7 +1688,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 						self#write "[\n";
 						self#indent_more;
 						List.iter
-							(fun (name, field) ->
+							(fun ((name,_,_), field) ->
 								self#write_indentation;
 								self#write_const_string name;
 								self#write " => ";
@@ -2359,7 +2359,7 @@ class code_writer (ctx:Common.context) hx_type_path php_name =
 				| _ ->
 					self#write ("new " ^ (self#use hxanon_type_path)  ^ "([\n");
 					self#indent_more;
-					let write_field (key, value) = self#write_array_item ~key:key value in
+					let write_field ((key,_,_), value) = self#write_array_item ~key:key value in
 					List.iter write_field fields;
 					self#indent_less;
 					self#write_indentation;

+ 3 - 3
src/generators/genpy.ml

@@ -1314,7 +1314,7 @@ module Printer = struct
 				begin match follow e.etype with
 					| TAnon an ->
 						PMap.iter (fun s cf ->
-							if not (List.mem_assoc s fl) then fl2 := (s,null cf.cf_type cf.cf_pos) :: !fl2
+							if not (Expr.field_mem_assoc s fl) then fl2 := ((s,null_pos,NoQuotes),null cf.cf_type cf.cf_pos) :: !fl2
 						) an.a_fields
 					| _ ->
 						()
@@ -1683,10 +1683,10 @@ module Printer = struct
 			print_exprs pctx sep el
 
 	and print_exprs_named pctx sep fl =
-		let args = String.concat sep (List.map (fun (s,e) -> Printf.sprintf "'%s': %s" (Ast.s_escape (handle_keywords s)) (print_expr pctx e)) fl) in
+		let args = String.concat sep (List.map (fun ((s,_,_),e) -> Printf.sprintf "'%s': %s" (Ast.s_escape (handle_keywords s)) (print_expr pctx e)) fl) in
 		Printf.sprintf "{%s}" args
 	and print_params_named pctx sep fl =
-		let args = String.concat sep (List.map (fun (s,e) -> Printf.sprintf "%s= %s" (handle_keywords s) (print_expr pctx e)) fl) in
+		let args = String.concat sep (List.map (fun ((s,_,_),e) -> Printf.sprintf "%s= %s" (handle_keywords s) (print_expr pctx e)) fl) in
 		Printf.sprintf "%s" args
 	let handle_keywords s =
 		KeywordHandler.handle_keywords s

+ 1 - 1
src/generators/genswf9.ml

@@ -1025,7 +1025,7 @@ let rec gen_expr_content ctx retval e =
 	| TParenthesis e | TMeta (_,e) ->
 		gen_expr ctx retval e
 	| TObjectDecl fl ->
-		List.iter (fun (name,e) ->
+		List.iter (fun ((name,_,_),e) ->
 			write ctx (HString (reserved name));
 			gen_expr ctx true e
 		) fl;

+ 3 - 2
src/macro/eval/evalEncode.ml

@@ -85,6 +85,7 @@ let encode_enum i pos index pl =
 		| IFieldAccess -> key_haxe_macro_FieldAccess
 		| IAnonStatus -> key_haxe_macro_AnonStatus
 		| IImportMode -> key_haxe_macro_ImportMode
+		| IQuoteStatus -> key_haxe_macro_QuoteStatus
 	in
 	encode_enum_value key index (Array.of_list pl) pos
 
@@ -128,10 +129,10 @@ let encode_bytes s =
 
 let encode_int_map_direct h =
 	encode_instance key_haxe_ds_IntMap ~kind:(IIntMap h)
-	
+
 let encode_string_map_direct h =
 	encode_instance key_haxe_ds_StringMap ~kind:(IStringMap h)
-	
+
 let encode_object_map_direct h =
 	encode_instance key_haxe_ds_ObjectMap ~kind:(IObjectMap (Obj.magic h))
 

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

@@ -119,6 +119,7 @@ let key_haxe_macro_ModuleType = hash_s "haxe.macro.ModuleType"
 let key_haxe_macro_FieldAccess = hash_s "haxe.macro.FieldAccess"
 let key_haxe_macro_AnonStatus = hash_s "haxe.macro.AnonStatus"
 let key_haxe_macro_ImportMode = hash_s "haxe.macro.ImportMode"
+let key_haxe_macro_QuoteStatus = hash_s "haxe.macro.QuoteStatus"
 let key_haxe_CallStack = hash_s "haxe.CallStack"
 let key___init__ = hash_s "__init__"
 let key_new = hash_s "new"

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

@@ -242,7 +242,7 @@ and jit_expr jit return e =
 	| TConst ct ->
 		emit_const (eval_const ct)
 	| TObjectDecl fl ->
-		let fl = List.map (fun (s,e) -> hash_s s,jit_expr jit false e) fl in
+		let fl = List.map (fun ((s,_,_),e) -> hash_s s,jit_expr jit false e) fl in
 		let proto,_ = ctx.get_object_prototype ctx fl in
 		let fl = List.map (fun (s,exec) -> get_instance_field_index proto s e.epos,exec) fl in
 		let fa = Array.of_list fl in

+ 4 - 1
src/macro/eval/evalMain.ml

@@ -397,7 +397,10 @@ let rec value_to_expr v p =
 	| VFloat f -> haxe_float f p
 	| VString(r,s) -> (EConst (String (Lazy.force s)),p)
 	| VArray va -> (EArrayDecl (List.map (fun v -> value_to_expr v p) (EvalArray.to_list va)),p)
-	| VObject o -> (EObjectDecl (List.map (fun (k,v) -> ((rev_hash_s k,p),(value_to_expr v p))) (object_fields o)),p)
+	| VObject o -> (EObjectDecl (List.map (fun (k,v) ->
+			let n = rev_hash_s k in
+			((n,p,(if Lexer.is_valid_identifier n then NoQuotes else DoubleQuotes)),(value_to_expr v p))
+		) (object_fields o)),p)
 	| VEnumValue e ->
 		let epath =
 			let proto = get_static_prototype_raise (get_ctx()) e.epath in

+ 3 - 3
src/macro/hlmacro.ml

@@ -516,9 +516,9 @@ let value_to_expr v p =
 				(Ast.EConst (Ast.Float (Common.float_repres f)), p)
 		| VAbstract (APos p) ->
 			(Ast.EObjectDecl (
-				(("fileName",Globals.null_pos) , (Ast.EConst (Ast.String p.Globals.pfile) , p)) ::
-				(("lineNumber",Globals.null_pos) , (Ast.EConst (Ast.Int (string_of_int (Lexer.get_error_line p))),p)) ::
-				(("className",Globals.null_pos) , (Ast.EConst (Ast.String ("")),p)) ::
+				(("fileName",Globals.null_pos,NoQuotes) , (Ast.EConst (Ast.String p.Globals.pfile) , p)) ::
+				(("lineNumber",Globals.null_pos,NoQuotes) , (Ast.EConst (Ast.Int (string_of_int (Lexer.get_error_line p))),p)) ::
+				(("className",Globals.null_pos,NoQuotes) , (Ast.EConst (Ast.String ("")),p)) ::
 				[]
 			), p)
 		| VObj { oproto = { pclass = { pname = "String" } }; ofields = [|VBytes content;VInt _|] } ->

+ 16 - 5
src/macro/macroApi.ml

@@ -75,6 +75,7 @@ type enum_type =
 	| IModuleType
 	| IFieldAccess
 	| IAnonStatus
+	| IQuoteStatus
 	| IImportMode
 
 type obj_type =
@@ -213,6 +214,7 @@ let enum_name = function
 	| IFieldAccess -> "FieldAccess"
 	| IAnonStatus -> "AnonStatus"
 	| IImportMode -> "ImportMode"
+	| IQuoteStatus -> "QuoteStatus"
 
 let proto_name = function
 	| O__Const -> assert false
@@ -474,9 +476,10 @@ and encode_expr e =
 			| EParenthesis e ->
 				4, [loop e]
 			| EObjectDecl fl ->
-				5, [encode_array (List.map (fun ((f,p),e) -> encode_obj OExprDef_fields [
+				5, [encode_array (List.map (fun ((f,p,qs),e) -> encode_obj OExprDef_fields [
 					"field",encode_string f;
 					"name_pos",encode_pos p;
+					"quotes",encode_enum IQuoteStatus (match qs with NoQuotes -> 0 | DoubleQuotes -> 1) [];
 					"expr",loop e;
 				]) fl)]
 			| EArrayDecl el ->
@@ -750,7 +753,15 @@ and decode_expr v =
 			EParenthesis (loop e)
 		| 5, [a] ->
 			EObjectDecl (List.map (fun o ->
-				(decode_placed_name (field o "name_pos") (field o "field")),loop (field o "expr")
+				let name,p = decode_placed_name (field o "name_pos") (field o "field") in
+				let vquotes = field o "quotes" in
+				let quotes = if vquotes = vnull then NoQuotes
+				else match decode_enum vquotes with
+					| 0,[] -> NoQuotes
+					| 1,[] -> DoubleQuotes
+					| _ -> raise Invalid_expr
+				in
+				(name,p,quotes),loop (field o "expr")
 			) (decode_array a))
 		| 6, [a] ->
 			EArrayDecl (List.map loop (decode_array a))
@@ -1191,7 +1202,7 @@ and encode_texpr e =
 			| TField(e1,fa) -> 4,[loop e1;encode_field_access fa]
 			| TTypeExpr mt -> 5,[encode_module_type mt]
 			| TParenthesis e1 -> 6,[loop e1]
-			| TObjectDecl fl -> 7, [encode_array (List.map (fun (f,e) ->
+			| TObjectDecl fl -> 7, [encode_array (List.map (fun ((f,_,_),e) ->
 				encode_obj OTypedExprDef_fields [
 					"name",encode_string f;
 					"expr",loop e;
@@ -1355,7 +1366,7 @@ and decode_texpr v =
 		| 4, [v1;fa] -> TField(loop v1,decode_field_access fa)
 		| 5, [mt] -> TTypeExpr(decode_module_type mt)
 		| 6, [v1] -> TParenthesis(loop v1)
-		| 7, [v] -> TObjectDecl(List.map (fun v -> decode_string (field v "name"),loop (field v "expr")) (decode_array v))
+		| 7, [v] -> TObjectDecl(List.map (fun v -> (decode_string (field v "name"),Globals.null_pos,NoQuotes),loop (field v "expr")) (decode_array v))
 		| 8, [vl] -> TArrayDecl(List.map loop (decode_array vl))
 		| 9, [v1;vl] -> TCall(loop v1,List.map loop (decode_array vl))
 		| 10, [c;tl;vl] -> TNew(decode_ref c,List.map decode_type (decode_array tl),List.map loop (decode_array vl))
@@ -1477,7 +1488,7 @@ let rec make_const e =
 	| TParenthesis e | TMeta(_,e) | TCast(e,None) ->
 		make_const e
 	| TObjectDecl el ->
-		encode_obj O__Const (List.map (fun (f,e) -> f, make_const e) el)
+		encode_obj O__Const (List.map (fun ((f,_,_),e) -> f, make_const e) el)
 	| TArrayDecl al ->
 		encode_array (List.map make_const al)
 	| _ ->

+ 1 - 1
src/optimization/dce.ml

@@ -489,7 +489,7 @@ and expr dce e =
 		begin match el with
 			| [{eexpr = TObjectDecl fl}] ->
 				begin try
-					begin match List.assoc "customParams" fl with
+					begin match Expr.field_assoc "customParams" fl with
 						| {eexpr = TArrayDecl el} ->
 							List.iter (fun e -> to_string dce e.etype) el
 						| _ ->

+ 12 - 29
src/optimization/inlineConstructors.ml

@@ -49,7 +49,7 @@ open Globals
 	which is converted into TBlocks by the caller as needed.
 *)
 
-type inline_object_kind = 
+type inline_object_kind =
 	| IOKCtor of tclass_field * bool * tvar list
 	| IOKStructure
 	| IOKArray of int
@@ -84,23 +84,6 @@ and inline_var = {
 }
 
 let inline_constructors ctx e =
-	let is_valid_ident s =
-		try
-			if String.length s = 0 then raise Exit;
-			begin match String.unsafe_get s 0 with
-				| 'a'..'z' | 'A'..'Z' | '_' -> ()
-				| _ -> raise Exit
-			end;
-			for i = 1 to String.length s - 1 do
-				match String.unsafe_get s i with
-				| 'a'..'z' | 'A'..'Z' | '_' -> ()
-				| '0'..'9' when i > 0 -> ()
-				| _ -> raise Exit
-			done;
-			true
-		with Exit ->
-			false
-	in
 	let inline_objs = ref IntMap.empty in
 	let vars = ref IntMap.empty in
 	let scoped_ivs = ref [] in
@@ -245,7 +228,7 @@ let inline_constructors ctx e =
 					| e :: el ->
 						begin match e.eexpr with
 						| TConst _ -> loop (vs, decls, e::es) el
-						| _ -> 
+						| _ ->
 							let v = alloc_var "arg" e.etype e.epos in
 							let decle = mk (TVar(v, Some e)) ctx.t.tvoid e.epos in
 							let io_id_start = !current_io_id in
@@ -263,9 +246,9 @@ let inline_constructors ctx e =
 				| Some inlined_expr ->
 					let has_untyped = (Meta.has Meta.HasUntyped cf.cf_meta) in
 					let io = mk_io (IOKCtor(cf,is_extern_ctor c cf,argvs)) io_id inlined_expr ~has_untyped:has_untyped in
-					let rec loop (c:tclass) (tl:t list) = 
+					let rec loop (c:tclass) (tl:t list) =
 						let apply = apply_params c.cl_params tl in
-						List.iter (fun cf -> 
+						List.iter (fun cf ->
 							match cf.cf_kind,cf.cf_expr with
 							| Var _, _ ->
 								let fieldt = apply cf.cf_type in
@@ -289,17 +272,17 @@ let inline_constructors ctx e =
 			end
 		| TNew({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some _} as cf)} as c,_,pl),_ when is_extern_ctor c cf ->
 			error "Extern constructor could not be inlined" e.epos;
-		| TObjectDecl fl, _ when captured && fl <> [] && List.for_all (fun(s,_) -> is_valid_ident s) fl ->
+		| TObjectDecl fl, _ when captured && fl <> [] && List.for_all (fun((s,_,_),_) -> Lexer.is_valid_identifier s) fl ->
 			let v = alloc_var "inlobj" e.etype e.epos in
 			let ev = mk (TLocal v) v.v_type e.epos in
-			let el = List.map (fun (s,e) ->
+			let el = List.map (fun ((s,_,_),e) ->
 				let ef = mk (TField(ev,FDynamic s)) e.etype e.epos in
 				let e = mk (TBinop(OpAssign,ef,e)) e.etype e.epos in
 				e
 			) fl in
 			let io_expr = make_expr_for_list el ctx.t.tvoid e.epos in
 			let io = mk_io (IOKStructure) !current_io_id io_expr in
-			List.iter (fun (s,e) -> ignore(alloc_io_field io s e.etype v.v_pos)) fl;
+			List.iter (fun ((s,_,_),e) -> ignore(alloc_io_field io s e.etype v.v_pos)) fl;
 			let iv = add v IVKLocal in
 			set_iv_alias iv io;
 			List.iter (fun e -> ignore(analyze_aliases true e)) el;
@@ -361,7 +344,7 @@ let inline_constructors ctx e =
 				| [] -> None
 			in loop el
 		| TMeta((Meta.InlineConstructorArgument (vid,_),_,_),_),_ ->
-			(try 
+			(try
 				let iv = get_iv vid in
 				if iv.iv_closed || not captured then cancel_iv iv e.epos;
 				Some(get_iv vid)
@@ -387,16 +370,16 @@ let inline_constructors ctx e =
 			let v = iv.iv_var in
 			[(mk (TVar(v,None)) ctx.t.tvoid v.v_pos)]
 		| _ -> []
-	and get_io_var_decls (io:inline_object) : texpr list = 
+	and get_io_var_decls (io:inline_object) : texpr list =
 		if io.io_declared then [] else begin
 			io.io_declared <- true;
 			PMap.foldi (fun _ iv acc -> acc@(get_iv_var_decls iv)) io.io_fields []
 		end
 	in
 	let included_untyped = ref false in
-	let rec final_map ?(unwrap_block = false) (e:texpr) : ((texpr list) * (inline_object option)) = 
+	let rec final_map ?(unwrap_block = false) (e:texpr) : ((texpr list) * (inline_object option)) =
 		increment_io_id e;
-		let default_case e = 
+		let default_case e =
 			let f e =
 				let (el,_) = final_map e in
 				make_expr_for_rev_list el e.etype e.epos
@@ -437,7 +420,7 @@ let inline_constructors ctx e =
 				let rve = make_expr_for_rev_list rvel rve.etype rve.epos in
 				begin match lvel with
 				| [] -> assert false
-				| e::el -> 
+				| e::el ->
 					let e = mk (TBinop(OpAssign, e, rve)) e.etype e.epos in
 					(e::el), None
 				end

+ 2 - 19
src/optimization/optimizer.ml

@@ -1207,23 +1207,6 @@ type inline_info = {
 
 let inline_constructors ctx e =
 	let vars = ref IntMap.empty in
-	let is_valid_ident s =
-		try
-			if String.length s = 0 then raise Exit;
-			begin match String.unsafe_get s 0 with
-				| 'a'..'z' | 'A'..'Z' | '_' -> ()
-				| _ -> raise Exit
-			end;
-			for i = 1 to String.length s - 1 do
-				match String.unsafe_get s i with
-				| 'a'..'z' | 'A'..'Z' | '_' -> ()
-				| '0'..'9' when i > 0 -> ()
-				| _ -> raise Exit
-			done;
-			true
-		with Exit ->
-			false
-	in
 	let cancel v p =
 		try
 			let ii = IntMap.find v.v_id !vars in
@@ -1291,8 +1274,8 @@ let inline_constructors ctx e =
 				| TObjectDecl fl when fl <> [] ->
 					begin try
 						let ev = mk (TLocal v) v.v_type e.epos in
-						let el = List.fold_left (fun acc (s,e) ->
-							if not (is_valid_ident s) then raise Exit;
+						let el = List.fold_left (fun acc ((s,_,_),e) ->
+							if not (Lexer.is_valid_identifier s) then raise Exit;
 							let ef = mk (TField(ev,FDynamic s)) e.etype e.epos in
 							let e = mk (TBinop(OpAssign,ef,e)) e.etype e.epos in
 							e :: acc

+ 12 - 0
src/syntax/lexer.ml

@@ -87,6 +87,18 @@ let keywords =
 		Inline;Using;Null;True;False;Abstract;Macro;Final];
 	h
 
+let is_valid_identifier s = try
+	for i = 0 to String.length s - 1 do
+		match String.unsafe_get s i with
+		| 'a'..'z' | 'A'..'Z' | '_' -> ()
+		| '0'..'9' when i > 0 -> ()
+		| _ -> raise Exit
+	done;
+	if Hashtbl.mem keywords s then raise Exit;
+	true
+with Exit ->
+	false
+
 let init file do_add =
 	let f = make_file file in
 	cur := f;

+ 13 - 30
src/syntax/parser.mly

@@ -63,30 +63,6 @@ let decl_flag_to_abstract_flag = function
 
 let special_identifier_files = Hashtbl.create 0
 
-let quoted_ident_prefix = "@$__hx__"
-
-let quote_ident s =
-	quoted_ident_prefix ^ s
-
-let unquote_ident f =
-	let pf = quoted_ident_prefix in
-	let pflen = String.length pf in
-	let is_quoted = String.length f >= pflen && String.sub f 0 pflen = pf in
-	let s = if is_quoted then String.sub f pflen (String.length f - pflen) else f in
-	let is_valid = not is_quoted || try
-		for i = 0 to String.length s - 1 do
-			match String.unsafe_get s i with
-			| 'a'..'z' | 'A'..'Z' | '_' -> ()
-			| '0'..'9' when i > 0 -> ()
-			| _ -> raise Exit
-		done;
-		if Hashtbl.mem Lexer.keywords s then raise Exit;
-		true
-	with Exit ->
-		false
-	in
-	s,is_quoted,is_valid
-
 let cache = ref (DynArray.create())
 let last_doc = ref None
 let use_doc = ref false
@@ -254,7 +230,7 @@ let reify in_macro =
 		(EConst (Ident (if o then "true" else "false")),p)
 	in
 	let to_obj fields p =
-		(EObjectDecl (List.map (fun (s,e) -> (s,null_pos),e) fields),p)
+		(EObjectDecl (List.map (fun (s,e) -> (s,null_pos,NoQuotes),e) fields),p)
 	in
 	let rec to_tparam t p =
 		let n, v = (match t with
@@ -406,7 +382,14 @@ let reify in_macro =
 		| EParenthesis e ->
 			expr "EParenthesis" [loop e]
 		| EObjectDecl fl ->
-			expr "EObjectDecl" [to_array (fun ((f,_),e) -> to_obj [("field",to_string f p);("expr",loop e)]) fl p]
+			let quote_kind kk p =
+				let n = match kk with
+					| NoQuotes -> "NoQuotes"
+					| DoubleQuotes -> "DoubleQuotes"
+				in
+				mk_enum "QuoteStatus" n [] p
+			in
+			expr "EObjectDecl" [to_array (fun ((f,pn,kk),e) -> to_obj [("field",to_string f p);("expr",loop e);("quotes",quote_kind kk pn)]) fl p]
 		| EArrayDecl el ->
 			expr "EArrayDecl" [to_expr_array el p]
 		| ECall (e,el) ->
@@ -1192,8 +1175,8 @@ and parse_class_herit = parser
 	| [< '(Kwd Implements,p1); t = parse_type_path_or_resume p1 >] -> HImplements t
 
 and block1 = parser
-	| [< name,p = dollar_ident; s >] -> block2 (name,p) (Ident name) p s
-	| [< '(Const (String name),p); s >] -> block2 (quote_ident name,p) (String name) p s
+	| [< name,p = dollar_ident; s >] -> block2 (name,p,NoQuotes) (Ident name) p s
+	| [< '(Const (String name),p); s >] -> block2 (name,p,DoubleQuotes) (String name) p s
 	| [< b = block [] >] -> EBlock b
 
 and block2 name ident p s =
@@ -1238,8 +1221,8 @@ and parse_block_elt = parser
 and parse_obj_decl = parser
 	| [< '(Comma,_); s >] ->
 		(match s with parser
-		| [< name,p = ident; '(DblDot,_); e = expr; l = parse_obj_decl >] -> ((name,p),e) :: l
-		| [< '(Const (String name),p); '(DblDot,_); e = expr; l = parse_obj_decl >] -> ((quote_ident name,p),e) :: l
+		| [< name,p = ident; '(DblDot,_); e = expr; l = parse_obj_decl >] -> ((name,p,NoQuotes),e) :: l
+		| [< '(Const (String name),p); '(DblDot,_); e = expr; l = parse_obj_decl >] -> ((name,p,DoubleQuotes),e) :: l
 		| [< >] -> [])
 	| [< >] -> []
 

+ 1 - 1
src/typing/matcher.ml

@@ -428,7 +428,7 @@ module Pattern = struct
 						else
 							patterns,fields
 				) ([],[]) known_fields in
-				List.iter (fun ((s,_),e) -> if not (List.mem s fields) then error (Printf.sprintf "%s has no field %s" (s_type t) s) (pos e)) fl;
+				List.iter (fun ((s,_,_),e) -> if not (List.mem s fields) then error (Printf.sprintf "%s has no field %s" (s_type t) s) (pos e)) fl;
 				PatConstructor(ConFields fields,patterns)
 			| EBinop(OpOr,e1,e2) ->
 				let pctx1 = {pctx with current_locals = PMap.empty} in

+ 2 - 2
src/typing/typeload.ml

@@ -430,7 +430,7 @@ let requires_value_meta com co =
 
 let generate_value_meta com co cf args =
 	if requires_value_meta com co then begin
-		let values = List.fold_left (fun acc ((name,p),_,_,_,eo) -> match eo with Some e -> ((name,p),e) :: acc | _ -> acc) [] args in
+		let values = List.fold_left (fun acc ((name,p),_,_,_,eo) -> match eo with Some e -> ((name,p,NoQuotes),e) :: acc | _ -> acc) [] args in
 		match values with
 			| [] -> ()
 			| _ -> cf.cf_meta <- ((Meta.Value,[EObjectDecl values,cf.cf_pos],null_pos) :: cf.cf_meta)
@@ -1140,7 +1140,7 @@ let field_to_type_path ctx e =
 	loop e [] []
 
 let handle_fields ctx fields_to_check with_type_expr =
-	List.map (fun ((name,_),expr) ->
+	List.map (fun ((name,_,_),expr) ->
 		let pos = snd expr in
 		let field = (EField(with_type_expr,name), pos) in
 		let fieldexpr = (EConst(Ident name),pos) in

+ 13 - 18
src/typing/typer.ml

@@ -56,13 +56,13 @@ let build_call_ref : (typer -> access_kind -> expr list -> with_type -> pos -> t
 let mk_infos ctx p params =
 	let file = if ctx.in_macro then p.pfile else if Common.defined ctx.com Define.AbsolutePath then Path.get_full_path p.pfile else Filename.basename p.pfile in
 	(EObjectDecl (
-		(("fileName",null_pos) , (EConst (String file) , p)) ::
-		(("lineNumber",null_pos) , (EConst (Int (string_of_int (Lexer.get_error_line p))),p)) ::
-		(("className",null_pos) , (EConst (String (s_type_path ctx.curclass.cl_path)),p)) ::
+		(("fileName",null_pos,NoQuotes) , (EConst (String file) , p)) ::
+		(("lineNumber",null_pos,NoQuotes) , (EConst (Int (string_of_int (Lexer.get_error_line p))),p)) ::
+		(("className",null_pos,NoQuotes) , (EConst (String (s_type_path ctx.curclass.cl_path)),p)) ::
 		if ctx.curfield.cf_name = "" then
 			params
 		else
-			(("methodName",null_pos), (EConst (String ctx.curfield.cf_name),p)) :: params
+			(("methodName",null_pos,NoQuotes), (EConst (String ctx.curfield.cf_name),p)) :: params
 	) ,p)
 
 let check_assign ctx e =
@@ -2923,14 +2923,11 @@ and type_object_decl ctx fl with_type p =
 	| _ ->
 		ODKPlain
 	) in
-	let wrap_quoted_meta e =
-		mk (TMeta((Meta.QuotedField,[],e.epos),e)) e.etype e.epos
-	in
 	let type_fields field_map =
 		let fields = ref PMap.empty in
 		let extra_fields = ref [] in
-		let fl = List.map (fun ((n,pn),e) ->
-			let n,is_quoted,is_valid = Parser.unquote_ident n in
+		let fl = List.map (fun ((n,pn,qs),e) ->
+			let is_valid = Lexer.is_valid_identifier n in
 			if PMap.mem n !fields then error ("Duplicate field in object declaration : " ^ n) p;
 			let e = try
 				let t = match !dynamic_parameter with
@@ -2953,8 +2950,7 @@ and type_object_decl ctx fl with_type p =
 				let cf = mk_field n e.etype (punion pn e.epos) pn in
 				fields := PMap.add n cf !fields;
 			end;
-			let e = if is_quoted then wrap_quoted_meta e else e in
-			(n,e)
+			((n,pn,qs),e)
 		) fl in
 		let t = (TAnon { a_fields = !fields; a_status = ref Const }) in
 		if not ctx.untyped then begin
@@ -2970,15 +2966,14 @@ and type_object_decl ctx fl with_type p =
 	in
 	(match a with
 	| ODKPlain ->
-		let rec loop (l,acc) ((f,pf),e) =
-			let f,is_quoted,is_valid = Parser.unquote_ident f in
+		let rec loop (l,acc) ((f,pf,qs),e) =
+			let is_valid = Lexer.is_valid_identifier f in
 			if PMap.mem f acc then error ("Duplicate field in object declaration : " ^ f) p;
 			let e = type_expr ctx e Value in
 			(match follow e.etype with TAbstract({a_path=[],"Void"},_) -> error "Fields of type Void are not allowed in structures" e.epos | _ -> ());
 			let cf = mk_field f e.etype (punion pf e.epos) pf in
 			if ctx.in_display && Display.is_display_position pf then Display.DisplayEmitter.display_field ctx.com.display cf pf;
-			let e = if is_quoted then wrap_quoted_meta e else e in
-			((f,e) :: l, if is_valid then begin
+			(((f,pf,qs),e) :: l, if is_valid then begin
 				if String.length f > 0 && f.[0] = '$' then error "Field names starting with a dollar are not allowed" p;
 				PMap.add f cf acc
 			end else acc)
@@ -3018,7 +3013,7 @@ and type_object_decl ctx fl with_type p =
 			end
 		) ([],[],false) (List.rev fl) in
 		let el = List.map (fun (n,_,t) ->
-			try List.assoc n fl
+			try Expr.field_assoc n fl
 			with Not_found -> mk (TConst TNull) t p
 		) args in
 		let e = mk (TNew(c,tl,el)) (TInst(c,tl)) p in
@@ -3466,7 +3461,7 @@ and type_expr ctx (e,p) (with_type:with_type) =
 			| EMeta(m,e1) ->
 				EMeta(m,map_compr e1),p
 			| EConst _ | EArray _ | EBinop _ | EField _ | EObjectDecl _ | EArrayDecl _
-			| ECall _ | ENew _ | EUnop _ | EVars _ | EFunction _ | EDisplayNew _ | EMeta _ | ECheckType _ ->
+			| ECall _ | ENew _ | EUnop _ | EVars _ | EFunction _ | EDisplayNew _ | ECheckType _ ->
 				et := (EArrayDecl [],p);
 				(ECall ((EField ((EConst (Ident v.v_name),p),"push"),p),[(e,p)]),p)
 		in
@@ -4176,7 +4171,7 @@ and type_call ctx e el (with_type:with_type) p =
 			null ctx.t.tvoid p
 		else
 		let mk_to_string_meta e = EMeta((Meta.ToString,[],null_pos),e),pos e in
-		let params = (match el with [] -> [] | _ -> [("customParams",null_pos),(EArrayDecl (List.map mk_to_string_meta el) , p)]) in
+		let params = (match el with [] -> [] | _ -> [("customParams",null_pos,NoQuotes),(EArrayDecl (List.map mk_to_string_meta el) , p)]) in
 		let infos = mk_infos ctx p params in
 		if (platform ctx.com Js || platform ctx.com Python) && el = [] && has_dce ctx.com then
 			let e = type_expr ctx e Value in

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

@@ -336,6 +336,41 @@ typedef Catch = {
 	var expr : Expr;
 }
 
+/**
+	Represents the way something is quoted.
+**/
+enum QuoteStatus {
+	/**
+		No qutoes
+	**/
+	NoQuotes;
+
+	/**
+		Double quotes `"`
+	**/
+	DoubleQuotes;
+}
+
+/**
+	Represents the field of an object declaration.
+**/
+typedef ObjectField = {
+	/**
+		The name of the field.
+	**/
+	var field : String;
+
+	/**
+		The field expression.
+	**/
+	var expr : Expr;
+
+	/**
+		How the field name is quoted.
+	**/
+	@:optional var quotes : QuoteStatus;
+}
+
 /**
 	Represents the kind of a node in the AST.
 **/
@@ -368,7 +403,7 @@ enum ExprDef {
 	/**
 		An object declaration.
 	**/
-	EObjectDecl( fields : Array<{ field : String, expr : Expr }> );
+	EObjectDecl( fields : Array<ObjectField> );
 
 	/**
 		An array declaration `[el]`.

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

@@ -164,7 +164,7 @@ class ExprTools {
 			case EObjectDecl(fields):
 				var ret = [];
 				for (field in fields)
-					ret.push( { field: field.field, expr: f(field.expr) } );
+					ret.push( { field: field.field, expr: f(field.expr), quotes: field.quotes } );
 				EObjectDecl(ret);
 			case EArrayDecl(el): EArrayDecl(ExprArrayTools.map(el, f));
 			case ECall(e, params): ECall(f(e), ExprArrayTools.map(params, f));

+ 12 - 1
std/haxe/macro/Printer.hx

@@ -171,6 +171,17 @@ class Printer {
 		+ opt(v.expr, printExpr, " = ");
 
 
+	public function printObjectFieldKey(of:ObjectField) {
+		return switch (of.quotes) {
+			case NoQuotes: of.field;
+			case DoubleQuotes: '"${of.field}"'; // TODO: Have to escape that?
+		}
+	}
+
+	public function printObjectField(of:ObjectField) {
+		return '${printObjectFieldKey(of)} : ${printExpr(of.expr)}';
+	}
+
 	public function printExpr(e:Expr) return e == null ? "#NULL" : switch(e.expr) {
 		#if macro
 		case EConst(CString(s)): haxe.macro.MacroStringTools.isFormatExpr(e) ? printFormatString(s) : printString(s);
@@ -181,7 +192,7 @@ class Printer {
 		case EField(e1, n): '${printExpr(e1)}.$n';
 		case EParenthesis(e1): '(${printExpr(e1)})';
 		case EObjectDecl(fl):
-			"{ " + fl.map(function(fld) return '${fld.field} : ${printExpr(fld.expr)}').join(", ") + " }";
+			"{ " + fl.map(function(fld) return printObjectField(fld)).join(", ") + " }";
 		case EArrayDecl(el): '[${printExprs(el, ", ")}]';
 		case ECall(e1, el): '${printExpr(e1)}(${printExprs(el,", ")})';
 		case ENew(tp, el): 'new ${printTypePath(tp)}(${printExprs(el,", ")})';

+ 6 - 0
tests/unit/src/unit/HelperMacros.hx

@@ -51,4 +51,10 @@ class HelperMacros {
 		} catch (e:Dynamic) Std.string(e.message);
 		return macro $v{result};
 	}
+
+	static public macro function parseAndPrint(s:String) {
+		var e = haxe.macro.Context.parse(s, haxe.macro.Context.currentPos());
+		var s2 = new haxe.macro.Printer().printExpr(e);
+		return macro eq($v{s}, $v{s2});
+	}
 }

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

@@ -0,0 +1,61 @@
+package unit;
+
+import unit.HelperMacros.parseAndPrint;
+
+class TestMacro extends Test {
+	function testPrinter() {
+		parseAndPrint("1");
+		parseAndPrint("a[b]");
+		parseAndPrint("a + b");
+		parseAndPrint("a.b");
+		parseAndPrint("(a)");
+		parseAndPrint("{ a : b }");
+		parseAndPrint("{ \"a\" : b }");
+		parseAndPrint("[]");
+		parseAndPrint("[a]");
+		parseAndPrint("[a, b]");
+		parseAndPrint("a()");
+		parseAndPrint("a(b)");
+		parseAndPrint("a(b, c)");
+		parseAndPrint("new A()");
+		parseAndPrint("new A(a)");
+		parseAndPrint("new A(a, b)");
+		parseAndPrint("new A<A>()");
+		parseAndPrint("new A<A>(a)");
+		parseAndPrint("new A<A>(a, b)");
+		parseAndPrint("new A<A, B>()");
+		parseAndPrint("new A<A, B>(a)");
+		parseAndPrint("new A<A, B>(a, b)");
+		parseAndPrint("--a");
+		parseAndPrint("++a");
+		parseAndPrint("-a");
+		parseAndPrint("!a");
+		parseAndPrint("~a");
+		parseAndPrint("a--");
+		parseAndPrint("a++");
+		parseAndPrint("a!");
+		parseAndPrint("var a");
+		parseAndPrint("var a:A");
+		parseAndPrint("var a = b");
+		parseAndPrint("var a:A = b");
+		parseAndPrint("function() { }");
+		parseAndPrint("for (a in b) { }");
+		parseAndPrint("if (a) b");
+		parseAndPrint("if (a) b else c");
+		parseAndPrint("while (a) b");
+		parseAndPrint("do a while (b)");
+		parseAndPrint("return");
+		parseAndPrint("return a");
+		parseAndPrint("break");
+		parseAndPrint("continue");
+		parseAndPrint("untyped a");
+		parseAndPrint("throw a");
+		parseAndPrint("cast a");
+		parseAndPrint("cast(a, B)");
+		parseAndPrint("a ? b : c");
+		// parseAndPrint("(a : B)"); // TODO
+		parseAndPrint("@:meta a");
+		parseAndPrint("@:meta(a) b");
+		parseAndPrint("@:meta(a, b) b");
+	}
+}

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

@@ -94,6 +94,7 @@ class TestMain {
 			new TestDCE(),
 			#end
 			new TestMapComprehension(),
+			new TestMacro(),
 			// #if ( (java || neko) && !macro && !interp)
 			// new TestThreads(),
 			// #end