Skip to content
This repository was archived by the owner on Mar 23, 2026. It is now read-only.

Commit c76cc60

Browse files
authored
StepFunctions: Migration to String Expressions (#12028)
1 parent a25d0d9 commit c76cc60

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+6713
-9700
lines changed

localstack-core/localstack/services/stepfunctions/asl/antlr/ASLParser.g4

Lines changed: 106 additions & 237 deletions
Large diffs are not rendered by default.

localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParser.py

Lines changed: 5433 additions & 7041 deletions
Large diffs are not rendered by default.

localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParserListener.py

Lines changed: 201 additions & 453 deletions
Large diffs are not rendered by default.

localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/ASLParserVisitor.py

Lines changed: 105 additions & 245 deletions
Large diffs are not rendered by default.

localstack-core/localstack/services/stepfunctions/asl/component/common/assign/assign_template_binding.py

Lines changed: 8 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66
from localstack.services.stepfunctions.asl.component.common.assign.assign_template_value import (
77
AssignTemplateValue,
88
)
9-
from localstack.services.stepfunctions.asl.component.common.variable_sample import VariableSample
9+
from localstack.services.stepfunctions.asl.component.common.string.string_expression import (
10+
StringExpressionSimple,
11+
)
1012
from localstack.services.stepfunctions.asl.component.eval_component import EvalComponent
11-
from localstack.services.stepfunctions.asl.component.intrinsic.function.function import Function
1213
from localstack.services.stepfunctions.asl.eval.environment import Environment
13-
from localstack.services.stepfunctions.asl.parse.intrinsic.intrinsic_parser import IntrinsicParser
14-
from localstack.services.stepfunctions.asl.utils.json_path import extract_json
1514

1615

1716
class AssignTemplateBinding(EvalComponent, abc.ABC):
@@ -31,58 +30,15 @@ def _eval_body(self, env: Environment) -> None:
3130
env.stack.append(assign_object)
3231

3332

34-
class AssignTemplateBindingPath(AssignTemplateBinding):
35-
path: Final[str]
36-
37-
def __init__(self, identifier: str, path: str):
38-
super().__init__(identifier=identifier)
39-
self.path = path
40-
41-
def _eval_value(self, env: Environment) -> Any:
42-
memory_value = env.stack[-1]
43-
path_output = extract_json(self.path, memory_value)
44-
return path_output
45-
46-
47-
class AssignTemplateBindingPathContext(AssignTemplateBindingPath):
48-
@classmethod
49-
def from_raw(
50-
cls, identifier: str, string_path_context_obj: str
51-
) -> AssignTemplateBindingPathContext:
52-
path_context_obj: str = string_path_context_obj[1:]
53-
return cls(identifier=identifier, path=path_context_obj)
54-
55-
def _eval_value(self, env: Environment) -> Any:
56-
path_output = extract_json(self.path, env.states.context_object.context_object_data)
57-
return path_output
58-
59-
60-
class AssignTemplateBindingIntrinsicFunction(AssignTemplateBinding):
61-
function_literal: Final[str]
62-
function: Final[Function]
63-
64-
def __init__(self, identifier: str, function_literal: str):
65-
super().__init__(identifier=identifier)
66-
self.function_literal = function_literal
67-
self.function, _ = IntrinsicParser.parse(self.function_literal)
68-
69-
def _eval_value(self, env: Environment) -> Any:
70-
# TODO: resolve jsonata variable references as arguments.
71-
# should probably be done in the function object.
72-
self.function.eval(env=env)
73-
val = env.stack.pop()
74-
return val
75-
76-
77-
class AssignTemplateBindingVar(AssignTemplateBinding):
78-
variable_sample: Final[VariableSample]
33+
class AssignTemplateBindingStringExpressionSimple(AssignTemplateBinding):
34+
string_expression_simple: Final[StringExpressionSimple]
7935

80-
def __init__(self, identifier: str, variable_sample: VariableSample):
36+
def __init__(self, identifier: str, string_expression_simple: StringExpressionSimple):
8137
super().__init__(identifier=identifier)
82-
self.variable_sample = variable_sample
38+
self.string_expression_simple = string_expression_simple
8339

8440
def _eval_value(self, env: Environment) -> Any:
85-
self.variable_sample.eval(env=env)
41+
self.string_expression_simple.eval(env=env)
8642
value = env.stack.pop()
8743
return value
8844

localstack-core/localstack/services/stepfunctions/asl/component/common/assign/assign_template_value_terminal.py

Lines changed: 7 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,10 @@
44
from localstack.services.stepfunctions.asl.component.common.assign.assign_template_value import (
55
AssignTemplateValue,
66
)
7-
from localstack.services.stepfunctions.asl.component.intrinsic.jsonata import (
8-
get_intrinsic_functions_declarations,
7+
from localstack.services.stepfunctions.asl.component.common.string.string_expression import (
8+
StringJSONata,
99
)
1010
from localstack.services.stepfunctions.asl.eval.environment import Environment
11-
from localstack.services.stepfunctions.asl.jsonata.jsonata import (
12-
JSONataExpression,
13-
VariableDeclarations,
14-
VariableReference,
15-
compose_jsonata_expression,
16-
eval_jsonata_expression,
17-
extract_jsonata_variable_references,
18-
)
19-
from localstack.services.stepfunctions.asl.jsonata.validations import (
20-
validate_jsonata_expression_output,
21-
)
2211

2312

2413
class AssignTemplateValueTerminal(AssignTemplateValue, abc.ABC): ...
@@ -35,50 +24,12 @@ def _eval_body(self, env: Environment) -> None:
3524
env.stack.append(self.value)
3625

3726

38-
class AssignTemplateValueTerminalExpression(AssignTemplateValueTerminal):
39-
expression: Final[str]
27+
class AssignTemplateValueTerminalStringJSONata(AssignTemplateValueTerminal):
28+
string_jsonata: Final[StringJSONata]
4029

41-
def __init__(self, expression: str):
30+
def __init__(self, string_jsonata: StringJSONata):
4231
super().__init__()
43-
# TODO: check for illegal functions ($, $$, $eval)
44-
self.expression = expression
45-
46-
def _eval_body(self, env: Environment) -> None:
47-
# Get the variables sampled in the jsonata expression.
48-
expression_variable_references: set[VariableReference] = (
49-
extract_jsonata_variable_references(self.expression)
50-
)
51-
52-
# Sample declarations for used intrinsic functions. Place this at the start allowing users to
53-
# override these identifiers with custom variable declarations.
54-
functions_variable_declarations: VariableDeclarations = (
55-
get_intrinsic_functions_declarations(variable_references=expression_variable_references)
56-
)
57-
58-
# Sample $states values into expression.
59-
states_variable_declarations: VariableDeclarations = env.states.to_variable_declarations(
60-
variable_references=expression_variable_references
61-
)
62-
63-
# Sample Variable store values in to expression.
64-
# TODO: this could be optimised by sampling only those invoked.
65-
variable_declarations: VariableDeclarations = env.variable_store.get_variable_declarations()
66-
67-
rich_jsonata_expression: JSONataExpression = compose_jsonata_expression(
68-
final_jsonata_expression=self.expression,
69-
variable_declarations_list=[
70-
functions_variable_declarations,
71-
states_variable_declarations,
72-
variable_declarations,
73-
],
74-
)
75-
result = eval_jsonata_expression(rich_jsonata_expression)
76-
77-
validate_jsonata_expression_output(env, self.expression, rich_jsonata_expression, result)
78-
79-
env.stack.append(result)
80-
32+
self.string_jsonata = string_jsonata
8133

82-
class AssignTemplateValueTerminalExpressionSuppressed(AssignTemplateValueTerminalExpression):
8334
def _eval_body(self, env: Environment) -> None:
84-
env.stack.append(self.expression)
35+
self.string_jsonata.eval(env=env)

localstack-core/localstack/services/stepfunctions/asl/component/common/jsonata/jsonata_template_value_terminal.py

Lines changed: 7 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,10 @@
44
from localstack.services.stepfunctions.asl.component.common.jsonata.jsonata_template_value import (
55
JSONataTemplateValue,
66
)
7-
from localstack.services.stepfunctions.asl.component.intrinsic.jsonata import (
8-
get_intrinsic_functions_declarations,
7+
from localstack.services.stepfunctions.asl.component.common.string.string_expression import (
8+
StringJSONata,
99
)
1010
from localstack.services.stepfunctions.asl.eval.environment import Environment
11-
from localstack.services.stepfunctions.asl.jsonata.jsonata import (
12-
JSONataExpression,
13-
VariableDeclarations,
14-
VariableReference,
15-
compose_jsonata_expression,
16-
eval_jsonata_expression,
17-
extract_jsonata_variable_references,
18-
)
19-
from localstack.services.stepfunctions.asl.jsonata.validations import (
20-
validate_jsonata_expression_output,
21-
)
2211

2312

2413
class JSONataTemplateValueTerminal(JSONataTemplateValue, abc.ABC): ...
@@ -35,45 +24,12 @@ def _eval_body(self, env: Environment) -> None:
3524
env.stack.append(self.value)
3625

3726

38-
class JSONataTemplateValueTerminalExpression(JSONataTemplateValueTerminal):
39-
expression: Final[str]
27+
class JSONataTemplateValueTerminalStringJSONata(JSONataTemplateValueTerminal):
28+
string_jsonata: Final[StringJSONata]
4029

41-
def __init__(self, expression: str):
30+
def __init__(self, string_jsonata: StringJSONata):
4231
super().__init__()
43-
# TODO: check for illegal functions ($, $$, $eval)
44-
self.expression = expression
32+
self.string_jsonata = string_jsonata
4533

4634
def _eval_body(self, env: Environment) -> None:
47-
# Get the variables sampled in the jsonata expression.
48-
expression_variable_references: set[VariableReference] = (
49-
extract_jsonata_variable_references(self.expression)
50-
)
51-
52-
# Sample declarations for used intrinsic functions. Place this at the start allowing users to
53-
# override these identifiers with custom variable declarations.
54-
functions_variable_declarations: VariableDeclarations = (
55-
get_intrinsic_functions_declarations(variable_references=expression_variable_references)
56-
)
57-
58-
# Sample $states values into expression.
59-
states_variable_declarations: VariableDeclarations = env.states.to_variable_declarations(
60-
variable_references=expression_variable_references
61-
)
62-
63-
# Sample Variable store values in to expression.
64-
# TODO: this could be optimised by sampling only those invoked.
65-
variable_declarations: VariableDeclarations = env.variable_store.get_variable_declarations()
66-
67-
rich_jsonata_expression: JSONataExpression = compose_jsonata_expression(
68-
final_jsonata_expression=self.expression,
69-
variable_declarations_list=[
70-
functions_variable_declarations,
71-
states_variable_declarations,
72-
variable_declarations,
73-
],
74-
)
75-
result = eval_jsonata_expression(rich_jsonata_expression)
76-
77-
validate_jsonata_expression_output(env, self.expression, rich_jsonata_expression, result)
78-
79-
env.stack.append(result)
35+
self.string_jsonata.eval(env=env)

localstack-core/localstack/services/stepfunctions/asl/component/common/parargs.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import abc
22
from typing import Final
33

4-
from localstack.services.stepfunctions.asl.component.common.jsonata.jsonata_template_value import (
5-
JSONataTemplateValue,
4+
from localstack.services.stepfunctions.asl.component.common.jsonata.jsonata_template_value_object import (
5+
JSONataTemplateValueObject,
66
)
77
from localstack.services.stepfunctions.asl.component.common.payload.payloadvalue.payloadtmpl.payload_tmpl import (
88
PayloadTmpl,
99
)
10+
from localstack.services.stepfunctions.asl.component.common.string.string_expression import (
11+
StringJSONata,
12+
)
1013
from localstack.services.stepfunctions.asl.component.eval_component import EvalComponent
1114
from localstack.services.stepfunctions.asl.eval.environment import Environment
1215

@@ -26,6 +29,14 @@ def __init__(self, payload_tmpl: PayloadTmpl):
2629
super().__init__(template_eval_component=payload_tmpl)
2730

2831

29-
class Arguments(Parargs):
30-
def __init__(self, jsonata_payload_value: JSONataTemplateValue):
31-
super().__init__(template_eval_component=jsonata_payload_value)
32+
class Arguments(Parargs, abc.ABC): ...
33+
34+
35+
class ArgumentsJSONataTemplateValueObject(Arguments):
36+
def __init__(self, jsonata_template_value_object: JSONataTemplateValueObject):
37+
super().__init__(template_eval_component=jsonata_template_value_object)
38+
39+
40+
class ArgumentsStringJSONata(Arguments):
41+
def __init__(self, string_jsonata: StringJSONata):
42+
super().__init__(template_eval_component=string_jsonata)
Lines changed: 15 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,24 @@
1-
import abc
2-
import copy
31
from typing import Final, Optional
42

5-
from localstack.services.stepfunctions.asl.component.common.variable_sample import VariableSample
3+
from localstack.services.stepfunctions.asl.component.common.string.string_expression import (
4+
StringJsonPath,
5+
StringSampler,
6+
)
67
from localstack.services.stepfunctions.asl.component.eval_component import EvalComponent
78
from localstack.services.stepfunctions.asl.eval.environment import Environment
8-
from localstack.services.stepfunctions.asl.utils.json_path import extract_json
99

1010

11-
class InputPath(EvalComponent, abc.ABC): ...
11+
class InputPath(EvalComponent):
12+
string_sampler: Final[Optional[StringSampler]]
1213

13-
14-
class InputPathBase(InputPath):
15-
DEFAULT_PATH: Final[str] = "$"
16-
17-
path: Final[Optional[str]]
18-
19-
def __init__(self, path: Optional[str]):
20-
self.path = path
21-
22-
def _eval_body(self, env: Environment) -> None:
23-
match self.path:
24-
case None:
25-
value = dict()
26-
case self.DEFAULT_PATH:
27-
value = env.states.get_input()
28-
case _:
29-
value = extract_json(self.path, env.states.get_input())
30-
env.stack.append(copy.deepcopy(value))
31-
32-
33-
class InputPathContextObject(InputPathBase):
34-
def __init__(self, path: str):
35-
path_tail = path[1:]
36-
super().__init__(path=path_tail)
37-
38-
def _eval_body(self, env: Environment) -> None:
39-
value = extract_json(self.path, env.states.context_object.context_object_data)
40-
env.stack.append(copy.deepcopy(value))
41-
42-
43-
class InputPathVar(InputPath):
44-
variable_sample: Final[VariableSample]
45-
46-
def __init__(self, variable_sample: VariableSample):
47-
self.variable_sample = variable_sample
14+
def __init__(self, string_sampler: Optional[StringSampler]):
15+
self.string_sampler = string_sampler
4816

4917
def _eval_body(self, env: Environment) -> None:
50-
self.variable_sample.eval(env=env)
18+
if self.string_sampler is None:
19+
env.stack.append(dict())
20+
return
21+
if isinstance(self.string_sampler, StringJsonPath):
22+
# JsonPaths are sampled from a given state, hence pass the state's input.
23+
env.stack.append(env.states.get_input())
24+
self.string_sampler.eval(env=env)
Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,17 @@
1-
import copy
21
from typing import Final
32

3+
from localstack.services.stepfunctions.asl.component.common.string.string_expression import (
4+
StringSampler,
5+
)
46
from localstack.services.stepfunctions.asl.component.eval_component import EvalComponent
57
from localstack.services.stepfunctions.asl.eval.environment import Environment
6-
from localstack.services.stepfunctions.asl.jsonata.jsonata import (
7-
VariableDeclarations,
8-
compose_jsonata_expression,
9-
eval_jsonata_expression,
10-
)
11-
from localstack.services.stepfunctions.asl.utils.json_path import extract_json
128

139

1410
class ItemsPath(EvalComponent):
15-
DEFAULT_PATH: Final[str] = "$"
16-
path: Final[str]
17-
18-
def __init__(self, path: str = DEFAULT_PATH):
19-
self.path = path
20-
21-
def _eval_body(self, env: Environment) -> None:
22-
value = copy.deepcopy(env.stack[-1])
23-
if self.path != ItemsPath.DEFAULT_PATH:
24-
value = extract_json(self.path, value)
25-
env.stack.append(value)
26-
27-
28-
class ItemsPathContextObject(ItemsPath):
29-
def __init__(self, path: str):
30-
path_tail = path[1:]
31-
super().__init__(path=path_tail)
32-
33-
def _eval_body(self, env: Environment) -> None:
34-
value = extract_json(self.path, env.states.context_object.context_object_data)
35-
env.stack.append(copy.deepcopy(value))
11+
string_sampler: Final[StringSampler]
3612

13+
def __init__(self, string_sampler: StringSampler):
14+
self.string_sampler = string_sampler
3715

38-
class ItemsPathVar(ItemsPath):
3916
def _eval_body(self, env: Environment) -> None:
40-
variable_declarations: VariableDeclarations = env.variable_store.get_variable_declarations()
41-
jsonata_expression = compose_jsonata_expression(
42-
final_jsonata_expression=self.path, # noqa
43-
variable_declarations_list=[variable_declarations],
44-
)
45-
value = eval_jsonata_expression(jsonata_expression=jsonata_expression)
46-
env.stack.append(copy.deepcopy(value))
17+
self.string_sampler.eval(env=env)

0 commit comments

Comments
 (0)