diff options
-rw-r--r-- | docs/markdown/Syntax.md | 12 | ||||
-rw-r--r-- | docs/markdown/snippets/add_dictionary_variable_key.md | 20 | ||||
-rw-r--r-- | mesonbuild/interpreterbase.py | 25 | ||||
-rw-r--r-- | mesonbuild/mparser.py | 14 | ||||
-rw-r--r-- | test cases/common/193 dict/meson.build | 36 | ||||
-rw-r--r-- | test cases/common/228 add dict variable key/meson.build | 21 |
6 files changed, 67 insertions, 61 deletions
diff --git a/docs/markdown/Syntax.md b/docs/markdown/Syntax.md index b96e6e1..cf0516c 100644 --- a/docs/markdown/Syntax.md +++ b/docs/markdown/Syntax.md @@ -324,8 +324,8 @@ Dictionaries -- Dictionaries are delimited by curly braces. A dictionary can contain an -arbitrary number of key value pairs. Keys are required to be literal -strings, values can be objects of any type. +arbitrary number of key value pairs. Keys are required to be strings, values can +be objects of any type. Prior to *0.53.0* keys were required to be literal strings. ```meson my_dict = {'foo': 42, 'bar': 'baz'} @@ -359,6 +359,14 @@ if 'foo' not in my_dict endif ``` +*Since 0.53.0* Keys can be any expression evaluating to a string value, not limited +to string literals any more. +```meson +d = {'a' + 'b' : 42} +k = 'cd' +d += {k : 43} +``` + Function calls -- diff --git a/docs/markdown/snippets/add_dictionary_variable_key.md b/docs/markdown/snippets/add_dictionary_variable_key.md index 373ce04..72294ae 100644 --- a/docs/markdown/snippets/add_dictionary_variable_key.md +++ b/docs/markdown/snippets/add_dictionary_variable_key.md @@ -1,17 +1,9 @@ -## Adding dictionary entry using string variable as key - -New dictionary entry can now be added using string variable as key, -in addition to using string literal as key. +## Dictionary entry using string variable as key +Keys can now be any expression evaluating to a string value, not limited +to string literals any more. ```meson -dict = {} - -# A variable to be used as a key -key = 'myKey' - -# Add new entry using the variable -dict += {key : 'myValue'} - -# Test that the stored value is correct -assert(dict[key] == 'myValue', 'Incorrect value retrieved from dictionary') +d = {'a' + 'b' : 42} +k = 'cd' +d += {k : 43} ``` diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index 46f578e..2a976d3 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -496,7 +496,19 @@ class InterpreterBase: def evaluate_dictstatement(self, cur): (arguments, kwargs) = self.reduce_arguments(cur.args) assert (not arguments) - return kwargs + result = {} + self.argument_depth += 1 + for key, value in kwargs.items(): + if not isinstance(key, mparser.StringNode): + FeatureNew('Dictionary entry using non literal key', '0.53.0').use(self.subproject) + key = self.evaluate_statement(key) + if not isinstance(key, str): + raise InvalidArguments('Key must be a string') + if key in result: + raise InvalidArguments('Duplicate dictionary key: {}'.format(key)) + result[key] = value + self.argument_depth -= 1 + return result def evaluate_notstatement(self, cur): v = self.evaluate_statement(cur.value) @@ -731,16 +743,7 @@ The result of this is undefined and will become a hard error in a future Meson r elif isinstance(old_variable, dict): if not isinstance(addition, dict): raise InvalidArguments('The += operator requires a dict on the right hand side if the variable on the left is a dict') - new_addition = {} - for (key, value) in addition.items(): - if isinstance(key, str): - new_addition[key] = value - elif isinstance(key, mparser.IdNode) and isinstance(self.get_variable(key.value), str): - FeatureNew('Adding dictionary entry using string variable as key', '0.53.0').use(self.subproject) - new_addition[self.get_variable(key.value)] = value - else: - raise InvalidArguments('Dictionary key must be a string or string variable') - new_value = {**old_variable, **new_addition} + new_value = {**old_variable, **addition} # Add other data types here. else: raise InvalidArguments('The += operator currently only works with arrays, dicts, strings or ints ') diff --git a/mesonbuild/mparser.py b/mesonbuild/mparser.py index 80ffefd..76ad374 100644 --- a/mesonbuild/mparser.py +++ b/mesonbuild/mparser.py @@ -676,19 +676,7 @@ class Parser: while not isinstance(s, EmptyNode): potential = self.current if self.accept('colon'): - key_value = self.statement() - if isinstance(s, StringNode): - if s.value in a.kwargs: - # + 1 to colno to point to the actual string, not the opening quote - raise ParseException('Duplicate dictionary key: {}'.format(s.value), self.getline(), s.lineno, s.colno + 1) - a.set_kwarg(s.value, key_value) - elif isinstance(s, IdNode) and isinstance(s.value, str): - for key in a.kwargs: - if s.value == key.value: - raise ParseException('Duplicate dictionary variable key: {}'.format(s.value), self.getline(), s.lineno, s.colno) - a.set_kwarg(s, key_value) - else: - raise ParseException('Key must be a string or string variable', self.getline(), s.lineno, s.colno) + a.set_kwarg(s, self.statement()) potential = self.current if not self.accept('comma'): return a diff --git a/test cases/common/193 dict/meson.build b/test cases/common/193 dict/meson.build index 41eea31..dacf01d 100644 --- a/test cases/common/193 dict/meson.build +++ b/test cases/common/193 dict/meson.build @@ -33,3 +33,39 @@ d3 = d2 d3 += {'e' : 'f'} assert(d3 == {'a' : 'b2', 'c' : 'd', 'e' : 'f'}, 'dict plusassign is not working') assert(d2 == {'a' : 'b2', 'c' : 'd'}, 'dict should be immutable') + +dict1 = {} + +# A variable to be used as a key +testkey1 = 'myKey1' +testkey2 = 'myKey2' + +# Add new entry using the variable +dict1 += {testkey1 : 'myValue'} +dict1 += {testkey2 : 42} + +# Test that the stored values are correct +assert(dict1[testkey1] == 'myValue', + 'Incorrect string value retrieved from dictionary - variable key') +assert(dict1['myKey1'] == 'myValue', + 'Incorrect string value retrieved from dictionary - literal key') +assert(dict1[testkey2] == 42, + 'Incorrect int value retrieved from dictionary - variable key') +assert(dict1['myKey2'] == 42, + 'Incorrect int value retrieved from dictionary - literal key') + +d = {testkey1 : 1} +assert(d[testkey1] == 1, + 'Incorrect int value retrieved from dictionary - variable key') +assert(d['myKey1'] == 1, + 'Incorrect int value retrieved from dictionary - literal key') + +d = {'1' / '2' : 1, join_paths('a', 'b') : 2} +k1 = '1' / '2' +k2 = join_paths('a', 'b') +assert(d[k1] == 1, 'Incorrect expression evaluation in dictionary key') +assert(d[k2] == 2, 'Incorrect expression evaluation in dictionary key') + +d = {'a' + 'b' : 1} +assert(d['a' + 'b'] == 1, 'Incorrect expression evaluation in dictionary key') +assert(d['ab'] == 1, 'Incorrect expression evaluation in dictionary key') diff --git a/test cases/common/228 add dict variable key/meson.build b/test cases/common/228 add dict variable key/meson.build deleted file mode 100644 index faa6854..0000000 --- a/test cases/common/228 add dict variable key/meson.build +++ /dev/null @@ -1,21 +0,0 @@ -project('add dictionary entry using string variable as key', meson_version: '>=0.52') - -dict1 = {} - -# A variable to be used as a key -testkey1 = 'myKey1' -testkey2 = 'myKey2' - -# Add new entry using the variable -dict1 += {testkey1 : 'myValue'} -dict1 += {testkey2 : 42} - -# Test that the stored values are correct -assert(dict1[testkey1] == 'myValue', - 'Incorrect string value retrieved from dictionary - variable key') -assert(dict1['myKey1'] == 'myValue', - 'Incorrect string value retrieved from dictionary - literal key') -assert(dict1[testkey2] == 42, - 'Incorrect int value retrieved from dictionary - variable key') -assert(dict1['myKey2'] == 42, - 'Incorrect int value retrieved from dictionary - literal key') |