Browse Source

emit an error on "invalid-version-str" vs version("1.0.0") comparison (fixes #8650)

Aleksandr Kuzmenko 6 years ago
parent
commit
a127de6427

+ 25 - 9
src/syntax/parserEntry.ml

@@ -35,17 +35,29 @@ let is_true = function
 	| TBool false | TNull | TFloat 0. | TString "" -> false
 	| _ -> true
 
+let s_small_type v =
+	match v with
+	| TNull -> "null"
+	| TBool _ -> "boolean"
+	| TFloat _ -> "float"
+	| TString _ -> "string"
+	| TVersion _ -> "version"
+
+let parse_version s p =
+	try match parse_version s with release,pre -> TVersion (release,pre)
+	with Invalid_argument msg -> error (Custom msg) p
+
 let cmp v1 v2 =
 	match v1, v2 with
-	| TNull, TNull -> 0
+	| TNull, _ | _, TNull -> raise Exit
 	| TFloat a, TFloat b -> compare a b
 	| TString a, TString b -> compare a b
 	| TBool a, TBool b -> compare a b
 	| TString a, TFloat b -> compare (float_of_string a) b
 	| TFloat a, TString b -> compare a (float_of_string b)
-	| TString a, TVersion (release,pre) -> compare_version (parse_version a) (release,pre)
-	| TVersion (release,pre), TString b -> compare_version (release,pre) (parse_version b)
 	| TVersion (release1,pre1), TVersion (release2,pre2) -> compare_version (release1,pre1) (release2,pre2)
+	| _, TVersion _
+	| TVersion _, _ -> raise (Invalid_argument ("Cannot compare " ^ (s_small_type v1) ^ " and " ^ (s_small_type v2)))
 	| _ -> raise Exit (* always false *)
 
 let rec eval ctx (e,p) =
@@ -55,18 +67,15 @@ let rec eval ctx (e,p) =
 	| EConst (String s) -> TString s
 	| EConst (Int i) -> TFloat (float_of_string i)
 	| EConst (Float f) -> TFloat (float_of_string f)
-	| ECall ((EConst (Ident "version"),_),[(EConst (String s), p)]) ->
-		(try match parse_version s with release,pre -> TVersion (release,pre)
-		with Invalid_argument msg -> error (Custom msg) p)
+	| 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))
 	| EUnop (Not, _, e) -> TBool (not (is_true (eval ctx e)))
 	| EParenthesis e -> eval ctx e
 	| EBinop (op, e1, e2) ->
-		let v1 = eval ctx e1 in
-		let v2 = eval ctx e2 in
+		let v1, v2 = eval_binop_exprs ctx e1 e2 in
 		let compare op =
-			try TBool (try op (cmp v1 v2) 0 with _ -> false)
+			try TBool (try op (cmp v1 v2) 0 with Exit -> false)
 			with Invalid_argument msg -> error (Custom msg) p
 		in
 		(match op with
@@ -88,6 +97,13 @@ let rec eval ctx (e,p) =
 	| _ ->
 		error (Custom "Invalid condition expression") p
 
+and eval_binop_exprs ctx e1 e2 =
+	match eval ctx e1, eval ctx e2 with
+	| (TVersion _ as v1), (TVersion _ as v2) -> (v1, v2)
+	| (TVersion _ as v1), TString s -> (v1, parse_version s (snd e2))
+	| TString s, (TVersion _ as v2) -> (parse_version s (snd e1), v2)
+	| v1, v2 -> (v1, v2)
+
 (* parse main *)
 let parse ctx code file =
 	let old = Lexer.save() in

+ 3 - 1
src/syntax/semver.ml

@@ -44,7 +44,9 @@ let to_string ((major,minor,patch),pre) =
 	Parse SemVer string
 *)
 let parse_version s =
-	let error () = raise (Invalid_argument "Invalid version string. Should follow SemVer.") in
+	let error () =
+		raise (Invalid_argument ("Invalid version string \"" ^ s ^ "\". Should follow SemVer."))
+	in
 	let parse dotted_str =
 		List.map
 			(fun s ->

+ 6 - 0
tests/misc/projects/Issue8650/Main.hx

@@ -0,0 +1,6 @@
+class Main {
+	static function main() {
+		#if (my_ver >= version("1.0.0"))
+		#end
+	}
+}

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

@@ -0,0 +1,2 @@
+-main Main
+-D my_ver=2.0

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

@@ -0,0 +1 @@
+Main.hx:3: characters 8-14 : Invalid version string "2.0". Should follow SemVer.

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

@@ -1 +1 @@
-InvalidVersion.hx:3: characters 16-21 : Invalid version string. Should follow SemVer.
+InvalidVersion.hx:3: characters 16-21 : Invalid version string "wat". Should follow SemVer.