Skip to content

Commit e144200

Browse files
committed
Merge branch 'jep-10' into develop
* jep-10: Implement JEP-10, slice projections
2 parents 4c0271d + f63868b commit e144200

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

jmespath/parser.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class Parser(object):
4646
'number': 0,
4747
'current': 0,
4848
'expref': 0,
49+
'colon': 0,
4950
'pipe': 1,
5051
'eq': 2,
5152
'gt': 2,
@@ -165,7 +166,12 @@ def _token_nud_flatten(self, token):
165166

166167
def _token_nud_lbracket(self, token):
167168
if self._current_token() in ['number', 'colon']:
168-
return self._parse_index_expression()
169+
right = self._parse_index_expression()
170+
# We could optimize this and remove the identity() node.
171+
# We don't really need an index_expression node, we can
172+
# just use emit an index node here if we're not dealing
173+
# with a slice.
174+
return self._project_if_slice(ast.identity(), right)
169175
elif self._current_token() == 'star' and \
170176
self._lookahead(1) == 'rbracket':
171177
self._advance()
@@ -300,17 +306,29 @@ def _token_led_lbracket(self, left):
300306
if token['type'] in ['number', 'colon']:
301307
right = self._parse_index_expression()
302308
if left['type'] == 'index_expression':
309+
# Optimization: if the left node is an index expr,
310+
# we can avoid creating another node and instead just add
311+
# the right node as a child of the left.
303312
left['children'].append(right)
304313
return left
305314
else:
306-
return ast.index_expression([left, right])
315+
return self._project_if_slice(left, right)
307316
else:
308317
# We have a projection
309318
self._match('star')
310319
self._match('rbracket')
311320
right = self._parse_projection_rhs(self.BINDING_POWER['star'])
312321
return ast.projection(left, right)
313322

323+
def _project_if_slice(self, left, right):
324+
index_expr = ast.index_expression([left, right])
325+
if right['type'] == 'slice':
326+
return ast.projection(
327+
index_expr,
328+
self._parse_projection_rhs(self.BINDING_POWER['star']))
329+
else:
330+
return index_expr
331+
314332
def _parse_comparator(self, left, comparator):
315333
right = self._expression(self.BINDING_POWER[comparator])
316334
return ast.comparator(comparator, left, right)

tests/compliance/slice.json

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,4 +127,52 @@
127127
"error": "syntax"
128128
}
129129
]
130+
}, {
131+
"given": {
132+
"foo": [{"a": 1}, {"a": 2}, {"a": 3}],
133+
"bar": [{"a": {"b": 1}}, {"a": {"b": 2}},
134+
{"a": {"b": 3}}]
135+
},
136+
"cases": [
137+
{
138+
"expression": "foo[:2].a",
139+
"result": [1, 2]
140+
},
141+
{
142+
"expression": "foo[:2].b",
143+
"result": []
144+
},
145+
{
146+
"expression": "foo[:2].a.b",
147+
"result": []
148+
},
149+
{
150+
"expression": "bar[::-1].a.b",
151+
"result": [3, 2, 1]
152+
},
153+
{
154+
"expression": "bar[:2].a.b",
155+
"result": [1, 2]
156+
}
157+
]
158+
}, {
159+
"given": [{"a": 1}, {"a": 2}, {"a": 3}],
160+
"cases": [
161+
{
162+
"expression": "[:]",
163+
"result": [{"a": 1}, {"a": 2}, {"a": 3}]
164+
},
165+
{
166+
"expression": "[:2].a",
167+
"result": [1, 2]
168+
},
169+
{
170+
"expression": "[::-1].a",
171+
"result": [3, 2, 1]
172+
},
173+
{
174+
"expression": "[:2].b",
175+
"result": []
176+
}
177+
]
130178
}]

0 commit comments

Comments
 (0)