Browse Source

[parser] allow `var ?x` and `final ?x` parsing in structures

closes #6707
Simon Krajewski 7 years ago
parent
commit
bb1e8cfb08

+ 33 - 11
src/syntax/grammar.mly

@@ -73,6 +73,19 @@ let property_ident = parser
 	| [< '(Kwd Default,p) >] -> "default",p
 	| [< '(Kwd Default,p) >] -> "default",p
 	| [< '(Kwd Null,p) >] -> "null",p
 	| [< '(Kwd Null,p) >] -> "null",p
 
 
+let questionable_dollar_ident s =
+	let po = match s with parser
+		| [< '(Question,p) >] -> Some p
+		| [< >] -> None
+	in
+	let name,p = dollar_ident s in
+	match po with
+		| None ->
+			false,(name,p)
+		| Some p' ->
+			if p.pmin <> p'.pmax then error (Custom (Printf.sprintf "Invalid usage of ?, use ?%s instead" name)) p';
+			true,(name,p)
+
 let bropen = parser
 let bropen = parser
 	| [< '(BrOpen,_) >] -> ()
 	| [< '(BrOpen,_) >] -> ()
 
 
@@ -368,9 +381,9 @@ and resume tdecl fdecl s =
 
 
 and parse_class_field_resume tdecl s =
 and parse_class_field_resume tdecl s =
 	if not (!in_display) then
 	if not (!in_display) then
-		plist parse_class_field s
+		plist (parse_class_field tdecl) s
 	else try
 	else try
-		let c = parse_class_field s in
+		let c = parse_class_field tdecl s in
 		c :: parse_class_field_resume tdecl s
 		c :: parse_class_field_resume tdecl s
 	with Stream.Error _ | Stream.Failure ->
 	with Stream.Error _ | Stream.Failure ->
 		if resume tdecl true s then parse_class_field_resume tdecl s else []
 		if resume tdecl true s then parse_class_field_resume tdecl s else []
@@ -685,32 +698,41 @@ and parse_function_field doc meta al = parser
 			f_type = t;
 			f_type = t;
 			f_expr = e;
 			f_expr = e;
 		} in
 		} in
-		name, punion p1 p2, FFun f, al
+		name,punion p1 p2,FFun f,al,meta
 
 
 and parse_var_field_assignment = parser
 and parse_var_field_assignment = parser
 	| [< '(Binop OpAssign,_); e = toplevel_expr; p2 = semicolon >] -> Some e , p2
 	| [< '(Binop OpAssign,_); e = toplevel_expr; p2 = semicolon >] -> Some e , p2
 	| [< p2 = semicolon >] -> None , p2
 	| [< p2 = semicolon >] -> None , p2
 	| [< >] -> serror()
 	| [< >] -> serror()
 
 
-and parse_class_field s =
+and parse_class_field tdecl s =
 	let doc = get_doc s in
 	let doc = get_doc s in
 	match s with parser
 	match s with parser
 	| [< meta = parse_meta; al = plist parse_cf_rights; s >] ->
 	| [< meta = parse_meta; al = plist parse_cf_rights; s >] ->
-		let name, pos, k, al = (match s with parser
-		| [< '(Kwd Var,p1); name = dollar_ident; s >] ->
+		let check_optional opt name =
+			if opt then begin
+				if not tdecl then error (Custom "?var syntax is only allowed in structures") (pos name);
+				(Meta.Optional,[],null_pos) :: meta
+			end else
+				meta
+		in
+		let name,pos,k,al,meta = (match s with parser
+		| [< '(Kwd Var,p1); opt,name = questionable_dollar_ident; s >] ->
+			let meta = check_optional opt name in
 			begin match s with parser
 			begin match s with parser
 			| [< '(POpen,_); i1 = property_ident; '(Comma,_); i2 = property_ident; '(PClose,_) >] ->
 			| [< '(POpen,_); i1 = property_ident; '(Comma,_); i2 = property_ident; '(PClose,_) >] ->
 				let t = popt parse_type_hint s in
 				let t = popt parse_type_hint s in
 				let e,p2 = parse_var_field_assignment s in
 				let e,p2 = parse_var_field_assignment s in
-				name, punion p1 p2, FProp (i1,i2,t, e), al
+				name,punion p1 p2,FProp (i1,i2,t,e),al,meta
 			| [< t = popt parse_type_hint; s >] ->
 			| [< t = popt parse_type_hint; s >] ->
 				let e,p2 = parse_var_field_assignment s in
 				let e,p2 = parse_var_field_assignment s in
-				name, punion p1 p2, FVar (t,e), al
+				name,punion p1 p2,FVar (t,e),al,meta
 			end
 			end
 		| [< '(Kwd Final,p1) >] ->
 		| [< '(Kwd Final,p1) >] ->
 			begin match s with parser
 			begin match s with parser
-			| [< name = dollar_ident; t = popt parse_type_hint; e,p2 = parse_var_field_assignment >] ->
-				name,punion p1 p2,FVar(t,e),(al @ [AFinal,p1])
+			| [< opt,name = questionable_dollar_ident; t = popt parse_type_hint; e,p2 = parse_var_field_assignment >] ->
+				let meta = check_optional opt name in
+				name,punion p1 p2,FVar(t,e),(al @ [AFinal,p1]),meta
 			| [< al2 = plist parse_cf_rights; f = parse_function_field doc meta (al @ ((AFinal,p1) :: al2)) >] ->
 			| [< al2 = plist parse_cf_rights; f = parse_function_field doc meta (al @ ((AFinal,p1) :: al2)) >] ->
 				f
 				f
 			| [< >] ->
 			| [< >] ->
@@ -729,7 +751,7 @@ and parse_class_field s =
 						f_expr = None
 						f_expr = None
 					} in
 					} in
 					let _,p2 = next_token s in
 					let _,p2 = next_token s in
-					(magic_display_field_name,p2),punion po p2,FFun f,al
+					(magic_display_field_name,p2),punion po p2,FFun f,al,meta
 				| _ -> serror()
 				| _ -> serror()
 			end
 			end
 		) in
 		) in

+ 7 - 0
tests/misc/projects/Issue6707/Main.hx

@@ -0,0 +1,7 @@
+typedef MyTypedef = {
+	var ? x:String;
+}
+
+class Main {
+	static public function main() { }
+}

+ 2 - 0
tests/misc/projects/Issue6707/compile-fail.hxml

@@ -0,0 +1,2 @@
+-main Main
+--interp

+ 1 - 0
tests/misc/projects/Issue6707/compile-fail.hxml.stderr

@@ -0,0 +1 @@
+Main.hx:2: characters 6-7 : Invalid usage of ?, use ?x instead

+ 18 - 0
tests/unit/src/unit/issues/Issue6707.hx

@@ -0,0 +1,18 @@
+package unit.issues;
+
+private typedef T1 = {
+	var ?x:Int;
+	var y:String;
+}
+
+private typedef T2 = {
+	final ?x:Int;
+	var y:String;
+}
+
+class Issue6707 extends unit.Test {
+	function test() {
+		var t1:T1 = { y: "foo" };
+		var t2:T2 = { y: "foo" };
+	}
+}