Browse Source

[display] fiddle with ESwitch positions

closes #7327
Simon Krajewski 6 years ago
parent
commit
f6a47954d8

+ 45 - 1
src/context/display/display.ml

@@ -29,7 +29,6 @@ end
 
 module ExprPreprocessing = struct
 	let find_before_pos dm e =
-
 		let display_pos = ref (DisplayPosition.display_position#get) in
 		let was_annotated = ref false in
 		let is_annotated,is_completion = match dm with
@@ -135,6 +134,51 @@ module ExprPreprocessing = struct
 				EArrayDecl el,(pos e)
 			| EObjectDecl fl when is_annotated (pos e) && is_completion ->
 				annotate e DKStructure
+			| ESwitch(e1,cases,def) when is_annotated (pos e) ->
+				(* We must be "between" two cases, or at the end of the last case.
+				   Let's find the last case which has a position that is < the display
+				   position and mark it. *)
+				let did_mark = ref false in
+				let mark_case ec p =
+					did_mark := true;
+					let ep = mk_null p in
+					match ec with
+					| Some ec ->
+						let ec = match fst ec with
+							| EBlock el -> (EBlock (el @ [ep]),p)
+							| _ -> (EBlock [ec;ep],p)
+						in
+						Some ec
+					| None ->
+						Some (mk_null p)
+				in
+				let rec loop cases = match cases with
+					| [el,eg,ec,p1] ->
+						let ec = match def with
+						| None when (pos e).pmax > !display_pos.pmin -> (* this is so we don't trigger if we're on the } *)
+							mark_case ec p1 (* no default, must be the last case *)
+						| Some (_,p2) when p1.pmax <= !display_pos.pmin && p2.pmin >= !display_pos.pmax ->
+							mark_case ec p1 (* default is beyond display position, mark *)
+						| _ ->
+							ec (* default contains display position, don't mark *)
+						in
+						[el,eg,ec,p1]
+					| (el1,eg1,ec1,p1) :: (el2,eg2,ec2,p2) :: cases ->
+						if p1.pmax <= !display_pos.pmin && p2.pmin >= !display_pos.pmax then
+							(el1,eg1,mark_case ec1 p1,p1) :: (el2,eg2,ec2,p2) :: cases
+						else
+							(el1,eg1,ec1,p1) :: loop ((el2,eg2,ec2,p2) :: cases)
+					| [] ->
+						[]
+				in
+				let cases = loop cases in
+				let def = if !did_mark then
+					def
+				else match def with
+					| Some(eo,p) when (pos e).pmax > !display_pos.pmin -> Some (mark_case eo p,p)
+					| _ -> def
+				in
+				ESwitch(e1,cases,def),pos e
 			| EDisplay _ ->
 				raise Exit
 			| EMeta((Meta.Markup,_,_),(EConst(String _),p)) when is_annotated p ->

+ 3 - 5
src/syntax/grammar.mly

@@ -1386,10 +1386,10 @@ and expr_or_var = parser
 	| [< e = secure_expr >] -> e
 
 and parse_switch_cases eswitch cases = parser
-	| [< '(Kwd Default,p1); '(DblDot,_); s >] ->
+	| [< '(Kwd Default,p1); '(DblDot,pdot); s >] ->
 		let b,p2 = (block_with_pos [] p1 s) in
 		let b = match b with
-			| [] -> None,p1
+			| [] -> None,pdot
 			| _ -> let p = punion p1 p2 in Some ((EBlock b,p)),p
 		in
 		let l , def = parse_switch_cases eswitch cases s in
@@ -1403,9 +1403,7 @@ and parse_switch_cases eswitch cases = parser
 		| _ ->
 			let b,p2 = (block_with_pos [] p1 s) in
 			let b,p = match b with
-				| [] ->
-					let p2 = match eg with Some e -> pos e | None -> match List.rev el with (_,p) :: _ -> p | [] -> p1 in
-					None,punion p1 p2
+				| [] -> None,punion p1 pdot
 				| _ -> let p = punion p1 p2 in Some ((EBlock b,p)),p
 			in
 			parse_switch_cases eswitch ((el,eg,b,p) :: cases) s

+ 71 - 0
tests/display/src/cases/Issue7327.hx

@@ -0,0 +1,71 @@
+package cases;
+
+class Issue7327 extends DisplayTestCase {
+	/**
+		import haxe.ds.Option;
+
+		class Main {
+			public static function main() {
+				var o:Option<Int> = None;
+				switch (o) {
+					case Some(v):{-1-} {-2-}
+					case None:
+				}
+			}
+		}
+	**/
+	function test1() {
+		eq(true, hasToplevel(toplevel(pos(1)), "local", "v", "Int"));
+		eq(true, hasToplevel(toplevel(pos(2)), "local", "v", "Int"));
+	}
+
+	/**
+		import haxe.ds.Option;
+
+		class Main {
+			public static function main() {
+				var o:Option<Int> = None;
+				switch (o) {
+					case Some(v):{-1-} {-2-}
+				{-3-}}{-4-}
+			}
+		}
+	**/
+	function test2() {
+		eq(true, hasToplevel(toplevel(pos(1)), "local", "v", "Int"));
+		eq(true, hasToplevel(toplevel(pos(2)), "local", "v", "Int"));
+		eq(true, hasToplevel(toplevel(pos(3)), "local", "v", "Int"));
+		eq(false, hasToplevel(toplevel(pos(4)), "local", "v", "Int"));
+	}
+
+	/**
+		import haxe.ds.Option;
+
+		class Main {
+			public static function main() {
+				var o:Option<Int> = None;
+				switch (o) {
+					case Some(v):{-1-}
+					default: {-2-}
+				}
+			}
+		}
+	**/
+	function test3() {
+		eq(true, hasToplevel(toplevel(pos(1)), "local", "v", "Int"));
+		eq(false, hasToplevel(toplevel(pos(2)), "local", "v", "Int"));
+	}
+
+	/**
+		import haxe.ds.Option;
+
+		class Main {
+			public static function main() {
+				var o:Option<Int> = None;
+				switch (o) {
+					case Some(v):{-1-}
+	**/
+	function test4() {
+		eq(true, hasToplevel(toplevel(pos(1)), "local", "v", "Int"));
+	}
+}

+ 1 - 1
tests/display/src/cases/Issue7947.hx

@@ -11,7 +11,7 @@ class Issue7947 extends DisplayTestCase {
 						trace('Some logic...');
 						trace('Some logic...');
 						true;
-					{-1-}case Right(_){-2-}:
+					{-1-}case Right(_):{-2-}
 				}
 			}
 		}