Browse Source

Numeric literal suffixes (#10493)

* Add optional suffix string to Int constants

* Add initial optional float suffix and some support in float lexing

* add optional float suffixes to all of the float constant lexing cases

* Update some tests to reflect changes to CInt

* Append the suffix when converting an int or float constant to a string

* Update the macro printer to append the suffix if not null

* Manually construct the cint enum in cases where the suffix is i64

* Use a ECheckType instead of a safe cast for UInt

* Use CIdent for test case now CInt signature has changed

* Support suffixes for hex literals

* Add some suffix tests

* make suffix eq tests more robust to platform differences

* Don't convert ints to floats if they have the i32 suffix and the literal is too large

* ensure suffix is appended for type parameters

* Keep suffixes when using type reification

* Check suffixes when decoding with the macro api
Aidan Lee 3 năm trước cách đây
mục cha
commit
07678d7c39

+ 2 - 2
src/codegen/dotnet.ml

@@ -265,9 +265,9 @@ let convert_ilenum ctx p ?(is_flag=false) ilcls =
 				| Some IChar i
 				| Some IByte i
 				| Some IShort i ->
-					[Meta.CsNative, [EConst (Int (string_of_int i) ), p], p ], Int64.of_int i
+					[Meta.CsNative, [EConst (Int (string_of_int i, None) ), p], p ], Int64.of_int i
 				| Some IInt i ->
-					[Meta.CsNative, [EConst (Int (Int32.to_string i) ), p], p ], Int64.of_int32 i
+					[Meta.CsNative, [EConst (Int (Int32.to_string i, None) ), p], p ], Int64.of_int32 i
 				| Some IFloat32 f | Some IFloat64 f ->
 					[], Int64.of_float f
 				| Some IInt64 i ->

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

@@ -672,7 +672,7 @@ struct
 					iface.cl_meta <-
 						(Meta.HxGen, [], cl.cl_pos)
 						::
-						(Meta.Custom "generic_iface", [(EConst(Int(string_of_int(List.length cl.cl_params))), cl.cl_pos)], cl.cl_pos)
+						(Meta.Custom "generic_iface", [(EConst(Int(string_of_int(List.length cl.cl_params), None)), cl.cl_pos)], cl.cl_pos)
 						::
 						iface.cl_meta;
 					Hashtbl.add ifaces cl.cl_path iface;

+ 2 - 2
src/codegen/java.ml

@@ -172,8 +172,8 @@ and convert_signature ctx p jsig =
 let convert_constant ctx p const =
 	Option.map_default (function
 		| ConstString s -> Some (EConst (String(s,SDoubleQuotes)), p)
-		| ConstInt i -> Some (EConst (Int (Printf.sprintf "%ld" i)), p)
-		| ConstFloat f | ConstDouble f -> Some (EConst (Float (Printf.sprintf "%E" f)), p)
+		| ConstInt i -> Some (EConst (Int (Printf.sprintf "%ld" i, None)), p)
+		| ConstFloat f | ConstDouble f -> Some (EConst (Float (Printf.sprintf "%E" f, None)), p)
 		| _ -> None) None const
 
 let convert_constraints ctx p tl = match tl with

+ 2 - 2
src/codegen/swfLoader.ml

@@ -270,9 +270,9 @@ let build_class com c file =
 							| HVBool b ->
 								Some (Ident (if b then "true" else "false"))
 							| HVInt i | HVUInt i ->
-								Some (Int (Int32.to_string i))
+								Some (Int (Int32.to_string i, None))
 							| HVFloat f ->
-								Some (Float (Numeric.float_repres f))
+								Some (Float (Numeric.float_repres f, None))
 							) in
 							match v with
 							| None -> None

+ 1 - 1
src/context/typecore.ml

@@ -634,7 +634,7 @@ 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 relative_path ctx p.pfile in
 	(EObjectDecl (
 		(("fileName",null_pos,NoQuotes) , (EConst (String(file,SDoubleQuotes)) , p)) ::
-		(("lineNumber",null_pos,NoQuotes) , (EConst (Int (string_of_int (Lexer.get_error_line p))),p)) ::
+		(("lineNumber",null_pos,NoQuotes) , (EConst (Int (string_of_int (Lexer.get_error_line p), None)),p)) ::
 		(("className",null_pos,NoQuotes) , (EConst (String (s_type_path ctx.curclass.cl_path,SDoubleQuotes)),p)) ::
 		if ctx.curfield.cf_name = "" then
 			params

+ 6 - 4
src/core/ast.ml

@@ -106,8 +106,8 @@ type string_literal_kind =
 	(* | SMarkup *)
 
 type constant =
-	| Int of string
-	| Float of string
+	| Int of string * string option
+	| Float of string * string option
 	| String of string * string_literal_kind
 	| Ident of string
 	| Regexp of string * string
@@ -458,8 +458,10 @@ let parse_path s =
 	| x :: l -> List.rev l, x
 
 let s_constant = function
-	| Int s -> s
-	| Float s -> s
+	| Int (s, None) -> s
+	| Int (s, Some suffix) -> s ^ suffix
+	| Float (s, None) -> s
+	| Float (s, Some suffix) -> s ^ suffix
 	| String(s,qs) ->
 		begin match qs with
 		| SDoubleQuotes -> "\"" ^ StringHelper.s_escape s ^ "\""

+ 2 - 2
src/core/tFunctions.ml

@@ -630,8 +630,8 @@ let rec module_type_of_type = function
 		raise Exit
 
 let tconst_to_const = function
-	| TInt i -> Int (Int32.to_string i)
-	| TFloat s -> Float s
+	| TInt i -> Int (Int32.to_string i, None)
+	| TFloat s -> Float (s, None)
 	| TString s -> String(s,SDoubleQuotes)
 	| TBool b -> Ident (if b then "true" else "false")
 	| TNull -> Ident "null"

+ 2 - 2
src/core/texpr.ml

@@ -568,11 +568,11 @@ let rec constructor_side_effects e =
 
 let type_constant basic c p =
 	match c with
-	| Int s ->
+	| Int (s,_) ->
 		if String.length s > 10 && String.sub s 0 2 = "0x" then typing_error "Invalid hexadecimal integer" p;
 		(try mk (TConst (TInt (Int32.of_string s))) basic.tint p
 		with _ -> mk (TConst (TFloat s)) basic.tfloat p)
-	| Float f -> mk (TConst (TFloat f)) basic.tfloat p
+	| Float (f,_) -> mk (TConst (TFloat f)) basic.tfloat p
 	| String(s,qs) -> mk (TConst (TString s)) basic.tstring p (* STRINGTODO: qs? *)
 	| Ident "true" -> mk (TConst (TBool true)) basic.tbool p
 	| Ident "false" -> mk (TConst (TBool false)) basic.tbool p

+ 1 - 1
src/filters/filters.ml

@@ -198,7 +198,7 @@ let check_local_vars_init com e =
 
 let mark_switch_break_loops e =
 	let add_loop_label n e =
-		{ e with eexpr = TMeta ((Meta.LoopLabel,[(EConst(Int(string_of_int n)),e.epos)],e.epos), e) }
+		{ e with eexpr = TMeta ((Meta.LoopLabel,[(EConst(Int(string_of_int n, None)),e.epos)],e.epos), e) }
 	in
 	let in_switch = ref false in
 	let did_found = ref (-1) in

+ 3 - 3
src/generators/gencs.ml

@@ -1466,7 +1466,7 @@ let generate con =
 						)
 					| TParenthesis e ->
 						write w "("; expr_s w e; write w ")"
-					| TMeta ((Meta.LoopLabel,[(EConst(Int n),_)],_), e) ->
+					| TMeta ((Meta.LoopLabel,[(EConst(Int (n, _)),_)],_), e) ->
 						(match e.eexpr with
 						| TFor _ | TWhile _ ->
 							expr_s w e;
@@ -1899,7 +1899,7 @@ let generate con =
 
 		let rec gen_spart w = function
 			| EConst c, p -> (match c with
-				| Int s | Float s | Ident s ->
+				| Int (s, _) | Float (s, _) | Ident s ->
 					write w s
 				| String(s,_) ->
 					write w "\"";
@@ -2633,7 +2633,7 @@ let generate con =
 					else
 						"object" :: (loop (pred i) acc)
 				in
-				let tparams = loop (match m with [(EConst(Int s),_)] -> int_of_string s | _ -> die "" __LOC__) [] in
+				let tparams = loop (match m with [(EConst(Int (s, _)),_)] -> int_of_string s | _ -> die "" __LOC__) [] in
 				cl.cl_meta <- (Meta.Meta, [
 					EConst(String("global::haxe.lang.GenericInterface(typeof(global::" ^ module_s (TClassDecl cl) ^ "<" ^ String.concat ", " tparams ^ ">))",SDoubleQuotes) ), cl.cl_pos
 				], cl.cl_pos) :: cl.cl_meta

+ 1 - 1
src/generators/genhl.ml

@@ -3318,7 +3318,7 @@ let generate_static ctx c f =
 				add_native lib name
 			| (Meta.HlNative,[(EConst(String(lib,_)),_)] ,_ ) :: _ ->
 				add_native lib f.cf_name
-			| (Meta.HlNative,[(EConst(Float(ver)),_)] ,_ ) :: _ ->
+			| (Meta.HlNative,[(EConst(Float(ver,_)),_)] ,_ ) :: _ ->
 				let cur_ver = (try Common.defined_value ctx.com Define.HlVer with Not_found -> "") in
 				if cur_ver < ver then
 					let gen_content() =

+ 5 - 5
src/generators/genhxold.ml

@@ -180,14 +180,14 @@ let generate_type com t =
 							| [] -> Ident "null"
 							| (Meta.DefParam,[(EConst (String(p,_)),_);(EConst v,_)],_) :: _ when p = a ->
 								(match v with
-								| Float "1.#QNAN" -> Float "0./*NaN*/"
-								| Float "4294967295." -> Int "0xFFFFFFFF"
-								| Int "16777215" -> Int "0xFFFFFF"
-								| Float x ->
+								| Float ("1.#QNAN", _) -> Float ("0./*NaN*/", None)
+								| Float ("4294967295.", _) -> Int ("0xFFFFFFFF", None)
+								| Int ("16777215", _) -> Int ("0xFFFFFF", None)
+								| Float (x, _) ->
 									(try
 										let f = float_of_string x in
 										let s = string_of_int (int_of_float f) in
-										if s ^ "." = x then Int s else v
+										if s ^ "." = x then Int (s, None) else v
 									with _ ->
 										v)
 								| _ -> v)

+ 2 - 2
src/generators/genjava.ml

@@ -1524,7 +1524,7 @@ let generate con =
 				| TTypeExpr mt -> write w (md_s e.epos mt)
 				| TParenthesis e ->
 					write w "("; expr_s w e; write w ")"
-				| TMeta ((Meta.LoopLabel,[(EConst(Int n),_)],_), e) ->
+				| TMeta ((Meta.LoopLabel,[(EConst(Int (n, _)),_)],_), e) ->
 					(match e.eexpr with
 					| TFor _ | TWhile _ ->
 						print w "label%s:" n;
@@ -1834,7 +1834,7 @@ let generate con =
 
 	let rec gen_spart w = function
 		| EConst c, p -> (match c with
-			| Int s | Float s | Ident s ->
+			| Int (s, _) | Float (s, _) | Ident s ->
 				write w s
 			| String(s,_) ->
 				write w "\"";

+ 1 - 1
src/generators/genjs.ml

@@ -716,7 +716,7 @@ and gen_expr ctx e =
 		spr ctx "(";
 		gen_value ctx e;
 		spr ctx ")";
-	| TMeta ((Meta.LoopLabel,[(EConst(Int n),_)],_), e) ->
+	| TMeta ((Meta.LoopLabel,[(EConst(Int (n, _)),_)],_), e) ->
 		(match e.eexpr with
 		| TWhile _ | TFor _ ->
 			print ctx "_hx_loop%s: " n;

+ 2 - 2
src/generators/genjvm.ml

@@ -221,8 +221,8 @@ module AnnotationHandler = struct
 			path
 		in
 		let rec parse_value e = match fst e with
-			| EConst (Int s) -> AInt (Int32.of_string s)
-			| EConst (Float s) -> ADouble (float_of_string s)
+			| EConst (Int (s, _)) -> AInt (Int32.of_string s)
+			| EConst (Float (s, _)) -> ADouble (float_of_string s)
 			| EConst (String(s,_)) -> AString s
 			| EConst (Ident "true") -> ABool true
 			| EConst (Ident "false") -> ABool false

+ 4 - 4
src/generators/genshared.ml

@@ -195,7 +195,7 @@ module Info = struct
 
 		method get_class_info (c : tclass) =
 			let rec loop ml = match ml with
-			| (Meta.Custom ":jvm.classInfo",[(EConst (Int s),_)],_) :: _ ->
+			| (Meta.Custom ":jvm.classInfo",[(EConst (Int (s, _)),_)],_) :: _ ->
 				DynArray.get class_infos (int_of_string s)
 			| _ :: ml ->
 				loop ml
@@ -206,7 +206,7 @@ module Info = struct
 					implicit_ctors = PMap.empty;
 				} in
 				DynArray.add class_infos infos;
-				c.cl_meta <- (Meta.Custom ":jvm.classInfo",[(EConst (Int (string_of_int index)),null_pos)],null_pos) :: c.cl_meta;
+				c.cl_meta <- (Meta.Custom ":jvm.classInfo",[(EConst (Int (string_of_int index, None)),null_pos)],null_pos) :: c.cl_meta;
 				infos
 			in
 			loop c.cl_meta
@@ -241,7 +241,7 @@ object(self)
 
 	method get_field_info (ml : metadata) =
 		let rec loop ml = match ml with
-		| (Meta.Custom ":jvm.fieldInfo",[(EConst (Int s),_)],_) :: _ ->
+		| (Meta.Custom ":jvm.fieldInfo",[(EConst (Int (s, _)),_)],_) :: _ ->
 			Some (DynArray.get field_infos (int_of_string s))
 		| _ :: ml ->
 			loop ml
@@ -367,7 +367,7 @@ object(self)
 					let info = self#preprocess_constructor_expr c cf e in
 					let index = DynArray.length field_infos in
 					DynArray.add field_infos info;
-					cf.cf_meta <- (Meta.Custom ":jvm.fieldInfo",[(EConst (Int (string_of_int index)),null_pos)],null_pos) :: cf.cf_meta;
+					cf.cf_meta <- (Meta.Custom ":jvm.fieldInfo",[(EConst (Int (string_of_int index, None)),null_pos)],null_pos) :: cf.cf_meta;
 					if not (Meta.has Meta.HxGen cf.cf_meta) then begin
 						let rec loop next c =
 							if (has_class_flag c CExtern) then make_native cf

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

@@ -204,8 +204,8 @@ let rec expr_to_value ctx env e =
 		| EConst cst ->
 			begin match cst with
 				| String(s,_) -> EvalString.create_unknown s
-				| Int s -> VInt32 (Int32.of_string s)
-				| Float s -> VFloat (float_of_string s)
+				| Int (s,_) -> VInt32 (Int32.of_string s)
+				| Float (s,_) -> VFloat (float_of_string s)
 				| Ident "true" -> VTrue
 				| Ident "false" -> VFalse
 				| Ident "null" -> VNull

+ 2 - 2
src/macro/eval/evalMain.ml

@@ -439,7 +439,7 @@ let rec value_to_expr v p =
 	| VNull -> (EConst (Ident "null"),p)
 	| VTrue -> (EConst (Ident "true"),p)
 	| VFalse -> (EConst (Ident "false"),p)
-	| VInt32 i -> (EConst (Int (Int32.to_string i)),p)
+	| VInt32 i -> (EConst (Int (Int32.to_string i,None)),p)
 	| VFloat f -> haxe_float f p
 	| VString s -> (EConst (String(s.sstring,SDoubleQuotes)),p)
 	| VArray va -> (EArrayDecl (List.map (fun v -> value_to_expr v p) (EvalArray.to_list va)),p)
@@ -470,7 +470,7 @@ let rec value_to_expr v p =
 		end
 	| VInstance {ikind = IIntMap m} ->
 		let el = IntHashtbl.fold (fun k v acc ->
-			let e_key = (EConst (Int (string_of_int k)),p) in
+			let e_key = (EConst (Int (string_of_int k, None)),p) in
 			(make_map_entry e_key v) :: acc
 		) m [] in
 		(EArrayDecl el,p)

+ 17 - 5
src/macro/macroApi.ml

@@ -198,7 +198,7 @@ let haxe_float f p =
 	else if (f <> f) then
 		(Ast.EField (math, "NaN"), p)
 	else
-		(Ast.EConst (Ast.Float (Numeric.float_repres f)), p)
+		(Ast.EConst (Ast.Float (Numeric.float_repres f, None)), p)
 
 (* ------------------------------------------------------------------------------------------------------------- *)
 (* Our macro api functor *)
@@ -226,8 +226,8 @@ let encode_string_literal_kind qs =
 
 let encode_const c =
 	let tag, pl = match c with
-	| Int s -> 0, [encode_string s]
-	| Float s -> 1, [encode_string s]
+	| Int (s, suffix) -> 0, [encode_string s;null encode_string suffix]
+	| Float (s, suffix) -> 1, [encode_string s;null encode_string suffix]
 	| String(s,qs) -> 2, [encode_string s;encode_string_literal_kind qs]
 	| Ident s -> 3, [encode_string s]
 	| Regexp (s,opt) -> 4, [encode_string s;encode_string opt]
@@ -547,8 +547,20 @@ let decode_string_literal_kind v =
 
 let decode_const c =
 	match decode_enum c with
-	| 0, [s] -> Int (decode_string s)
-	| 1, [s] -> Float (decode_string s)
+	| 0, [s;suffix] ->
+		let decoded_suffix = opt decode_string suffix in
+		(match decoded_suffix with
+		| None | Some "i32" | Some "i64" | Some "u32" ->
+			Int (decode_string s, decoded_suffix)
+		| Some other ->
+			raise Invalid_expr)
+	| 1, [s;suffix] ->
+		let decoded_suffix = opt decode_string suffix in
+		(match decoded_suffix with
+		| None | Some "f64" ->
+			Float (decode_string s, opt decode_string suffix)
+		| Some other ->
+			raise Invalid_expr)
 	| 2, [s;qs] -> String (decode_string s,decode_string_literal_kind qs)
 	| 3, [s] -> Ident (decode_string s)
 	| 4, [s;opt] -> Regexp (decode_string s, decode_string opt)

+ 4 - 4
src/optimization/inlineConstructors.ml

@@ -227,7 +227,7 @@ let inline_constructors ctx original_e =
 		let e = Type.map_expr (mark_ctors ~force_inline:is_meta_inline) e in
 		let mark() =
 			incr curr_io_id;
-			let id_expr = (EConst(Int (string_of_int !curr_io_id)), e.epos) in
+			let id_expr = (EConst(Int (string_of_int !curr_io_id, None)), e.epos) in
 			let meta = (Meta.InlineObject, [id_expr], e.epos) in
 			mk (TMeta(meta, e)) e.etype e.epos
 		in
@@ -439,10 +439,10 @@ let inline_constructors ctx original_e =
 				handle_default_case e
 		in
 		match e.eexpr with
-		| TMeta((Meta.Inline,_,_),{eexpr = TMeta((Meta.InlineObject, [(EConst(Int (id_str)), _)], _), e)}) ->
+		| TMeta((Meta.Inline,_,_),{eexpr = TMeta((Meta.InlineObject, [(EConst(Int (id_str, None)), _)], _), e)}) ->
 			let io_id = int_of_string id_str in
 			handle_inline_object_case io_id true e
-		| TMeta((Meta.InlineObject, [(EConst(Int (id_str)), _)], _), e) ->
+		| TMeta((Meta.InlineObject, [(EConst(Int (id_str, None)), _)], _), e) ->
 			let io_id = int_of_string id_str in
 			handle_inline_object_case io_id false e
 		| TVar(v,None) -> ignore(add v IVKLocal); None
@@ -592,7 +592,7 @@ let inline_constructors ctx original_e =
 			end
 		in
 		match e.eexpr with
-		| TMeta((Meta.InlineObject, [(EConst(Int (id_str)), _)], _), e) ->
+		| TMeta((Meta.InlineObject, [(EConst(Int (id_str, _)), _)], _), e) ->
 			let io_id = int_of_string id_str in
 			begin try
 				let io = get_io io_id in

+ 8 - 8
src/syntax/grammar.mly

@@ -1456,7 +1456,7 @@ and expr = parser
 				syntax_error (Expected ["{"]) s (ESwitch(e,[],None),punion p1 (pos e))
 		end
 	| [< '(Kwd Try,p1); e = secure_expr; cl,p2 = parse_catches e [] (pos e) >] -> (ETry (e,cl),punion p1 p2)
-	| [< '(IntInterval i,p1); e2 = expr >] -> make_binop OpInterval (EConst (Int i),p1) e2
+	| [< '(IntInterval i,p1); e2 = expr >] -> make_binop OpInterval (EConst (Int (i, None)),p1) e2
 	| [< '(Kwd Untyped,p1); e = secure_expr >] -> (EUntyped e,punion p1 (pos e))
 	| [< '(Dollar v,p); s >] -> expr_next (EConst (Ident ("$"^v)),p) s
 	| [< '(Kwd Inline,p); e = secure_expr >] -> make_meta Meta.Inline [] e p
@@ -1527,7 +1527,7 @@ and parse_field e1 p s =
 		| [< >] ->
 			(* turn an integer followed by a dot into a float *)
 			match e1 with
-			| (EConst (Int v),p2) when p2.pmax = p.pmin -> expr_next (EConst (Float (v ^ ".")),punion p p2) s
+			| (EConst (Int (v, None)),p2) when p2.pmax = p.pmin -> expr_next (EConst (Float (v ^ ".", None)),punion p p2) s
 			| _ -> serror()
 		end
 	)
@@ -1637,8 +1637,8 @@ and secure_expr = parser
 let rec validate_macro_cond s e = match fst e with
 	| EConst (Ident _)
 	| EConst (String _)
-	| EConst (Int _)
-	| EConst (Float _)
+	| EConst (Int (_, _))
+	| EConst (Float (_, _))
 		-> e
 	| EUnop (op,p,e1) -> (EUnop (op, p, validate_macro_cond s e1), snd e)
 	| EBinop (op,e1,e2) -> (EBinop(op, (validate_macro_cond s e1), (validate_macro_cond s e2)), snd e)
@@ -1660,10 +1660,10 @@ let rec parse_macro_cond s =
 				parse_macro_ident t p s
 			| [< '(Const (String(s,qs)),p) >] ->
 				None, (EConst (String(s,qs)),p)
-			| [< '(Const (Int i),p) >] ->
-				None, (EConst (Int i),p)
-			| [< '(Const (Float f),p) >] ->
-				None, (EConst (Float f),p)
+			| [< '(Const (Int (i, s)),p) >] ->
+				None, (EConst (Int (i, s)),p)
+			| [< '(Const (Float (f, s)),p) >] ->
+				None, (EConst (Float (f, s)),p)
 			| [< '(Kwd k,p) >] ->
 				parse_macro_ident (s_keyword k) p s
 			| [< '(Unop op,p); tk, e = parse_macro_cond >] ->

+ 33 - 6
src/syntax/lexer.ml

@@ -111,6 +111,25 @@ let is_valid_identifier s =
 		with Exit ->
 			false
 
+let split_int_suffix s =
+	let is_signed = String.contains s 'i' in
+	match String.index_opt s (if is_signed then 'i' else 'u') with
+	| Some pivot ->
+		let literal = String.sub s 0 pivot in
+		let suffix  = String.sub s pivot ((String.length s) - pivot) in
+		Const (Int (literal, Some suffix))
+	| None ->
+		Const (Int (s, None))
+
+let split_float_suffix s =
+	match String.index_opt s 'f' with
+	| Some pivot ->
+		let literal = String.sub s 0 pivot in
+		let suffix  = String.sub s pivot ((String.length s) - pivot) in
+		Const (Float (literal, Some suffix))
+	| None ->
+		Const (Float (s, None))
+	
 let init file =
 	let f = make_file file in
 	cur := f;
@@ -301,6 +320,10 @@ let idtype = [%sedlex.regexp? Star '_', 'A'..'Z', Star ('_' | 'a'..'z' | 'A'..'Z
 
 let integer = [%sedlex.regexp? ('1'..'9', Star ('0'..'9')) | '0']
 
+let integer_suffix = [%sedlex.regexp? ('i'|'u'), Plus integer]
+
+let float_suffix = [%sedlex.regexp? 'f', Plus integer]
+
 (* https://www.w3.org/TR/xml/#sec-common-syn plus '$' for JSX *)
 let xml_name_start_char = [%sedlex.regexp? '$' | ':' | 'A'..'Z' | '_' | 'a'..'z' | 0xC0 .. 0xD6 | 0xD8 .. 0xF6 | 0xF8 .. 0x2FF | 0x370 .. 0x37D | 0x37F .. 0x1FFF | 0x200C .. 0x200D | 0x2070 .. 0x218F | 0x2C00 .. 0x2FEF | 0x3001 .. 0xD7FF | 0xF900 .. 0xFDCF | 0xFDF0 .. 0xFFFD | 0x10000 .. 0xEFFFF]
 let xml_name_char = [%sedlex.regexp? xml_name_start_char | '-' | '.' | '0'..'9' | 0xB7 | 0x0300 .. 0x036F | 0x203F .. 0x2040]
@@ -319,12 +342,16 @@ let rec token lexbuf =
 	| Plus (Chars " \t") -> token lexbuf
 	| "\r\n" -> newline lexbuf; token lexbuf
 	| '\n' | '\r' -> newline lexbuf; token lexbuf
-	| "0x", Plus ('0'..'9'|'a'..'f'|'A'..'F') -> mk lexbuf (Const (Int (lexeme lexbuf)))
-	| integer -> mk lexbuf (Const (Int (lexeme lexbuf)))
-	| integer, '.', Plus '0'..'9' -> mk lexbuf (Const (Float (lexeme lexbuf)))
-	| '.', Plus '0'..'9' -> mk lexbuf (Const (Float (lexeme lexbuf)))
-	| integer, ('e'|'E'), Opt ('+'|'-'), Plus '0'..'9' -> mk lexbuf (Const (Float (lexeme lexbuf)))
-	| integer, '.', Star '0'..'9', ('e'|'E'), Opt ('+'|'-'), Plus '0'..'9' -> mk lexbuf (Const (Float (lexeme lexbuf)))
+	| "0x", Plus ('0'..'9'|'a'..'f'|'A'..'F'), Opt integer_suffix ->
+		mk lexbuf (split_int_suffix (lexeme lexbuf))
+	| integer, Opt integer_suffix ->
+		mk lexbuf (split_int_suffix (lexeme lexbuf))
+	| integer, float_suffix ->
+		mk lexbuf (split_float_suffix (lexeme lexbuf))
+	| integer, '.', Plus '0'..'9', Opt float_suffix -> mk lexbuf (split_float_suffix (lexeme lexbuf))
+	| '.', Plus '0'..'9', Opt float_suffix -> mk lexbuf (split_float_suffix (lexeme lexbuf))
+	| integer, ('e'|'E'), Opt ('+'|'-'), Plus '0'..'9', Opt float_suffix -> mk lexbuf (split_float_suffix (lexeme lexbuf))
+	| integer, '.', Star '0'..'9', ('e'|'E'), Opt ('+'|'-'), Plus '0'..'9', Opt float_suffix -> mk lexbuf (split_float_suffix (lexeme lexbuf))
 	| integer, "..." ->
 		let s = lexeme lexbuf in
 		mk lexbuf (IntInterval (String.sub s 0 (String.length s - 3)))

+ 2 - 2
src/syntax/parser.ml

@@ -302,8 +302,8 @@ let rec make_unop op ((v,p2) as e) p1 =
 	| EBinop (bop,e,e2) -> EBinop (bop, make_unop op e p1 , e2) , (punion p1 p2)
 	| ETernary (e1,e2,e3) -> ETernary (make_unop op e1 p1 , e2, e3), punion p1 p2
 	| EIs (e, t) -> EIs (make_unop op e p1, t), punion p1 p2
-	| EConst (Int i) when op = Neg -> EConst (Int (neg i)),punion p1 p2
-	| EConst (Float j) when op = Neg -> EConst (Float (neg j)),punion p1 p2
+	| EConst (Int (i, suffix)) when op = Neg -> EConst (Int (neg i, suffix)),punion p1 p2
+	| EConst (Float (j, suffix)) when op = Neg -> EConst (Float (neg j, suffix)),punion p1 p2
 	| _ -> EUnop (op,Prefix,e), punion p1 p2
 
 let rec make_meta name params ((v,p2) as e) p1 =

+ 3 - 3
src/syntax/parserEntry.ml

@@ -72,8 +72,8 @@ let rec eval ctx (e,p) =
 	| EConst (Ident i) ->
 		(try TString (Define.raw_defined_value ctx i) with Not_found -> TNull)
 	| EConst (String(s,_)) -> TString s
-	| EConst (Int i) -> TFloat (float_of_string i)
-	| EConst (Float f) -> TFloat (float_of_string f)
+	| EConst (Int (i, _)) -> TFloat (float_of_string i)
+	| EConst (Float (f, _)) -> TFloat (float_of_string f)
 	| ECall ((EConst (Ident "version"),_),[(EConst (String(s,_)), p)]) -> parse_version s p
 	| EBinop (OpBoolAnd, e1, e2) -> TBool (is_true (eval ctx e1) && is_true (eval ctx e2))
 	| EBinop (OpBoolOr, e1, e2) -> TBool (is_true (eval ctx e1) || is_true(eval ctx e2))
@@ -290,7 +290,7 @@ let parse entry ctx code file =
 			| _ -> error Unimplemented (snd tk))
 		| Sharp "line" ->
 			let line = (match next_token() with
-				| (Const (Int s),p) -> (try int_of_string s with _ -> error (Custom ("Could not parse ridiculous line number " ^ s)) p)
+				| (Const (Int (s, _)),p) -> (try int_of_string s with _ -> error (Custom ("Could not parse ridiculous line number " ^ s)) p)
 				| (t,p) -> error (Unexpected t) p
 			) in
 			!(Lexer.cur).Lexer.lline <- line - 1;

+ 13 - 7
src/syntax/reification.ml

@@ -30,14 +30,17 @@ let reify in_macro =
 		| _ -> (ECall (constr,vl),pmin)
 	in
 	let to_const c p =
-		let cst n v = mk_enum "Constant" n [EConst (String(v,SDoubleQuotes)),p] p in
 		match c with
-		| Int i -> cst "CInt" i
+		| Int (i, suffix) ->
+			let suffix = match suffix with None -> (EConst (Ident "null"),p) | Some s -> (EConst (String (s, SDoubleQuotes)),p) in
+			mk_enum "Constant" "CInt" [(EConst (String(i,SDoubleQuotes)),p);suffix] p
 		| String(s,qs) ->
 			let qs = mk_enum "StringLiteralKind" (match qs with SDoubleQuotes -> "DoubleQuotes" | SSingleQuotes -> "SingleQuotes") [] p in
 			mk_enum "Constant" "CString" [(EConst (String(s,SDoubleQuotes)),p);qs] p
-		| Float s -> cst "CFloat" s
-		| Ident s -> cst "CIdent" s
+		| Float (f, suffix) ->
+			let suffix = match suffix with None -> (EConst (Ident "null"),p) | Some s -> (EConst (String (s, SDoubleQuotes)),p) in
+			mk_enum "Constant" "CFloat" [(EConst (String(f,SDoubleQuotes)),p);suffix] p
+		| Ident s -> mk_enum "Constant" "CIdent" [EConst (String(s,SDoubleQuotes)),p] p
 		| Regexp (r,o) -> mk_enum "Constant" "CRegexp" [(EConst (String(r,SDoubleQuotes)),p);(EConst (String(o,SDoubleQuotes)),p)] p
 	in
 	let rec to_binop o p =
@@ -220,8 +223,8 @@ let reify in_macro =
 			p
 		| None ->
 		let file = (EConst (String(p.pfile,SDoubleQuotes)),p) in
-		let pmin = (EConst (Int (string_of_int p.pmin)),p) in
-		let pmax = (EConst (Int (string_of_int p.pmax)),p) in
+		let pmin = (EConst (Int ((string_of_int p.pmin), None)),p) in
+		let pmax = (EConst (Int ((string_of_int p.pmax), None)),p) in
 		if in_macro then
 			(EUntyped (ECall ((EConst (Ident "$__mk_pos__"),p),[file;pmin;pmax]),p),p)
 		else
@@ -351,7 +354,10 @@ let reify in_macro =
 				| EParenthesis (ECheckType (e2, (CTPath{tname="String";tpackage=[]},_)),_) -> expr "EConst" [mk_enum "Constant" "CString" [e2] (pos e2)]
 				| EParenthesis (ECheckType (e2, (CTPath{tname="Int";tpackage=[]},_)),_) -> expr "EConst" [mk_enum "Constant" "CInt" [e2] (pos e2)]
 				| EParenthesis (ECheckType (e2, (CTPath{tname="Float";tpackage=[]},_)),_) -> expr "EConst" [mk_enum "Constant" "CFloat" [e2] (pos e2)]
-				| _ -> (ECall ((EField ((EField ((EField ((EConst (Ident "haxe"),p),"macro"),p),"Context"),p),"makeExpr"),p),[e; to_enc_pos (pos e)]),p)
+				| EConst (Int (s, Some "i64")) ->
+					expr "EConst" [mk_enum "Constant" "CInt" [ (EConst(String (s, SDoubleQuotes)),(pos e1)); (EConst(String ("i64", SDoubleQuotes)),(pos e1)) ] (pos e1)]
+				| _ ->
+					(ECall ((EField ((EField ((EField ((EConst (Ident "haxe"),p),"macro"),p),"Context"),p),"makeExpr"),p),[e1; to_enc_pos (pos e1)]),p)
 				end
 			| Meta.Dollar "i", _ ->
 				expr "EConst" [mk_enum "Constant" "CIdent" [e1] (pos e1)]

+ 3 - 3
src/typing/macroContext.ml

@@ -210,7 +210,7 @@ let make_macro_api ctx p =
 			let p = te.epos in
 			let id = get_next_stored_typed_expr_id() in
 			ctx.com.stored_typed_exprs <- PMap.add id te ctx.com.stored_typed_exprs;
-			let eid = (EConst (Int (string_of_int id))), p in
+			let eid = (EConst (Int (string_of_int id, None))), p in
 			(EMeta ((Meta.StoredTypedExpr,[],p), eid)), p
 		);
 		MacroApi.allow_package = (fun v -> Common.allow_package ctx.com v);
@@ -696,7 +696,7 @@ let type_macro ctx mode cpath f (el:Ast.expr list) p =
 			in
 			(* let's track the index by doing [e][index] (we will keep the expression type this way) *)
 			incr index;
-			(EArray ((EArrayDecl [e],p),(EConst (Int (string_of_int (!index))),p)),p)
+			(EArray ((EArrayDecl [e],p),(EConst (Int (string_of_int (!index), None)),p)),p)
 		) el in
 		let elt = fst (CallUnification.unify_call_args mctx constants (List.map fst eargs) t_dynamic p false false false) in
 		List.map2 (fun ((n,_,t),mct) e ->
@@ -814,7 +814,7 @@ let setup() =
 	Interp.setup Interp.macro_api
 
 let type_stored_expr ctx e1 =
-	let id = match e1 with (EConst (Int s),_) -> int_of_string s | _ -> die "" __LOC__ in
+	let id = match e1 with (EConst (Int (s, _)),_) -> int_of_string s | _ -> die "" __LOC__ in
 	get_stored_typed_expr ctx.com id
 
 ;;

+ 1 - 1
src/typing/matcher.ml

@@ -334,7 +334,7 @@ module Pattern = struct
 				let e = loop e in
 				pctx.in_reification <- old;
 				e
-			| EConst((Ident ("false" | "true") | Int _ | String _ | Float _) as ct) ->
+			| EConst((Ident ("false" | "true") | Int (_,_) | String _ | Float (_,_)) as ct) ->
 				begin match ct with
 					| String (value,kind) when kind = Ast.SSingleQuotes ->
 						let e = ctx.g.do_format_string ctx value p in

+ 2 - 2
src/typing/typeload.ml

@@ -345,8 +345,8 @@ let rec load_instance' ctx (t,p) allow_no_params =
 				| TPExpr e ->
 					let name = (match fst e with
 						| EConst (String(s,_)) -> "S" ^ s
-						| EConst (Int i) -> "I" ^ i
-						| EConst (Float f) -> "F" ^ f
+						| EConst (Int (_,_) as c) -> "I" ^ s_constant c
+						| EConst (Float (_,_) as c) -> "F" ^ s_constant c
 						| EDisplay _ ->
 							ignore(type_expr ctx e WithType.value);
 							"Expr"

+ 3 - 3
src/typing/typeloadFields.ml

@@ -418,14 +418,14 @@ let build_enum_abstract ctx c a fields p =
 						| EAString ->
 							set_field field ct (EConst (String (fst field.cff_name,SDoubleQuotes)),null_pos)
 						| EAInt i ->
-							set_field field ct (EConst (Int (string_of_int !i)),null_pos);
+							set_field field ct (EConst (Int (string_of_int !i, None)),null_pos);
 							incr i;
 						| EAOther ->
 							typing_error "Value required" field.cff_pos
 					end else field.cff_kind <- FProp(("default",null_pos),("never",null_pos),ct,None)
 				| Some e ->
 					begin match mode,e with
-						| EAInt i,(EConst(Int s),_) ->
+						| EAInt i,(EConst(Int (s, None)),_) ->
 							begin try
 								let i' = int_of_string s in
 								i := (i' + 1)
@@ -1607,7 +1607,7 @@ let init_class ctx c p context_init herits fields =
 				| e :: l ->
 					let sc = match fst e with
 						| EConst (Ident s) -> s
-						| EBinop ((OpEq|OpNotEq|OpGt|OpGte|OpLt|OpLte) as op,(EConst (Ident s),_),(EConst ((Int _ | Float _ | String _) as c),_)) -> s ^ s_binop op ^ s_constant c
+						| EBinop ((OpEq|OpNotEq|OpGt|OpGte|OpLt|OpLte) as op,(EConst (Ident s),_),(EConst ((Int (_,_) | Float (_,_) | String _) as c),_)) -> s ^ s_binop op ^ s_constant c
 						| _ -> ""
 					in
 					if not (ParserEntry.is_true (ParserEntry.eval ctx.com.defines e)) then

+ 2 - 2
src/typing/typeloadModule.ml

@@ -83,9 +83,9 @@ module StrictMeta = struct
 		| TField(e,f) ->
 			(EField(process_meta_argument ~toplevel:false ctx e,field_name f),expr.epos)
 		| TConst(TInt i) ->
-			(EConst(Int (Int32.to_string i)), expr.epos)
+			(EConst(Int (Int32.to_string i, None)), expr.epos)
 		| TConst(TFloat f) ->
-			(EConst(Float f), expr.epos)
+			(EConst(Float (f, None)), expr.epos)
 		| TConst(TString s) ->
 			(EConst(String(s,SDoubleQuotes)), expr.epos)
 		| TConst TNull ->

+ 27 - 0
src/typing/typer.ml

@@ -1673,6 +1673,33 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
 		mk (TNew ((match t with TInst (c,[]) -> c | _ -> die "" __LOC__),[],[str;opt])) t p
 	| EConst (String(s,SSingleQuotes)) when s <> "" ->
 		type_expr ctx (format_string ctx s p) with_type
+	| EConst (Int (s, Some suffix)) ->
+		(match suffix with
+		| "i32" ->
+			(try mk (TConst (TInt (Int32.of_string s))) ctx.com.basic.tint p
+			with _ -> typing_error ("Cannot represent " ^ s ^ " with a 32 bit integer") p)
+		| "i64" ->
+			if String.length s > 18 && String.sub s 0 2 = "0x" then typing_error "Invalid hexadecimal integer" p;
+
+			let i64  = Int64.of_string s in
+			let high = Int64.to_int32 (Int64.shift_right i64 32) in
+			let low  = Int64.to_int32 i64 in
+
+			let ident = EConst (Ident "haxe"), p in
+			let field = EField ((EField (ident, "Int64"), p), "make"), p in
+
+			let arg_high = EConst (Int (Int32.to_string high, None)), p in
+			let arg_low  = EConst (Int (Int32.to_string low, None)), p in
+			let call     = ECall (field, [ arg_high; arg_low ]), p in
+			type_expr ctx call with_type
+		| "u32" ->
+			let check = ECheckType ((EConst (Int (s, None)), p), (CTPath (mk_type_path ([],"UInt")), p)), p in
+			type_expr ctx check with_type
+		| other -> typing_error (other ^ " is not a valid integer suffix") p)
+	| EConst (Float (s, Some suffix) as c) ->
+		(match suffix with
+		| "f64" -> Texpr.type_constant ctx.com.basic c p
+		| other -> typing_error (other ^ " is not a valid float suffix") p)
 	| EConst c ->
 		Texpr.type_constant ctx.com.basic c p
 	| EBinop (op,e1,e2) ->

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

@@ -60,12 +60,12 @@ enum Constant {
 	/**
 		Represents an integer literal.
 	**/
-	CInt(v:String);
+	CInt(v:String, ?s:String);
 
 	/**
 		Represents a float literal.
 	**/
-	CFloat(f:String);
+	CFloat(f:String, ?s:String);
 
 	/**
 		Represents a string literal.

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

@@ -101,8 +101,10 @@ class Printer {
 		return switch (c) {
 			case CString(s, SingleQuotes): printFormatString(s);
 			case CString(s, _): printString(s);
-			case CIdent(s), CInt(s), CFloat(s):
+			case CIdent(s), CInt(s, null), CFloat(s, null):
 				s;
+			case CInt(s, suffix), CFloat(s, suffix):
+				s + suffix;
 			case CRegexp(s, opt): '~/$s/$opt';
 		}
 

+ 2 - 2
tests/display/src/cases/Issue7328.hx

@@ -7,13 +7,13 @@ class Issue7328 extends DisplayTestCase {
 		class Main {
 			public static function main() {
 				switch (null:ExprDef) {
-					case EConst(CInt({-1-}v)):
+					case EConst(CIdent({-1-}s)):
 					case _:
 				}
 			}
 		}
 	**/
 	function test() {
-		sigEq(0, [["v:String"]], signature(pos(1)));
+		sigEq(0, [["s:String"]], signature(pos(1)));
 	}
 }

+ 8 - 0
tests/unit/src/unit/TestInt64.hx

@@ -13,6 +13,14 @@ class TestInt64 extends Test {
 		eq( a.high, 10 );
 		eq( a.low, 0xFFFFFFFF );
 
+		a = 47244640255i64;
+		eq( a.high, 10 );
+		eq( a.low, 0xFFFFFFFF );
+
+		a = 0x7FFFFFFFFFFFFFFFi64;
+		eq( a.high, 0x7FFFFFFF );
+		eq( a.low, 0xFFFFFFFF );
+
 		// Int casts
 		a = 1;
 		eq( a.toInt(), 1 );

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

@@ -50,6 +50,7 @@ function main() {
 	var classes = [
 		new TestOps(),
 		new TestBasetypes(),
+		new TestNumericSuffixes(),
 		new TestExceptions(),
 		new TestBytes(),
 		new TestIO(),

+ 3 - 3
tests/unit/src/unit/TestMatch.hx

@@ -136,7 +136,7 @@ class TestMatch extends Test {
 		eq("foo", switchNormal(macro null.foo));
 		eq("22", switchNormal(macro null[22]));
 		eq("22.5", switchNormal(macro null[22.5]));
-		eq("EConst(CInt(0))", switchNormal(macro 1 in 0));
+		eq("EConst(CInt(0,null))", switchNormal(macro 1 in 0));
 		eq("not_found", switchNormal(macro null["22"]));
 
 		t(null != switchCapture(macro "foobar"));
@@ -146,8 +146,8 @@ class TestMatch extends Test {
 
 		eq("[]", switchArray(macro []));
 		eq("_", switchArray(macro 2));
-		eq("[EConst(CInt(22))]", switchArray(macro [22]));
-		eq("[EConst(CInt(22)),EConst(CString(foo,DoubleQuotes))]", switchArray(macro [22,"foo"]));
+		eq("[EConst(CInt(22,null))]", switchArray(macro [22]));
+		eq("[EConst(CInt(22,null)),EConst(CString(foo,DoubleQuotes))]", switchArray(macro [22,"foo"]));
 		eq("_", switchArray(macro [22, "foo", "bar"]));
 
 		eq("0", switchArray2(["a", "b"]));

+ 29 - 0
tests/unit/src/unit/TestNumericSuffixes.hx

@@ -0,0 +1,29 @@
+package unit;
+
+class TestNumericSuffixes extends Test {
+    
+    public function testIntSuffixes() {
+        eq(7i32, 7);
+        eq(-7i32, -7);
+        eq(-1u32, (-1 : UInt));
+        eq(3000000000000i64 + "", "3000000000000");
+        eq(9223372036854775807i64 + "", "9223372036854775807");
+    }
+
+    public function testFloatSuffixes() {
+        eq(7.0f64, 7.0);
+        eq(-7.0f64, -7.0);
+        eq(1f64 is Float, true);
+        eq(.0f64, 0.0);
+        eq(7e+0f64, 7e+0);
+        eq(7.0e+0f64, 7.0e+0);
+    }
+
+    public function testHexSuffixes() {
+        eq(0xFFFFFFFFi32, -1);
+        eq(0xFFFFFFFFu32, (0xFFFFFFFF : UInt));
+        eq(0xFFFFFFFFi64 + "", "4294967295");
+        eq(0xFFFFFFFFFFFFFFFFi64 + "", "-1");
+        eq(0x7FFFFFFFFFFFFFFFi64 + "", "9223372036854775807");
+    }
+}

+ 23 - 23
tests/unit/src/unitstd/haxe/macro/ExprTools.unit.hx

@@ -72,29 +72,29 @@ iter(econst, fail);
 iter(econtinue, fail);
 iter(ebreak, fail);
 iter(efield, seq.bind("EConst(CString(foo,DoubleQuotes))"));
-iter(eparenthesis, seq.bind("EConst(CInt(1))"));
-iter(euntyped, seq.bind("EConst(CInt(1))"));
-iter(ethrow, seq.bind("EConst(CInt(1))"));
-iter(eunop, seq.bind("EConst(CInt(1))"));
-iter(ecast, seq.bind("EConst(CInt(1))"));
-iter(emeta, seq.bind("EConst(CInt(1))"));
-check(earray, ["EConst(CInt(1))", "EConst(CInt(0))"]);
-check(ewhile1, ["EConst(CInt(1))", "EConst(CString(foo,DoubleQuotes))"]);
-check(ewhile2, ["EConst(CInt(1))", "EConst(CString(foo,DoubleQuotes))"]);
-check(ebinop, ["EConst(CInt(1))", "EConst(CInt(1))"]);
-check(efor, ["EConst(CInt(1))", "EConst(CString(foo,DoubleQuotes))"]);
-check(ein, ["EConst(CIdent(i))", "EConst(CInt(1))"]);
-check(evars, ["EConst(CInt(1))", "EConst(CInt(2))"]);
-check(etry, ["EConst(CInt(1))", "EConst(CString(foo,DoubleQuotes))", "EConst(CString(bar,DoubleQuotes))"]);
-check(eternary, ["EConst(CInt(1))", "EConst(CInt(2))", "EConst(CInt(3))"]);
-check(earraydecl, ["EConst(CInt(1))", "EConst(CInt(2))"]);
-check(enew, ["EConst(CInt(1))", "EConst(CInt(2))"]);
-check(eblock, ["EConst(CInt(1))", "EConst(CInt(2))"]);
-check(eobjectdecl, ["EConst(CInt(1))", "EConst(CInt(2))"]);
-check(ecall, ["EConst(CIdent(foo))", "EConst(CInt(1))", "EConst(CInt(2))"]);
-check(ereturn, ["EConst(CInt(1))"]);
-check(efunction, ["EConst(CInt(1))", "EConst(CInt(2))", "EConst(CInt(3))"]);
-check(eswitch, ["EConst(CInt(1))", "EConst(CInt(2))", "EConst(CInt(3))", "EConst(CInt(4))", "EConst(CInt(5))", "EConst(CInt(6))"]);
+iter(eparenthesis, seq.bind("EConst(CInt(1,null))"));
+iter(euntyped, seq.bind("EConst(CInt(1,null))"));
+iter(ethrow, seq.bind("EConst(CInt(1,null))"));
+iter(eunop, seq.bind("EConst(CInt(1,null))"));
+iter(ecast, seq.bind("EConst(CInt(1,null))"));
+iter(emeta, seq.bind("EConst(CInt(1,null))"));
+check(earray, ["EConst(CInt(1,null))", "EConst(CInt(0,null))"]);
+check(ewhile1, ["EConst(CInt(1,null))", "EConst(CString(foo,DoubleQuotes))"]);
+check(ewhile2, ["EConst(CInt(1,null))", "EConst(CString(foo,DoubleQuotes))"]);
+check(ebinop, ["EConst(CInt(1,null))", "EConst(CInt(1,null))"]);
+check(efor, ["EConst(CInt(1,null))", "EConst(CString(foo,DoubleQuotes))"]);
+check(ein, ["EConst(CIdent(i))", "EConst(CInt(1,null))"]);
+check(evars, ["EConst(CInt(1,null))", "EConst(CInt(2,null))"]);
+check(etry, ["EConst(CInt(1,null))", "EConst(CString(foo,DoubleQuotes))", "EConst(CString(bar,DoubleQuotes))"]);
+check(eternary, ["EConst(CInt(1,null))", "EConst(CInt(2,null))", "EConst(CInt(3,null))"]);
+check(earraydecl, ["EConst(CInt(1,null))", "EConst(CInt(2,null))"]);
+check(enew, ["EConst(CInt(1,null))", "EConst(CInt(2,null))"]);
+check(eblock, ["EConst(CInt(1,null))", "EConst(CInt(2,null))"]);
+check(eobjectdecl, ["EConst(CInt(1,null))", "EConst(CInt(2,null))"]);
+check(ecall, ["EConst(CIdent(foo))", "EConst(CInt(1,null))", "EConst(CInt(2,null))"]);
+check(ereturn, ["EConst(CInt(1,null))"]);
+check(efunction, ["EConst(CInt(1,null))", "EConst(CInt(2,null))", "EConst(CInt(3,null))"]);
+check(eswitch, ["EConst(CInt(1,null))", "EConst(CInt(2,null))", "EConst(CInt(3,null))", "EConst(CInt(4,null))", "EConst(CInt(5,null))", "EConst(CInt(6,null))"]);
 
 // map
 function wrap(e) return macro ($e);