From ac976a4bf42d475328f26f34e70bf1317fc0bdec Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Wed, 1 Nov 2023 09:08:57 +0100 Subject: Parser: fix ambiguity with whitespace in version ranges (#40344) Allowing white space around `:` in version ranges introduces an ambiguity: ``` a@1: b ``` parses as `a@1:b` but should really be parsed as two separate specs `a@1:` and `b`. With white space disallowed around `:` in ranges, the ambiguity is resolved. --- lib/spack/spack/parser.py | 6 +++--- lib/spack/spack/test/spec_syntax.py | 35 ++++++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/lib/spack/spack/parser.py b/lib/spack/spack/parser.py index 55eee4f154..b73a189797 100644 --- a/lib/spack/spack/parser.py +++ b/lib/spack/spack/parser.py @@ -96,9 +96,9 @@ else: VALUE = r"(?:[a-zA-Z_0-9\-+\*.,:=\~\/\\]+)" QUOTED_VALUE = r"[\"']+(?:[a-zA-Z_0-9\-+\*.,:=\~\/\\\s]+)[\"']+" -VERSION = r"=?([a-zA-Z0-9_][a-zA-Z_0-9\-\.]*\b)" -VERSION_RANGE = rf"({VERSION}\s*:\s*{VERSION}(?!\s*=)|:\s*{VERSION}(?!\s*=)|{VERSION}\s*:|:)" -VERSION_LIST = rf"({VERSION_RANGE}|{VERSION})(\s*[,]\s*({VERSION_RANGE}|{VERSION}))*" +VERSION = r"=?(?:[a-zA-Z0-9_][a-zA-Z_0-9\-\.]*\b)" +VERSION_RANGE = rf"(?:(?:{VERSION})?:(?:{VERSION}(?!\s*=))?)" +VERSION_LIST = rf"(?:{VERSION_RANGE}|{VERSION})(?:\s*,\s*(?:{VERSION_RANGE}|{VERSION}))*" class TokenBase(enum.Enum): diff --git a/lib/spack/spack/test/spec_syntax.py b/lib/spack/spack/test/spec_syntax.py index e7a760dc93..1d98731785 100644 --- a/lib/spack/spack/test/spec_syntax.py +++ b/lib/spack/spack/test/spec_syntax.py @@ -472,33 +472,46 @@ def specfile_for(default_mock_concretization): [Token(TokenType.PROPAGATED_KEY_VALUE_PAIR, value='cflags=="-O3 -g"')], 'cflags=="-O3 -g"', ), - # Way too many spaces + # Whitespace is allowed in version lists + ("@1.2:1.4 , 1.6 ", [Token(TokenType.VERSION, value="@1.2:1.4 , 1.6")], "@1.2:1.4,1.6"), + # But not in ranges. `a@1:` and `b` are separate specs, not a single `a@1:b`. ( - "@1.2 : 1.4 , 1.6 ", - [Token(TokenType.VERSION, value="@1.2 : 1.4 , 1.6")], - "@1.2:1.4,1.6", + "a@1: b", + [ + Token(TokenType.UNQUALIFIED_PACKAGE_NAME, value="a"), + Token(TokenType.VERSION, value="@1:"), + Token(TokenType.UNQUALIFIED_PACKAGE_NAME, value="b"), + ], + "a@1:", + ), + ( + "@1.2: develop = foo", + [ + Token(TokenType.VERSION, value="@1.2:"), + Token(TokenType.KEY_VALUE_PAIR, value="develop = foo"), + ], + "@1.2: develop=foo", ), - ("@1.2 : develop", [Token(TokenType.VERSION, value="@1.2 : develop")], "@1.2:develop"), ( - "@1.2 : develop = foo", + "@1.2:develop = foo", [ - Token(TokenType.VERSION, value="@1.2 :"), + Token(TokenType.VERSION, value="@1.2:"), Token(TokenType.KEY_VALUE_PAIR, value="develop = foo"), ], "@1.2: develop=foo", ), ( - "% intel @ 12.1 : 12.6 + debug", + "% intel @ 12.1:12.6 + debug", [ - Token(TokenType.COMPILER_AND_VERSION, value="% intel @ 12.1 : 12.6"), + Token(TokenType.COMPILER_AND_VERSION, value="% intel @ 12.1:12.6"), Token(TokenType.BOOL_VARIANT, value="+ debug"), ], "%intel@12.1:12.6+debug", ), ( - "@ 12.1 : 12.6 + debug - qt_4", + "@ 12.1:12.6 + debug - qt_4", [ - Token(TokenType.VERSION, value="@ 12.1 : 12.6"), + Token(TokenType.VERSION, value="@ 12.1:12.6"), Token(TokenType.BOOL_VARIANT, value="+ debug"), Token(TokenType.BOOL_VARIANT, value="- qt_4"), ], -- cgit v1.2.3-70-g09d2