aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/markdown/Syntax.md12
-rw-r--r--docs/markdown/snippets/add_dictionary_variable_key.md20
-rw-r--r--mesonbuild/interpreterbase.py25
-rw-r--r--mesonbuild/mparser.py14
-rw-r--r--test cases/common/193 dict/meson.build36
-rw-r--r--test cases/common/228 add dict variable key/meson.build21
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')