Browse Source

[parser] make semicolon after xml literals optional

see #7438
Simon Krajewski 6 years ago
parent
commit
b7944d40e2

+ 10 - 11
src/syntax/grammar.mly

@@ -945,6 +945,14 @@ and parse_block_elt = parser
 		| [< e = secure_expr; _ = semicolon >] -> make_meta Meta.Inline [] e p1
 		| [< >] -> serror()
 		end
+	| [< '(Binop OpLt,p1); i = dollar_ident; s >] ->
+		let e = handle_xml_literal p1 i in
+		(* accept but don't expect semicolon *)
+		begin match s with parser
+			| [< '(Semicolon,_) >] -> ()
+			| [< >] -> ()
+		end;
+		e
 	| [< e = expr; _ = semicolon >] -> e
 
 and parse_obj_decl name e p0 s =
@@ -1102,17 +1110,8 @@ and expr = parser
 			let e = EConst (Ident "null"),null_pos in
 			make_meta name params e p
 		end
-	| [< '(Binop OpLt,p1); name,pi = dollar_ident; s >] ->
-		if p1.pmax <> pi.pmin then error (Custom("Unexpected <")) p1;
-		let open_tag = "<" ^ name in
-		let close_tag = "</" ^ name ^ ">" in
-		Lexer.reset();
-		Buffer.add_string Lexer.buf ("<" ^ name);
-		let i = Lexer.lex_xml p1.pmin open_tag close_tag !code_ref in
-		let xml = Lexer.contents() in
-		let e = EConst (String xml),{p1 with pmax = i} in
-		let e = make_meta Meta.Markup [] e p1 in
-		expr_next e s
+	| [< '(Binop OpLt,p1); i = dollar_ident >] ->
+		handle_xml_literal p1 i
 	| [< '(BrOpen,p1); s >] ->
 		(match s with parser
 		| [< b = block1; s >] ->

+ 12 - 0
src/syntax/parser.ml

@@ -224,6 +224,18 @@ let make_is e (t,p_t) p p_is =
 	let e2 = expr_of_type_path (t.tpackage,t.tname) p_t in
 	ECall(e_is,[e;e2]),p
 
+let handle_xml_literal p1 (name,pi) =
+	if p1.pmax <> pi.pmin then error (Custom("Unexpected <")) p1;
+	let open_tag = "<" ^ name in
+	let close_tag = "</" ^ name ^ ">" in
+	Lexer.reset();
+	Buffer.add_string Lexer.buf ("<" ^ name);
+	let i = Lexer.lex_xml p1.pmin open_tag close_tag !code_ref in
+	let xml = Lexer.contents() in
+	let e = EConst (String xml),{p1 with pmax = i} in
+	let e = make_meta Meta.Markup [] e p1 in
+	e
+
 let next_token s = match Stream.peek s with
 	| Some (Eof,p) ->
 		(Eof,{p with pmax = max_int})

+ 11 - 5
tests/unit/src/unit/HelperMacros.hx

@@ -86,12 +86,18 @@ class HelperMacros {
 	}
 
 	static public macro function pipeMarkupLiteral(e:Expr) {
-		return switch (e) {
-			case macro @:markup $v{(s:String)}:
-				formatString(s, e.pos);
-			case _:
-				error("Markup literal expected", e.pos);
+		function loop(e:Expr) {
+			return switch (e) {
+				case macro @:markup $v{(s:String)}:
+					formatString(s, e.pos);
+				case macro $b{el}:
+					el = el.map(loop);
+					macro $a{el}.join("");
+				case _:
+					error("Markup literal expected", e.pos);
+			}
 		}
+		return loop(e);
 	}
 
 	static public macro function pipeMarkupLiteralUnprocessed(e:Expr) {

+ 4 - 1
tests/unit/src/unitstd/InlineXml.unit.hx

@@ -33,4 +33,7 @@ unit.HelperMacros.pipeMarkupLiteral(<xml>$count + <xml>$count</xml> = ${count*2}
 unit.HelperMacros.pipeMarkupLiteralUnprocessed(<$xml></$xml>) == "<$xml></$xml>";
 
 // uppercase
-unit.HelperMacros.pipeMarkupLiteral(<Xml></Xml>) == "<Xml></Xml>";
+unit.HelperMacros.pipeMarkupLiteral(<Xml></Xml>) == "<Xml></Xml>";
+
+// no semicolon at block-level
+unit.HelperMacros.pipeMarkupLiteral({ <Xml></Xml><yml /> }) == "<Xml></Xml><yml />";