diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e737948d5..36d23cc7a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,6 +69,7 @@ jobs: pip install -r requirements-dev.txt - name: Lint run: + mkdir .mypy_cache make lint javatest: diff --git a/.github/workflows/tests_servermode.yml b/.github/workflows/tests_servermode.yml index aa229a565..a7f6a3ca2 100644 --- a/.github/workflows/tests_servermode.yml +++ b/.github/workflows/tests_servermode.yml @@ -59,10 +59,11 @@ jobs: - name: "Stop MotoServer" if: always() run: | + ls -la + docker stop motoserver mkdir serverlogs cp server_output.log serverlogs/server_output.log - docker stop motoserver - - name: Archive TF logs + - name: Archive Server logs if: always() uses: actions/upload-artifact@v4 with: diff --git a/IMPLEMENTATION_COVERAGE.md b/IMPLEMENTATION_COVERAGE.md index b18aa501f..fedeb40d1 100644 --- a/IMPLEMENTATION_COVERAGE.md +++ b/IMPLEMENTATION_COVERAGE.md @@ -7731,7 +7731,7 @@ ## stepfunctions
-36% implemented +55% implemented - [ ] create_activity - [X] create_state_machine @@ -7742,31 +7742,31 @@ - [ ] delete_state_machine_version - [ ] describe_activity - [X] describe_execution -- [ ] describe_map_run +- [X] describe_map_run - [X] describe_state_machine - [ ] describe_state_machine_alias -- [ ] describe_state_machine_for_execution +- [X] describe_state_machine_for_execution - [ ] get_activity_task - [X] get_execution_history - [ ] list_activities - [X] list_executions -- [ ] list_map_runs +- [X] list_map_runs - [ ] list_state_machine_aliases - [ ] list_state_machine_versions - [X] list_state_machines - [X] list_tags_for_resource - [ ] publish_state_machine_version - [ ] redrive_execution -- [ ] send_task_failure -- [ ] send_task_heartbeat -- [ ] send_task_success +- [X] send_task_failure +- [X] send_task_heartbeat +- [X] send_task_success - [X] start_execution - [ ] start_sync_execution - [X] stop_execution - [X] tag_resource - [ ] test_state - [X] untag_resource -- [ ] update_map_run +- [X] update_map_run - [X] update_state_machine - [ ] update_state_machine_alias
diff --git a/codecov.yml b/codecov.yml index 750eb3b17..de8319310 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,3 +1,6 @@ +ignore: + - "moto/stepfunctions/parser/asl/antlr" + codecov: notify: # Leave a GitHub comment after all builds have passed diff --git a/docs/docs/configuration/index.rst b/docs/docs/configuration/index.rst index 3a2e59d06..4718b94dc 100644 --- a/docs/docs/configuration/index.rst +++ b/docs/docs/configuration/index.rst @@ -22,6 +22,7 @@ If you are using the decorators, some options are configurable within the decora "reset_boto3_session": True, }, "iam": {"load_aws_managed_policies": False}, + "stepfunctions": {"execute_state_machine": True}, }) diff --git a/docs/docs/services/stepfunctions.rst b/docs/docs/services/stepfunctions.rst index 01ae82cfa..067ddedee 100644 --- a/docs/docs/services/stepfunctions.rst +++ b/docs/docs/services/stepfunctions.rst @@ -12,6 +12,8 @@ stepfunctions ============= +.. autoclass:: moto.stepfunctions.models.StepFunctionBackend + |start-h3| Implemented features for this service |end-h3| - [ ] create_activity @@ -23,58 +25,31 @@ stepfunctions - [ ] delete_state_machine_version - [ ] describe_activity - [X] describe_execution - - The status of every execution is set to 'RUNNING' by default. - Set the following environment variable if you want to get a FAILED status back: - - .. sourcecode:: bash - - SF_EXECUTION_HISTORY_TYPE=FAILURE - - -- [ ] describe_map_run +- [X] describe_map_run - [X] describe_state_machine - [ ] describe_state_machine_alias -- [ ] describe_state_machine_for_execution +- [X] describe_state_machine_for_execution - [ ] get_activity_task - [X] get_execution_history - - A static list of successful events is returned by default. - Set the following environment variable if you want to get a static list of events for a failed execution: - - .. sourcecode:: bash - - SF_EXECUTION_HISTORY_TYPE=FAILURE - - - [ ] list_activities - [X] list_executions - - The status of every execution is set to 'RUNNING' by default. - Set the following environment variable if you want to get a FAILED status back: - - .. sourcecode:: bash - - SF_EXECUTION_HISTORY_TYPE=FAILURE - - -- [ ] list_map_runs +- [X] list_map_runs - [ ] list_state_machine_aliases - [ ] list_state_machine_versions - [X] list_state_machines - [X] list_tags_for_resource - [ ] publish_state_machine_version - [ ] redrive_execution -- [ ] send_task_failure -- [ ] send_task_heartbeat -- [ ] send_task_success +- [X] send_task_failure +- [X] send_task_heartbeat +- [X] send_task_success - [X] start_execution - [ ] start_sync_execution - [X] stop_execution - [X] tag_resource - [ ] test_state - [X] untag_resource -- [ ] update_map_run +- [X] update_map_run - [X] update_state_machine - [ ] update_state_machine_alias diff --git a/moto/core/config.py b/moto/core/config.py index 8420b5be6..5958c44fc 100644 --- a/moto/core/config.py +++ b/moto/core/config.py @@ -21,6 +21,10 @@ class _iam_config(TypedDict, total=False): load_aws_managed_policies: bool +class _sfn_config(TypedDict, total=False): + execute_state_machine: bool + + DefaultConfig = TypedDict( "DefaultConfig", { @@ -28,6 +32,7 @@ DefaultConfig = TypedDict( "core": _core_config, "lambda": _docker_config, "iam": _iam_config, + "stepfunctions": _sfn_config, }, total=False, ) @@ -41,6 +46,7 @@ default_user_config: DefaultConfig = { "reset_boto3_session": True, }, "iam": {"load_aws_managed_policies": False}, + "stepfunctions": {"execute_state_machine": False}, } diff --git a/moto/moto_api/_internal/models.py b/moto/moto_api/_internal/models.py index 7c5b98b68..d490f6010 100644 --- a/moto/moto_api/_internal/models.py +++ b/moto/moto_api/_internal/models.py @@ -128,6 +128,8 @@ class MotoAPIBackend(BaseBackend): default_user_config["batch"] = config["batch"] if "lambda" in config: default_user_config["lambda"] = config["lambda"] + if "stepfunctions" in config: + default_user_config["stepfunctions"] = config["stepfunctions"] moto_api_backend = MotoAPIBackend(region_name="global", account_id=DEFAULT_ACCOUNT_ID) diff --git a/moto/stepfunctions/models.py b/moto/stepfunctions/models.py index 868bbc21f..62e9b3dcd 100644 --- a/moto/stepfunctions/models.py +++ b/moto/stepfunctions/models.py @@ -73,7 +73,7 @@ class StateMachine(CloudFormationModel): raise ExecutionDoesNotExist( "Execution Does Not Exist: '" + execution_arn + "'" ) - execution.stop() + execution.stop(stop_date=datetime.now(), error="", cause="") return execution def _ensure_execution_name_doesnt_exist(self, name: str) -> None: @@ -265,6 +265,12 @@ class Execution: else "FAILED" ) self.stop_date: Optional[str] = None + self.account_id = account_id + self.region_name = region_name + self.output: Optional[str] = None + self.output_details: Optional[str] = None + self.cause: Optional[str] = None + self.error: Optional[str] = None def get_execution_history(self, roleArn: str) -> List[Dict[str, Any]]: sf_execution_history_type = settings.get_sf_execution_history_type() @@ -365,12 +371,28 @@ class Execution: ] return [] - def stop(self) -> None: + def stop(self, *args: Any, **kwargs: Any) -> None: self.status = "ABORTED" self.stop_date = iso_8601_datetime_with_milliseconds() class StepFunctionBackend(BaseBackend): + """ + Configure Moto to explicitly parse and execute the StateMachine: + + .. sourcecode:: python + + @mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) + + By default, executing a StateMachine does nothing, and calling `describe_state_machine` will return static data. + + Set the following environment variable if you want to get the static data to have a FAILED status: + + .. sourcecode:: bash + + SF_EXECUTION_HISTORY_TYPE=FAILURE + + """ # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/stepfunctions.html#SFN.Client.create_state_machine # A name must not contain: @@ -484,7 +506,6 @@ class StepFunctionBackend(BaseBackend): def __init__(self, region_name: str, account_id: str): super().__init__(region_name, account_id) self.state_machines: List[StateMachine] = [] - self.executions: List[Execution] = [] self._account_id = None def create_state_machine( @@ -556,14 +577,6 @@ class StepFunctionBackend(BaseBackend): def list_executions( self, state_machine_arn: str, status_filter: Optional[str] = None ) -> List[Execution]: - """ - The status of every execution is set to 'RUNNING' by default. - Set the following environment variable if you want to get a FAILED status back: - - .. sourcecode:: bash - - SF_EXECUTION_HISTORY_TYPE=FAILURE - """ executions = self.describe_state_machine(state_machine_arn).executions if status_filter: @@ -572,14 +585,6 @@ class StepFunctionBackend(BaseBackend): return sorted(executions, key=lambda x: x.start_date, reverse=True) def describe_execution(self, execution_arn: str) -> Execution: - """ - The status of every execution is set to 'RUNNING' by default. - Set the following environment variable if you want to get a FAILED status back: - - .. sourcecode:: bash - - SF_EXECUTION_HISTORY_TYPE=FAILURE - """ self._validate_execution_arn(execution_arn) state_machine = self._get_state_machine_for_execution(execution_arn) exctn = next( @@ -593,14 +598,6 @@ class StepFunctionBackend(BaseBackend): return exctn def get_execution_history(self, execution_arn: str) -> List[Dict[str, Any]]: - """ - A static list of successful events is returned by default. - Set the following environment variable if you want to get a static list of events for a failed execution: - - .. sourcecode:: bash - - SF_EXECUTION_HISTORY_TYPE=FAILURE - """ self._validate_execution_arn(execution_arn) state_machine = self._get_state_machine_for_execution(execution_arn) execution = next( @@ -613,6 +610,13 @@ class StepFunctionBackend(BaseBackend): ) return execution.get_execution_history(state_machine.roleArn) + def describe_state_machine_for_execution(self, execution_arn: str) -> StateMachine: + for sm in self.state_machines: + for exc in sm.executions: + if exc.execution_arn == execution_arn: + return sm + raise ResourceNotFound(execution_arn) + def list_tags_for_resource(self, arn: str) -> List[Dict[str, str]]: try: state_machine = self.describe_state_machine(arn) @@ -634,6 +638,30 @@ class StepFunctionBackend(BaseBackend): except StateMachineDoesNotExist: raise ResourceNotFound(resource_arn) + def send_task_failure(self, task_token: str) -> None: + pass + + def send_task_heartbeat(self, task_token: str) -> None: + pass + + def send_task_success(self, task_token: str, outcome: str) -> None: + pass + + def describe_map_run(self, map_run_arn: str) -> Dict[str, Any]: + return {} + + def list_map_runs(self, execution_arn: str) -> Any: + return [] + + def update_map_run( + self, + map_run_arn: str, + max_concurrency: int, + tolerated_failure_count: str, + tolerated_failure_percentage: str, + ) -> None: + pass + def _validate_name(self, name: str) -> None: if any(invalid_char in name for invalid_char in self.invalid_chars_for_name): raise InvalidName("Invalid Name: '" + name + "'") diff --git a/moto/stepfunctions/parser/README.md b/moto/stepfunctions/parser/README.md new file mode 100644 index 000000000..af786b0a7 --- /dev/null +++ b/moto/stepfunctions/parser/README.md @@ -0,0 +1,3 @@ +In-memory ASL (Amazon StepFunctions Language) parser. + +Created for Localstack by @mepalma (https://github.com/MEPalma) \ No newline at end of file diff --git a/moto/stepfunctions/parser/__init__.py b/moto/stepfunctions/parser/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/api.py b/moto/stepfunctions/parser/api.py new file mode 100644 index 000000000..96fe9859e --- /dev/null +++ b/moto/stepfunctions/parser/api.py @@ -0,0 +1,1048 @@ +from datetime import datetime +from typing import List, Optional, TypedDict + +from ..exceptions import AWSError as ServiceException + +AliasDescription = str +CharacterRestrictedName = str +ClientToken = str +ConnectorParameters = str +Definition = str +Enabled = bool +ErrorMessage = str +HTTPBody = str +HTTPHeaders = str +HTTPMethod = str +HTTPProtocol = str +HTTPStatusCode = str +HTTPStatusMessage = str +Identity = str +IncludeExecutionData = bool +IncludeExecutionDataGetExecutionHistory = bool +ListExecutionsPageToken = str +MapRunLabel = str +MaxConcurrency = int +Name = str +PageSize = int +PageToken = str +Publish = bool +RedriveCount = int +RevealSecrets = bool +ReverseOrder = bool +RevisionId = str +SensitiveCause = str +SensitiveData = str +SensitiveDataJobInput = str +SensitiveError = str +StateName = str +TagKey = str +TagValue = str +TaskToken = str +ToleratedFailurePercentage = float +TraceHeader = str +URL = str +UnsignedInteger = int +VersionDescription = str +VersionWeight = int +includedDetails = bool +truncated = bool + + +class ExecutionRedriveFilter(str): + REDRIVEN = "REDRIVEN" + NOT_REDRIVEN = "NOT_REDRIVEN" + + +class ExecutionRedriveStatus(str): + REDRIVABLE = "REDRIVABLE" + NOT_REDRIVABLE = "NOT_REDRIVABLE" + REDRIVABLE_BY_MAP_RUN = "REDRIVABLE_BY_MAP_RUN" + + +class ExecutionStatus(str): + RUNNING = "RUNNING" + SUCCEEDED = "SUCCEEDED" + FAILED = "FAILED" + TIMED_OUT = "TIMED_OUT" + ABORTED = "ABORTED" + PENDING_REDRIVE = "PENDING_REDRIVE" + + +class HistoryEventType(str): + ActivityFailed = "ActivityFailed" + ActivityScheduled = "ActivityScheduled" + ActivityScheduleFailed = "ActivityScheduleFailed" + ActivityStarted = "ActivityStarted" + ActivitySucceeded = "ActivitySucceeded" + ActivityTimedOut = "ActivityTimedOut" + ChoiceStateEntered = "ChoiceStateEntered" + ChoiceStateExited = "ChoiceStateExited" + ExecutionAborted = "ExecutionAborted" + ExecutionFailed = "ExecutionFailed" + ExecutionStarted = "ExecutionStarted" + ExecutionSucceeded = "ExecutionSucceeded" + ExecutionTimedOut = "ExecutionTimedOut" + FailStateEntered = "FailStateEntered" + LambdaFunctionFailed = "LambdaFunctionFailed" + LambdaFunctionScheduled = "LambdaFunctionScheduled" + LambdaFunctionScheduleFailed = "LambdaFunctionScheduleFailed" + LambdaFunctionStarted = "LambdaFunctionStarted" + LambdaFunctionStartFailed = "LambdaFunctionStartFailed" + LambdaFunctionSucceeded = "LambdaFunctionSucceeded" + LambdaFunctionTimedOut = "LambdaFunctionTimedOut" + MapIterationAborted = "MapIterationAborted" + MapIterationFailed = "MapIterationFailed" + MapIterationStarted = "MapIterationStarted" + MapIterationSucceeded = "MapIterationSucceeded" + MapStateAborted = "MapStateAborted" + MapStateEntered = "MapStateEntered" + MapStateExited = "MapStateExited" + MapStateFailed = "MapStateFailed" + MapStateStarted = "MapStateStarted" + MapStateSucceeded = "MapStateSucceeded" + ParallelStateAborted = "ParallelStateAborted" + ParallelStateEntered = "ParallelStateEntered" + ParallelStateExited = "ParallelStateExited" + ParallelStateFailed = "ParallelStateFailed" + ParallelStateStarted = "ParallelStateStarted" + ParallelStateSucceeded = "ParallelStateSucceeded" + PassStateEntered = "PassStateEntered" + PassStateExited = "PassStateExited" + SucceedStateEntered = "SucceedStateEntered" + SucceedStateExited = "SucceedStateExited" + TaskFailed = "TaskFailed" + TaskScheduled = "TaskScheduled" + TaskStarted = "TaskStarted" + TaskStartFailed = "TaskStartFailed" + TaskStateAborted = "TaskStateAborted" + TaskStateEntered = "TaskStateEntered" + TaskStateExited = "TaskStateExited" + TaskSubmitFailed = "TaskSubmitFailed" + TaskSubmitted = "TaskSubmitted" + TaskSucceeded = "TaskSucceeded" + TaskTimedOut = "TaskTimedOut" + WaitStateAborted = "WaitStateAborted" + WaitStateEntered = "WaitStateEntered" + WaitStateExited = "WaitStateExited" + MapRunAborted = "MapRunAborted" + MapRunFailed = "MapRunFailed" + MapRunStarted = "MapRunStarted" + MapRunSucceeded = "MapRunSucceeded" + ExecutionRedriven = "ExecutionRedriven" + MapRunRedriven = "MapRunRedriven" + + +class InspectionLevel(str): + INFO = "INFO" + DEBUG = "DEBUG" + TRACE = "TRACE" + + +class LogLevel(str): + ALL = "ALL" + ERROR = "ERROR" + FATAL = "FATAL" + OFF = "OFF" + + +class MapRunStatus(str): + RUNNING = "RUNNING" + SUCCEEDED = "SUCCEEDED" + FAILED = "FAILED" + ABORTED = "ABORTED" + + +class StateMachineStatus(str): + ACTIVE = "ACTIVE" + DELETING = "DELETING" + + +class StateMachineType(str): + STANDARD = "STANDARD" + EXPRESS = "EXPRESS" + + +class SyncExecutionStatus(str): + SUCCEEDED = "SUCCEEDED" + FAILED = "FAILED" + TIMED_OUT = "TIMED_OUT" + + +class TestExecutionStatus(str): + SUCCEEDED = "SUCCEEDED" + FAILED = "FAILED" + RETRIABLE = "RETRIABLE" + CAUGHT_ERROR = "CAUGHT_ERROR" + + +class ValidationExceptionReason(str): + API_DOES_NOT_SUPPORT_LABELED_ARNS = "API_DOES_NOT_SUPPORT_LABELED_ARNS" + MISSING_REQUIRED_PARAMETER = "MISSING_REQUIRED_PARAMETER" + CANNOT_UPDATE_COMPLETED_MAP_RUN = "CANNOT_UPDATE_COMPLETED_MAP_RUN" + INVALID_ROUTING_CONFIGURATION = "INVALID_ROUTING_CONFIGURATION" + + +class ActivityDoesNotExist(ServiceException): + code: str = "ActivityDoesNotExist" + sender_fault: bool = False + status_code: int = 400 + + +class ActivityLimitExceeded(ServiceException): + code: str = "ActivityLimitExceeded" + sender_fault: bool = False + status_code: int = 400 + + +class ActivityWorkerLimitExceeded(ServiceException): + code: str = "ActivityWorkerLimitExceeded" + sender_fault: bool = False + status_code: int = 400 + + +class ConflictException(ServiceException): + code: str = "ConflictException" + sender_fault: bool = False + status_code: int = 400 + + +class ExecutionAlreadyExists(ServiceException): + code: str = "ExecutionAlreadyExists" + sender_fault: bool = False + status_code: int = 400 + + +class ExecutionDoesNotExist(ServiceException): + code: str = "ExecutionDoesNotExist" + sender_fault: bool = False + status_code: int = 400 + + +class ExecutionLimitExceeded(ServiceException): + code: str = "ExecutionLimitExceeded" + sender_fault: bool = False + status_code: int = 400 + + +class ExecutionNotRedrivable(ServiceException): + code: str = "ExecutionNotRedrivable" + sender_fault: bool = False + status_code: int = 400 + + +class InvalidArn(ServiceException): + code: str = "InvalidArn" + sender_fault: bool = False + status_code: int = 400 + + +class InvalidDefinition(ServiceException): + code: str = "InvalidDefinition" + sender_fault: bool = False + status_code: int = 400 + + +class InvalidExecutionInput(ServiceException): + code: str = "InvalidExecutionInput" + sender_fault: bool = False + status_code: int = 400 + + +class InvalidLoggingConfiguration(ServiceException): + code: str = "InvalidLoggingConfiguration" + sender_fault: bool = False + status_code: int = 400 + + +class InvalidName(ServiceException): + code: str = "InvalidName" + sender_fault: bool = False + status_code: int = 400 + + +class InvalidOutput(ServiceException): + code: str = "InvalidOutput" + sender_fault: bool = False + status_code: int = 400 + + +class InvalidToken(ServiceException): + code: str = "InvalidToken" + sender_fault: bool = False + status_code: int = 400 + + +class InvalidTracingConfiguration(ServiceException): + code: str = "InvalidTracingConfiguration" + sender_fault: bool = False + status_code: int = 400 + + +class MissingRequiredParameter(ServiceException): + code: str = "MissingRequiredParameter" + sender_fault: bool = False + status_code: int = 400 + + +class ResourceNotFound(ServiceException): + code: str = "ResourceNotFound" + sender_fault: bool = False + status_code: int = 400 + resourceName: Optional[str] + + +class ServiceQuotaExceededException(ServiceException): + code: str = "ServiceQuotaExceededException" + sender_fault: bool = False + status_code: int = 400 + + +class StateMachineAlreadyExists(ServiceException): + code: str = "StateMachineAlreadyExists" + sender_fault: bool = False + status_code: int = 400 + + +class StateMachineDeleting(ServiceException): + code: str = "StateMachineDeleting" + sender_fault: bool = False + status_code: int = 400 + + +class StateMachineDoesNotExist(ServiceException): + code: str = "StateMachineDoesNotExist" + sender_fault: bool = False + status_code: int = 400 + + +class StateMachineLimitExceeded(ServiceException): + code: str = "StateMachineLimitExceeded" + sender_fault: bool = False + status_code: int = 400 + + +class StateMachineTypeNotSupported(ServiceException): + code: str = "StateMachineTypeNotSupported" + sender_fault: bool = False + status_code: int = 400 + + +class TaskDoesNotExist(ServiceException): + code: str = "TaskDoesNotExist" + sender_fault: bool = False + status_code: int = 400 + + +class TaskTimedOut(ServiceException): + code: str = "TaskTimedOut" + sender_fault: bool = False + status_code: int = 400 + + +class ValidationException(ServiceException): + code: str = "ValidationException" + sender_fault: bool = False + status_code: int = 400 + reason: Optional[ValidationExceptionReason] + + +class ActivityFailedEventDetails(TypedDict, total=False): + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +Timestamp = datetime + + +class ActivityListItem(TypedDict, total=False): + activityArn: str + name: Name + creationDate: Timestamp + + +ActivityList = List[ActivityListItem] + + +class ActivityScheduleFailedEventDetails(TypedDict, total=False): + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +TimeoutInSeconds = int + + +class HistoryEventExecutionDataDetails(TypedDict, total=False): + truncated: Optional[truncated] + + +class ActivityScheduledEventDetails(TypedDict, total=False): + resource: str + input: Optional[SensitiveData] + inputDetails: Optional[HistoryEventExecutionDataDetails] + timeoutInSeconds: Optional[TimeoutInSeconds] + heartbeatInSeconds: Optional[TimeoutInSeconds] + + +class ActivityStartedEventDetails(TypedDict, total=False): + workerName: Optional[Identity] + + +class ActivitySucceededEventDetails(TypedDict, total=False): + output: Optional[SensitiveData] + outputDetails: Optional[HistoryEventExecutionDataDetails] + + +class ActivityTimedOutEventDetails(TypedDict, total=False): + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +BilledDuration = int +BilledMemoryUsed = int + + +class BillingDetails(TypedDict, total=False): + billedMemoryUsedInMB: Optional[BilledMemoryUsed] + billedDurationInMilliseconds: Optional[BilledDuration] + + +class CloudWatchEventsExecutionDataDetails(TypedDict, total=False): + included: Optional[includedDetails] + + +class CloudWatchLogsLogGroup(TypedDict, total=False): + logGroupArn: Optional[str] + + +class Tag(TypedDict, total=False): + key: Optional[TagKey] + value: Optional[TagValue] + + +TagList = List[Tag] + + +class CreateActivityOutput(TypedDict, total=False): + activityArn: str + creationDate: Timestamp + + +class RoutingConfigurationListItem(TypedDict, total=False): + stateMachineVersionArn: str + weight: VersionWeight + + +RoutingConfigurationList = List[RoutingConfigurationListItem] + + +class CreateStateMachineAliasOutput(TypedDict, total=False): + stateMachineAliasArn: str + creationDate: Timestamp + + +class TracingConfiguration(TypedDict, total=False): + enabled: Optional[Enabled] + + +class LogDestination(TypedDict, total=False): + cloudWatchLogsLogGroup: Optional[CloudWatchLogsLogGroup] + + +LogDestinationList = List[LogDestination] + + +class LoggingConfiguration(TypedDict, total=False): + level: Optional[LogLevel] + includeExecutionData: Optional[IncludeExecutionData] + destinations: Optional[LogDestinationList] + + +CreateStateMachineInput = TypedDict( + "CreateStateMachineInput", + { + "name": Name, + "definition": Definition, + "roleArn": str, + "type": Optional[StateMachineType], + "loggingConfiguration": Optional[LoggingConfiguration], + "tags": Optional[TagList], + "tracingConfiguration": Optional[TracingConfiguration], + "publish": Optional[Publish], + "versionDescription": Optional[VersionDescription], + }, + total=False, +) + + +class CreateStateMachineOutput(TypedDict, total=False): + stateMachineArn: str + creationDate: Timestamp + stateMachineVersionArn: Optional[str] + + +class DeleteActivityOutput(TypedDict, total=False): + pass + + +class DeleteStateMachineAliasOutput(TypedDict, total=False): + pass + + +class DeleteStateMachineOutput(TypedDict, total=False): + pass + + +class DeleteStateMachineVersionOutput(TypedDict, total=False): + pass + + +class DescribeActivityOutput(TypedDict, total=False): + activityArn: str + name: Name + creationDate: Timestamp + + +class DescribeExecutionOutput(TypedDict, total=False): + executionArn: str + stateMachineArn: str + name: Optional[Name] + status: ExecutionStatus + startDate: Timestamp + stopDate: Optional[Timestamp] + input: Optional[SensitiveData] + inputDetails: Optional[CloudWatchEventsExecutionDataDetails] + output: Optional[SensitiveData] + outputDetails: Optional[CloudWatchEventsExecutionDataDetails] + traceHeader: Optional[TraceHeader] + mapRunArn: Optional[str] + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + stateMachineVersionArn: Optional[str] + stateMachineAliasArn: Optional[str] + redriveCount: Optional[RedriveCount] + redriveDate: Optional[Timestamp] + redriveStatus: Optional[ExecutionRedriveStatus] + redriveStatusReason: Optional[SensitiveData] + + +LongObject = int +UnsignedLong = int + + +class MapRunExecutionCounts(TypedDict, total=False): + pending: UnsignedLong + running: UnsignedLong + succeeded: UnsignedLong + failed: UnsignedLong + timedOut: UnsignedLong + aborted: UnsignedLong + total: UnsignedLong + resultsWritten: UnsignedLong + failuresNotRedrivable: Optional[LongObject] + pendingRedrive: Optional[LongObject] + + +class MapRunItemCounts(TypedDict, total=False): + pending: UnsignedLong + running: UnsignedLong + succeeded: UnsignedLong + failed: UnsignedLong + timedOut: UnsignedLong + aborted: UnsignedLong + total: UnsignedLong + resultsWritten: UnsignedLong + failuresNotRedrivable: Optional[LongObject] + pendingRedrive: Optional[LongObject] + + +ToleratedFailureCount = int + + +class DescribeMapRunOutput(TypedDict, total=False): + mapRunArn: str + executionArn: str + status: MapRunStatus + startDate: Timestamp + stopDate: Optional[Timestamp] + maxConcurrency: MaxConcurrency + toleratedFailurePercentage: ToleratedFailurePercentage + toleratedFailureCount: ToleratedFailureCount + itemCounts: MapRunItemCounts + executionCounts: MapRunExecutionCounts + redriveCount: Optional[RedriveCount] + redriveDate: Optional[Timestamp] + + +class DescribeStateMachineAliasOutput(TypedDict, total=False): + stateMachineAliasArn: Optional[str] + name: Optional[Name] + description: Optional[AliasDescription] + routingConfiguration: Optional[RoutingConfigurationList] + creationDate: Optional[Timestamp] + updateDate: Optional[Timestamp] + + +class DescribeStateMachineForExecutionOutput(TypedDict, total=False): + stateMachineArn: str + name: Name + definition: Definition + roleArn: str + updateDate: Timestamp + loggingConfiguration: Optional[LoggingConfiguration] + tracingConfiguration: Optional[TracingConfiguration] + mapRunArn: Optional[str] + label: Optional[MapRunLabel] + revisionId: Optional[RevisionId] + + +DescribeStateMachineOutput = TypedDict( + "DescribeStateMachineOutput", + { + "stateMachineArn": str, + "name": Name, + "status": Optional[StateMachineStatus], + "definition": Definition, + "roleArn": str, + "type": StateMachineType, + "creationDate": Timestamp, + "loggingConfiguration": Optional[LoggingConfiguration], + "tracingConfiguration": Optional[TracingConfiguration], + "label": Optional[MapRunLabel], + "revisionId": Optional[RevisionId], + "description": Optional[VersionDescription], + }, + total=False, +) +EventId = int + + +class ExecutionAbortedEventDetails(TypedDict, total=False): + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +class ExecutionFailedEventDetails(TypedDict, total=False): + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +class ExecutionListItem(TypedDict, total=False): + executionArn: str + stateMachineArn: str + name: Name + status: ExecutionStatus + startDate: Timestamp + stopDate: Optional[Timestamp] + mapRunArn: Optional[str] + itemCount: Optional[UnsignedInteger] + stateMachineVersionArn: Optional[str] + stateMachineAliasArn: Optional[str] + redriveCount: Optional[RedriveCount] + redriveDate: Optional[Timestamp] + + +ExecutionList = List[ExecutionListItem] + + +class ExecutionRedrivenEventDetails(TypedDict, total=False): + redriveCount: Optional[RedriveCount] + + +class ExecutionStartedEventDetails(TypedDict, total=False): + input: Optional[SensitiveData] + inputDetails: Optional[HistoryEventExecutionDataDetails] + roleArn: Optional[str] + stateMachineAliasArn: Optional[str] + stateMachineVersionArn: Optional[str] + + +class ExecutionSucceededEventDetails(TypedDict, total=False): + output: Optional[SensitiveData] + outputDetails: Optional[HistoryEventExecutionDataDetails] + + +class ExecutionTimedOutEventDetails(TypedDict, total=False): + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +class GetActivityTaskOutput(TypedDict, total=False): + taskToken: Optional[TaskToken] + input: Optional[SensitiveDataJobInput] + + +class MapRunRedrivenEventDetails(TypedDict, total=False): + mapRunArn: Optional[str] + redriveCount: Optional[RedriveCount] + + +class MapRunFailedEventDetails(TypedDict, total=False): + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +class MapRunStartedEventDetails(TypedDict, total=False): + mapRunArn: Optional[str] + + +class StateExitedEventDetails(TypedDict, total=False): + name: Name + output: Optional[SensitiveData] + outputDetails: Optional[HistoryEventExecutionDataDetails] + + +class StateEnteredEventDetails(TypedDict, total=False): + name: Name + input: Optional[SensitiveData] + inputDetails: Optional[HistoryEventExecutionDataDetails] + + +class LambdaFunctionTimedOutEventDetails(TypedDict, total=False): + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +class LambdaFunctionSucceededEventDetails(TypedDict, total=False): + output: Optional[SensitiveData] + outputDetails: Optional[HistoryEventExecutionDataDetails] + + +class LambdaFunctionStartFailedEventDetails(TypedDict, total=False): + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +class TaskCredentials(TypedDict, total=False): + roleArn: Optional[str] + + +class LambdaFunctionScheduledEventDetails(TypedDict, total=False): + resource: str + input: Optional[SensitiveData] + inputDetails: Optional[HistoryEventExecutionDataDetails] + timeoutInSeconds: Optional[TimeoutInSeconds] + taskCredentials: Optional[TaskCredentials] + + +class LambdaFunctionScheduleFailedEventDetails(TypedDict, total=False): + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +class LambdaFunctionFailedEventDetails(TypedDict, total=False): + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +class MapIterationEventDetails(TypedDict, total=False): + name: Optional[Name] + index: Optional[UnsignedInteger] + + +class MapStateStartedEventDetails(TypedDict, total=False): + length: Optional[UnsignedInteger] + + +class TaskTimedOutEventDetails(TypedDict, total=False): + resourceType: Name + resource: Name + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +class TaskSucceededEventDetails(TypedDict, total=False): + resourceType: Name + resource: Name + output: Optional[SensitiveData] + outputDetails: Optional[HistoryEventExecutionDataDetails] + + +class TaskSubmittedEventDetails(TypedDict, total=False): + resourceType: Name + resource: Name + output: Optional[SensitiveData] + outputDetails: Optional[HistoryEventExecutionDataDetails] + + +class TaskSubmitFailedEventDetails(TypedDict, total=False): + resourceType: Name + resource: Name + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +class TaskStartedEventDetails(TypedDict, total=False): + resourceType: Name + resource: Name + + +class TaskStartFailedEventDetails(TypedDict, total=False): + resourceType: Name + resource: Name + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +class TaskScheduledEventDetails(TypedDict, total=False): + resourceType: Name + resource: Name + region: Name + parameters: ConnectorParameters + timeoutInSeconds: Optional[TimeoutInSeconds] + heartbeatInSeconds: Optional[TimeoutInSeconds] + taskCredentials: Optional[TaskCredentials] + + +class TaskFailedEventDetails(TypedDict, total=False): + resourceType: Name + resource: Name + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + + +HistoryEvent = TypedDict( + "HistoryEvent", + { + "timestamp": Timestamp, + "type": HistoryEventType, + "id": EventId, + "previousEventId": Optional[EventId], + "activityFailedEventDetails": Optional[ActivityFailedEventDetails], + "activityScheduleFailedEventDetails": Optional[ + ActivityScheduleFailedEventDetails + ], + "activityScheduledEventDetails": Optional[ActivityScheduledEventDetails], + "activityStartedEventDetails": Optional[ActivityStartedEventDetails], + "activitySucceededEventDetails": Optional[ActivitySucceededEventDetails], + "activityTimedOutEventDetails": Optional[ActivityTimedOutEventDetails], + "taskFailedEventDetails": Optional[TaskFailedEventDetails], + "taskScheduledEventDetails": Optional[TaskScheduledEventDetails], + "taskStartFailedEventDetails": Optional[TaskStartFailedEventDetails], + "taskStartedEventDetails": Optional[TaskStartedEventDetails], + "taskSubmitFailedEventDetails": Optional[TaskSubmitFailedEventDetails], + "taskSubmittedEventDetails": Optional[TaskSubmittedEventDetails], + "taskSucceededEventDetails": Optional[TaskSucceededEventDetails], + "taskTimedOutEventDetails": Optional[TaskTimedOutEventDetails], + "executionFailedEventDetails": Optional[ExecutionFailedEventDetails], + "executionStartedEventDetails": Optional[ExecutionStartedEventDetails], + "executionSucceededEventDetails": Optional[ExecutionSucceededEventDetails], + "executionAbortedEventDetails": Optional[ExecutionAbortedEventDetails], + "executionTimedOutEventDetails": Optional[ExecutionTimedOutEventDetails], + "executionRedrivenEventDetails": Optional[ExecutionRedrivenEventDetails], + "mapStateStartedEventDetails": Optional[MapStateStartedEventDetails], + "mapIterationStartedEventDetails": Optional[MapIterationEventDetails], + "mapIterationSucceededEventDetails": Optional[MapIterationEventDetails], + "mapIterationFailedEventDetails": Optional[MapIterationEventDetails], + "mapIterationAbortedEventDetails": Optional[MapIterationEventDetails], + "lambdaFunctionFailedEventDetails": Optional[LambdaFunctionFailedEventDetails], + "lambdaFunctionScheduleFailedEventDetails": Optional[ + LambdaFunctionScheduleFailedEventDetails + ], + "lambdaFunctionScheduledEventDetails": Optional[ + LambdaFunctionScheduledEventDetails + ], + "lambdaFunctionStartFailedEventDetails": Optional[ + LambdaFunctionStartFailedEventDetails + ], + "lambdaFunctionSucceededEventDetails": Optional[ + LambdaFunctionSucceededEventDetails + ], + "lambdaFunctionTimedOutEventDetails": Optional[ + LambdaFunctionTimedOutEventDetails + ], + "stateEnteredEventDetails": Optional[StateEnteredEventDetails], + "stateExitedEventDetails": Optional[StateExitedEventDetails], + "mapRunStartedEventDetails": Optional[MapRunStartedEventDetails], + "mapRunFailedEventDetails": Optional[MapRunFailedEventDetails], + "mapRunRedrivenEventDetails": Optional[MapRunRedrivenEventDetails], + }, + total=False, +) +HistoryEventList = List[HistoryEvent] + + +class GetExecutionHistoryOutput(TypedDict, total=False): + events: HistoryEventList + nextToken: Optional[PageToken] + + +class InspectionDataResponse(TypedDict, total=False): + protocol: Optional[HTTPProtocol] + statusCode: Optional[HTTPStatusCode] + statusMessage: Optional[HTTPStatusMessage] + headers: Optional[HTTPHeaders] + body: Optional[HTTPBody] + + +class InspectionDataRequest(TypedDict, total=False): + protocol: Optional[HTTPProtocol] + method: Optional[HTTPMethod] + url: Optional[URL] + headers: Optional[HTTPHeaders] + body: Optional[HTTPBody] + + +class InspectionData(TypedDict, total=False): + input: Optional[SensitiveData] + afterInputPath: Optional[SensitiveData] + afterParameters: Optional[SensitiveData] + result: Optional[SensitiveData] + afterResultSelector: Optional[SensitiveData] + afterResultPath: Optional[SensitiveData] + request: Optional[InspectionDataRequest] + response: Optional[InspectionDataResponse] + + +class ListActivitiesOutput(TypedDict, total=False): + activities: ActivityList + nextToken: Optional[PageToken] + + +class ListExecutionsOutput(TypedDict, total=False): + executions: ExecutionList + nextToken: Optional[ListExecutionsPageToken] + + +class MapRunListItem(TypedDict, total=False): + executionArn: str + mapRunArn: str + stateMachineArn: str + startDate: Timestamp + stopDate: Optional[Timestamp] + + +MapRunList = List[MapRunListItem] + + +class ListMapRunsOutput(TypedDict, total=False): + mapRuns: MapRunList + nextToken: Optional[PageToken] + + +class StateMachineAliasListItem(TypedDict, total=False): + stateMachineAliasArn: str + creationDate: Timestamp + + +StateMachineAliasList = List[StateMachineAliasListItem] + + +class ListStateMachineAliasesOutput(TypedDict, total=False): + stateMachineAliases: StateMachineAliasList + nextToken: Optional[PageToken] + + +class StateMachineVersionListItem(TypedDict, total=False): + stateMachineVersionArn: str + creationDate: Timestamp + + +StateMachineVersionList = List[StateMachineVersionListItem] + + +class ListStateMachineVersionsOutput(TypedDict, total=False): + stateMachineVersions: StateMachineVersionList + nextToken: Optional[PageToken] + + +StateMachineListItem = TypedDict( + "StateMachineListItem", + { + "stateMachineArn": str, + "name": Name, + "type": StateMachineType, + "creationDate": Timestamp, + }, + total=False, +) +StateMachineList = List[StateMachineListItem] + + +class ListStateMachinesOutput(TypedDict, total=False): + stateMachines: StateMachineList + nextToken: Optional[PageToken] + + +class ListTagsForResourceOutput(TypedDict, total=False): + tags: Optional[TagList] + + +class PublishStateMachineVersionOutput(TypedDict, total=False): + creationDate: Timestamp + stateMachineVersionArn: str + + +class RedriveExecutionOutput(TypedDict, total=False): + redriveDate: Timestamp + + +class SendTaskFailureOutput(TypedDict, total=False): + pass + + +class SendTaskHeartbeatOutput(TypedDict, total=False): + pass + + +class SendTaskSuccessOutput(TypedDict, total=False): + pass + + +class StartExecutionOutput(TypedDict, total=False): + executionArn: str + startDate: Timestamp + + +class StartSyncExecutionOutput(TypedDict, total=False): + executionArn: str + stateMachineArn: Optional[str] + name: Optional[Name] + startDate: Timestamp + stopDate: Timestamp + status: SyncExecutionStatus + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + input: Optional[SensitiveData] + inputDetails: Optional[CloudWatchEventsExecutionDataDetails] + output: Optional[SensitiveData] + outputDetails: Optional[CloudWatchEventsExecutionDataDetails] + traceHeader: Optional[TraceHeader] + billingDetails: Optional[BillingDetails] + + +class StopExecutionOutput(TypedDict, total=False): + stopDate: Timestamp + + +TagKeyList = List[TagKey] + + +class TagResourceOutput(TypedDict, total=False): + pass + + +class TestStateOutput(TypedDict, total=False): + output: Optional[SensitiveData] + error: Optional[SensitiveError] + cause: Optional[SensitiveCause] + inspectionData: Optional[InspectionData] + nextState: Optional[StateName] + status: Optional[TestExecutionStatus] + + +class UntagResourceOutput(TypedDict, total=False): + pass + + +class UpdateMapRunOutput(TypedDict, total=False): + pass + + +class UpdateStateMachineAliasOutput(TypedDict, total=False): + updateDate: Timestamp + + +class UpdateStateMachineOutput(TypedDict, total=False): + updateDate: Timestamp + revisionId: Optional[RevisionId] + stateMachineVersionArn: Optional[str] diff --git a/moto/stepfunctions/parser/asl/__init__.py b/moto/stepfunctions/parser/asl/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/antlr/ASLIntrinsicLexer.g4 b/moto/stepfunctions/parser/asl/antlr/ASLIntrinsicLexer.g4 new file mode 100644 index 000000000..4f1f4eae5 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/ASLIntrinsicLexer.g4 @@ -0,0 +1,79 @@ +lexer grammar ASLIntrinsicLexer; + +DOLLAR: '$'; +DOT: '.'; +STAR: '*'; +COMMA: ','; +LPAREN: '('; +RPAREN: ')'; +LBRACK: '['; +RBRACK: ']'; +LDIAM: '<'; +RDIAM: '>'; +ATDOT: '@.'; +ATDOTLENGTHDASH: '@.length-'; +ANDAND: '&&'; +OROR: '||'; +EQEQ: '=='; +EQ: '='; + +TRUE: 'true'; +FALSE: 'false'; + +States: 'States'; +Format: 'Format'; +StringToJson: 'StringToJson'; +JsonToString: 'JsonToString'; +Array: 'Array'; +ArrayPartition: 'ArrayPartition'; +ArrayContains: 'ArrayContains'; +ArrayRange: 'ArrayRange'; +ArrayGetItem: 'ArrayGetItem'; +ArrayLength: 'ArrayLength'; +ArrayUnique: 'ArrayUnique'; +Base64Encode: 'Base64Encode'; +Base64Decode: 'Base64Decode'; +Hash: 'Hash'; +JsonMerge: 'JsonMerge'; +MathRandom: 'MathRandom'; +MathAdd: 'MathAdd'; +StringSplit: 'StringSplit'; +UUID: 'UUID'; + + +STRING + : '\'' (ESC | SAFECODEPOINT)*? '\'' + ; + +fragment ESC + : '\\' (UNICODE | .) + ; +fragment UNICODE + : 'u' HEX HEX HEX HEX + ; +fragment HEX + : [0-9a-fA-F] + ; +fragment SAFECODEPOINT + : ~ ['\\\u0000-\u001F] + ; + +INT + : '-'? ('0' | [1-9] [0-9]*) + ; + +NUMBER + : '-'? INT ('.' [0-9] +)? EXP? + ; + +fragment EXP + : [Ee] [+\-]? INT + ; + +IDENTIFIER + : ([0-9a-zA-Z_] | UNICODE)+ + ; + +WS + : [ \t\n] + -> skip + ; \ No newline at end of file diff --git a/moto/stepfunctions/parser/asl/antlr/ASLIntrinsicParser.g4 b/moto/stepfunctions/parser/asl/antlr/ASLIntrinsicParser.g4 new file mode 100644 index 000000000..4d6f07c7b --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/ASLIntrinsicParser.g4 @@ -0,0 +1,92 @@ +parser grammar ASLIntrinsicParser; + +options { + tokenVocab=ASLIntrinsicLexer; +} + +func_decl + : states_func_decl + ; + +states_func_decl + : States DOT state_fun_name func_arg_list + ; + +state_fun_name + : Format + | StringToJson + | JsonToString + | Array + | ArrayPartition + | ArrayContains + | ArrayRange + | ArrayGetItem + | ArrayLength + | ArrayUnique + | Base64Encode + | Base64Decode + | Hash + | JsonMerge + | MathRandom + | MathAdd + | StringSplit + | UUID + ; + +func_arg_list + : LPAREN func_arg (COMMA func_arg)* RPAREN + | LPAREN RPAREN + ; + +func_arg + : STRING #func_arg_string + | INT #func_arg_int + | NUMBER #func_arg_float + | (TRUE | FALSE) #func_arg_bool + | context_path #func_arg_context_path + | json_path #func_arg_json_path + | func_decl #func_arg_func_decl + ; + +context_path + : DOLLAR json_path + ; + +json_path + : DOLLAR DOT json_path_part (DOT json_path_part)* + ; + +json_path_part + : json_path_iden + | json_path_iden_qual + ; + +json_path_iden + : identifier + ; + +json_path_iden_qual + : json_path_iden json_path_qual + ; + +json_path_qual + : LBRACK RBRACK #json_path_qual_void + | LBRACK INT RBRACK #json_path_qual_idx + | LBRACK json_path_query RBRACK #json_path_qual_query + ; + +json_path_query + : STAR # json_path_query_star + | ATDOT json_path_iden + ( (LDIAM | RDIAM | EQEQ) INT + | EQ STRING + ) # json_path_query_cmp + | ATDOTLENGTHDASH INT # json_path_query_length + | json_path_query ((ANDAND | OROR) json_path_query)+ # json_path_query_binary + ; + +identifier + : IDENTIFIER + // States. + | state_fun_name + ; diff --git a/moto/stepfunctions/parser/asl/antlr/ASLLexer.g4 b/moto/stepfunctions/parser/asl/antlr/ASLLexer.g4 new file mode 100644 index 000000000..9a5bd2e90 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/ASLLexer.g4 @@ -0,0 +1,200 @@ +lexer grammar ASLLexer; + +// Symbols. +COMMA: ','; +COLON: ':'; +LBRACK: '['; +RBRACK: ']'; +LBRACE: '{'; +RBRACE: '}'; + +// Literals. +TRUE: 'true'; +FALSE: 'false'; +NULL: 'null'; + +// Keywords. +COMMENT: '"Comment"'; +STATES: '"States"'; +STARTAT: '"StartAt"'; +NEXTSTATE: '"NextState"'; +VERSION: '"Version"'; + +TYPE: '"Type"'; +TASK: '"Task"'; +CHOICE: '"Choice"'; +FAIL: '"Fail"'; +SUCCEED: '"Succeed"'; +PASS: '"Pass"'; +WAIT: '"Wait"'; +PARALLEL: '"Parallel"'; +MAP: '"Map"'; + +CHOICES: '"Choices"'; +VARIABLE: '"Variable"'; +DEFAULT: '"Default"'; +BRANCHES: '"Branches"'; + +AND: '"And"'; +BOOLEANEQUALS: '"BooleanEquals"'; +BOOLEANQUALSPATH: '"BooleanEqualsPath"'; +ISBOOLEAN: '"IsBoolean"'; +ISNULL: '"IsNull"'; +ISNUMERIC: '"IsNumeric"'; +ISPRESENT: '"IsPresent"'; +ISSTRING: '"IsString"'; +ISTIMESTAMP: '"IsTimestamp"'; +NOT: '"Not"'; +NUMERICEQUALS: '"NumericEquals"'; +NUMERICEQUALSPATH: '"NumericEqualsPath"'; +NUMERICGREATERTHAN: '"NumericGreaterThan"'; +NUMERICGREATERTHANPATH: '"NumericGreaterThanPath"'; +NUMERICGREATERTHANEQUALS: '"NumericGreaterThanEquals"'; +NUMERICGREATERTHANEQUALSPATH: '"NumericGreaterThanEqualsPath"'; +NUMERICLESSTHAN: '"NumericLessThan"'; +NUMERICLESSTHANPATH: '"NumericLessThanPath"'; +NUMERICLESSTHANEQUALS: '"NumericLessThanEquals"'; +NUMERICLESSTHANEQUALSPATH: '"NumericLessThanEqualsPath"'; +OR: '"Or"'; +STRINGEQUALS: '"StringEquals"'; +STRINGEQUALSPATH: '"StringEqualsPath"'; +STRINGGREATERTHAN: '"StringGreaterThan"'; +STRINGGREATERTHANPATH: '"StringGreaterThanPath"'; +STRINGGREATERTHANEQUALS: '"StringGreaterThanEquals"'; +STRINGGREATERTHANEQUALSPATH: '"StringGreaterThanEqualsPath"'; +STRINGLESSTHAN: '"StringLessThan"'; +STRINGLESSTHANPATH: '"StringLessThanPath"'; +STRINGLESSTHANEQUALS: '"StringLessThanEquals"'; +STRINGLESSTHANEQUALSPATH: '"StringLessThanEqualsPath"'; +STRINGMATCHES: '"StringMatches"'; +TIMESTAMPEQUALS: '"TimestampEquals"'; +TIMESTAMPEQUALSPATH: '"TimestampEqualsPath"'; +TIMESTAMPGREATERTHAN: '"TimestampGreaterThan"'; +TIMESTAMPGREATERTHANPATH: '"TimestampGreaterThanPath"'; +TIMESTAMPGREATERTHANEQUALS: '"TimestampGreaterThanEquals"'; +TIMESTAMPGREATERTHANEQUALSPATH: '"TimestampGreaterThanEqualsPath"'; +TIMESTAMPLESSTHAN: '"TimestampLessThan"'; +TIMESTAMPLESSTHANPATH: '"TimestampLessThanPath"'; +TIMESTAMPLESSTHANEQUALS: '"TimestampLessThanEquals"'; +TIMESTAMPLESSTHANEQUALSPATH: '"TimestampLessThanEqualsPath"'; + +SECONDSPATH: '"SecondsPath"'; +SECONDS: '"Seconds"'; +TIMESTAMPPATH: '"TimestampPath"'; +TIMESTAMP: '"Timestamp"'; + +TIMEOUTSECONDS: '"TimeoutSeconds"'; +TIMEOUTSECONDSPATH: '"TimeoutSecondsPath"'; + +HEARTBEATSECONDS: '"HeartbeatSeconds"'; +HEARTBEATSECONDSPATH: '"HeartbeatSecondsPath"'; + +PROCESSORCONFIG: '"ProcessorConfig"'; +MODE: '"Mode"'; +INLINE: '"INLINE"'; +DISTRIBUTED: '"DISTRIBUTED"'; +EXECUTIONTYPE: '"ExecutionType"'; +STANDARD: '"STANDARD"'; + +ITEMPROCESSOR: '"ItemProcessor"'; +ITERATOR: '"Iterator"'; +ITEMSELECTOR: '"ItemSelector"'; +MAXCONCURRENCY: '"MaxConcurrency"'; + +RESOURCE: '"Resource"'; +INPUTPATH: '"InputPath"'; +OUTPUTPATH: '"OutputPath"'; +ITEMSPATH: '"ItemsPath"'; +RESULTPATH: '"ResultPath"'; +RESULT: '"Result"'; +PARAMETERS: '"Parameters"'; +RESULTSELECTOR: '"ResultSelector"'; + +ITEMREADER: '"ItemReader"'; +READERCONFIG: '"ReaderConfig"'; +INPUTTYPE: '"InputType"'; +CSVHEADERLOCATION: '"CSVHeaderLocation"'; +CSVHEADERS: '"CSVHeaders"'; +MAXITEMS: '"MaxItems"'; +MAXITEMSPATH: '"MaxItemsPath"'; + +NEXT: '"Next"'; +END: '"End"'; + +CAUSE: '"Cause"'; +ERROR: '"Error"'; + +// Retry. +RETRY: '"Retry"'; +ERROREQUALS: '"ErrorEquals"'; +INTERVALSECONDS: '"IntervalSeconds"'; +MAXATTEMPTS: '"MaxAttempts"'; +BACKOFFRATE: '"BackoffRate"'; + +// Catch. +CATCH: '"Catch"'; + +// ErrorNames +ERRORNAMEStatesALL: '"States.ALL"'; +ERRORNAMEStatesHeartbeatTimeout: '"States.HeartbeatTimeout"'; +ERRORNAMEStatesTimeout: '"States.Timeout"'; +ERRORNAMEStatesTaskFailed: '"States.TaskFailed"'; +ERRORNAMEStatesPermissions: '"States.Permissions"'; +ERRORNAMEStatesResultPathMatchFailure: '"States.ResultPathMatchFailure"'; +ERRORNAMEStatesParameterPathFailure: '"States.ParameterPathFailure"'; +ERRORNAMEStatesBranchFailed: '"States.BranchFailed"'; +ERRORNAMEStatesNoChoiceMatched: '"States.NoChoiceMatched"'; +ERRORNAMEStatesIntrinsicFailure: '"States.IntrinsicFailure"'; +ERRORNAMEStatesExceedToleratedFailureThreshold: '"States.ExceedToleratedFailureThreshold"'; +ERRORNAMEStatesItemReaderFailed: '"States.ItemReaderFailed"'; +ERRORNAMEStatesResultWriterFailed: '"States.ResultWriterFailed"'; +// Read-only: +ERRORNAMEStatesRuntime: '"States.Runtime"'; + +// Strings. + +STRINGDOLLAR + : '"' (ESC | SAFECODEPOINT)* '.$"' + ; + +STRINGPATHCONTEXTOBJ + : '"$$' (ESC | SAFECODEPOINT)* '"' + ; + +STRINGPATH + : '"$' (ESC | SAFECODEPOINT)* '"' + ; + +STRING + : '"' (ESC | SAFECODEPOINT)* '"' + ; +fragment ESC + : '\\' (["\\/bfnrt] | UNICODE) + ; +fragment UNICODE + : 'u' HEX HEX HEX HEX + ; +fragment HEX + : [0-9a-fA-F] + ; +fragment SAFECODEPOINT + : ~ ["\\\u0000-\u001F] + ; + +// Numbers. +INT + : '0' | [1-9] [0-9]* + ; + +NUMBER + : '-'? INT ('.' [0-9] +)? EXP? + ; + +fragment EXP + : [Ee] [+\-]? INT + ; + +// Whitespace. +WS + : [ \t\n\r] + -> skip + ; \ No newline at end of file diff --git a/moto/stepfunctions/parser/asl/antlr/ASLParser.g4 b/moto/stepfunctions/parser/asl/antlr/ASLParser.g4 new file mode 100644 index 000000000..78277f755 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/ASLParser.g4 @@ -0,0 +1,682 @@ +parser grammar ASLParser; + +options { + tokenVocab=ASLLexer; +} + +program_decl + : LBRACE + top_layer_stmt (COMMA top_layer_stmt)* + RBRACE + ; + +top_layer_stmt + : comment_decl + | version_decl + | startat_decl + | states_decl + | timeout_seconds_decl + ; + +startat_decl + : STARTAT COLON keyword_or_string + ; + +comment_decl + : COMMENT COLON keyword_or_string + ; + +version_decl + : VERSION COLON keyword_or_string + ; + +state_stmt + : comment_decl + | type_decl + | input_path_decl + | resource_decl + | next_decl + | result_decl + | result_path_decl + | output_path_decl + | end_decl + | default_decl + | choices_decl + | error_decl + | cause_decl + | seconds_decl + | seconds_path_decl + | timestamp_decl + | timestamp_path_decl + | items_path_decl + | item_processor_decl + | iterator_decl + | item_selector_decl + | item_reader_decl + | max_concurrency_decl + | timeout_seconds_decl + | timeout_seconds_path_decl + | heartbeat_seconds_decl + | heartbeat_seconds_path_decl + | branches_decl + | parameters_decl + | retry_decl + | catch_decl + | result_selector_decl + ; + +states_decl + : STATES + COLON + LBRACE + state_decl (COMMA state_decl)* + RBRACE + ; + +state_name + : keyword_or_string + ; + +// TODO: avoid redefinitions? -> check listener ok? +state_decl + : state_name + COLON + state_decl_body + ; + +state_decl_body + : LBRACE + state_stmt (COMMA state_stmt)* + RBRACE + ; + +type_decl + : TYPE COLON state_type + ; + +next_decl + : NEXT COLON keyword_or_string + ; + +resource_decl + : RESOURCE COLON keyword_or_string + ; + +input_path_decl + : INPUTPATH COLON (NULL | keyword_or_string) + ; + +result_decl + : RESULT COLON json_value_decl + ; + +result_path_decl + : RESULTPATH COLON (NULL | keyword_or_string) + ; + +output_path_decl + : OUTPUTPATH COLON (NULL | keyword_or_string) + ; + +end_decl + : END COLON (TRUE | FALSE) + ; + +default_decl + : DEFAULT COLON keyword_or_string + ; + +error_decl + : ERROR COLON keyword_or_string + ; + +cause_decl + : CAUSE COLON keyword_or_string + ; + +seconds_decl + : SECONDS COLON INT + ; + +seconds_path_decl + : SECONDSPATH COLON keyword_or_string + ; + +timestamp_decl + : TIMESTAMP COLON keyword_or_string + ; + +timestamp_path_decl + : TIMESTAMPPATH COLON keyword_or_string + ; + +items_path_decl + : ITEMSPATH COLON keyword_or_string + ; + +max_concurrency_decl + : MAXCONCURRENCY COLON INT + ; + +parameters_decl + : PARAMETERS COLON payload_tmpl_decl + ; + +timeout_seconds_decl + : TIMEOUTSECONDS COLON INT + ; + +timeout_seconds_path_decl + : TIMEOUTSECONDSPATH COLON STRINGPATH + ; + +heartbeat_seconds_decl + : HEARTBEATSECONDS COLON INT + ; + +heartbeat_seconds_path_decl + : HEARTBEATSECONDSPATH COLON STRINGPATH + ; + +payload_tmpl_decl + : LBRACE payload_binding (COMMA payload_binding)* RBRACE + | LBRACE RBRACE + ; + +payload_binding + : STRINGDOLLAR COLON STRINGPATH #payload_binding_path + | STRINGDOLLAR COLON STRINGPATHCONTEXTOBJ #payload_binding_path_context_obj + | STRINGDOLLAR COLON intrinsic_func #payload_binding_intrinsic_func + | keyword_or_string COLON payload_value_decl #payload_binding_value + ; + +intrinsic_func + : STRING + ; + +payload_arr_decl + : LBRACK payload_value_decl (COMMA payload_value_decl)* RBRACK + | LBRACK RBRACK + ; + +payload_value_decl + : payload_binding + | payload_arr_decl + | payload_tmpl_decl + | payload_value_lit + ; + +payload_value_lit + : NUMBER #payload_value_float + | INT #payload_value_int + | (TRUE | FALSE) #payload_value_bool + | NULL #payload_value_null + | keyword_or_string #payload_value_str + ; + +result_selector_decl + : RESULTSELECTOR COLON payload_tmpl_decl + ; + +state_type + : TASK + | PASS + | CHOICE + | FAIL + | SUCCEED + | WAIT + | MAP + | PARALLEL + ; + +choices_decl + : CHOICES + COLON + LBRACK + choice_rule (COMMA choice_rule)* + RBRACK + ; + +choice_rule + : LBRACE + comparison_variable_stmt (COMMA comparison_variable_stmt)+ + RBRACE #choice_rule_comparison_variable + | LBRACE + comparison_composite_stmt (COMMA comparison_composite_stmt)* + RBRACE #choice_rule_comparison_composite + ; + +comparison_variable_stmt + : variable_decl + | comparison_func + | next_decl + ; + +comparison_composite_stmt + : comparison_composite + | next_decl + ; + +comparison_composite +// TODO: this allows for Next definitions in nested choice_rules, is this supported at parse time? + : choice_operator COLON + ( choice_rule + | LBRACK + choice_rule (COMMA choice_rule)* + RBRACK + ) + ; + +variable_decl + : VARIABLE COLON keyword_or_string + ; + +comparison_func + : comparison_op COLON json_value_decl + ; + +branches_decl + : BRANCHES + COLON + LBRACK + program_decl (COMMA program_decl)* + RBRACK + ; + +item_processor_decl + : ITEMPROCESSOR + COLON + LBRACE + item_processor_item (COMMA item_processor_item)* + RBRACE + ; + +item_processor_item + : processor_config_decl + | startat_decl + | states_decl + | comment_decl + ; + +processor_config_decl + : PROCESSORCONFIG + COLON + LBRACE + processor_config_field (COMMA processor_config_field)* + RBRACE + ; + +processor_config_field + : mode_decl + | execution_decl + ; + +mode_decl + : MODE COLON mode_type + ; + +mode_type + : INLINE + | DISTRIBUTED + ; + +execution_decl + : EXECUTIONTYPE COLON execution_type + ; + +execution_type + : STANDARD + ; + +iterator_decl + : ITERATOR + COLON + LBRACE + iterator_decl_item (COMMA iterator_decl_item)* + RBRACE + ; + +iterator_decl_item + : startat_decl + | states_decl + | comment_decl + ; + +item_selector_decl + : ITEMSELECTOR COLON payload_tmpl_decl + ; + +item_reader_decl + : ITEMREADER + COLON + LBRACE + items_reader_field (COMMA items_reader_field)* + RBRACE + ; + +items_reader_field + : resource_decl + | parameters_decl + | reader_config_decl + ; + +reader_config_decl + : READERCONFIG + COLON + LBRACE + reader_config_field (COMMA reader_config_field)* + RBRACE + ; + +reader_config_field + : input_type_decl + | csv_header_location_decl + | csv_headers_decl + | max_items_decl + | max_items_path_decl + ; + +input_type_decl + : INPUTTYPE COLON keyword_or_string + ; + +csv_header_location_decl + : CSVHEADERLOCATION COLON keyword_or_string + ; + +csv_headers_decl // TODO: are empty "CSVHeaders" list values supported? + : CSVHEADERS + COLON + LBRACK + keyword_or_string (COMMA keyword_or_string)* + RBRACK + ; + +max_items_decl + : MAXITEMS COLON INT + ; + +max_items_path_decl + : MAXITEMSPATH COLON STRINGPATH + ; + +retry_decl + : RETRY + COLON + LBRACK + (retrier_decl (COMMA retrier_decl)*)? + RBRACK + ; + +retrier_decl + : LBRACE + retrier_stmt (COMMA retrier_stmt)* + RBRACE + ; + +retrier_stmt + : error_equals_decl + | interval_seconds_decl + | max_attempts_decl + | backoff_rate_decl + ; + +error_equals_decl + : ERROREQUALS + COLON + LBRACK + error_name (COMMA error_name)* + RBRACK + ; + +interval_seconds_decl + : INTERVALSECONDS COLON INT + ; + +max_attempts_decl + : MAXATTEMPTS COLON INT + ; + +backoff_rate_decl + : BACKOFFRATE COLON (INT | NUMBER) + ; + +catch_decl + : CATCH + COLON + LBRACK + (catcher_decl (COMMA catcher_decl)*)? + RBRACK + ; + +catcher_decl + : LBRACE + catcher_stmt (COMMA catcher_stmt)* + RBRACE + ; + +catcher_stmt + : error_equals_decl + | result_path_decl + | next_decl + ; + +comparison_op + : BOOLEANEQUALS + | BOOLEANQUALSPATH + | ISBOOLEAN + | ISNULL + | ISNUMERIC + | ISPRESENT + | ISSTRING + | ISTIMESTAMP + | NUMERICEQUALS + | NUMERICEQUALSPATH + | NUMERICGREATERTHAN + | NUMERICGREATERTHANPATH + | NUMERICGREATERTHANEQUALS + | NUMERICGREATERTHANEQUALSPATH + | NUMERICLESSTHAN + | NUMERICLESSTHANPATH + | NUMERICLESSTHANEQUALS + | NUMERICLESSTHANEQUALSPATH + | STRINGEQUALS + | STRINGEQUALSPATH + | STRINGGREATERTHAN + | STRINGGREATERTHANPATH + | STRINGGREATERTHANEQUALS + | STRINGGREATERTHANEQUALSPATH + | STRINGLESSTHAN + | STRINGLESSTHANPATH + | STRINGLESSTHANEQUALS + | STRINGLESSTHANEQUALSPATH + | STRINGMATCHES + | TIMESTAMPEQUALS + | TIMESTAMPEQUALSPATH + | TIMESTAMPGREATERTHAN + | TIMESTAMPGREATERTHANPATH + | TIMESTAMPGREATERTHANEQUALS + | TIMESTAMPGREATERTHANEQUALSPATH + | TIMESTAMPLESSTHAN + | TIMESTAMPLESSTHANPATH + | TIMESTAMPLESSTHANEQUALS + | TIMESTAMPLESSTHANEQUALSPATH + ; + +choice_operator + : NOT + | AND + | OR + ; + +states_error_name + : ERRORNAMEStatesALL + | ERRORNAMEStatesHeartbeatTimeout + | ERRORNAMEStatesTimeout + | ERRORNAMEStatesTaskFailed + | ERRORNAMEStatesPermissions + | ERRORNAMEStatesResultPathMatchFailure + | ERRORNAMEStatesParameterPathFailure + | ERRORNAMEStatesBranchFailed + | ERRORNAMEStatesNoChoiceMatched + | ERRORNAMEStatesIntrinsicFailure + | ERRORNAMEStatesExceedToleratedFailureThreshold + | ERRORNAMEStatesItemReaderFailed + | ERRORNAMEStatesResultWriterFailed + | ERRORNAMEStatesRuntime + ; + +error_name + : states_error_name + | keyword_or_string + ; + +json_obj_decl + : LBRACE json_binding (COMMA json_binding)* RBRACE + | LBRACE RBRACE + ; + +json_binding + : keyword_or_string COLON json_value_decl + ; + +json_arr_decl + : LBRACK json_value_decl (COMMA json_value_decl)* RBRACK + | LBRACK RBRACK + ; + +json_value_decl + : NUMBER + | INT + | TRUE + | FALSE + | NULL + | json_binding + | json_arr_decl + | json_obj_decl + | keyword_or_string + ; + +keyword_or_string // TODO: check keywords can be used as strings. + : STRINGDOLLAR + | STRINGPATHCONTEXTOBJ + | STRINGPATH + | STRING + // + | COMMENT + | STATES + | STARTAT + | NEXTSTATE + | TYPE + | TASK + | CHOICE + | FAIL + | SUCCEED + | PASS + | WAIT + | PARALLEL + | MAP + | CHOICES + | VARIABLE + | DEFAULT + | BRANCHES + | AND + | BOOLEANEQUALS + | BOOLEANQUALSPATH + | ISBOOLEAN + | ISNULL + | ISNUMERIC + | ISPRESENT + | ISSTRING + | ISTIMESTAMP + | NOT + | NUMERICEQUALS + | NUMERICEQUALSPATH + | NUMERICGREATERTHAN + | NUMERICGREATERTHANPATH + | NUMERICGREATERTHANEQUALS + | NUMERICGREATERTHANEQUALSPATH + | NUMERICLESSTHAN + | NUMERICLESSTHANPATH + | NUMERICLESSTHANEQUALS + | NUMERICLESSTHANEQUALSPATH + | OR + | STRINGEQUALS + | STRINGEQUALSPATH + | STRINGGREATERTHAN + | STRINGGREATERTHANPATH + | STRINGGREATERTHANEQUALS + | STRINGGREATERTHANEQUALSPATH + | STRINGLESSTHAN + | STRINGLESSTHANPATH + | STRINGLESSTHANEQUALS + | STRINGLESSTHANEQUALSPATH + | STRINGMATCHES + | TIMESTAMPEQUALS + | TIMESTAMPEQUALSPATH + | TIMESTAMPGREATERTHAN + | TIMESTAMPGREATERTHANPATH + | TIMESTAMPGREATERTHANEQUALS + | TIMESTAMPGREATERTHANEQUALSPATH + | TIMESTAMPLESSTHAN + | TIMESTAMPLESSTHANPATH + | TIMESTAMPLESSTHANEQUALS + | TIMESTAMPLESSTHANEQUALSPATH + | SECONDSPATH + | SECONDS + | TIMESTAMPPATH + | TIMESTAMP + | TIMEOUTSECONDS + | TIMEOUTSECONDSPATH + | HEARTBEATSECONDS + | HEARTBEATSECONDSPATH + | PROCESSORCONFIG + | MODE + | INLINE + | DISTRIBUTED + | EXECUTIONTYPE + | STANDARD + | ITEMPROCESSOR + | ITERATOR + | ITEMSELECTOR + | MAXCONCURRENCY + | RESOURCE + | INPUTPATH + | OUTPUTPATH + | ITEMSPATH + | RESULTPATH + | RESULT + | PARAMETERS + | RESULTSELECTOR + | ITEMREADER + | READERCONFIG + | INPUTTYPE + | CSVHEADERLOCATION + | CSVHEADERS + | MAXITEMS + | MAXITEMSPATH + | NEXT + | END + | CAUSE + | ERROR + | RETRY + | ERROREQUALS + | INTERVALSECONDS + | MAXATTEMPTS + | BACKOFFRATE + | CATCH + | ERRORNAMEStatesALL + | ERRORNAMEStatesHeartbeatTimeout + | ERRORNAMEStatesTimeout + | ERRORNAMEStatesTaskFailed + | ERRORNAMEStatesPermissions + | ERRORNAMEStatesResultPathMatchFailure + | ERRORNAMEStatesParameterPathFailure + | ERRORNAMEStatesBranchFailed + | ERRORNAMEStatesNoChoiceMatched + | ERRORNAMEStatesIntrinsicFailure + | ERRORNAMEStatesExceedToleratedFailureThreshold + | ERRORNAMEStatesItemReaderFailed + | ERRORNAMEStatesResultWriterFailed + | ERRORNAMEStatesRuntime + ; diff --git a/moto/stepfunctions/parser/asl/antlr/__init__.py b/moto/stepfunctions/parser/asl/antlr/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicLexer.interp b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicLexer.interp new file mode 100644 index 000000000..a433e3d53 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicLexer.interp @@ -0,0 +1,148 @@ +token literal names: +null +'$' +'.' +'*' +',' +'(' +')' +'[' +']' +'<' +'>' +'@.' +'@.length-' +'&&' +'||' +'==' +'=' +'true' +'false' +'States' +'Format' +'StringToJson' +'JsonToString' +'Array' +'ArrayPartition' +'ArrayContains' +'ArrayRange' +'ArrayGetItem' +'ArrayLength' +'ArrayUnique' +'Base64Encode' +'Base64Decode' +'Hash' +'JsonMerge' +'MathRandom' +'MathAdd' +'StringSplit' +'UUID' +null +null +null +null +null + +token symbolic names: +null +DOLLAR +DOT +STAR +COMMA +LPAREN +RPAREN +LBRACK +RBRACK +LDIAM +RDIAM +ATDOT +ATDOTLENGTHDASH +ANDAND +OROR +EQEQ +EQ +TRUE +FALSE +States +Format +StringToJson +JsonToString +Array +ArrayPartition +ArrayContains +ArrayRange +ArrayGetItem +ArrayLength +ArrayUnique +Base64Encode +Base64Decode +Hash +JsonMerge +MathRandom +MathAdd +StringSplit +UUID +STRING +INT +NUMBER +IDENTIFIER +WS + +rule names: +DOLLAR +DOT +STAR +COMMA +LPAREN +RPAREN +LBRACK +RBRACK +LDIAM +RDIAM +ATDOT +ATDOTLENGTHDASH +ANDAND +OROR +EQEQ +EQ +TRUE +FALSE +States +Format +StringToJson +JsonToString +Array +ArrayPartition +ArrayContains +ArrayRange +ArrayGetItem +ArrayLength +ArrayUnique +Base64Encode +Base64Decode +Hash +JsonMerge +MathRandom +MathAdd +StringSplit +UUID +STRING +ESC +UNICODE +HEX +SAFECODEPOINT +INT +NUMBER +EXP +IDENTIFIER +WS + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN + +mode names: +DEFAULT_MODE + +atn: +[4, 0, 42, 423, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 5, 37, 355, 8, 37, 10, 37, 12, 37, 358, 9, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 3, 38, 365, 8, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 41, 1, 41, 1, 42, 3, 42, 378, 8, 42, 1, 42, 1, 42, 1, 42, 5, 42, 383, 8, 42, 10, 42, 12, 42, 386, 9, 42, 3, 42, 388, 8, 42, 1, 43, 3, 43, 391, 8, 43, 1, 43, 1, 43, 1, 43, 4, 43, 396, 8, 43, 11, 43, 12, 43, 397, 3, 43, 400, 8, 43, 1, 43, 3, 43, 403, 8, 43, 1, 44, 1, 44, 3, 44, 407, 8, 44, 1, 44, 1, 44, 1, 45, 1, 45, 4, 45, 413, 8, 45, 11, 45, 12, 45, 414, 1, 46, 4, 46, 418, 8, 46, 11, 46, 12, 46, 419, 1, 46, 1, 46, 1, 356, 0, 47, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77, 0, 79, 0, 81, 0, 83, 0, 85, 39, 87, 40, 89, 0, 91, 41, 93, 42, 1, 0, 8, 3, 0, 48, 57, 65, 70, 97, 102, 3, 0, 0, 31, 39, 39, 92, 92, 1, 0, 49, 57, 1, 0, 48, 57, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 2, 0, 9, 10, 32, 32, 432, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 1, 95, 1, 0, 0, 0, 3, 97, 1, 0, 0, 0, 5, 99, 1, 0, 0, 0, 7, 101, 1, 0, 0, 0, 9, 103, 1, 0, 0, 0, 11, 105, 1, 0, 0, 0, 13, 107, 1, 0, 0, 0, 15, 109, 1, 0, 0, 0, 17, 111, 1, 0, 0, 0, 19, 113, 1, 0, 0, 0, 21, 115, 1, 0, 0, 0, 23, 118, 1, 0, 0, 0, 25, 128, 1, 0, 0, 0, 27, 131, 1, 0, 0, 0, 29, 134, 1, 0, 0, 0, 31, 137, 1, 0, 0, 0, 33, 139, 1, 0, 0, 0, 35, 144, 1, 0, 0, 0, 37, 150, 1, 0, 0, 0, 39, 157, 1, 0, 0, 0, 41, 164, 1, 0, 0, 0, 43, 177, 1, 0, 0, 0, 45, 190, 1, 0, 0, 0, 47, 196, 1, 0, 0, 0, 49, 211, 1, 0, 0, 0, 51, 225, 1, 0, 0, 0, 53, 236, 1, 0, 0, 0, 55, 249, 1, 0, 0, 0, 57, 261, 1, 0, 0, 0, 59, 273, 1, 0, 0, 0, 61, 286, 1, 0, 0, 0, 63, 299, 1, 0, 0, 0, 65, 304, 1, 0, 0, 0, 67, 314, 1, 0, 0, 0, 69, 325, 1, 0, 0, 0, 71, 333, 1, 0, 0, 0, 73, 345, 1, 0, 0, 0, 75, 350, 1, 0, 0, 0, 77, 361, 1, 0, 0, 0, 79, 366, 1, 0, 0, 0, 81, 372, 1, 0, 0, 0, 83, 374, 1, 0, 0, 0, 85, 377, 1, 0, 0, 0, 87, 390, 1, 0, 0, 0, 89, 404, 1, 0, 0, 0, 91, 412, 1, 0, 0, 0, 93, 417, 1, 0, 0, 0, 95, 96, 5, 36, 0, 0, 96, 2, 1, 0, 0, 0, 97, 98, 5, 46, 0, 0, 98, 4, 1, 0, 0, 0, 99, 100, 5, 42, 0, 0, 100, 6, 1, 0, 0, 0, 101, 102, 5, 44, 0, 0, 102, 8, 1, 0, 0, 0, 103, 104, 5, 40, 0, 0, 104, 10, 1, 0, 0, 0, 105, 106, 5, 41, 0, 0, 106, 12, 1, 0, 0, 0, 107, 108, 5, 91, 0, 0, 108, 14, 1, 0, 0, 0, 109, 110, 5, 93, 0, 0, 110, 16, 1, 0, 0, 0, 111, 112, 5, 60, 0, 0, 112, 18, 1, 0, 0, 0, 113, 114, 5, 62, 0, 0, 114, 20, 1, 0, 0, 0, 115, 116, 5, 64, 0, 0, 116, 117, 5, 46, 0, 0, 117, 22, 1, 0, 0, 0, 118, 119, 5, 64, 0, 0, 119, 120, 5, 46, 0, 0, 120, 121, 5, 108, 0, 0, 121, 122, 5, 101, 0, 0, 122, 123, 5, 110, 0, 0, 123, 124, 5, 103, 0, 0, 124, 125, 5, 116, 0, 0, 125, 126, 5, 104, 0, 0, 126, 127, 5, 45, 0, 0, 127, 24, 1, 0, 0, 0, 128, 129, 5, 38, 0, 0, 129, 130, 5, 38, 0, 0, 130, 26, 1, 0, 0, 0, 131, 132, 5, 124, 0, 0, 132, 133, 5, 124, 0, 0, 133, 28, 1, 0, 0, 0, 134, 135, 5, 61, 0, 0, 135, 136, 5, 61, 0, 0, 136, 30, 1, 0, 0, 0, 137, 138, 5, 61, 0, 0, 138, 32, 1, 0, 0, 0, 139, 140, 5, 116, 0, 0, 140, 141, 5, 114, 0, 0, 141, 142, 5, 117, 0, 0, 142, 143, 5, 101, 0, 0, 143, 34, 1, 0, 0, 0, 144, 145, 5, 102, 0, 0, 145, 146, 5, 97, 0, 0, 146, 147, 5, 108, 0, 0, 147, 148, 5, 115, 0, 0, 148, 149, 5, 101, 0, 0, 149, 36, 1, 0, 0, 0, 150, 151, 5, 83, 0, 0, 151, 152, 5, 116, 0, 0, 152, 153, 5, 97, 0, 0, 153, 154, 5, 116, 0, 0, 154, 155, 5, 101, 0, 0, 155, 156, 5, 115, 0, 0, 156, 38, 1, 0, 0, 0, 157, 158, 5, 70, 0, 0, 158, 159, 5, 111, 0, 0, 159, 160, 5, 114, 0, 0, 160, 161, 5, 109, 0, 0, 161, 162, 5, 97, 0, 0, 162, 163, 5, 116, 0, 0, 163, 40, 1, 0, 0, 0, 164, 165, 5, 83, 0, 0, 165, 166, 5, 116, 0, 0, 166, 167, 5, 114, 0, 0, 167, 168, 5, 105, 0, 0, 168, 169, 5, 110, 0, 0, 169, 170, 5, 103, 0, 0, 170, 171, 5, 84, 0, 0, 171, 172, 5, 111, 0, 0, 172, 173, 5, 74, 0, 0, 173, 174, 5, 115, 0, 0, 174, 175, 5, 111, 0, 0, 175, 176, 5, 110, 0, 0, 176, 42, 1, 0, 0, 0, 177, 178, 5, 74, 0, 0, 178, 179, 5, 115, 0, 0, 179, 180, 5, 111, 0, 0, 180, 181, 5, 110, 0, 0, 181, 182, 5, 84, 0, 0, 182, 183, 5, 111, 0, 0, 183, 184, 5, 83, 0, 0, 184, 185, 5, 116, 0, 0, 185, 186, 5, 114, 0, 0, 186, 187, 5, 105, 0, 0, 187, 188, 5, 110, 0, 0, 188, 189, 5, 103, 0, 0, 189, 44, 1, 0, 0, 0, 190, 191, 5, 65, 0, 0, 191, 192, 5, 114, 0, 0, 192, 193, 5, 114, 0, 0, 193, 194, 5, 97, 0, 0, 194, 195, 5, 121, 0, 0, 195, 46, 1, 0, 0, 0, 196, 197, 5, 65, 0, 0, 197, 198, 5, 114, 0, 0, 198, 199, 5, 114, 0, 0, 199, 200, 5, 97, 0, 0, 200, 201, 5, 121, 0, 0, 201, 202, 5, 80, 0, 0, 202, 203, 5, 97, 0, 0, 203, 204, 5, 114, 0, 0, 204, 205, 5, 116, 0, 0, 205, 206, 5, 105, 0, 0, 206, 207, 5, 116, 0, 0, 207, 208, 5, 105, 0, 0, 208, 209, 5, 111, 0, 0, 209, 210, 5, 110, 0, 0, 210, 48, 1, 0, 0, 0, 211, 212, 5, 65, 0, 0, 212, 213, 5, 114, 0, 0, 213, 214, 5, 114, 0, 0, 214, 215, 5, 97, 0, 0, 215, 216, 5, 121, 0, 0, 216, 217, 5, 67, 0, 0, 217, 218, 5, 111, 0, 0, 218, 219, 5, 110, 0, 0, 219, 220, 5, 116, 0, 0, 220, 221, 5, 97, 0, 0, 221, 222, 5, 105, 0, 0, 222, 223, 5, 110, 0, 0, 223, 224, 5, 115, 0, 0, 224, 50, 1, 0, 0, 0, 225, 226, 5, 65, 0, 0, 226, 227, 5, 114, 0, 0, 227, 228, 5, 114, 0, 0, 228, 229, 5, 97, 0, 0, 229, 230, 5, 121, 0, 0, 230, 231, 5, 82, 0, 0, 231, 232, 5, 97, 0, 0, 232, 233, 5, 110, 0, 0, 233, 234, 5, 103, 0, 0, 234, 235, 5, 101, 0, 0, 235, 52, 1, 0, 0, 0, 236, 237, 5, 65, 0, 0, 237, 238, 5, 114, 0, 0, 238, 239, 5, 114, 0, 0, 239, 240, 5, 97, 0, 0, 240, 241, 5, 121, 0, 0, 241, 242, 5, 71, 0, 0, 242, 243, 5, 101, 0, 0, 243, 244, 5, 116, 0, 0, 244, 245, 5, 73, 0, 0, 245, 246, 5, 116, 0, 0, 246, 247, 5, 101, 0, 0, 247, 248, 5, 109, 0, 0, 248, 54, 1, 0, 0, 0, 249, 250, 5, 65, 0, 0, 250, 251, 5, 114, 0, 0, 251, 252, 5, 114, 0, 0, 252, 253, 5, 97, 0, 0, 253, 254, 5, 121, 0, 0, 254, 255, 5, 76, 0, 0, 255, 256, 5, 101, 0, 0, 256, 257, 5, 110, 0, 0, 257, 258, 5, 103, 0, 0, 258, 259, 5, 116, 0, 0, 259, 260, 5, 104, 0, 0, 260, 56, 1, 0, 0, 0, 261, 262, 5, 65, 0, 0, 262, 263, 5, 114, 0, 0, 263, 264, 5, 114, 0, 0, 264, 265, 5, 97, 0, 0, 265, 266, 5, 121, 0, 0, 266, 267, 5, 85, 0, 0, 267, 268, 5, 110, 0, 0, 268, 269, 5, 105, 0, 0, 269, 270, 5, 113, 0, 0, 270, 271, 5, 117, 0, 0, 271, 272, 5, 101, 0, 0, 272, 58, 1, 0, 0, 0, 273, 274, 5, 66, 0, 0, 274, 275, 5, 97, 0, 0, 275, 276, 5, 115, 0, 0, 276, 277, 5, 101, 0, 0, 277, 278, 5, 54, 0, 0, 278, 279, 5, 52, 0, 0, 279, 280, 5, 69, 0, 0, 280, 281, 5, 110, 0, 0, 281, 282, 5, 99, 0, 0, 282, 283, 5, 111, 0, 0, 283, 284, 5, 100, 0, 0, 284, 285, 5, 101, 0, 0, 285, 60, 1, 0, 0, 0, 286, 287, 5, 66, 0, 0, 287, 288, 5, 97, 0, 0, 288, 289, 5, 115, 0, 0, 289, 290, 5, 101, 0, 0, 290, 291, 5, 54, 0, 0, 291, 292, 5, 52, 0, 0, 292, 293, 5, 68, 0, 0, 293, 294, 5, 101, 0, 0, 294, 295, 5, 99, 0, 0, 295, 296, 5, 111, 0, 0, 296, 297, 5, 100, 0, 0, 297, 298, 5, 101, 0, 0, 298, 62, 1, 0, 0, 0, 299, 300, 5, 72, 0, 0, 300, 301, 5, 97, 0, 0, 301, 302, 5, 115, 0, 0, 302, 303, 5, 104, 0, 0, 303, 64, 1, 0, 0, 0, 304, 305, 5, 74, 0, 0, 305, 306, 5, 115, 0, 0, 306, 307, 5, 111, 0, 0, 307, 308, 5, 110, 0, 0, 308, 309, 5, 77, 0, 0, 309, 310, 5, 101, 0, 0, 310, 311, 5, 114, 0, 0, 311, 312, 5, 103, 0, 0, 312, 313, 5, 101, 0, 0, 313, 66, 1, 0, 0, 0, 314, 315, 5, 77, 0, 0, 315, 316, 5, 97, 0, 0, 316, 317, 5, 116, 0, 0, 317, 318, 5, 104, 0, 0, 318, 319, 5, 82, 0, 0, 319, 320, 5, 97, 0, 0, 320, 321, 5, 110, 0, 0, 321, 322, 5, 100, 0, 0, 322, 323, 5, 111, 0, 0, 323, 324, 5, 109, 0, 0, 324, 68, 1, 0, 0, 0, 325, 326, 5, 77, 0, 0, 326, 327, 5, 97, 0, 0, 327, 328, 5, 116, 0, 0, 328, 329, 5, 104, 0, 0, 329, 330, 5, 65, 0, 0, 330, 331, 5, 100, 0, 0, 331, 332, 5, 100, 0, 0, 332, 70, 1, 0, 0, 0, 333, 334, 5, 83, 0, 0, 334, 335, 5, 116, 0, 0, 335, 336, 5, 114, 0, 0, 336, 337, 5, 105, 0, 0, 337, 338, 5, 110, 0, 0, 338, 339, 5, 103, 0, 0, 339, 340, 5, 83, 0, 0, 340, 341, 5, 112, 0, 0, 341, 342, 5, 108, 0, 0, 342, 343, 5, 105, 0, 0, 343, 344, 5, 116, 0, 0, 344, 72, 1, 0, 0, 0, 345, 346, 5, 85, 0, 0, 346, 347, 5, 85, 0, 0, 347, 348, 5, 73, 0, 0, 348, 349, 5, 68, 0, 0, 349, 74, 1, 0, 0, 0, 350, 356, 5, 39, 0, 0, 351, 355, 5, 10, 0, 0, 352, 355, 3, 77, 38, 0, 353, 355, 3, 83, 41, 0, 354, 351, 1, 0, 0, 0, 354, 352, 1, 0, 0, 0, 354, 353, 1, 0, 0, 0, 355, 358, 1, 0, 0, 0, 356, 357, 1, 0, 0, 0, 356, 354, 1, 0, 0, 0, 357, 359, 1, 0, 0, 0, 358, 356, 1, 0, 0, 0, 359, 360, 5, 39, 0, 0, 360, 76, 1, 0, 0, 0, 361, 364, 5, 92, 0, 0, 362, 365, 3, 79, 39, 0, 363, 365, 9, 0, 0, 0, 364, 362, 1, 0, 0, 0, 364, 363, 1, 0, 0, 0, 365, 78, 1, 0, 0, 0, 366, 367, 5, 117, 0, 0, 367, 368, 3, 81, 40, 0, 368, 369, 3, 81, 40, 0, 369, 370, 3, 81, 40, 0, 370, 371, 3, 81, 40, 0, 371, 80, 1, 0, 0, 0, 372, 373, 7, 0, 0, 0, 373, 82, 1, 0, 0, 0, 374, 375, 8, 1, 0, 0, 375, 84, 1, 0, 0, 0, 376, 378, 5, 45, 0, 0, 377, 376, 1, 0, 0, 0, 377, 378, 1, 0, 0, 0, 378, 387, 1, 0, 0, 0, 379, 388, 5, 48, 0, 0, 380, 384, 7, 2, 0, 0, 381, 383, 7, 3, 0, 0, 382, 381, 1, 0, 0, 0, 383, 386, 1, 0, 0, 0, 384, 382, 1, 0, 0, 0, 384, 385, 1, 0, 0, 0, 385, 388, 1, 0, 0, 0, 386, 384, 1, 0, 0, 0, 387, 379, 1, 0, 0, 0, 387, 380, 1, 0, 0, 0, 388, 86, 1, 0, 0, 0, 389, 391, 5, 45, 0, 0, 390, 389, 1, 0, 0, 0, 390, 391, 1, 0, 0, 0, 391, 392, 1, 0, 0, 0, 392, 399, 3, 85, 42, 0, 393, 395, 5, 46, 0, 0, 394, 396, 7, 3, 0, 0, 395, 394, 1, 0, 0, 0, 396, 397, 1, 0, 0, 0, 397, 395, 1, 0, 0, 0, 397, 398, 1, 0, 0, 0, 398, 400, 1, 0, 0, 0, 399, 393, 1, 0, 0, 0, 399, 400, 1, 0, 0, 0, 400, 402, 1, 0, 0, 0, 401, 403, 3, 89, 44, 0, 402, 401, 1, 0, 0, 0, 402, 403, 1, 0, 0, 0, 403, 88, 1, 0, 0, 0, 404, 406, 7, 4, 0, 0, 405, 407, 7, 5, 0, 0, 406, 405, 1, 0, 0, 0, 406, 407, 1, 0, 0, 0, 407, 408, 1, 0, 0, 0, 408, 409, 3, 85, 42, 0, 409, 90, 1, 0, 0, 0, 410, 413, 7, 6, 0, 0, 411, 413, 3, 79, 39, 0, 412, 410, 1, 0, 0, 0, 412, 411, 1, 0, 0, 0, 413, 414, 1, 0, 0, 0, 414, 412, 1, 0, 0, 0, 414, 415, 1, 0, 0, 0, 415, 92, 1, 0, 0, 0, 416, 418, 7, 7, 0, 0, 417, 416, 1, 0, 0, 0, 418, 419, 1, 0, 0, 0, 419, 417, 1, 0, 0, 0, 419, 420, 1, 0, 0, 0, 420, 421, 1, 0, 0, 0, 421, 422, 6, 46, 0, 0, 422, 94, 1, 0, 0, 0, 15, 0, 354, 356, 364, 377, 384, 387, 390, 397, 399, 402, 406, 412, 414, 419, 1, 6, 0, 0] \ No newline at end of file diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicLexer.py b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicLexer.py new file mode 100644 index 000000000..cb0699a78 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicLexer.py @@ -0,0 +1,3851 @@ +# Generated from /Users/mep/LocalStack/localstack/localstack/services/stepfunctions/asl/antlr/ASLIntrinsicLexer.g4 by ANTLR 4.13.1 +import sys +from typing import TextIO + +from antlr4 import ( + DFA, + ATNDeserializer, + Lexer, + LexerATNSimulator, + PredictionContextCache, +) + + +def serializedATN(): + return [ + 4, + 0, + 42, + 423, + 6, + -1, + 2, + 0, + 7, + 0, + 2, + 1, + 7, + 1, + 2, + 2, + 7, + 2, + 2, + 3, + 7, + 3, + 2, + 4, + 7, + 4, + 2, + 5, + 7, + 5, + 2, + 6, + 7, + 6, + 2, + 7, + 7, + 7, + 2, + 8, + 7, + 8, + 2, + 9, + 7, + 9, + 2, + 10, + 7, + 10, + 2, + 11, + 7, + 11, + 2, + 12, + 7, + 12, + 2, + 13, + 7, + 13, + 2, + 14, + 7, + 14, + 2, + 15, + 7, + 15, + 2, + 16, + 7, + 16, + 2, + 17, + 7, + 17, + 2, + 18, + 7, + 18, + 2, + 19, + 7, + 19, + 2, + 20, + 7, + 20, + 2, + 21, + 7, + 21, + 2, + 22, + 7, + 22, + 2, + 23, + 7, + 23, + 2, + 24, + 7, + 24, + 2, + 25, + 7, + 25, + 2, + 26, + 7, + 26, + 2, + 27, + 7, + 27, + 2, + 28, + 7, + 28, + 2, + 29, + 7, + 29, + 2, + 30, + 7, + 30, + 2, + 31, + 7, + 31, + 2, + 32, + 7, + 32, + 2, + 33, + 7, + 33, + 2, + 34, + 7, + 34, + 2, + 35, + 7, + 35, + 2, + 36, + 7, + 36, + 2, + 37, + 7, + 37, + 2, + 38, + 7, + 38, + 2, + 39, + 7, + 39, + 2, + 40, + 7, + 40, + 2, + 41, + 7, + 41, + 2, + 42, + 7, + 42, + 2, + 43, + 7, + 43, + 2, + 44, + 7, + 44, + 2, + 45, + 7, + 45, + 2, + 46, + 7, + 46, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 3, + 1, + 3, + 1, + 4, + 1, + 4, + 1, + 5, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 7, + 1, + 7, + 1, + 8, + 1, + 8, + 1, + 9, + 1, + 9, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 13, + 1, + 13, + 1, + 13, + 1, + 14, + 1, + 14, + 1, + 14, + 1, + 15, + 1, + 15, + 1, + 16, + 1, + 16, + 1, + 16, + 1, + 16, + 1, + 16, + 1, + 17, + 1, + 17, + 1, + 17, + 1, + 17, + 1, + 17, + 1, + 17, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 19, + 1, + 19, + 1, + 19, + 1, + 19, + 1, + 19, + 1, + 19, + 1, + 19, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 22, + 1, + 22, + 1, + 22, + 1, + 22, + 1, + 22, + 1, + 22, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 31, + 1, + 31, + 1, + 31, + 1, + 31, + 1, + 31, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 36, + 1, + 36, + 1, + 36, + 1, + 36, + 1, + 36, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 5, + 37, + 355, + 8, + 37, + 10, + 37, + 12, + 37, + 358, + 9, + 37, + 1, + 37, + 1, + 37, + 1, + 38, + 1, + 38, + 1, + 38, + 3, + 38, + 365, + 8, + 38, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 40, + 1, + 40, + 1, + 41, + 1, + 41, + 1, + 42, + 3, + 42, + 378, + 8, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 5, + 42, + 383, + 8, + 42, + 10, + 42, + 12, + 42, + 386, + 9, + 42, + 3, + 42, + 388, + 8, + 42, + 1, + 43, + 3, + 43, + 391, + 8, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 4, + 43, + 396, + 8, + 43, + 11, + 43, + 12, + 43, + 397, + 3, + 43, + 400, + 8, + 43, + 1, + 43, + 3, + 43, + 403, + 8, + 43, + 1, + 44, + 1, + 44, + 3, + 44, + 407, + 8, + 44, + 1, + 44, + 1, + 44, + 1, + 45, + 1, + 45, + 4, + 45, + 413, + 8, + 45, + 11, + 45, + 12, + 45, + 414, + 1, + 46, + 4, + 46, + 418, + 8, + 46, + 11, + 46, + 12, + 46, + 419, + 1, + 46, + 1, + 46, + 1, + 356, + 0, + 47, + 1, + 1, + 3, + 2, + 5, + 3, + 7, + 4, + 9, + 5, + 11, + 6, + 13, + 7, + 15, + 8, + 17, + 9, + 19, + 10, + 21, + 11, + 23, + 12, + 25, + 13, + 27, + 14, + 29, + 15, + 31, + 16, + 33, + 17, + 35, + 18, + 37, + 19, + 39, + 20, + 41, + 21, + 43, + 22, + 45, + 23, + 47, + 24, + 49, + 25, + 51, + 26, + 53, + 27, + 55, + 28, + 57, + 29, + 59, + 30, + 61, + 31, + 63, + 32, + 65, + 33, + 67, + 34, + 69, + 35, + 71, + 36, + 73, + 37, + 75, + 38, + 77, + 0, + 79, + 0, + 81, + 0, + 83, + 0, + 85, + 39, + 87, + 40, + 89, + 0, + 91, + 41, + 93, + 42, + 1, + 0, + 8, + 3, + 0, + 48, + 57, + 65, + 70, + 97, + 102, + 3, + 0, + 0, + 31, + 39, + 39, + 92, + 92, + 1, + 0, + 49, + 57, + 1, + 0, + 48, + 57, + 2, + 0, + 69, + 69, + 101, + 101, + 2, + 0, + 43, + 43, + 45, + 45, + 4, + 0, + 48, + 57, + 65, + 90, + 95, + 95, + 97, + 122, + 2, + 0, + 9, + 10, + 32, + 32, + 432, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 3, + 1, + 0, + 0, + 0, + 0, + 5, + 1, + 0, + 0, + 0, + 0, + 7, + 1, + 0, + 0, + 0, + 0, + 9, + 1, + 0, + 0, + 0, + 0, + 11, + 1, + 0, + 0, + 0, + 0, + 13, + 1, + 0, + 0, + 0, + 0, + 15, + 1, + 0, + 0, + 0, + 0, + 17, + 1, + 0, + 0, + 0, + 0, + 19, + 1, + 0, + 0, + 0, + 0, + 21, + 1, + 0, + 0, + 0, + 0, + 23, + 1, + 0, + 0, + 0, + 0, + 25, + 1, + 0, + 0, + 0, + 0, + 27, + 1, + 0, + 0, + 0, + 0, + 29, + 1, + 0, + 0, + 0, + 0, + 31, + 1, + 0, + 0, + 0, + 0, + 33, + 1, + 0, + 0, + 0, + 0, + 35, + 1, + 0, + 0, + 0, + 0, + 37, + 1, + 0, + 0, + 0, + 0, + 39, + 1, + 0, + 0, + 0, + 0, + 41, + 1, + 0, + 0, + 0, + 0, + 43, + 1, + 0, + 0, + 0, + 0, + 45, + 1, + 0, + 0, + 0, + 0, + 47, + 1, + 0, + 0, + 0, + 0, + 49, + 1, + 0, + 0, + 0, + 0, + 51, + 1, + 0, + 0, + 0, + 0, + 53, + 1, + 0, + 0, + 0, + 0, + 55, + 1, + 0, + 0, + 0, + 0, + 57, + 1, + 0, + 0, + 0, + 0, + 59, + 1, + 0, + 0, + 0, + 0, + 61, + 1, + 0, + 0, + 0, + 0, + 63, + 1, + 0, + 0, + 0, + 0, + 65, + 1, + 0, + 0, + 0, + 0, + 67, + 1, + 0, + 0, + 0, + 0, + 69, + 1, + 0, + 0, + 0, + 0, + 71, + 1, + 0, + 0, + 0, + 0, + 73, + 1, + 0, + 0, + 0, + 0, + 75, + 1, + 0, + 0, + 0, + 0, + 85, + 1, + 0, + 0, + 0, + 0, + 87, + 1, + 0, + 0, + 0, + 0, + 91, + 1, + 0, + 0, + 0, + 0, + 93, + 1, + 0, + 0, + 0, + 1, + 95, + 1, + 0, + 0, + 0, + 3, + 97, + 1, + 0, + 0, + 0, + 5, + 99, + 1, + 0, + 0, + 0, + 7, + 101, + 1, + 0, + 0, + 0, + 9, + 103, + 1, + 0, + 0, + 0, + 11, + 105, + 1, + 0, + 0, + 0, + 13, + 107, + 1, + 0, + 0, + 0, + 15, + 109, + 1, + 0, + 0, + 0, + 17, + 111, + 1, + 0, + 0, + 0, + 19, + 113, + 1, + 0, + 0, + 0, + 21, + 115, + 1, + 0, + 0, + 0, + 23, + 118, + 1, + 0, + 0, + 0, + 25, + 128, + 1, + 0, + 0, + 0, + 27, + 131, + 1, + 0, + 0, + 0, + 29, + 134, + 1, + 0, + 0, + 0, + 31, + 137, + 1, + 0, + 0, + 0, + 33, + 139, + 1, + 0, + 0, + 0, + 35, + 144, + 1, + 0, + 0, + 0, + 37, + 150, + 1, + 0, + 0, + 0, + 39, + 157, + 1, + 0, + 0, + 0, + 41, + 164, + 1, + 0, + 0, + 0, + 43, + 177, + 1, + 0, + 0, + 0, + 45, + 190, + 1, + 0, + 0, + 0, + 47, + 196, + 1, + 0, + 0, + 0, + 49, + 211, + 1, + 0, + 0, + 0, + 51, + 225, + 1, + 0, + 0, + 0, + 53, + 236, + 1, + 0, + 0, + 0, + 55, + 249, + 1, + 0, + 0, + 0, + 57, + 261, + 1, + 0, + 0, + 0, + 59, + 273, + 1, + 0, + 0, + 0, + 61, + 286, + 1, + 0, + 0, + 0, + 63, + 299, + 1, + 0, + 0, + 0, + 65, + 304, + 1, + 0, + 0, + 0, + 67, + 314, + 1, + 0, + 0, + 0, + 69, + 325, + 1, + 0, + 0, + 0, + 71, + 333, + 1, + 0, + 0, + 0, + 73, + 345, + 1, + 0, + 0, + 0, + 75, + 350, + 1, + 0, + 0, + 0, + 77, + 361, + 1, + 0, + 0, + 0, + 79, + 366, + 1, + 0, + 0, + 0, + 81, + 372, + 1, + 0, + 0, + 0, + 83, + 374, + 1, + 0, + 0, + 0, + 85, + 377, + 1, + 0, + 0, + 0, + 87, + 390, + 1, + 0, + 0, + 0, + 89, + 404, + 1, + 0, + 0, + 0, + 91, + 412, + 1, + 0, + 0, + 0, + 93, + 417, + 1, + 0, + 0, + 0, + 95, + 96, + 5, + 36, + 0, + 0, + 96, + 2, + 1, + 0, + 0, + 0, + 97, + 98, + 5, + 46, + 0, + 0, + 98, + 4, + 1, + 0, + 0, + 0, + 99, + 100, + 5, + 42, + 0, + 0, + 100, + 6, + 1, + 0, + 0, + 0, + 101, + 102, + 5, + 44, + 0, + 0, + 102, + 8, + 1, + 0, + 0, + 0, + 103, + 104, + 5, + 40, + 0, + 0, + 104, + 10, + 1, + 0, + 0, + 0, + 105, + 106, + 5, + 41, + 0, + 0, + 106, + 12, + 1, + 0, + 0, + 0, + 107, + 108, + 5, + 91, + 0, + 0, + 108, + 14, + 1, + 0, + 0, + 0, + 109, + 110, + 5, + 93, + 0, + 0, + 110, + 16, + 1, + 0, + 0, + 0, + 111, + 112, + 5, + 60, + 0, + 0, + 112, + 18, + 1, + 0, + 0, + 0, + 113, + 114, + 5, + 62, + 0, + 0, + 114, + 20, + 1, + 0, + 0, + 0, + 115, + 116, + 5, + 64, + 0, + 0, + 116, + 117, + 5, + 46, + 0, + 0, + 117, + 22, + 1, + 0, + 0, + 0, + 118, + 119, + 5, + 64, + 0, + 0, + 119, + 120, + 5, + 46, + 0, + 0, + 120, + 121, + 5, + 108, + 0, + 0, + 121, + 122, + 5, + 101, + 0, + 0, + 122, + 123, + 5, + 110, + 0, + 0, + 123, + 124, + 5, + 103, + 0, + 0, + 124, + 125, + 5, + 116, + 0, + 0, + 125, + 126, + 5, + 104, + 0, + 0, + 126, + 127, + 5, + 45, + 0, + 0, + 127, + 24, + 1, + 0, + 0, + 0, + 128, + 129, + 5, + 38, + 0, + 0, + 129, + 130, + 5, + 38, + 0, + 0, + 130, + 26, + 1, + 0, + 0, + 0, + 131, + 132, + 5, + 124, + 0, + 0, + 132, + 133, + 5, + 124, + 0, + 0, + 133, + 28, + 1, + 0, + 0, + 0, + 134, + 135, + 5, + 61, + 0, + 0, + 135, + 136, + 5, + 61, + 0, + 0, + 136, + 30, + 1, + 0, + 0, + 0, + 137, + 138, + 5, + 61, + 0, + 0, + 138, + 32, + 1, + 0, + 0, + 0, + 139, + 140, + 5, + 116, + 0, + 0, + 140, + 141, + 5, + 114, + 0, + 0, + 141, + 142, + 5, + 117, + 0, + 0, + 142, + 143, + 5, + 101, + 0, + 0, + 143, + 34, + 1, + 0, + 0, + 0, + 144, + 145, + 5, + 102, + 0, + 0, + 145, + 146, + 5, + 97, + 0, + 0, + 146, + 147, + 5, + 108, + 0, + 0, + 147, + 148, + 5, + 115, + 0, + 0, + 148, + 149, + 5, + 101, + 0, + 0, + 149, + 36, + 1, + 0, + 0, + 0, + 150, + 151, + 5, + 83, + 0, + 0, + 151, + 152, + 5, + 116, + 0, + 0, + 152, + 153, + 5, + 97, + 0, + 0, + 153, + 154, + 5, + 116, + 0, + 0, + 154, + 155, + 5, + 101, + 0, + 0, + 155, + 156, + 5, + 115, + 0, + 0, + 156, + 38, + 1, + 0, + 0, + 0, + 157, + 158, + 5, + 70, + 0, + 0, + 158, + 159, + 5, + 111, + 0, + 0, + 159, + 160, + 5, + 114, + 0, + 0, + 160, + 161, + 5, + 109, + 0, + 0, + 161, + 162, + 5, + 97, + 0, + 0, + 162, + 163, + 5, + 116, + 0, + 0, + 163, + 40, + 1, + 0, + 0, + 0, + 164, + 165, + 5, + 83, + 0, + 0, + 165, + 166, + 5, + 116, + 0, + 0, + 166, + 167, + 5, + 114, + 0, + 0, + 167, + 168, + 5, + 105, + 0, + 0, + 168, + 169, + 5, + 110, + 0, + 0, + 169, + 170, + 5, + 103, + 0, + 0, + 170, + 171, + 5, + 84, + 0, + 0, + 171, + 172, + 5, + 111, + 0, + 0, + 172, + 173, + 5, + 74, + 0, + 0, + 173, + 174, + 5, + 115, + 0, + 0, + 174, + 175, + 5, + 111, + 0, + 0, + 175, + 176, + 5, + 110, + 0, + 0, + 176, + 42, + 1, + 0, + 0, + 0, + 177, + 178, + 5, + 74, + 0, + 0, + 178, + 179, + 5, + 115, + 0, + 0, + 179, + 180, + 5, + 111, + 0, + 0, + 180, + 181, + 5, + 110, + 0, + 0, + 181, + 182, + 5, + 84, + 0, + 0, + 182, + 183, + 5, + 111, + 0, + 0, + 183, + 184, + 5, + 83, + 0, + 0, + 184, + 185, + 5, + 116, + 0, + 0, + 185, + 186, + 5, + 114, + 0, + 0, + 186, + 187, + 5, + 105, + 0, + 0, + 187, + 188, + 5, + 110, + 0, + 0, + 188, + 189, + 5, + 103, + 0, + 0, + 189, + 44, + 1, + 0, + 0, + 0, + 190, + 191, + 5, + 65, + 0, + 0, + 191, + 192, + 5, + 114, + 0, + 0, + 192, + 193, + 5, + 114, + 0, + 0, + 193, + 194, + 5, + 97, + 0, + 0, + 194, + 195, + 5, + 121, + 0, + 0, + 195, + 46, + 1, + 0, + 0, + 0, + 196, + 197, + 5, + 65, + 0, + 0, + 197, + 198, + 5, + 114, + 0, + 0, + 198, + 199, + 5, + 114, + 0, + 0, + 199, + 200, + 5, + 97, + 0, + 0, + 200, + 201, + 5, + 121, + 0, + 0, + 201, + 202, + 5, + 80, + 0, + 0, + 202, + 203, + 5, + 97, + 0, + 0, + 203, + 204, + 5, + 114, + 0, + 0, + 204, + 205, + 5, + 116, + 0, + 0, + 205, + 206, + 5, + 105, + 0, + 0, + 206, + 207, + 5, + 116, + 0, + 0, + 207, + 208, + 5, + 105, + 0, + 0, + 208, + 209, + 5, + 111, + 0, + 0, + 209, + 210, + 5, + 110, + 0, + 0, + 210, + 48, + 1, + 0, + 0, + 0, + 211, + 212, + 5, + 65, + 0, + 0, + 212, + 213, + 5, + 114, + 0, + 0, + 213, + 214, + 5, + 114, + 0, + 0, + 214, + 215, + 5, + 97, + 0, + 0, + 215, + 216, + 5, + 121, + 0, + 0, + 216, + 217, + 5, + 67, + 0, + 0, + 217, + 218, + 5, + 111, + 0, + 0, + 218, + 219, + 5, + 110, + 0, + 0, + 219, + 220, + 5, + 116, + 0, + 0, + 220, + 221, + 5, + 97, + 0, + 0, + 221, + 222, + 5, + 105, + 0, + 0, + 222, + 223, + 5, + 110, + 0, + 0, + 223, + 224, + 5, + 115, + 0, + 0, + 224, + 50, + 1, + 0, + 0, + 0, + 225, + 226, + 5, + 65, + 0, + 0, + 226, + 227, + 5, + 114, + 0, + 0, + 227, + 228, + 5, + 114, + 0, + 0, + 228, + 229, + 5, + 97, + 0, + 0, + 229, + 230, + 5, + 121, + 0, + 0, + 230, + 231, + 5, + 82, + 0, + 0, + 231, + 232, + 5, + 97, + 0, + 0, + 232, + 233, + 5, + 110, + 0, + 0, + 233, + 234, + 5, + 103, + 0, + 0, + 234, + 235, + 5, + 101, + 0, + 0, + 235, + 52, + 1, + 0, + 0, + 0, + 236, + 237, + 5, + 65, + 0, + 0, + 237, + 238, + 5, + 114, + 0, + 0, + 238, + 239, + 5, + 114, + 0, + 0, + 239, + 240, + 5, + 97, + 0, + 0, + 240, + 241, + 5, + 121, + 0, + 0, + 241, + 242, + 5, + 71, + 0, + 0, + 242, + 243, + 5, + 101, + 0, + 0, + 243, + 244, + 5, + 116, + 0, + 0, + 244, + 245, + 5, + 73, + 0, + 0, + 245, + 246, + 5, + 116, + 0, + 0, + 246, + 247, + 5, + 101, + 0, + 0, + 247, + 248, + 5, + 109, + 0, + 0, + 248, + 54, + 1, + 0, + 0, + 0, + 249, + 250, + 5, + 65, + 0, + 0, + 250, + 251, + 5, + 114, + 0, + 0, + 251, + 252, + 5, + 114, + 0, + 0, + 252, + 253, + 5, + 97, + 0, + 0, + 253, + 254, + 5, + 121, + 0, + 0, + 254, + 255, + 5, + 76, + 0, + 0, + 255, + 256, + 5, + 101, + 0, + 0, + 256, + 257, + 5, + 110, + 0, + 0, + 257, + 258, + 5, + 103, + 0, + 0, + 258, + 259, + 5, + 116, + 0, + 0, + 259, + 260, + 5, + 104, + 0, + 0, + 260, + 56, + 1, + 0, + 0, + 0, + 261, + 262, + 5, + 65, + 0, + 0, + 262, + 263, + 5, + 114, + 0, + 0, + 263, + 264, + 5, + 114, + 0, + 0, + 264, + 265, + 5, + 97, + 0, + 0, + 265, + 266, + 5, + 121, + 0, + 0, + 266, + 267, + 5, + 85, + 0, + 0, + 267, + 268, + 5, + 110, + 0, + 0, + 268, + 269, + 5, + 105, + 0, + 0, + 269, + 270, + 5, + 113, + 0, + 0, + 270, + 271, + 5, + 117, + 0, + 0, + 271, + 272, + 5, + 101, + 0, + 0, + 272, + 58, + 1, + 0, + 0, + 0, + 273, + 274, + 5, + 66, + 0, + 0, + 274, + 275, + 5, + 97, + 0, + 0, + 275, + 276, + 5, + 115, + 0, + 0, + 276, + 277, + 5, + 101, + 0, + 0, + 277, + 278, + 5, + 54, + 0, + 0, + 278, + 279, + 5, + 52, + 0, + 0, + 279, + 280, + 5, + 69, + 0, + 0, + 280, + 281, + 5, + 110, + 0, + 0, + 281, + 282, + 5, + 99, + 0, + 0, + 282, + 283, + 5, + 111, + 0, + 0, + 283, + 284, + 5, + 100, + 0, + 0, + 284, + 285, + 5, + 101, + 0, + 0, + 285, + 60, + 1, + 0, + 0, + 0, + 286, + 287, + 5, + 66, + 0, + 0, + 287, + 288, + 5, + 97, + 0, + 0, + 288, + 289, + 5, + 115, + 0, + 0, + 289, + 290, + 5, + 101, + 0, + 0, + 290, + 291, + 5, + 54, + 0, + 0, + 291, + 292, + 5, + 52, + 0, + 0, + 292, + 293, + 5, + 68, + 0, + 0, + 293, + 294, + 5, + 101, + 0, + 0, + 294, + 295, + 5, + 99, + 0, + 0, + 295, + 296, + 5, + 111, + 0, + 0, + 296, + 297, + 5, + 100, + 0, + 0, + 297, + 298, + 5, + 101, + 0, + 0, + 298, + 62, + 1, + 0, + 0, + 0, + 299, + 300, + 5, + 72, + 0, + 0, + 300, + 301, + 5, + 97, + 0, + 0, + 301, + 302, + 5, + 115, + 0, + 0, + 302, + 303, + 5, + 104, + 0, + 0, + 303, + 64, + 1, + 0, + 0, + 0, + 304, + 305, + 5, + 74, + 0, + 0, + 305, + 306, + 5, + 115, + 0, + 0, + 306, + 307, + 5, + 111, + 0, + 0, + 307, + 308, + 5, + 110, + 0, + 0, + 308, + 309, + 5, + 77, + 0, + 0, + 309, + 310, + 5, + 101, + 0, + 0, + 310, + 311, + 5, + 114, + 0, + 0, + 311, + 312, + 5, + 103, + 0, + 0, + 312, + 313, + 5, + 101, + 0, + 0, + 313, + 66, + 1, + 0, + 0, + 0, + 314, + 315, + 5, + 77, + 0, + 0, + 315, + 316, + 5, + 97, + 0, + 0, + 316, + 317, + 5, + 116, + 0, + 0, + 317, + 318, + 5, + 104, + 0, + 0, + 318, + 319, + 5, + 82, + 0, + 0, + 319, + 320, + 5, + 97, + 0, + 0, + 320, + 321, + 5, + 110, + 0, + 0, + 321, + 322, + 5, + 100, + 0, + 0, + 322, + 323, + 5, + 111, + 0, + 0, + 323, + 324, + 5, + 109, + 0, + 0, + 324, + 68, + 1, + 0, + 0, + 0, + 325, + 326, + 5, + 77, + 0, + 0, + 326, + 327, + 5, + 97, + 0, + 0, + 327, + 328, + 5, + 116, + 0, + 0, + 328, + 329, + 5, + 104, + 0, + 0, + 329, + 330, + 5, + 65, + 0, + 0, + 330, + 331, + 5, + 100, + 0, + 0, + 331, + 332, + 5, + 100, + 0, + 0, + 332, + 70, + 1, + 0, + 0, + 0, + 333, + 334, + 5, + 83, + 0, + 0, + 334, + 335, + 5, + 116, + 0, + 0, + 335, + 336, + 5, + 114, + 0, + 0, + 336, + 337, + 5, + 105, + 0, + 0, + 337, + 338, + 5, + 110, + 0, + 0, + 338, + 339, + 5, + 103, + 0, + 0, + 339, + 340, + 5, + 83, + 0, + 0, + 340, + 341, + 5, + 112, + 0, + 0, + 341, + 342, + 5, + 108, + 0, + 0, + 342, + 343, + 5, + 105, + 0, + 0, + 343, + 344, + 5, + 116, + 0, + 0, + 344, + 72, + 1, + 0, + 0, + 0, + 345, + 346, + 5, + 85, + 0, + 0, + 346, + 347, + 5, + 85, + 0, + 0, + 347, + 348, + 5, + 73, + 0, + 0, + 348, + 349, + 5, + 68, + 0, + 0, + 349, + 74, + 1, + 0, + 0, + 0, + 350, + 356, + 5, + 39, + 0, + 0, + 351, + 355, + 5, + 10, + 0, + 0, + 352, + 355, + 3, + 77, + 38, + 0, + 353, + 355, + 3, + 83, + 41, + 0, + 354, + 351, + 1, + 0, + 0, + 0, + 354, + 352, + 1, + 0, + 0, + 0, + 354, + 353, + 1, + 0, + 0, + 0, + 355, + 358, + 1, + 0, + 0, + 0, + 356, + 357, + 1, + 0, + 0, + 0, + 356, + 354, + 1, + 0, + 0, + 0, + 357, + 359, + 1, + 0, + 0, + 0, + 358, + 356, + 1, + 0, + 0, + 0, + 359, + 360, + 5, + 39, + 0, + 0, + 360, + 76, + 1, + 0, + 0, + 0, + 361, + 364, + 5, + 92, + 0, + 0, + 362, + 365, + 3, + 79, + 39, + 0, + 363, + 365, + 9, + 0, + 0, + 0, + 364, + 362, + 1, + 0, + 0, + 0, + 364, + 363, + 1, + 0, + 0, + 0, + 365, + 78, + 1, + 0, + 0, + 0, + 366, + 367, + 5, + 117, + 0, + 0, + 367, + 368, + 3, + 81, + 40, + 0, + 368, + 369, + 3, + 81, + 40, + 0, + 369, + 370, + 3, + 81, + 40, + 0, + 370, + 371, + 3, + 81, + 40, + 0, + 371, + 80, + 1, + 0, + 0, + 0, + 372, + 373, + 7, + 0, + 0, + 0, + 373, + 82, + 1, + 0, + 0, + 0, + 374, + 375, + 8, + 1, + 0, + 0, + 375, + 84, + 1, + 0, + 0, + 0, + 376, + 378, + 5, + 45, + 0, + 0, + 377, + 376, + 1, + 0, + 0, + 0, + 377, + 378, + 1, + 0, + 0, + 0, + 378, + 387, + 1, + 0, + 0, + 0, + 379, + 388, + 5, + 48, + 0, + 0, + 380, + 384, + 7, + 2, + 0, + 0, + 381, + 383, + 7, + 3, + 0, + 0, + 382, + 381, + 1, + 0, + 0, + 0, + 383, + 386, + 1, + 0, + 0, + 0, + 384, + 382, + 1, + 0, + 0, + 0, + 384, + 385, + 1, + 0, + 0, + 0, + 385, + 388, + 1, + 0, + 0, + 0, + 386, + 384, + 1, + 0, + 0, + 0, + 387, + 379, + 1, + 0, + 0, + 0, + 387, + 380, + 1, + 0, + 0, + 0, + 388, + 86, + 1, + 0, + 0, + 0, + 389, + 391, + 5, + 45, + 0, + 0, + 390, + 389, + 1, + 0, + 0, + 0, + 390, + 391, + 1, + 0, + 0, + 0, + 391, + 392, + 1, + 0, + 0, + 0, + 392, + 399, + 3, + 85, + 42, + 0, + 393, + 395, + 5, + 46, + 0, + 0, + 394, + 396, + 7, + 3, + 0, + 0, + 395, + 394, + 1, + 0, + 0, + 0, + 396, + 397, + 1, + 0, + 0, + 0, + 397, + 395, + 1, + 0, + 0, + 0, + 397, + 398, + 1, + 0, + 0, + 0, + 398, + 400, + 1, + 0, + 0, + 0, + 399, + 393, + 1, + 0, + 0, + 0, + 399, + 400, + 1, + 0, + 0, + 0, + 400, + 402, + 1, + 0, + 0, + 0, + 401, + 403, + 3, + 89, + 44, + 0, + 402, + 401, + 1, + 0, + 0, + 0, + 402, + 403, + 1, + 0, + 0, + 0, + 403, + 88, + 1, + 0, + 0, + 0, + 404, + 406, + 7, + 4, + 0, + 0, + 405, + 407, + 7, + 5, + 0, + 0, + 406, + 405, + 1, + 0, + 0, + 0, + 406, + 407, + 1, + 0, + 0, + 0, + 407, + 408, + 1, + 0, + 0, + 0, + 408, + 409, + 3, + 85, + 42, + 0, + 409, + 90, + 1, + 0, + 0, + 0, + 410, + 413, + 7, + 6, + 0, + 0, + 411, + 413, + 3, + 79, + 39, + 0, + 412, + 410, + 1, + 0, + 0, + 0, + 412, + 411, + 1, + 0, + 0, + 0, + 413, + 414, + 1, + 0, + 0, + 0, + 414, + 412, + 1, + 0, + 0, + 0, + 414, + 415, + 1, + 0, + 0, + 0, + 415, + 92, + 1, + 0, + 0, + 0, + 416, + 418, + 7, + 7, + 0, + 0, + 417, + 416, + 1, + 0, + 0, + 0, + 418, + 419, + 1, + 0, + 0, + 0, + 419, + 417, + 1, + 0, + 0, + 0, + 419, + 420, + 1, + 0, + 0, + 0, + 420, + 421, + 1, + 0, + 0, + 0, + 421, + 422, + 6, + 46, + 0, + 0, + 422, + 94, + 1, + 0, + 0, + 0, + 15, + 0, + 354, + 356, + 364, + 377, + 384, + 387, + 390, + 397, + 399, + 402, + 406, + 412, + 414, + 419, + 1, + 6, + 0, + 0, + ] + + +class ASLIntrinsicLexer(Lexer): + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [DFA(ds, i) for i, ds in enumerate(atn.decisionToState)] + + DOLLAR = 1 + DOT = 2 + STAR = 3 + COMMA = 4 + LPAREN = 5 + RPAREN = 6 + LBRACK = 7 + RBRACK = 8 + LDIAM = 9 + RDIAM = 10 + ATDOT = 11 + ATDOTLENGTHDASH = 12 + ANDAND = 13 + OROR = 14 + EQEQ = 15 + EQ = 16 + TRUE = 17 + FALSE = 18 + States = 19 + Format = 20 + StringToJson = 21 + JsonToString = 22 + Array = 23 + ArrayPartition = 24 + ArrayContains = 25 + ArrayRange = 26 + ArrayGetItem = 27 + ArrayLength = 28 + ArrayUnique = 29 + Base64Encode = 30 + Base64Decode = 31 + Hash = 32 + JsonMerge = 33 + MathRandom = 34 + MathAdd = 35 + StringSplit = 36 + UUID = 37 + STRING = 38 + INT = 39 + NUMBER = 40 + IDENTIFIER = 41 + WS = 42 + + channelNames = ["DEFAULT_TOKEN_CHANNEL", "HIDDEN"] + + modeNames = ["DEFAULT_MODE"] + + literalNames = [ + "", + "'$'", + "'.'", + "'*'", + "','", + "'('", + "')'", + "'['", + "']'", + "'<'", + "'>'", + "'@.'", + "'@.length-'", + "'&&'", + "'||'", + "'=='", + "'='", + "'true'", + "'false'", + "'States'", + "'Format'", + "'StringToJson'", + "'JsonToString'", + "'Array'", + "'ArrayPartition'", + "'ArrayContains'", + "'ArrayRange'", + "'ArrayGetItem'", + "'ArrayLength'", + "'ArrayUnique'", + "'Base64Encode'", + "'Base64Decode'", + "'Hash'", + "'JsonMerge'", + "'MathRandom'", + "'MathAdd'", + "'StringSplit'", + "'UUID'", + ] + + symbolicNames = [ + "", + "DOLLAR", + "DOT", + "STAR", + "COMMA", + "LPAREN", + "RPAREN", + "LBRACK", + "RBRACK", + "LDIAM", + "RDIAM", + "ATDOT", + "ATDOTLENGTHDASH", + "ANDAND", + "OROR", + "EQEQ", + "EQ", + "TRUE", + "FALSE", + "States", + "Format", + "StringToJson", + "JsonToString", + "Array", + "ArrayPartition", + "ArrayContains", + "ArrayRange", + "ArrayGetItem", + "ArrayLength", + "ArrayUnique", + "Base64Encode", + "Base64Decode", + "Hash", + "JsonMerge", + "MathRandom", + "MathAdd", + "StringSplit", + "UUID", + "STRING", + "INT", + "NUMBER", + "IDENTIFIER", + "WS", + ] + + ruleNames = [ + "DOLLAR", + "DOT", + "STAR", + "COMMA", + "LPAREN", + "RPAREN", + "LBRACK", + "RBRACK", + "LDIAM", + "RDIAM", + "ATDOT", + "ATDOTLENGTHDASH", + "ANDAND", + "OROR", + "EQEQ", + "EQ", + "TRUE", + "FALSE", + "States", + "Format", + "StringToJson", + "JsonToString", + "Array", + "ArrayPartition", + "ArrayContains", + "ArrayRange", + "ArrayGetItem", + "ArrayLength", + "ArrayUnique", + "Base64Encode", + "Base64Decode", + "Hash", + "JsonMerge", + "MathRandom", + "MathAdd", + "StringSplit", + "UUID", + "STRING", + "ESC", + "UNICODE", + "HEX", + "SAFECODEPOINT", + "INT", + "NUMBER", + "EXP", + "IDENTIFIER", + "WS", + ] + + grammarFileName = "ASLIntrinsicLexer.g4" + + def __init__(self, input=None, output: TextIO = sys.stdout): + super().__init__(input, output) + self.checkVersion("4.13.1") + self._interp = LexerATNSimulator( + self, self.atn, self.decisionsToDFA, PredictionContextCache() + ) + self._actions = None + self._predicates = None diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicLexer.tokens b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicLexer.tokens new file mode 100644 index 000000000..1759d1411 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicLexer.tokens @@ -0,0 +1,79 @@ +DOLLAR=1 +DOT=2 +STAR=3 +COMMA=4 +LPAREN=5 +RPAREN=6 +LBRACK=7 +RBRACK=8 +LDIAM=9 +RDIAM=10 +ATDOT=11 +ATDOTLENGTHDASH=12 +ANDAND=13 +OROR=14 +EQEQ=15 +EQ=16 +TRUE=17 +FALSE=18 +States=19 +Format=20 +StringToJson=21 +JsonToString=22 +Array=23 +ArrayPartition=24 +ArrayContains=25 +ArrayRange=26 +ArrayGetItem=27 +ArrayLength=28 +ArrayUnique=29 +Base64Encode=30 +Base64Decode=31 +Hash=32 +JsonMerge=33 +MathRandom=34 +MathAdd=35 +StringSplit=36 +UUID=37 +STRING=38 +INT=39 +NUMBER=40 +IDENTIFIER=41 +WS=42 +'$'=1 +'.'=2 +'*'=3 +','=4 +'('=5 +')'=6 +'['=7 +']'=8 +'<'=9 +'>'=10 +'@.'=11 +'@.length-'=12 +'&&'=13 +'||'=14 +'=='=15 +'='=16 +'true'=17 +'false'=18 +'States'=19 +'Format'=20 +'StringToJson'=21 +'JsonToString'=22 +'Array'=23 +'ArrayPartition'=24 +'ArrayContains'=25 +'ArrayRange'=26 +'ArrayGetItem'=27 +'ArrayLength'=28 +'ArrayUnique'=29 +'Base64Encode'=30 +'Base64Decode'=31 +'Hash'=32 +'JsonMerge'=33 +'MathRandom'=34 +'MathAdd'=35 +'StringSplit'=36 +'UUID'=37 diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParser.interp b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParser.interp new file mode 100644 index 000000000..58cfb0be6 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParser.interp @@ -0,0 +1,108 @@ +token literal names: +null +'$' +'.' +'*' +',' +'(' +')' +'[' +']' +'<' +'>' +'@.' +'@.length-' +'&&' +'||' +'==' +'=' +'true' +'false' +'States' +'Format' +'StringToJson' +'JsonToString' +'Array' +'ArrayPartition' +'ArrayContains' +'ArrayRange' +'ArrayGetItem' +'ArrayLength' +'ArrayUnique' +'Base64Encode' +'Base64Decode' +'Hash' +'JsonMerge' +'MathRandom' +'MathAdd' +'StringSplit' +'UUID' +null +null +null +null +null + +token symbolic names: +null +DOLLAR +DOT +STAR +COMMA +LPAREN +RPAREN +LBRACK +RBRACK +LDIAM +RDIAM +ATDOT +ATDOTLENGTHDASH +ANDAND +OROR +EQEQ +EQ +TRUE +FALSE +States +Format +StringToJson +JsonToString +Array +ArrayPartition +ArrayContains +ArrayRange +ArrayGetItem +ArrayLength +ArrayUnique +Base64Encode +Base64Decode +Hash +JsonMerge +MathRandom +MathAdd +StringSplit +UUID +STRING +INT +NUMBER +IDENTIFIER +WS + +rule names: +func_decl +states_func_decl +state_fun_name +func_arg_list +func_arg +context_path +json_path +json_path_part +json_path_iden +json_path_iden_qual +json_path_qual +json_path_query +identifier + + +atn: +[4, 1, 42, 123, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 5, 3, 40, 8, 3, 10, 3, 12, 3, 43, 9, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 49, 8, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 3, 4, 58, 8, 4, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 5, 6, 68, 8, 6, 10, 6, 12, 6, 71, 9, 6, 1, 7, 1, 7, 3, 7, 75, 8, 7, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 91, 8, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 3, 11, 101, 8, 11, 1, 11, 1, 11, 3, 11, 105, 8, 11, 1, 11, 1, 11, 1, 11, 4, 11, 110, 8, 11, 11, 11, 12, 11, 111, 5, 11, 114, 8, 11, 10, 11, 12, 11, 117, 9, 11, 1, 12, 1, 12, 3, 12, 121, 8, 12, 1, 12, 0, 1, 22, 13, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 0, 4, 1, 0, 20, 37, 1, 0, 17, 18, 2, 0, 9, 10, 15, 15, 1, 0, 13, 14, 127, 0, 26, 1, 0, 0, 0, 2, 28, 1, 0, 0, 0, 4, 33, 1, 0, 0, 0, 6, 48, 1, 0, 0, 0, 8, 57, 1, 0, 0, 0, 10, 59, 1, 0, 0, 0, 12, 62, 1, 0, 0, 0, 14, 74, 1, 0, 0, 0, 16, 76, 1, 0, 0, 0, 18, 78, 1, 0, 0, 0, 20, 90, 1, 0, 0, 0, 22, 104, 1, 0, 0, 0, 24, 120, 1, 0, 0, 0, 26, 27, 3, 2, 1, 0, 27, 1, 1, 0, 0, 0, 28, 29, 5, 19, 0, 0, 29, 30, 5, 2, 0, 0, 30, 31, 3, 4, 2, 0, 31, 32, 3, 6, 3, 0, 32, 3, 1, 0, 0, 0, 33, 34, 7, 0, 0, 0, 34, 5, 1, 0, 0, 0, 35, 36, 5, 5, 0, 0, 36, 41, 3, 8, 4, 0, 37, 38, 5, 4, 0, 0, 38, 40, 3, 8, 4, 0, 39, 37, 1, 0, 0, 0, 40, 43, 1, 0, 0, 0, 41, 39, 1, 0, 0, 0, 41, 42, 1, 0, 0, 0, 42, 44, 1, 0, 0, 0, 43, 41, 1, 0, 0, 0, 44, 45, 5, 6, 0, 0, 45, 49, 1, 0, 0, 0, 46, 47, 5, 5, 0, 0, 47, 49, 5, 6, 0, 0, 48, 35, 1, 0, 0, 0, 48, 46, 1, 0, 0, 0, 49, 7, 1, 0, 0, 0, 50, 58, 5, 38, 0, 0, 51, 58, 5, 39, 0, 0, 52, 58, 5, 40, 0, 0, 53, 58, 7, 1, 0, 0, 54, 58, 3, 10, 5, 0, 55, 58, 3, 12, 6, 0, 56, 58, 3, 0, 0, 0, 57, 50, 1, 0, 0, 0, 57, 51, 1, 0, 0, 0, 57, 52, 1, 0, 0, 0, 57, 53, 1, 0, 0, 0, 57, 54, 1, 0, 0, 0, 57, 55, 1, 0, 0, 0, 57, 56, 1, 0, 0, 0, 58, 9, 1, 0, 0, 0, 59, 60, 5, 1, 0, 0, 60, 61, 3, 12, 6, 0, 61, 11, 1, 0, 0, 0, 62, 63, 5, 1, 0, 0, 63, 64, 5, 2, 0, 0, 64, 69, 3, 14, 7, 0, 65, 66, 5, 2, 0, 0, 66, 68, 3, 14, 7, 0, 67, 65, 1, 0, 0, 0, 68, 71, 1, 0, 0, 0, 69, 67, 1, 0, 0, 0, 69, 70, 1, 0, 0, 0, 70, 13, 1, 0, 0, 0, 71, 69, 1, 0, 0, 0, 72, 75, 3, 16, 8, 0, 73, 75, 3, 18, 9, 0, 74, 72, 1, 0, 0, 0, 74, 73, 1, 0, 0, 0, 75, 15, 1, 0, 0, 0, 76, 77, 3, 24, 12, 0, 77, 17, 1, 0, 0, 0, 78, 79, 3, 16, 8, 0, 79, 80, 3, 20, 10, 0, 80, 19, 1, 0, 0, 0, 81, 82, 5, 7, 0, 0, 82, 91, 5, 8, 0, 0, 83, 84, 5, 7, 0, 0, 84, 85, 5, 39, 0, 0, 85, 91, 5, 8, 0, 0, 86, 87, 5, 7, 0, 0, 87, 88, 3, 22, 11, 0, 88, 89, 5, 8, 0, 0, 89, 91, 1, 0, 0, 0, 90, 81, 1, 0, 0, 0, 90, 83, 1, 0, 0, 0, 90, 86, 1, 0, 0, 0, 91, 21, 1, 0, 0, 0, 92, 93, 6, 11, -1, 0, 93, 105, 5, 3, 0, 0, 94, 95, 5, 11, 0, 0, 95, 100, 3, 16, 8, 0, 96, 97, 7, 2, 0, 0, 97, 101, 5, 39, 0, 0, 98, 99, 5, 16, 0, 0, 99, 101, 5, 38, 0, 0, 100, 96, 1, 0, 0, 0, 100, 98, 1, 0, 0, 0, 101, 105, 1, 0, 0, 0, 102, 103, 5, 12, 0, 0, 103, 105, 5, 39, 0, 0, 104, 92, 1, 0, 0, 0, 104, 94, 1, 0, 0, 0, 104, 102, 1, 0, 0, 0, 105, 115, 1, 0, 0, 0, 106, 109, 10, 1, 0, 0, 107, 108, 7, 3, 0, 0, 108, 110, 3, 22, 11, 0, 109, 107, 1, 0, 0, 0, 110, 111, 1, 0, 0, 0, 111, 109, 1, 0, 0, 0, 111, 112, 1, 0, 0, 0, 112, 114, 1, 0, 0, 0, 113, 106, 1, 0, 0, 0, 114, 117, 1, 0, 0, 0, 115, 113, 1, 0, 0, 0, 115, 116, 1, 0, 0, 0, 116, 23, 1, 0, 0, 0, 117, 115, 1, 0, 0, 0, 118, 121, 5, 41, 0, 0, 119, 121, 3, 4, 2, 0, 120, 118, 1, 0, 0, 0, 120, 119, 1, 0, 0, 0, 121, 25, 1, 0, 0, 0, 11, 41, 48, 57, 69, 74, 90, 100, 104, 111, 115, 120] \ No newline at end of file diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParser.py b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParser.py new file mode 100644 index 000000000..af786f1a8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParser.py @@ -0,0 +1,2661 @@ +# Generated from /Users/mep/LocalStack/localstack/localstack/services/stepfunctions/asl/antlr/ASLIntrinsicParser.g4 by ANTLR 4.13.1 +# encoding: utf-8 +import sys +from typing import TextIO + +from antlr4 import ( + ATN, + DFA, + ATNDeserializer, + NoViableAltException, + Parser, + ParserATNSimulator, + ParserRuleContext, + ParseTreeListener, + ParseTreeVisitor, + PredictionContextCache, + RecognitionException, + RuleContext, + Token, + TokenStream, +) + + +def serializedATN(): + return [ + 4, + 1, + 42, + 123, + 2, + 0, + 7, + 0, + 2, + 1, + 7, + 1, + 2, + 2, + 7, + 2, + 2, + 3, + 7, + 3, + 2, + 4, + 7, + 4, + 2, + 5, + 7, + 5, + 2, + 6, + 7, + 6, + 2, + 7, + 7, + 7, + 2, + 8, + 7, + 8, + 2, + 9, + 7, + 9, + 2, + 10, + 7, + 10, + 2, + 11, + 7, + 11, + 2, + 12, + 7, + 12, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 3, + 1, + 3, + 1, + 3, + 1, + 3, + 5, + 3, + 40, + 8, + 3, + 10, + 3, + 12, + 3, + 43, + 9, + 3, + 1, + 3, + 1, + 3, + 1, + 3, + 1, + 3, + 3, + 3, + 49, + 8, + 3, + 1, + 4, + 1, + 4, + 1, + 4, + 1, + 4, + 1, + 4, + 1, + 4, + 1, + 4, + 3, + 4, + 58, + 8, + 4, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 5, + 6, + 68, + 8, + 6, + 10, + 6, + 12, + 6, + 71, + 9, + 6, + 1, + 7, + 1, + 7, + 3, + 7, + 75, + 8, + 7, + 1, + 8, + 1, + 8, + 1, + 9, + 1, + 9, + 1, + 9, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 3, + 10, + 91, + 8, + 10, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 3, + 11, + 101, + 8, + 11, + 1, + 11, + 1, + 11, + 3, + 11, + 105, + 8, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 4, + 11, + 110, + 8, + 11, + 11, + 11, + 12, + 11, + 111, + 5, + 11, + 114, + 8, + 11, + 10, + 11, + 12, + 11, + 117, + 9, + 11, + 1, + 12, + 1, + 12, + 3, + 12, + 121, + 8, + 12, + 1, + 12, + 0, + 1, + 22, + 13, + 0, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18, + 20, + 22, + 24, + 0, + 4, + 1, + 0, + 20, + 37, + 1, + 0, + 17, + 18, + 2, + 0, + 9, + 10, + 15, + 15, + 1, + 0, + 13, + 14, + 127, + 0, + 26, + 1, + 0, + 0, + 0, + 2, + 28, + 1, + 0, + 0, + 0, + 4, + 33, + 1, + 0, + 0, + 0, + 6, + 48, + 1, + 0, + 0, + 0, + 8, + 57, + 1, + 0, + 0, + 0, + 10, + 59, + 1, + 0, + 0, + 0, + 12, + 62, + 1, + 0, + 0, + 0, + 14, + 74, + 1, + 0, + 0, + 0, + 16, + 76, + 1, + 0, + 0, + 0, + 18, + 78, + 1, + 0, + 0, + 0, + 20, + 90, + 1, + 0, + 0, + 0, + 22, + 104, + 1, + 0, + 0, + 0, + 24, + 120, + 1, + 0, + 0, + 0, + 26, + 27, + 3, + 2, + 1, + 0, + 27, + 1, + 1, + 0, + 0, + 0, + 28, + 29, + 5, + 19, + 0, + 0, + 29, + 30, + 5, + 2, + 0, + 0, + 30, + 31, + 3, + 4, + 2, + 0, + 31, + 32, + 3, + 6, + 3, + 0, + 32, + 3, + 1, + 0, + 0, + 0, + 33, + 34, + 7, + 0, + 0, + 0, + 34, + 5, + 1, + 0, + 0, + 0, + 35, + 36, + 5, + 5, + 0, + 0, + 36, + 41, + 3, + 8, + 4, + 0, + 37, + 38, + 5, + 4, + 0, + 0, + 38, + 40, + 3, + 8, + 4, + 0, + 39, + 37, + 1, + 0, + 0, + 0, + 40, + 43, + 1, + 0, + 0, + 0, + 41, + 39, + 1, + 0, + 0, + 0, + 41, + 42, + 1, + 0, + 0, + 0, + 42, + 44, + 1, + 0, + 0, + 0, + 43, + 41, + 1, + 0, + 0, + 0, + 44, + 45, + 5, + 6, + 0, + 0, + 45, + 49, + 1, + 0, + 0, + 0, + 46, + 47, + 5, + 5, + 0, + 0, + 47, + 49, + 5, + 6, + 0, + 0, + 48, + 35, + 1, + 0, + 0, + 0, + 48, + 46, + 1, + 0, + 0, + 0, + 49, + 7, + 1, + 0, + 0, + 0, + 50, + 58, + 5, + 38, + 0, + 0, + 51, + 58, + 5, + 39, + 0, + 0, + 52, + 58, + 5, + 40, + 0, + 0, + 53, + 58, + 7, + 1, + 0, + 0, + 54, + 58, + 3, + 10, + 5, + 0, + 55, + 58, + 3, + 12, + 6, + 0, + 56, + 58, + 3, + 0, + 0, + 0, + 57, + 50, + 1, + 0, + 0, + 0, + 57, + 51, + 1, + 0, + 0, + 0, + 57, + 52, + 1, + 0, + 0, + 0, + 57, + 53, + 1, + 0, + 0, + 0, + 57, + 54, + 1, + 0, + 0, + 0, + 57, + 55, + 1, + 0, + 0, + 0, + 57, + 56, + 1, + 0, + 0, + 0, + 58, + 9, + 1, + 0, + 0, + 0, + 59, + 60, + 5, + 1, + 0, + 0, + 60, + 61, + 3, + 12, + 6, + 0, + 61, + 11, + 1, + 0, + 0, + 0, + 62, + 63, + 5, + 1, + 0, + 0, + 63, + 64, + 5, + 2, + 0, + 0, + 64, + 69, + 3, + 14, + 7, + 0, + 65, + 66, + 5, + 2, + 0, + 0, + 66, + 68, + 3, + 14, + 7, + 0, + 67, + 65, + 1, + 0, + 0, + 0, + 68, + 71, + 1, + 0, + 0, + 0, + 69, + 67, + 1, + 0, + 0, + 0, + 69, + 70, + 1, + 0, + 0, + 0, + 70, + 13, + 1, + 0, + 0, + 0, + 71, + 69, + 1, + 0, + 0, + 0, + 72, + 75, + 3, + 16, + 8, + 0, + 73, + 75, + 3, + 18, + 9, + 0, + 74, + 72, + 1, + 0, + 0, + 0, + 74, + 73, + 1, + 0, + 0, + 0, + 75, + 15, + 1, + 0, + 0, + 0, + 76, + 77, + 3, + 24, + 12, + 0, + 77, + 17, + 1, + 0, + 0, + 0, + 78, + 79, + 3, + 16, + 8, + 0, + 79, + 80, + 3, + 20, + 10, + 0, + 80, + 19, + 1, + 0, + 0, + 0, + 81, + 82, + 5, + 7, + 0, + 0, + 82, + 91, + 5, + 8, + 0, + 0, + 83, + 84, + 5, + 7, + 0, + 0, + 84, + 85, + 5, + 39, + 0, + 0, + 85, + 91, + 5, + 8, + 0, + 0, + 86, + 87, + 5, + 7, + 0, + 0, + 87, + 88, + 3, + 22, + 11, + 0, + 88, + 89, + 5, + 8, + 0, + 0, + 89, + 91, + 1, + 0, + 0, + 0, + 90, + 81, + 1, + 0, + 0, + 0, + 90, + 83, + 1, + 0, + 0, + 0, + 90, + 86, + 1, + 0, + 0, + 0, + 91, + 21, + 1, + 0, + 0, + 0, + 92, + 93, + 6, + 11, + -1, + 0, + 93, + 105, + 5, + 3, + 0, + 0, + 94, + 95, + 5, + 11, + 0, + 0, + 95, + 100, + 3, + 16, + 8, + 0, + 96, + 97, + 7, + 2, + 0, + 0, + 97, + 101, + 5, + 39, + 0, + 0, + 98, + 99, + 5, + 16, + 0, + 0, + 99, + 101, + 5, + 38, + 0, + 0, + 100, + 96, + 1, + 0, + 0, + 0, + 100, + 98, + 1, + 0, + 0, + 0, + 101, + 105, + 1, + 0, + 0, + 0, + 102, + 103, + 5, + 12, + 0, + 0, + 103, + 105, + 5, + 39, + 0, + 0, + 104, + 92, + 1, + 0, + 0, + 0, + 104, + 94, + 1, + 0, + 0, + 0, + 104, + 102, + 1, + 0, + 0, + 0, + 105, + 115, + 1, + 0, + 0, + 0, + 106, + 109, + 10, + 1, + 0, + 0, + 107, + 108, + 7, + 3, + 0, + 0, + 108, + 110, + 3, + 22, + 11, + 0, + 109, + 107, + 1, + 0, + 0, + 0, + 110, + 111, + 1, + 0, + 0, + 0, + 111, + 109, + 1, + 0, + 0, + 0, + 111, + 112, + 1, + 0, + 0, + 0, + 112, + 114, + 1, + 0, + 0, + 0, + 113, + 106, + 1, + 0, + 0, + 0, + 114, + 117, + 1, + 0, + 0, + 0, + 115, + 113, + 1, + 0, + 0, + 0, + 115, + 116, + 1, + 0, + 0, + 0, + 116, + 23, + 1, + 0, + 0, + 0, + 117, + 115, + 1, + 0, + 0, + 0, + 118, + 121, + 5, + 41, + 0, + 0, + 119, + 121, + 3, + 4, + 2, + 0, + 120, + 118, + 1, + 0, + 0, + 0, + 120, + 119, + 1, + 0, + 0, + 0, + 121, + 25, + 1, + 0, + 0, + 0, + 11, + 41, + 48, + 57, + 69, + 74, + 90, + 100, + 104, + 111, + 115, + 120, + ] + + +class ASLIntrinsicParser(Parser): + + grammarFileName = "ASLIntrinsicParser.g4" + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [DFA(ds, i) for i, ds in enumerate(atn.decisionToState)] + + sharedContextCache = PredictionContextCache() + + literalNames = [ + "", + "'$'", + "'.'", + "'*'", + "','", + "'('", + "')'", + "'['", + "']'", + "'<'", + "'>'", + "'@.'", + "'@.length-'", + "'&&'", + "'||'", + "'=='", + "'='", + "'true'", + "'false'", + "'States'", + "'Format'", + "'StringToJson'", + "'JsonToString'", + "'Array'", + "'ArrayPartition'", + "'ArrayContains'", + "'ArrayRange'", + "'ArrayGetItem'", + "'ArrayLength'", + "'ArrayUnique'", + "'Base64Encode'", + "'Base64Decode'", + "'Hash'", + "'JsonMerge'", + "'MathRandom'", + "'MathAdd'", + "'StringSplit'", + "'UUID'", + ] + + symbolicNames = [ + "", + "DOLLAR", + "DOT", + "STAR", + "COMMA", + "LPAREN", + "RPAREN", + "LBRACK", + "RBRACK", + "LDIAM", + "RDIAM", + "ATDOT", + "ATDOTLENGTHDASH", + "ANDAND", + "OROR", + "EQEQ", + "EQ", + "TRUE", + "FALSE", + "States", + "Format", + "StringToJson", + "JsonToString", + "Array", + "ArrayPartition", + "ArrayContains", + "ArrayRange", + "ArrayGetItem", + "ArrayLength", + "ArrayUnique", + "Base64Encode", + "Base64Decode", + "Hash", + "JsonMerge", + "MathRandom", + "MathAdd", + "StringSplit", + "UUID", + "STRING", + "INT", + "NUMBER", + "IDENTIFIER", + "WS", + ] + + RULE_func_decl = 0 + RULE_states_func_decl = 1 + RULE_state_fun_name = 2 + RULE_func_arg_list = 3 + RULE_func_arg = 4 + RULE_context_path = 5 + RULE_json_path = 6 + RULE_json_path_part = 7 + RULE_json_path_iden = 8 + RULE_json_path_iden_qual = 9 + RULE_json_path_qual = 10 + RULE_json_path_query = 11 + RULE_identifier = 12 + + ruleNames = [ + "func_decl", + "states_func_decl", + "state_fun_name", + "func_arg_list", + "func_arg", + "context_path", + "json_path", + "json_path_part", + "json_path_iden", + "json_path_iden_qual", + "json_path_qual", + "json_path_query", + "identifier", + ] + + EOF = Token.EOF + DOLLAR = 1 + DOT = 2 + STAR = 3 + COMMA = 4 + LPAREN = 5 + RPAREN = 6 + LBRACK = 7 + RBRACK = 8 + LDIAM = 9 + RDIAM = 10 + ATDOT = 11 + ATDOTLENGTHDASH = 12 + ANDAND = 13 + OROR = 14 + EQEQ = 15 + EQ = 16 + TRUE = 17 + FALSE = 18 + States = 19 + Format = 20 + StringToJson = 21 + JsonToString = 22 + Array = 23 + ArrayPartition = 24 + ArrayContains = 25 + ArrayRange = 26 + ArrayGetItem = 27 + ArrayLength = 28 + ArrayUnique = 29 + Base64Encode = 30 + Base64Decode = 31 + Hash = 32 + JsonMerge = 33 + MathRandom = 34 + MathAdd = 35 + StringSplit = 36 + UUID = 37 + STRING = 38 + INT = 39 + NUMBER = 40 + IDENTIFIER = 41 + WS = 42 + + def __init__(self, input: TokenStream, output: TextIO = sys.stdout): + super().__init__(input, output) + self.checkVersion("4.13.1") + self._interp = ParserATNSimulator( + self, self.atn, self.decisionsToDFA, self.sharedContextCache + ) + self._predicates = None + + class Func_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def states_func_decl(self): + return self.getTypedRuleContext( + ASLIntrinsicParser.States_func_declContext, 0 + ) + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_func_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterFunc_decl"): + listener.enterFunc_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitFunc_decl"): + listener.exitFunc_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitFunc_decl"): + return visitor.visitFunc_decl(self) + else: + return visitor.visitChildren(self) + + def func_decl(self): + + localctx = ASLIntrinsicParser.Func_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 0, self.RULE_func_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 26 + self.states_func_decl() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class States_func_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def States(self): + return self.getToken(ASLIntrinsicParser.States, 0) + + def DOT(self): + return self.getToken(ASLIntrinsicParser.DOT, 0) + + def state_fun_name(self): + return self.getTypedRuleContext(ASLIntrinsicParser.State_fun_nameContext, 0) + + def func_arg_list(self): + return self.getTypedRuleContext(ASLIntrinsicParser.Func_arg_listContext, 0) + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_states_func_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterStates_func_decl"): + listener.enterStates_func_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitStates_func_decl"): + listener.exitStates_func_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitStates_func_decl"): + return visitor.visitStates_func_decl(self) + else: + return visitor.visitChildren(self) + + def states_func_decl(self): + + localctx = ASLIntrinsicParser.States_func_declContext( + self, self._ctx, self.state + ) + self.enterRule(localctx, 2, self.RULE_states_func_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 28 + self.match(ASLIntrinsicParser.States) + self.state = 29 + self.match(ASLIntrinsicParser.DOT) + self.state = 30 + self.state_fun_name() + self.state = 31 + self.func_arg_list() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class State_fun_nameContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def Format(self): + return self.getToken(ASLIntrinsicParser.Format, 0) + + def StringToJson(self): + return self.getToken(ASLIntrinsicParser.StringToJson, 0) + + def JsonToString(self): + return self.getToken(ASLIntrinsicParser.JsonToString, 0) + + def Array(self): + return self.getToken(ASLIntrinsicParser.Array, 0) + + def ArrayPartition(self): + return self.getToken(ASLIntrinsicParser.ArrayPartition, 0) + + def ArrayContains(self): + return self.getToken(ASLIntrinsicParser.ArrayContains, 0) + + def ArrayRange(self): + return self.getToken(ASLIntrinsicParser.ArrayRange, 0) + + def ArrayGetItem(self): + return self.getToken(ASLIntrinsicParser.ArrayGetItem, 0) + + def ArrayLength(self): + return self.getToken(ASLIntrinsicParser.ArrayLength, 0) + + def ArrayUnique(self): + return self.getToken(ASLIntrinsicParser.ArrayUnique, 0) + + def Base64Encode(self): + return self.getToken(ASLIntrinsicParser.Base64Encode, 0) + + def Base64Decode(self): + return self.getToken(ASLIntrinsicParser.Base64Decode, 0) + + def Hash(self): + return self.getToken(ASLIntrinsicParser.Hash, 0) + + def JsonMerge(self): + return self.getToken(ASLIntrinsicParser.JsonMerge, 0) + + def MathRandom(self): + return self.getToken(ASLIntrinsicParser.MathRandom, 0) + + def MathAdd(self): + return self.getToken(ASLIntrinsicParser.MathAdd, 0) + + def StringSplit(self): + return self.getToken(ASLIntrinsicParser.StringSplit, 0) + + def UUID(self): + return self.getToken(ASLIntrinsicParser.UUID, 0) + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_state_fun_name + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterState_fun_name"): + listener.enterState_fun_name(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitState_fun_name"): + listener.exitState_fun_name(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitState_fun_name"): + return visitor.visitState_fun_name(self) + else: + return visitor.visitChildren(self) + + def state_fun_name(self): + + localctx = ASLIntrinsicParser.State_fun_nameContext(self, self._ctx, self.state) + self.enterRule(localctx, 4, self.RULE_state_fun_name) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 33 + _la = self._input.LA(1) + if not ((((_la) & ~0x3F) == 0 and ((1 << _la) & 274876858368) != 0)): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Func_arg_listContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def LPAREN(self): + return self.getToken(ASLIntrinsicParser.LPAREN, 0) + + def func_arg(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLIntrinsicParser.Func_argContext) + else: + return self.getTypedRuleContext(ASLIntrinsicParser.Func_argContext, i) + + def RPAREN(self): + return self.getToken(ASLIntrinsicParser.RPAREN, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLIntrinsicParser.COMMA) + else: + return self.getToken(ASLIntrinsicParser.COMMA, i) + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_func_arg_list + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterFunc_arg_list"): + listener.enterFunc_arg_list(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitFunc_arg_list"): + listener.exitFunc_arg_list(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitFunc_arg_list"): + return visitor.visitFunc_arg_list(self) + else: + return visitor.visitChildren(self) + + def func_arg_list(self): + + localctx = ASLIntrinsicParser.Func_arg_listContext(self, self._ctx, self.state) + self.enterRule(localctx, 6, self.RULE_func_arg_list) + self._la = 0 # Token type + try: + self.state = 48 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 1, self._ctx) + if la_ == 1: + self.enterOuterAlt(localctx, 1) + self.state = 35 + self.match(ASLIntrinsicParser.LPAREN) + self.state = 36 + self.func_arg() + self.state = 41 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 4: + self.state = 37 + self.match(ASLIntrinsicParser.COMMA) + self.state = 38 + self.func_arg() + self.state = 43 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 44 + self.match(ASLIntrinsicParser.RPAREN) + pass + + elif la_ == 2: + self.enterOuterAlt(localctx, 2) + self.state = 46 + self.match(ASLIntrinsicParser.LPAREN) + self.state = 47 + self.match(ASLIntrinsicParser.RPAREN) + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Func_argContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_func_arg + + def copyFrom(self, ctx: ParserRuleContext): + super().copyFrom(ctx) + + class Func_arg_context_pathContext(Func_argContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Func_argContext + super().__init__(parser) + self.copyFrom(ctx) + + def context_path(self): + return self.getTypedRuleContext(ASLIntrinsicParser.Context_pathContext, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterFunc_arg_context_path"): + listener.enterFunc_arg_context_path(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitFunc_arg_context_path"): + listener.exitFunc_arg_context_path(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitFunc_arg_context_path"): + return visitor.visitFunc_arg_context_path(self) + else: + return visitor.visitChildren(self) + + class Func_arg_floatContext(Func_argContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Func_argContext + super().__init__(parser) + self.copyFrom(ctx) + + def NUMBER(self): + return self.getToken(ASLIntrinsicParser.NUMBER, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterFunc_arg_float"): + listener.enterFunc_arg_float(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitFunc_arg_float"): + listener.exitFunc_arg_float(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitFunc_arg_float"): + return visitor.visitFunc_arg_float(self) + else: + return visitor.visitChildren(self) + + class Func_arg_func_declContext(Func_argContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Func_argContext + super().__init__(parser) + self.copyFrom(ctx) + + def func_decl(self): + return self.getTypedRuleContext(ASLIntrinsicParser.Func_declContext, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterFunc_arg_func_decl"): + listener.enterFunc_arg_func_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitFunc_arg_func_decl"): + listener.exitFunc_arg_func_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitFunc_arg_func_decl"): + return visitor.visitFunc_arg_func_decl(self) + else: + return visitor.visitChildren(self) + + class Func_arg_intContext(Func_argContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Func_argContext + super().__init__(parser) + self.copyFrom(ctx) + + def INT(self): + return self.getToken(ASLIntrinsicParser.INT, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterFunc_arg_int"): + listener.enterFunc_arg_int(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitFunc_arg_int"): + listener.exitFunc_arg_int(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitFunc_arg_int"): + return visitor.visitFunc_arg_int(self) + else: + return visitor.visitChildren(self) + + class Func_arg_boolContext(Func_argContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Func_argContext + super().__init__(parser) + self.copyFrom(ctx) + + def TRUE(self): + return self.getToken(ASLIntrinsicParser.TRUE, 0) + + def FALSE(self): + return self.getToken(ASLIntrinsicParser.FALSE, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterFunc_arg_bool"): + listener.enterFunc_arg_bool(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitFunc_arg_bool"): + listener.exitFunc_arg_bool(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitFunc_arg_bool"): + return visitor.visitFunc_arg_bool(self) + else: + return visitor.visitChildren(self) + + class Func_arg_stringContext(Func_argContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Func_argContext + super().__init__(parser) + self.copyFrom(ctx) + + def STRING(self): + return self.getToken(ASLIntrinsicParser.STRING, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterFunc_arg_string"): + listener.enterFunc_arg_string(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitFunc_arg_string"): + listener.exitFunc_arg_string(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitFunc_arg_string"): + return visitor.visitFunc_arg_string(self) + else: + return visitor.visitChildren(self) + + class Func_arg_json_pathContext(Func_argContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Func_argContext + super().__init__(parser) + self.copyFrom(ctx) + + def json_path(self): + return self.getTypedRuleContext(ASLIntrinsicParser.Json_pathContext, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterFunc_arg_json_path"): + listener.enterFunc_arg_json_path(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitFunc_arg_json_path"): + listener.exitFunc_arg_json_path(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitFunc_arg_json_path"): + return visitor.visitFunc_arg_json_path(self) + else: + return visitor.visitChildren(self) + + def func_arg(self): + + localctx = ASLIntrinsicParser.Func_argContext(self, self._ctx, self.state) + self.enterRule(localctx, 8, self.RULE_func_arg) + self._la = 0 # Token type + try: + self.state = 57 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 2, self._ctx) + if la_ == 1: + localctx = ASLIntrinsicParser.Func_arg_stringContext(self, localctx) + self.enterOuterAlt(localctx, 1) + self.state = 50 + self.match(ASLIntrinsicParser.STRING) + pass + + elif la_ == 2: + localctx = ASLIntrinsicParser.Func_arg_intContext(self, localctx) + self.enterOuterAlt(localctx, 2) + self.state = 51 + self.match(ASLIntrinsicParser.INT) + pass + + elif la_ == 3: + localctx = ASLIntrinsicParser.Func_arg_floatContext(self, localctx) + self.enterOuterAlt(localctx, 3) + self.state = 52 + self.match(ASLIntrinsicParser.NUMBER) + pass + + elif la_ == 4: + localctx = ASLIntrinsicParser.Func_arg_boolContext(self, localctx) + self.enterOuterAlt(localctx, 4) + self.state = 53 + _la = self._input.LA(1) + if not (_la == 17 or _la == 18): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + pass + + elif la_ == 5: + localctx = ASLIntrinsicParser.Func_arg_context_pathContext( + self, localctx + ) + self.enterOuterAlt(localctx, 5) + self.state = 54 + self.context_path() + pass + + elif la_ == 6: + localctx = ASLIntrinsicParser.Func_arg_json_pathContext(self, localctx) + self.enterOuterAlt(localctx, 6) + self.state = 55 + self.json_path() + pass + + elif la_ == 7: + localctx = ASLIntrinsicParser.Func_arg_func_declContext(self, localctx) + self.enterOuterAlt(localctx, 7) + self.state = 56 + self.func_decl() + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Context_pathContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def DOLLAR(self): + return self.getToken(ASLIntrinsicParser.DOLLAR, 0) + + def json_path(self): + return self.getTypedRuleContext(ASLIntrinsicParser.Json_pathContext, 0) + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_context_path + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterContext_path"): + listener.enterContext_path(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitContext_path"): + listener.exitContext_path(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitContext_path"): + return visitor.visitContext_path(self) + else: + return visitor.visitChildren(self) + + def context_path(self): + + localctx = ASLIntrinsicParser.Context_pathContext(self, self._ctx, self.state) + self.enterRule(localctx, 10, self.RULE_context_path) + try: + self.enterOuterAlt(localctx, 1) + self.state = 59 + self.match(ASLIntrinsicParser.DOLLAR) + self.state = 60 + self.json_path() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Json_pathContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def DOLLAR(self): + return self.getToken(ASLIntrinsicParser.DOLLAR, 0) + + def DOT(self, i: int = None): + if i is None: + return self.getTokens(ASLIntrinsicParser.DOT) + else: + return self.getToken(ASLIntrinsicParser.DOT, i) + + def json_path_part(self, i: int = None): + if i is None: + return self.getTypedRuleContexts( + ASLIntrinsicParser.Json_path_partContext + ) + else: + return self.getTypedRuleContext( + ASLIntrinsicParser.Json_path_partContext, i + ) + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_json_path + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_path"): + listener.enterJson_path(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_path"): + listener.exitJson_path(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_path"): + return visitor.visitJson_path(self) + else: + return visitor.visitChildren(self) + + def json_path(self): + + localctx = ASLIntrinsicParser.Json_pathContext(self, self._ctx, self.state) + self.enterRule(localctx, 12, self.RULE_json_path) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 62 + self.match(ASLIntrinsicParser.DOLLAR) + self.state = 63 + self.match(ASLIntrinsicParser.DOT) + self.state = 64 + self.json_path_part() + self.state = 69 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 2: + self.state = 65 + self.match(ASLIntrinsicParser.DOT) + self.state = 66 + self.json_path_part() + self.state = 71 + self._errHandler.sync(self) + _la = self._input.LA(1) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Json_path_partContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def json_path_iden(self): + return self.getTypedRuleContext(ASLIntrinsicParser.Json_path_idenContext, 0) + + def json_path_iden_qual(self): + return self.getTypedRuleContext( + ASLIntrinsicParser.Json_path_iden_qualContext, 0 + ) + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_json_path_part + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_path_part"): + listener.enterJson_path_part(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_path_part"): + listener.exitJson_path_part(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_path_part"): + return visitor.visitJson_path_part(self) + else: + return visitor.visitChildren(self) + + def json_path_part(self): + + localctx = ASLIntrinsicParser.Json_path_partContext(self, self._ctx, self.state) + self.enterRule(localctx, 14, self.RULE_json_path_part) + try: + self.state = 74 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 4, self._ctx) + if la_ == 1: + self.enterOuterAlt(localctx, 1) + self.state = 72 + self.json_path_iden() + pass + + elif la_ == 2: + self.enterOuterAlt(localctx, 2) + self.state = 73 + self.json_path_iden_qual() + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Json_path_idenContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def identifier(self): + return self.getTypedRuleContext(ASLIntrinsicParser.IdentifierContext, 0) + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_json_path_iden + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_path_iden"): + listener.enterJson_path_iden(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_path_iden"): + listener.exitJson_path_iden(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_path_iden"): + return visitor.visitJson_path_iden(self) + else: + return visitor.visitChildren(self) + + def json_path_iden(self): + + localctx = ASLIntrinsicParser.Json_path_idenContext(self, self._ctx, self.state) + self.enterRule(localctx, 16, self.RULE_json_path_iden) + try: + self.enterOuterAlt(localctx, 1) + self.state = 76 + self.identifier() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Json_path_iden_qualContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def json_path_iden(self): + return self.getTypedRuleContext(ASLIntrinsicParser.Json_path_idenContext, 0) + + def json_path_qual(self): + return self.getTypedRuleContext(ASLIntrinsicParser.Json_path_qualContext, 0) + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_json_path_iden_qual + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_path_iden_qual"): + listener.enterJson_path_iden_qual(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_path_iden_qual"): + listener.exitJson_path_iden_qual(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_path_iden_qual"): + return visitor.visitJson_path_iden_qual(self) + else: + return visitor.visitChildren(self) + + def json_path_iden_qual(self): + + localctx = ASLIntrinsicParser.Json_path_iden_qualContext( + self, self._ctx, self.state + ) + self.enterRule(localctx, 18, self.RULE_json_path_iden_qual) + try: + self.enterOuterAlt(localctx, 1) + self.state = 78 + self.json_path_iden() + self.state = 79 + self.json_path_qual() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Json_path_qualContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_json_path_qual + + def copyFrom(self, ctx: ParserRuleContext): + super().copyFrom(ctx) + + class Json_path_qual_voidContext(Json_path_qualContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Json_path_qualContext + super().__init__(parser) + self.copyFrom(ctx) + + def LBRACK(self): + return self.getToken(ASLIntrinsicParser.LBRACK, 0) + + def RBRACK(self): + return self.getToken(ASLIntrinsicParser.RBRACK, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_path_qual_void"): + listener.enterJson_path_qual_void(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_path_qual_void"): + listener.exitJson_path_qual_void(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_path_qual_void"): + return visitor.visitJson_path_qual_void(self) + else: + return visitor.visitChildren(self) + + class Json_path_qual_queryContext(Json_path_qualContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Json_path_qualContext + super().__init__(parser) + self.copyFrom(ctx) + + def LBRACK(self): + return self.getToken(ASLIntrinsicParser.LBRACK, 0) + + def json_path_query(self): + return self.getTypedRuleContext( + ASLIntrinsicParser.Json_path_queryContext, 0 + ) + + def RBRACK(self): + return self.getToken(ASLIntrinsicParser.RBRACK, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_path_qual_query"): + listener.enterJson_path_qual_query(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_path_qual_query"): + listener.exitJson_path_qual_query(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_path_qual_query"): + return visitor.visitJson_path_qual_query(self) + else: + return visitor.visitChildren(self) + + class Json_path_qual_idxContext(Json_path_qualContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Json_path_qualContext + super().__init__(parser) + self.copyFrom(ctx) + + def LBRACK(self): + return self.getToken(ASLIntrinsicParser.LBRACK, 0) + + def INT(self): + return self.getToken(ASLIntrinsicParser.INT, 0) + + def RBRACK(self): + return self.getToken(ASLIntrinsicParser.RBRACK, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_path_qual_idx"): + listener.enterJson_path_qual_idx(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_path_qual_idx"): + listener.exitJson_path_qual_idx(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_path_qual_idx"): + return visitor.visitJson_path_qual_idx(self) + else: + return visitor.visitChildren(self) + + def json_path_qual(self): + + localctx = ASLIntrinsicParser.Json_path_qualContext(self, self._ctx, self.state) + self.enterRule(localctx, 20, self.RULE_json_path_qual) + try: + self.state = 90 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 5, self._ctx) + if la_ == 1: + localctx = ASLIntrinsicParser.Json_path_qual_voidContext(self, localctx) + self.enterOuterAlt(localctx, 1) + self.state = 81 + self.match(ASLIntrinsicParser.LBRACK) + self.state = 82 + self.match(ASLIntrinsicParser.RBRACK) + pass + + elif la_ == 2: + localctx = ASLIntrinsicParser.Json_path_qual_idxContext(self, localctx) + self.enterOuterAlt(localctx, 2) + self.state = 83 + self.match(ASLIntrinsicParser.LBRACK) + self.state = 84 + self.match(ASLIntrinsicParser.INT) + self.state = 85 + self.match(ASLIntrinsicParser.RBRACK) + pass + + elif la_ == 3: + localctx = ASLIntrinsicParser.Json_path_qual_queryContext( + self, localctx + ) + self.enterOuterAlt(localctx, 3) + self.state = 86 + self.match(ASLIntrinsicParser.LBRACK) + self.state = 87 + self.json_path_query(0) + self.state = 88 + self.match(ASLIntrinsicParser.RBRACK) + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Json_path_queryContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_json_path_query + + def copyFrom(self, ctx: ParserRuleContext): + super().copyFrom(ctx) + + class Json_path_query_cmpContext(Json_path_queryContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Json_path_queryContext + super().__init__(parser) + self.copyFrom(ctx) + + def ATDOT(self): + return self.getToken(ASLIntrinsicParser.ATDOT, 0) + + def json_path_iden(self): + return self.getTypedRuleContext(ASLIntrinsicParser.Json_path_idenContext, 0) + + def INT(self): + return self.getToken(ASLIntrinsicParser.INT, 0) + + def EQ(self): + return self.getToken(ASLIntrinsicParser.EQ, 0) + + def STRING(self): + return self.getToken(ASLIntrinsicParser.STRING, 0) + + def LDIAM(self): + return self.getToken(ASLIntrinsicParser.LDIAM, 0) + + def RDIAM(self): + return self.getToken(ASLIntrinsicParser.RDIAM, 0) + + def EQEQ(self): + return self.getToken(ASLIntrinsicParser.EQEQ, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_path_query_cmp"): + listener.enterJson_path_query_cmp(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_path_query_cmp"): + listener.exitJson_path_query_cmp(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_path_query_cmp"): + return visitor.visitJson_path_query_cmp(self) + else: + return visitor.visitChildren(self) + + class Json_path_query_lengthContext(Json_path_queryContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Json_path_queryContext + super().__init__(parser) + self.copyFrom(ctx) + + def ATDOTLENGTHDASH(self): + return self.getToken(ASLIntrinsicParser.ATDOTLENGTHDASH, 0) + + def INT(self): + return self.getToken(ASLIntrinsicParser.INT, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_path_query_length"): + listener.enterJson_path_query_length(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_path_query_length"): + listener.exitJson_path_query_length(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_path_query_length"): + return visitor.visitJson_path_query_length(self) + else: + return visitor.visitChildren(self) + + class Json_path_query_binaryContext(Json_path_queryContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Json_path_queryContext + super().__init__(parser) + self.copyFrom(ctx) + + def json_path_query(self, i: int = None): + if i is None: + return self.getTypedRuleContexts( + ASLIntrinsicParser.Json_path_queryContext + ) + else: + return self.getTypedRuleContext( + ASLIntrinsicParser.Json_path_queryContext, i + ) + + def ANDAND(self, i: int = None): + if i is None: + return self.getTokens(ASLIntrinsicParser.ANDAND) + else: + return self.getToken(ASLIntrinsicParser.ANDAND, i) + + def OROR(self, i: int = None): + if i is None: + return self.getTokens(ASLIntrinsicParser.OROR) + else: + return self.getToken(ASLIntrinsicParser.OROR, i) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_path_query_binary"): + listener.enterJson_path_query_binary(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_path_query_binary"): + listener.exitJson_path_query_binary(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_path_query_binary"): + return visitor.visitJson_path_query_binary(self) + else: + return visitor.visitChildren(self) + + class Json_path_query_starContext(Json_path_queryContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLIntrinsicParser.Json_path_queryContext + super().__init__(parser) + self.copyFrom(ctx) + + def STAR(self): + return self.getToken(ASLIntrinsicParser.STAR, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_path_query_star"): + listener.enterJson_path_query_star(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_path_query_star"): + listener.exitJson_path_query_star(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_path_query_star"): + return visitor.visitJson_path_query_star(self) + else: + return visitor.visitChildren(self) + + def json_path_query(self, _p: int = 0): + _parentctx = self._ctx + _parentState = self.state + localctx = ASLIntrinsicParser.Json_path_queryContext( + self, self._ctx, _parentState + ) + _prevctx = localctx + _startState = 22 + self.enterRecursionRule(localctx, 22, self.RULE_json_path_query, _p) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 104 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [3]: + localctx = ASLIntrinsicParser.Json_path_query_starContext( + self, localctx + ) + self._ctx = localctx + _prevctx = localctx + + self.state = 93 + self.match(ASLIntrinsicParser.STAR) + pass + elif token in [11]: + localctx = ASLIntrinsicParser.Json_path_query_cmpContext(self, localctx) + self._ctx = localctx + _prevctx = localctx + self.state = 94 + self.match(ASLIntrinsicParser.ATDOT) + self.state = 95 + self.json_path_iden() + self.state = 100 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [9, 10, 15]: + self.state = 96 + _la = self._input.LA(1) + if not ((((_la) & ~0x3F) == 0 and ((1 << _la) & 34304) != 0)): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + self.state = 97 + self.match(ASLIntrinsicParser.INT) + pass + elif token in [16]: + self.state = 98 + self.match(ASLIntrinsicParser.EQ) + self.state = 99 + self.match(ASLIntrinsicParser.STRING) + pass + else: + raise NoViableAltException(self) + + pass + elif token in [12]: + localctx = ASLIntrinsicParser.Json_path_query_lengthContext( + self, localctx + ) + self._ctx = localctx + _prevctx = localctx + self.state = 102 + self.match(ASLIntrinsicParser.ATDOTLENGTHDASH) + self.state = 103 + self.match(ASLIntrinsicParser.INT) + pass + else: + raise NoViableAltException(self) + + self._ctx.stop = self._input.LT(-1) + self.state = 115 + self._errHandler.sync(self) + _alt = self._interp.adaptivePredict(self._input, 9, self._ctx) + while _alt != 2 and _alt != ATN.INVALID_ALT_NUMBER: + if _alt == 1: + if self._parseListeners is not None: + self.triggerExitRuleEvent() + _prevctx = localctx + localctx = ASLIntrinsicParser.Json_path_query_binaryContext( + self, + ASLIntrinsicParser.Json_path_queryContext( + self, _parentctx, _parentState + ), + ) + self.pushNewRecursionContext( + localctx, _startState, self.RULE_json_path_query + ) + self.state = 106 + if not self.precpred(self._ctx, 1): + from antlr4.error.Errors import FailedPredicateException + + raise FailedPredicateException( + self, "self.precpred(self._ctx, 1)" + ) + self.state = 109 + self._errHandler.sync(self) + _alt = 1 + while _alt != 2 and _alt != ATN.INVALID_ALT_NUMBER: + if _alt == 1: + self.state = 107 + _la = self._input.LA(1) + if not (_la == 13 or _la == 14): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + self.state = 108 + self.json_path_query(0) + + else: + raise NoViableAltException(self) + self.state = 111 + self._errHandler.sync(self) + _alt = self._interp.adaptivePredict(self._input, 8, self._ctx) + + self.state = 117 + self._errHandler.sync(self) + _alt = self._interp.adaptivePredict(self._input, 9, self._ctx) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.unrollRecursionContexts(_parentctx) + return localctx + + class IdentifierContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def IDENTIFIER(self): + return self.getToken(ASLIntrinsicParser.IDENTIFIER, 0) + + def state_fun_name(self): + return self.getTypedRuleContext(ASLIntrinsicParser.State_fun_nameContext, 0) + + def getRuleIndex(self): + return ASLIntrinsicParser.RULE_identifier + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterIdentifier"): + listener.enterIdentifier(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitIdentifier"): + listener.exitIdentifier(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitIdentifier"): + return visitor.visitIdentifier(self) + else: + return visitor.visitChildren(self) + + def identifier(self): + + localctx = ASLIntrinsicParser.IdentifierContext(self, self._ctx, self.state) + self.enterRule(localctx, 24, self.RULE_identifier) + try: + self.state = 120 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [41]: + self.enterOuterAlt(localctx, 1) + self.state = 118 + self.match(ASLIntrinsicParser.IDENTIFIER) + pass + elif token in [ + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + ]: + self.enterOuterAlt(localctx, 2) + self.state = 119 + self.state_fun_name() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + def sempred(self, localctx: RuleContext, ruleIndex: int, actionIndex: int): + if self._predicates is None: + self._predicates = dict() + self._predicates[11] = self.json_path_query_sempred + pred = self._predicates.get(ruleIndex, None) + if pred is None: + raise Exception("No predicate with index:" + str(ruleIndex)) + else: + return pred(localctx, actionIndex) + + def json_path_query_sempred(self, localctx: Json_path_queryContext, predIndex: int): + if predIndex == 0: + return self.precpred(self._ctx, 1) diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParser.tokens b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParser.tokens new file mode 100644 index 000000000..1759d1411 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParser.tokens @@ -0,0 +1,79 @@ +DOLLAR=1 +DOT=2 +STAR=3 +COMMA=4 +LPAREN=5 +RPAREN=6 +LBRACK=7 +RBRACK=8 +LDIAM=9 +RDIAM=10 +ATDOT=11 +ATDOTLENGTHDASH=12 +ANDAND=13 +OROR=14 +EQEQ=15 +EQ=16 +TRUE=17 +FALSE=18 +States=19 +Format=20 +StringToJson=21 +JsonToString=22 +Array=23 +ArrayPartition=24 +ArrayContains=25 +ArrayRange=26 +ArrayGetItem=27 +ArrayLength=28 +ArrayUnique=29 +Base64Encode=30 +Base64Decode=31 +Hash=32 +JsonMerge=33 +MathRandom=34 +MathAdd=35 +StringSplit=36 +UUID=37 +STRING=38 +INT=39 +NUMBER=40 +IDENTIFIER=41 +WS=42 +'$'=1 +'.'=2 +'*'=3 +','=4 +'('=5 +')'=6 +'['=7 +']'=8 +'<'=9 +'>'=10 +'@.'=11 +'@.length-'=12 +'&&'=13 +'||'=14 +'=='=15 +'='=16 +'true'=17 +'false'=18 +'States'=19 +'Format'=20 +'StringToJson'=21 +'JsonToString'=22 +'Array'=23 +'ArrayPartition'=24 +'ArrayContains'=25 +'ArrayRange'=26 +'ArrayGetItem'=27 +'ArrayLength'=28 +'ArrayUnique'=29 +'Base64Encode'=30 +'Base64Decode'=31 +'Hash'=32 +'JsonMerge'=33 +'MathRandom'=34 +'MathAdd'=35 +'StringSplit'=36 +'UUID'=37 diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParserListener.py b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParserListener.py new file mode 100644 index 000000000..38a7e6280 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParserListener.py @@ -0,0 +1,243 @@ +# Generated from /Users/mep/LocalStack/localstack/localstack/services/stepfunctions/asl/antlr/ASLIntrinsicParser.g4 by ANTLR 4.13.1 +from antlr4 import ParseTreeListener + +if "." in __name__: + from .ASLIntrinsicParser import ASLIntrinsicParser +else: + from ASLIntrinsicParser import ASLIntrinsicParser + +# This class defines a complete listener for a parse tree produced by ASLIntrinsicParser. +class ASLIntrinsicParserListener(ParseTreeListener): + + # Enter a parse tree produced by ASLIntrinsicParser#func_decl. + def enterFunc_decl(self, ctx: ASLIntrinsicParser.Func_declContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#func_decl. + def exitFunc_decl(self, ctx: ASLIntrinsicParser.Func_declContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#states_func_decl. + def enterStates_func_decl(self, ctx: ASLIntrinsicParser.States_func_declContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#states_func_decl. + def exitStates_func_decl(self, ctx: ASLIntrinsicParser.States_func_declContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#state_fun_name. + def enterState_fun_name(self, ctx: ASLIntrinsicParser.State_fun_nameContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#state_fun_name. + def exitState_fun_name(self, ctx: ASLIntrinsicParser.State_fun_nameContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#func_arg_list. + def enterFunc_arg_list(self, ctx: ASLIntrinsicParser.Func_arg_listContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#func_arg_list. + def exitFunc_arg_list(self, ctx: ASLIntrinsicParser.Func_arg_listContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#func_arg_string. + def enterFunc_arg_string(self, ctx: ASLIntrinsicParser.Func_arg_stringContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#func_arg_string. + def exitFunc_arg_string(self, ctx: ASLIntrinsicParser.Func_arg_stringContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#func_arg_int. + def enterFunc_arg_int(self, ctx: ASLIntrinsicParser.Func_arg_intContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#func_arg_int. + def exitFunc_arg_int(self, ctx: ASLIntrinsicParser.Func_arg_intContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#func_arg_float. + def enterFunc_arg_float(self, ctx: ASLIntrinsicParser.Func_arg_floatContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#func_arg_float. + def exitFunc_arg_float(self, ctx: ASLIntrinsicParser.Func_arg_floatContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#func_arg_bool. + def enterFunc_arg_bool(self, ctx: ASLIntrinsicParser.Func_arg_boolContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#func_arg_bool. + def exitFunc_arg_bool(self, ctx: ASLIntrinsicParser.Func_arg_boolContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#func_arg_context_path. + def enterFunc_arg_context_path( + self, ctx: ASLIntrinsicParser.Func_arg_context_pathContext + ): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#func_arg_context_path. + def exitFunc_arg_context_path( + self, ctx: ASLIntrinsicParser.Func_arg_context_pathContext + ): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#func_arg_json_path. + def enterFunc_arg_json_path( + self, ctx: ASLIntrinsicParser.Func_arg_json_pathContext + ): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#func_arg_json_path. + def exitFunc_arg_json_path(self, ctx: ASLIntrinsicParser.Func_arg_json_pathContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#func_arg_func_decl. + def enterFunc_arg_func_decl( + self, ctx: ASLIntrinsicParser.Func_arg_func_declContext + ): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#func_arg_func_decl. + def exitFunc_arg_func_decl(self, ctx: ASLIntrinsicParser.Func_arg_func_declContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#context_path. + def enterContext_path(self, ctx: ASLIntrinsicParser.Context_pathContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#context_path. + def exitContext_path(self, ctx: ASLIntrinsicParser.Context_pathContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#json_path. + def enterJson_path(self, ctx: ASLIntrinsicParser.Json_pathContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#json_path. + def exitJson_path(self, ctx: ASLIntrinsicParser.Json_pathContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#json_path_part. + def enterJson_path_part(self, ctx: ASLIntrinsicParser.Json_path_partContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#json_path_part. + def exitJson_path_part(self, ctx: ASLIntrinsicParser.Json_path_partContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#json_path_iden. + def enterJson_path_iden(self, ctx: ASLIntrinsicParser.Json_path_idenContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#json_path_iden. + def exitJson_path_iden(self, ctx: ASLIntrinsicParser.Json_path_idenContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#json_path_iden_qual. + def enterJson_path_iden_qual( + self, ctx: ASLIntrinsicParser.Json_path_iden_qualContext + ): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#json_path_iden_qual. + def exitJson_path_iden_qual( + self, ctx: ASLIntrinsicParser.Json_path_iden_qualContext + ): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#json_path_qual_void. + def enterJson_path_qual_void( + self, ctx: ASLIntrinsicParser.Json_path_qual_voidContext + ): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#json_path_qual_void. + def exitJson_path_qual_void( + self, ctx: ASLIntrinsicParser.Json_path_qual_voidContext + ): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#json_path_qual_idx. + def enterJson_path_qual_idx( + self, ctx: ASLIntrinsicParser.Json_path_qual_idxContext + ): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#json_path_qual_idx. + def exitJson_path_qual_idx(self, ctx: ASLIntrinsicParser.Json_path_qual_idxContext): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#json_path_qual_query. + def enterJson_path_qual_query( + self, ctx: ASLIntrinsicParser.Json_path_qual_queryContext + ): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#json_path_qual_query. + def exitJson_path_qual_query( + self, ctx: ASLIntrinsicParser.Json_path_qual_queryContext + ): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#json_path_query_cmp. + def enterJson_path_query_cmp( + self, ctx: ASLIntrinsicParser.Json_path_query_cmpContext + ): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#json_path_query_cmp. + def exitJson_path_query_cmp( + self, ctx: ASLIntrinsicParser.Json_path_query_cmpContext + ): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#json_path_query_length. + def enterJson_path_query_length( + self, ctx: ASLIntrinsicParser.Json_path_query_lengthContext + ): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#json_path_query_length. + def exitJson_path_query_length( + self, ctx: ASLIntrinsicParser.Json_path_query_lengthContext + ): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#json_path_query_binary. + def enterJson_path_query_binary( + self, ctx: ASLIntrinsicParser.Json_path_query_binaryContext + ): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#json_path_query_binary. + def exitJson_path_query_binary( + self, ctx: ASLIntrinsicParser.Json_path_query_binaryContext + ): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#json_path_query_star. + def enterJson_path_query_star( + self, ctx: ASLIntrinsicParser.Json_path_query_starContext + ): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#json_path_query_star. + def exitJson_path_query_star( + self, ctx: ASLIntrinsicParser.Json_path_query_starContext + ): + pass + + # Enter a parse tree produced by ASLIntrinsicParser#identifier. + def enterIdentifier(self, ctx: ASLIntrinsicParser.IdentifierContext): + pass + + # Exit a parse tree produced by ASLIntrinsicParser#identifier. + def exitIdentifier(self, ctx: ASLIntrinsicParser.IdentifierContext): + pass + + +del ASLIntrinsicParser diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParserVisitor.py b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParserVisitor.py new file mode 100644 index 000000000..987a0683e --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLIntrinsicParserVisitor.py @@ -0,0 +1,133 @@ +# Generated from /Users/mep/LocalStack/localstack/localstack/services/stepfunctions/asl/antlr/ASLIntrinsicParser.g4 by ANTLR 4.13.1 +from antlr4 import ParseTreeVisitor + +if "." in __name__: + from .ASLIntrinsicParser import ASLIntrinsicParser +else: + from ASLIntrinsicParser import ASLIntrinsicParser + +# This class defines a complete generic visitor for a parse tree produced by ASLIntrinsicParser. + + +class ASLIntrinsicParserVisitor(ParseTreeVisitor): + + # Visit a parse tree produced by ASLIntrinsicParser#func_decl. + def visitFunc_decl(self, ctx: ASLIntrinsicParser.Func_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#states_func_decl. + def visitStates_func_decl(self, ctx: ASLIntrinsicParser.States_func_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#state_fun_name. + def visitState_fun_name(self, ctx: ASLIntrinsicParser.State_fun_nameContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#func_arg_list. + def visitFunc_arg_list(self, ctx: ASLIntrinsicParser.Func_arg_listContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#func_arg_string. + def visitFunc_arg_string(self, ctx: ASLIntrinsicParser.Func_arg_stringContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#func_arg_int. + def visitFunc_arg_int(self, ctx: ASLIntrinsicParser.Func_arg_intContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#func_arg_float. + def visitFunc_arg_float(self, ctx: ASLIntrinsicParser.Func_arg_floatContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#func_arg_bool. + def visitFunc_arg_bool(self, ctx: ASLIntrinsicParser.Func_arg_boolContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#func_arg_context_path. + def visitFunc_arg_context_path( + self, ctx: ASLIntrinsicParser.Func_arg_context_pathContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#func_arg_json_path. + def visitFunc_arg_json_path( + self, ctx: ASLIntrinsicParser.Func_arg_json_pathContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#func_arg_func_decl. + def visitFunc_arg_func_decl( + self, ctx: ASLIntrinsicParser.Func_arg_func_declContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#context_path. + def visitContext_path(self, ctx: ASLIntrinsicParser.Context_pathContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#json_path. + def visitJson_path(self, ctx: ASLIntrinsicParser.Json_pathContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#json_path_part. + def visitJson_path_part(self, ctx: ASLIntrinsicParser.Json_path_partContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#json_path_iden. + def visitJson_path_iden(self, ctx: ASLIntrinsicParser.Json_path_idenContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#json_path_iden_qual. + def visitJson_path_iden_qual( + self, ctx: ASLIntrinsicParser.Json_path_iden_qualContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#json_path_qual_void. + def visitJson_path_qual_void( + self, ctx: ASLIntrinsicParser.Json_path_qual_voidContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#json_path_qual_idx. + def visitJson_path_qual_idx( + self, ctx: ASLIntrinsicParser.Json_path_qual_idxContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#json_path_qual_query. + def visitJson_path_qual_query( + self, ctx: ASLIntrinsicParser.Json_path_qual_queryContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#json_path_query_cmp. + def visitJson_path_query_cmp( + self, ctx: ASLIntrinsicParser.Json_path_query_cmpContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#json_path_query_length. + def visitJson_path_query_length( + self, ctx: ASLIntrinsicParser.Json_path_query_lengthContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#json_path_query_binary. + def visitJson_path_query_binary( + self, ctx: ASLIntrinsicParser.Json_path_query_binaryContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#json_path_query_star. + def visitJson_path_query_star( + self, ctx: ASLIntrinsicParser.Json_path_query_starContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLIntrinsicParser#identifier. + def visitIdentifier(self, ctx: ASLIntrinsicParser.IdentifierContext): + return self.visitChildren(ctx) + + +del ASLIntrinsicParser diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLLexer.interp b/moto/stepfunctions/parser/asl/antlr/runtime/ASLLexer.interp new file mode 100644 index 000000000..8bf4c1c2a --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLLexer.interp @@ -0,0 +1,421 @@ +token literal names: +null +',' +':' +'[' +']' +'{' +'}' +'true' +'false' +'null' +'"Comment"' +'"States"' +'"StartAt"' +'"NextState"' +'"Version"' +'"Type"' +'"Task"' +'"Choice"' +'"Fail"' +'"Succeed"' +'"Pass"' +'"Wait"' +'"Parallel"' +'"Map"' +'"Choices"' +'"Variable"' +'"Default"' +'"Branches"' +'"And"' +'"BooleanEquals"' +'"BooleanEqualsPath"' +'"IsBoolean"' +'"IsNull"' +'"IsNumeric"' +'"IsPresent"' +'"IsString"' +'"IsTimestamp"' +'"Not"' +'"NumericEquals"' +'"NumericEqualsPath"' +'"NumericGreaterThan"' +'"NumericGreaterThanPath"' +'"NumericGreaterThanEquals"' +'"NumericGreaterThanEqualsPath"' +'"NumericLessThan"' +'"NumericLessThanPath"' +'"NumericLessThanEquals"' +'"NumericLessThanEqualsPath"' +'"Or"' +'"StringEquals"' +'"StringEqualsPath"' +'"StringGreaterThan"' +'"StringGreaterThanPath"' +'"StringGreaterThanEquals"' +'"StringGreaterThanEqualsPath"' +'"StringLessThan"' +'"StringLessThanPath"' +'"StringLessThanEquals"' +'"StringLessThanEqualsPath"' +'"StringMatches"' +'"TimestampEquals"' +'"TimestampEqualsPath"' +'"TimestampGreaterThan"' +'"TimestampGreaterThanPath"' +'"TimestampGreaterThanEquals"' +'"TimestampGreaterThanEqualsPath"' +'"TimestampLessThan"' +'"TimestampLessThanPath"' +'"TimestampLessThanEquals"' +'"TimestampLessThanEqualsPath"' +'"SecondsPath"' +'"Seconds"' +'"TimestampPath"' +'"Timestamp"' +'"TimeoutSeconds"' +'"TimeoutSecondsPath"' +'"HeartbeatSeconds"' +'"HeartbeatSecondsPath"' +'"ProcessorConfig"' +'"Mode"' +'"INLINE"' +'"DISTRIBUTED"' +'"ExecutionType"' +'"STANDARD"' +'"ItemProcessor"' +'"Iterator"' +'"ItemSelector"' +'"MaxConcurrency"' +'"Resource"' +'"InputPath"' +'"OutputPath"' +'"ItemsPath"' +'"ResultPath"' +'"Result"' +'"Parameters"' +'"ResultSelector"' +'"ItemReader"' +'"ReaderConfig"' +'"InputType"' +'"CSVHeaderLocation"' +'"CSVHeaders"' +'"MaxItems"' +'"MaxItemsPath"' +'"Next"' +'"End"' +'"Cause"' +'"Error"' +'"Retry"' +'"ErrorEquals"' +'"IntervalSeconds"' +'"MaxAttempts"' +'"BackoffRate"' +'"Catch"' +'"States.ALL"' +'"States.HeartbeatTimeout"' +'"States.Timeout"' +'"States.TaskFailed"' +'"States.Permissions"' +'"States.ResultPathMatchFailure"' +'"States.ParameterPathFailure"' +'"States.BranchFailed"' +'"States.NoChoiceMatched"' +'"States.IntrinsicFailure"' +'"States.ExceedToleratedFailureThreshold"' +'"States.ItemReaderFailed"' +'"States.ResultWriterFailed"' +'"States.Runtime"' +null +null +null +null +null +null +null + +token symbolic names: +null +COMMA +COLON +LBRACK +RBRACK +LBRACE +RBRACE +TRUE +FALSE +NULL +COMMENT +STATES +STARTAT +NEXTSTATE +VERSION +TYPE +TASK +CHOICE +FAIL +SUCCEED +PASS +WAIT +PARALLEL +MAP +CHOICES +VARIABLE +DEFAULT +BRANCHES +AND +BOOLEANEQUALS +BOOLEANQUALSPATH +ISBOOLEAN +ISNULL +ISNUMERIC +ISPRESENT +ISSTRING +ISTIMESTAMP +NOT +NUMERICEQUALS +NUMERICEQUALSPATH +NUMERICGREATERTHAN +NUMERICGREATERTHANPATH +NUMERICGREATERTHANEQUALS +NUMERICGREATERTHANEQUALSPATH +NUMERICLESSTHAN +NUMERICLESSTHANPATH +NUMERICLESSTHANEQUALS +NUMERICLESSTHANEQUALSPATH +OR +STRINGEQUALS +STRINGEQUALSPATH +STRINGGREATERTHAN +STRINGGREATERTHANPATH +STRINGGREATERTHANEQUALS +STRINGGREATERTHANEQUALSPATH +STRINGLESSTHAN +STRINGLESSTHANPATH +STRINGLESSTHANEQUALS +STRINGLESSTHANEQUALSPATH +STRINGMATCHES +TIMESTAMPEQUALS +TIMESTAMPEQUALSPATH +TIMESTAMPGREATERTHAN +TIMESTAMPGREATERTHANPATH +TIMESTAMPGREATERTHANEQUALS +TIMESTAMPGREATERTHANEQUALSPATH +TIMESTAMPLESSTHAN +TIMESTAMPLESSTHANPATH +TIMESTAMPLESSTHANEQUALS +TIMESTAMPLESSTHANEQUALSPATH +SECONDSPATH +SECONDS +TIMESTAMPPATH +TIMESTAMP +TIMEOUTSECONDS +TIMEOUTSECONDSPATH +HEARTBEATSECONDS +HEARTBEATSECONDSPATH +PROCESSORCONFIG +MODE +INLINE +DISTRIBUTED +EXECUTIONTYPE +STANDARD +ITEMPROCESSOR +ITERATOR +ITEMSELECTOR +MAXCONCURRENCY +RESOURCE +INPUTPATH +OUTPUTPATH +ITEMSPATH +RESULTPATH +RESULT +PARAMETERS +RESULTSELECTOR +ITEMREADER +READERCONFIG +INPUTTYPE +CSVHEADERLOCATION +CSVHEADERS +MAXITEMS +MAXITEMSPATH +NEXT +END +CAUSE +ERROR +RETRY +ERROREQUALS +INTERVALSECONDS +MAXATTEMPTS +BACKOFFRATE +CATCH +ERRORNAMEStatesALL +ERRORNAMEStatesHeartbeatTimeout +ERRORNAMEStatesTimeout +ERRORNAMEStatesTaskFailed +ERRORNAMEStatesPermissions +ERRORNAMEStatesResultPathMatchFailure +ERRORNAMEStatesParameterPathFailure +ERRORNAMEStatesBranchFailed +ERRORNAMEStatesNoChoiceMatched +ERRORNAMEStatesIntrinsicFailure +ERRORNAMEStatesExceedToleratedFailureThreshold +ERRORNAMEStatesItemReaderFailed +ERRORNAMEStatesResultWriterFailed +ERRORNAMEStatesRuntime +STRINGDOLLAR +STRINGPATHCONTEXTOBJ +STRINGPATH +STRING +INT +NUMBER +WS + +rule names: +COMMA +COLON +LBRACK +RBRACK +LBRACE +RBRACE +TRUE +FALSE +NULL +COMMENT +STATES +STARTAT +NEXTSTATE +VERSION +TYPE +TASK +CHOICE +FAIL +SUCCEED +PASS +WAIT +PARALLEL +MAP +CHOICES +VARIABLE +DEFAULT +BRANCHES +AND +BOOLEANEQUALS +BOOLEANQUALSPATH +ISBOOLEAN +ISNULL +ISNUMERIC +ISPRESENT +ISSTRING +ISTIMESTAMP +NOT +NUMERICEQUALS +NUMERICEQUALSPATH +NUMERICGREATERTHAN +NUMERICGREATERTHANPATH +NUMERICGREATERTHANEQUALS +NUMERICGREATERTHANEQUALSPATH +NUMERICLESSTHAN +NUMERICLESSTHANPATH +NUMERICLESSTHANEQUALS +NUMERICLESSTHANEQUALSPATH +OR +STRINGEQUALS +STRINGEQUALSPATH +STRINGGREATERTHAN +STRINGGREATERTHANPATH +STRINGGREATERTHANEQUALS +STRINGGREATERTHANEQUALSPATH +STRINGLESSTHAN +STRINGLESSTHANPATH +STRINGLESSTHANEQUALS +STRINGLESSTHANEQUALSPATH +STRINGMATCHES +TIMESTAMPEQUALS +TIMESTAMPEQUALSPATH +TIMESTAMPGREATERTHAN +TIMESTAMPGREATERTHANPATH +TIMESTAMPGREATERTHANEQUALS +TIMESTAMPGREATERTHANEQUALSPATH +TIMESTAMPLESSTHAN +TIMESTAMPLESSTHANPATH +TIMESTAMPLESSTHANEQUALS +TIMESTAMPLESSTHANEQUALSPATH +SECONDSPATH +SECONDS +TIMESTAMPPATH +TIMESTAMP +TIMEOUTSECONDS +TIMEOUTSECONDSPATH +HEARTBEATSECONDS +HEARTBEATSECONDSPATH +PROCESSORCONFIG +MODE +INLINE +DISTRIBUTED +EXECUTIONTYPE +STANDARD +ITEMPROCESSOR +ITERATOR +ITEMSELECTOR +MAXCONCURRENCY +RESOURCE +INPUTPATH +OUTPUTPATH +ITEMSPATH +RESULTPATH +RESULT +PARAMETERS +RESULTSELECTOR +ITEMREADER +READERCONFIG +INPUTTYPE +CSVHEADERLOCATION +CSVHEADERS +MAXITEMS +MAXITEMSPATH +NEXT +END +CAUSE +ERROR +RETRY +ERROREQUALS +INTERVALSECONDS +MAXATTEMPTS +BACKOFFRATE +CATCH +ERRORNAMEStatesALL +ERRORNAMEStatesHeartbeatTimeout +ERRORNAMEStatesTimeout +ERRORNAMEStatesTaskFailed +ERRORNAMEStatesPermissions +ERRORNAMEStatesResultPathMatchFailure +ERRORNAMEStatesParameterPathFailure +ERRORNAMEStatesBranchFailed +ERRORNAMEStatesNoChoiceMatched +ERRORNAMEStatesIntrinsicFailure +ERRORNAMEStatesExceedToleratedFailureThreshold +ERRORNAMEStatesItemReaderFailed +ERRORNAMEStatesResultWriterFailed +ERRORNAMEStatesRuntime +STRINGDOLLAR +STRINGPATHCONTEXTOBJ +STRINGPATH +STRING +ESC +UNICODE +HEX +SAFECODEPOINT +INT +NUMBER +EXP +WS + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN + +mode names: +DEFAULT_MODE + +atn: +[4, 0, 133, 2328, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 1, 0, 1, 0, 1, 1, 1, 1, 1, 2, 1, 2, 1, 3, 1, 3, 1, 4, 1, 4, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 77, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 78, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 96, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 102, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 109, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 110, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 115, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 116, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 117, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 118, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 121, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 5, 126, 2232, 8, 126, 10, 126, 12, 126, 2235, 9, 126, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 1, 127, 5, 127, 2247, 8, 127, 10, 127, 12, 127, 2250, 9, 127, 1, 127, 1, 127, 1, 128, 1, 128, 1, 128, 1, 128, 1, 128, 5, 128, 2259, 8, 128, 10, 128, 12, 128, 2262, 9, 128, 1, 128, 1, 128, 1, 129, 1, 129, 1, 129, 5, 129, 2269, 8, 129, 10, 129, 12, 129, 2272, 9, 129, 1, 129, 1, 129, 1, 130, 1, 130, 1, 130, 3, 130, 2279, 8, 130, 1, 131, 1, 131, 1, 131, 1, 131, 1, 131, 1, 131, 1, 132, 1, 132, 1, 133, 1, 133, 1, 134, 1, 134, 1, 134, 5, 134, 2294, 8, 134, 10, 134, 12, 134, 2297, 9, 134, 3, 134, 2299, 8, 134, 1, 135, 3, 135, 2302, 8, 135, 1, 135, 1, 135, 1, 135, 4, 135, 2307, 8, 135, 11, 135, 12, 135, 2308, 3, 135, 2311, 8, 135, 1, 135, 3, 135, 2314, 8, 135, 1, 136, 1, 136, 3, 136, 2318, 8, 136, 1, 136, 1, 136, 1, 137, 4, 137, 2323, 8, 137, 11, 137, 12, 137, 2324, 1, 137, 1, 137, 0, 0, 138, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77, 39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, 95, 48, 97, 49, 99, 50, 101, 51, 103, 52, 105, 53, 107, 54, 109, 55, 111, 56, 113, 57, 115, 58, 117, 59, 119, 60, 121, 61, 123, 62, 125, 63, 127, 64, 129, 65, 131, 66, 133, 67, 135, 68, 137, 69, 139, 70, 141, 71, 143, 72, 145, 73, 147, 74, 149, 75, 151, 76, 153, 77, 155, 78, 157, 79, 159, 80, 161, 81, 163, 82, 165, 83, 167, 84, 169, 85, 171, 86, 173, 87, 175, 88, 177, 89, 179, 90, 181, 91, 183, 92, 185, 93, 187, 94, 189, 95, 191, 96, 193, 97, 195, 98, 197, 99, 199, 100, 201, 101, 203, 102, 205, 103, 207, 104, 209, 105, 211, 106, 213, 107, 215, 108, 217, 109, 219, 110, 221, 111, 223, 112, 225, 113, 227, 114, 229, 115, 231, 116, 233, 117, 235, 118, 237, 119, 239, 120, 241, 121, 243, 122, 245, 123, 247, 124, 249, 125, 251, 126, 253, 127, 255, 128, 257, 129, 259, 130, 261, 0, 263, 0, 265, 0, 267, 0, 269, 131, 271, 132, 273, 0, 275, 133, 1, 0, 8, 8, 0, 34, 34, 47, 47, 92, 92, 98, 98, 102, 102, 110, 110, 114, 114, 116, 116, 3, 0, 48, 57, 65, 70, 97, 102, 3, 0, 0, 31, 34, 34, 92, 92, 1, 0, 49, 57, 1, 0, 48, 57, 2, 0, 69, 69, 101, 101, 2, 0, 43, 43, 45, 45, 3, 0, 9, 10, 13, 13, 32, 32, 2339, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 95, 1, 0, 0, 0, 0, 97, 1, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 101, 1, 0, 0, 0, 0, 103, 1, 0, 0, 0, 0, 105, 1, 0, 0, 0, 0, 107, 1, 0, 0, 0, 0, 109, 1, 0, 0, 0, 0, 111, 1, 0, 0, 0, 0, 113, 1, 0, 0, 0, 0, 115, 1, 0, 0, 0, 0, 117, 1, 0, 0, 0, 0, 119, 1, 0, 0, 0, 0, 121, 1, 0, 0, 0, 0, 123, 1, 0, 0, 0, 0, 125, 1, 0, 0, 0, 0, 127, 1, 0, 0, 0, 0, 129, 1, 0, 0, 0, 0, 131, 1, 0, 0, 0, 0, 133, 1, 0, 0, 0, 0, 135, 1, 0, 0, 0, 0, 137, 1, 0, 0, 0, 0, 139, 1, 0, 0, 0, 0, 141, 1, 0, 0, 0, 0, 143, 1, 0, 0, 0, 0, 145, 1, 0, 0, 0, 0, 147, 1, 0, 0, 0, 0, 149, 1, 0, 0, 0, 0, 151, 1, 0, 0, 0, 0, 153, 1, 0, 0, 0, 0, 155, 1, 0, 0, 0, 0, 157, 1, 0, 0, 0, 0, 159, 1, 0, 0, 0, 0, 161, 1, 0, 0, 0, 0, 163, 1, 0, 0, 0, 0, 165, 1, 0, 0, 0, 0, 167, 1, 0, 0, 0, 0, 169, 1, 0, 0, 0, 0, 171, 1, 0, 0, 0, 0, 173, 1, 0, 0, 0, 0, 175, 1, 0, 0, 0, 0, 177, 1, 0, 0, 0, 0, 179, 1, 0, 0, 0, 0, 181, 1, 0, 0, 0, 0, 183, 1, 0, 0, 0, 0, 185, 1, 0, 0, 0, 0, 187, 1, 0, 0, 0, 0, 189, 1, 0, 0, 0, 0, 191, 1, 0, 0, 0, 0, 193, 1, 0, 0, 0, 0, 195, 1, 0, 0, 0, 0, 197, 1, 0, 0, 0, 0, 199, 1, 0, 0, 0, 0, 201, 1, 0, 0, 0, 0, 203, 1, 0, 0, 0, 0, 205, 1, 0, 0, 0, 0, 207, 1, 0, 0, 0, 0, 209, 1, 0, 0, 0, 0, 211, 1, 0, 0, 0, 0, 213, 1, 0, 0, 0, 0, 215, 1, 0, 0, 0, 0, 217, 1, 0, 0, 0, 0, 219, 1, 0, 0, 0, 0, 221, 1, 0, 0, 0, 0, 223, 1, 0, 0, 0, 0, 225, 1, 0, 0, 0, 0, 227, 1, 0, 0, 0, 0, 229, 1, 0, 0, 0, 0, 231, 1, 0, 0, 0, 0, 233, 1, 0, 0, 0, 0, 235, 1, 0, 0, 0, 0, 237, 1, 0, 0, 0, 0, 239, 1, 0, 0, 0, 0, 241, 1, 0, 0, 0, 0, 243, 1, 0, 0, 0, 0, 245, 1, 0, 0, 0, 0, 247, 1, 0, 0, 0, 0, 249, 1, 0, 0, 0, 0, 251, 1, 0, 0, 0, 0, 253, 1, 0, 0, 0, 0, 255, 1, 0, 0, 0, 0, 257, 1, 0, 0, 0, 0, 259, 1, 0, 0, 0, 0, 269, 1, 0, 0, 0, 0, 271, 1, 0, 0, 0, 0, 275, 1, 0, 0, 0, 1, 277, 1, 0, 0, 0, 3, 279, 1, 0, 0, 0, 5, 281, 1, 0, 0, 0, 7, 283, 1, 0, 0, 0, 9, 285, 1, 0, 0, 0, 11, 287, 1, 0, 0, 0, 13, 289, 1, 0, 0, 0, 15, 294, 1, 0, 0, 0, 17, 300, 1, 0, 0, 0, 19, 305, 1, 0, 0, 0, 21, 315, 1, 0, 0, 0, 23, 324, 1, 0, 0, 0, 25, 334, 1, 0, 0, 0, 27, 346, 1, 0, 0, 0, 29, 356, 1, 0, 0, 0, 31, 363, 1, 0, 0, 0, 33, 370, 1, 0, 0, 0, 35, 379, 1, 0, 0, 0, 37, 386, 1, 0, 0, 0, 39, 396, 1, 0, 0, 0, 41, 403, 1, 0, 0, 0, 43, 410, 1, 0, 0, 0, 45, 421, 1, 0, 0, 0, 47, 427, 1, 0, 0, 0, 49, 437, 1, 0, 0, 0, 51, 448, 1, 0, 0, 0, 53, 458, 1, 0, 0, 0, 55, 469, 1, 0, 0, 0, 57, 475, 1, 0, 0, 0, 59, 491, 1, 0, 0, 0, 61, 511, 1, 0, 0, 0, 63, 523, 1, 0, 0, 0, 65, 532, 1, 0, 0, 0, 67, 544, 1, 0, 0, 0, 69, 556, 1, 0, 0, 0, 71, 567, 1, 0, 0, 0, 73, 581, 1, 0, 0, 0, 75, 587, 1, 0, 0, 0, 77, 603, 1, 0, 0, 0, 79, 623, 1, 0, 0, 0, 81, 644, 1, 0, 0, 0, 83, 669, 1, 0, 0, 0, 85, 696, 1, 0, 0, 0, 87, 727, 1, 0, 0, 0, 89, 745, 1, 0, 0, 0, 91, 767, 1, 0, 0, 0, 93, 791, 1, 0, 0, 0, 95, 819, 1, 0, 0, 0, 97, 824, 1, 0, 0, 0, 99, 839, 1, 0, 0, 0, 101, 858, 1, 0, 0, 0, 103, 878, 1, 0, 0, 0, 105, 902, 1, 0, 0, 0, 107, 928, 1, 0, 0, 0, 109, 958, 1, 0, 0, 0, 111, 975, 1, 0, 0, 0, 113, 996, 1, 0, 0, 0, 115, 1019, 1, 0, 0, 0, 117, 1046, 1, 0, 0, 0, 119, 1062, 1, 0, 0, 0, 121, 1080, 1, 0, 0, 0, 123, 1102, 1, 0, 0, 0, 125, 1125, 1, 0, 0, 0, 127, 1152, 1, 0, 0, 0, 129, 1181, 1, 0, 0, 0, 131, 1214, 1, 0, 0, 0, 133, 1234, 1, 0, 0, 0, 135, 1258, 1, 0, 0, 0, 137, 1284, 1, 0, 0, 0, 139, 1314, 1, 0, 0, 0, 141, 1328, 1, 0, 0, 0, 143, 1338, 1, 0, 0, 0, 145, 1354, 1, 0, 0, 0, 147, 1366, 1, 0, 0, 0, 149, 1383, 1, 0, 0, 0, 151, 1404, 1, 0, 0, 0, 153, 1423, 1, 0, 0, 0, 155, 1446, 1, 0, 0, 0, 157, 1464, 1, 0, 0, 0, 159, 1471, 1, 0, 0, 0, 161, 1480, 1, 0, 0, 0, 163, 1494, 1, 0, 0, 0, 165, 1510, 1, 0, 0, 0, 167, 1521, 1, 0, 0, 0, 169, 1537, 1, 0, 0, 0, 171, 1548, 1, 0, 0, 0, 173, 1563, 1, 0, 0, 0, 175, 1580, 1, 0, 0, 0, 177, 1591, 1, 0, 0, 0, 179, 1603, 1, 0, 0, 0, 181, 1616, 1, 0, 0, 0, 183, 1628, 1, 0, 0, 0, 185, 1641, 1, 0, 0, 0, 187, 1650, 1, 0, 0, 0, 189, 1663, 1, 0, 0, 0, 191, 1680, 1, 0, 0, 0, 193, 1693, 1, 0, 0, 0, 195, 1708, 1, 0, 0, 0, 197, 1720, 1, 0, 0, 0, 199, 1740, 1, 0, 0, 0, 201, 1753, 1, 0, 0, 0, 203, 1764, 1, 0, 0, 0, 205, 1779, 1, 0, 0, 0, 207, 1786, 1, 0, 0, 0, 209, 1792, 1, 0, 0, 0, 211, 1800, 1, 0, 0, 0, 213, 1808, 1, 0, 0, 0, 215, 1816, 1, 0, 0, 0, 217, 1830, 1, 0, 0, 0, 219, 1848, 1, 0, 0, 0, 221, 1862, 1, 0, 0, 0, 223, 1876, 1, 0, 0, 0, 225, 1884, 1, 0, 0, 0, 227, 1897, 1, 0, 0, 0, 229, 1923, 1, 0, 0, 0, 231, 1940, 1, 0, 0, 0, 233, 1960, 1, 0, 0, 0, 235, 1981, 1, 0, 0, 0, 237, 2013, 1, 0, 0, 0, 239, 2043, 1, 0, 0, 0, 241, 2065, 1, 0, 0, 0, 243, 2090, 1, 0, 0, 0, 245, 2116, 1, 0, 0, 0, 247, 2157, 1, 0, 0, 0, 249, 2183, 1, 0, 0, 0, 251, 2211, 1, 0, 0, 0, 253, 2228, 1, 0, 0, 0, 255, 2240, 1, 0, 0, 0, 257, 2253, 1, 0, 0, 0, 259, 2265, 1, 0, 0, 0, 261, 2275, 1, 0, 0, 0, 263, 2280, 1, 0, 0, 0, 265, 2286, 1, 0, 0, 0, 267, 2288, 1, 0, 0, 0, 269, 2298, 1, 0, 0, 0, 271, 2301, 1, 0, 0, 0, 273, 2315, 1, 0, 0, 0, 275, 2322, 1, 0, 0, 0, 277, 278, 5, 44, 0, 0, 278, 2, 1, 0, 0, 0, 279, 280, 5, 58, 0, 0, 280, 4, 1, 0, 0, 0, 281, 282, 5, 91, 0, 0, 282, 6, 1, 0, 0, 0, 283, 284, 5, 93, 0, 0, 284, 8, 1, 0, 0, 0, 285, 286, 5, 123, 0, 0, 286, 10, 1, 0, 0, 0, 287, 288, 5, 125, 0, 0, 288, 12, 1, 0, 0, 0, 289, 290, 5, 116, 0, 0, 290, 291, 5, 114, 0, 0, 291, 292, 5, 117, 0, 0, 292, 293, 5, 101, 0, 0, 293, 14, 1, 0, 0, 0, 294, 295, 5, 102, 0, 0, 295, 296, 5, 97, 0, 0, 296, 297, 5, 108, 0, 0, 297, 298, 5, 115, 0, 0, 298, 299, 5, 101, 0, 0, 299, 16, 1, 0, 0, 0, 300, 301, 5, 110, 0, 0, 301, 302, 5, 117, 0, 0, 302, 303, 5, 108, 0, 0, 303, 304, 5, 108, 0, 0, 304, 18, 1, 0, 0, 0, 305, 306, 5, 34, 0, 0, 306, 307, 5, 67, 0, 0, 307, 308, 5, 111, 0, 0, 308, 309, 5, 109, 0, 0, 309, 310, 5, 109, 0, 0, 310, 311, 5, 101, 0, 0, 311, 312, 5, 110, 0, 0, 312, 313, 5, 116, 0, 0, 313, 314, 5, 34, 0, 0, 314, 20, 1, 0, 0, 0, 315, 316, 5, 34, 0, 0, 316, 317, 5, 83, 0, 0, 317, 318, 5, 116, 0, 0, 318, 319, 5, 97, 0, 0, 319, 320, 5, 116, 0, 0, 320, 321, 5, 101, 0, 0, 321, 322, 5, 115, 0, 0, 322, 323, 5, 34, 0, 0, 323, 22, 1, 0, 0, 0, 324, 325, 5, 34, 0, 0, 325, 326, 5, 83, 0, 0, 326, 327, 5, 116, 0, 0, 327, 328, 5, 97, 0, 0, 328, 329, 5, 114, 0, 0, 329, 330, 5, 116, 0, 0, 330, 331, 5, 65, 0, 0, 331, 332, 5, 116, 0, 0, 332, 333, 5, 34, 0, 0, 333, 24, 1, 0, 0, 0, 334, 335, 5, 34, 0, 0, 335, 336, 5, 78, 0, 0, 336, 337, 5, 101, 0, 0, 337, 338, 5, 120, 0, 0, 338, 339, 5, 116, 0, 0, 339, 340, 5, 83, 0, 0, 340, 341, 5, 116, 0, 0, 341, 342, 5, 97, 0, 0, 342, 343, 5, 116, 0, 0, 343, 344, 5, 101, 0, 0, 344, 345, 5, 34, 0, 0, 345, 26, 1, 0, 0, 0, 346, 347, 5, 34, 0, 0, 347, 348, 5, 86, 0, 0, 348, 349, 5, 101, 0, 0, 349, 350, 5, 114, 0, 0, 350, 351, 5, 115, 0, 0, 351, 352, 5, 105, 0, 0, 352, 353, 5, 111, 0, 0, 353, 354, 5, 110, 0, 0, 354, 355, 5, 34, 0, 0, 355, 28, 1, 0, 0, 0, 356, 357, 5, 34, 0, 0, 357, 358, 5, 84, 0, 0, 358, 359, 5, 121, 0, 0, 359, 360, 5, 112, 0, 0, 360, 361, 5, 101, 0, 0, 361, 362, 5, 34, 0, 0, 362, 30, 1, 0, 0, 0, 363, 364, 5, 34, 0, 0, 364, 365, 5, 84, 0, 0, 365, 366, 5, 97, 0, 0, 366, 367, 5, 115, 0, 0, 367, 368, 5, 107, 0, 0, 368, 369, 5, 34, 0, 0, 369, 32, 1, 0, 0, 0, 370, 371, 5, 34, 0, 0, 371, 372, 5, 67, 0, 0, 372, 373, 5, 104, 0, 0, 373, 374, 5, 111, 0, 0, 374, 375, 5, 105, 0, 0, 375, 376, 5, 99, 0, 0, 376, 377, 5, 101, 0, 0, 377, 378, 5, 34, 0, 0, 378, 34, 1, 0, 0, 0, 379, 380, 5, 34, 0, 0, 380, 381, 5, 70, 0, 0, 381, 382, 5, 97, 0, 0, 382, 383, 5, 105, 0, 0, 383, 384, 5, 108, 0, 0, 384, 385, 5, 34, 0, 0, 385, 36, 1, 0, 0, 0, 386, 387, 5, 34, 0, 0, 387, 388, 5, 83, 0, 0, 388, 389, 5, 117, 0, 0, 389, 390, 5, 99, 0, 0, 390, 391, 5, 99, 0, 0, 391, 392, 5, 101, 0, 0, 392, 393, 5, 101, 0, 0, 393, 394, 5, 100, 0, 0, 394, 395, 5, 34, 0, 0, 395, 38, 1, 0, 0, 0, 396, 397, 5, 34, 0, 0, 397, 398, 5, 80, 0, 0, 398, 399, 5, 97, 0, 0, 399, 400, 5, 115, 0, 0, 400, 401, 5, 115, 0, 0, 401, 402, 5, 34, 0, 0, 402, 40, 1, 0, 0, 0, 403, 404, 5, 34, 0, 0, 404, 405, 5, 87, 0, 0, 405, 406, 5, 97, 0, 0, 406, 407, 5, 105, 0, 0, 407, 408, 5, 116, 0, 0, 408, 409, 5, 34, 0, 0, 409, 42, 1, 0, 0, 0, 410, 411, 5, 34, 0, 0, 411, 412, 5, 80, 0, 0, 412, 413, 5, 97, 0, 0, 413, 414, 5, 114, 0, 0, 414, 415, 5, 97, 0, 0, 415, 416, 5, 108, 0, 0, 416, 417, 5, 108, 0, 0, 417, 418, 5, 101, 0, 0, 418, 419, 5, 108, 0, 0, 419, 420, 5, 34, 0, 0, 420, 44, 1, 0, 0, 0, 421, 422, 5, 34, 0, 0, 422, 423, 5, 77, 0, 0, 423, 424, 5, 97, 0, 0, 424, 425, 5, 112, 0, 0, 425, 426, 5, 34, 0, 0, 426, 46, 1, 0, 0, 0, 427, 428, 5, 34, 0, 0, 428, 429, 5, 67, 0, 0, 429, 430, 5, 104, 0, 0, 430, 431, 5, 111, 0, 0, 431, 432, 5, 105, 0, 0, 432, 433, 5, 99, 0, 0, 433, 434, 5, 101, 0, 0, 434, 435, 5, 115, 0, 0, 435, 436, 5, 34, 0, 0, 436, 48, 1, 0, 0, 0, 437, 438, 5, 34, 0, 0, 438, 439, 5, 86, 0, 0, 439, 440, 5, 97, 0, 0, 440, 441, 5, 114, 0, 0, 441, 442, 5, 105, 0, 0, 442, 443, 5, 97, 0, 0, 443, 444, 5, 98, 0, 0, 444, 445, 5, 108, 0, 0, 445, 446, 5, 101, 0, 0, 446, 447, 5, 34, 0, 0, 447, 50, 1, 0, 0, 0, 448, 449, 5, 34, 0, 0, 449, 450, 5, 68, 0, 0, 450, 451, 5, 101, 0, 0, 451, 452, 5, 102, 0, 0, 452, 453, 5, 97, 0, 0, 453, 454, 5, 117, 0, 0, 454, 455, 5, 108, 0, 0, 455, 456, 5, 116, 0, 0, 456, 457, 5, 34, 0, 0, 457, 52, 1, 0, 0, 0, 458, 459, 5, 34, 0, 0, 459, 460, 5, 66, 0, 0, 460, 461, 5, 114, 0, 0, 461, 462, 5, 97, 0, 0, 462, 463, 5, 110, 0, 0, 463, 464, 5, 99, 0, 0, 464, 465, 5, 104, 0, 0, 465, 466, 5, 101, 0, 0, 466, 467, 5, 115, 0, 0, 467, 468, 5, 34, 0, 0, 468, 54, 1, 0, 0, 0, 469, 470, 5, 34, 0, 0, 470, 471, 5, 65, 0, 0, 471, 472, 5, 110, 0, 0, 472, 473, 5, 100, 0, 0, 473, 474, 5, 34, 0, 0, 474, 56, 1, 0, 0, 0, 475, 476, 5, 34, 0, 0, 476, 477, 5, 66, 0, 0, 477, 478, 5, 111, 0, 0, 478, 479, 5, 111, 0, 0, 479, 480, 5, 108, 0, 0, 480, 481, 5, 101, 0, 0, 481, 482, 5, 97, 0, 0, 482, 483, 5, 110, 0, 0, 483, 484, 5, 69, 0, 0, 484, 485, 5, 113, 0, 0, 485, 486, 5, 117, 0, 0, 486, 487, 5, 97, 0, 0, 487, 488, 5, 108, 0, 0, 488, 489, 5, 115, 0, 0, 489, 490, 5, 34, 0, 0, 490, 58, 1, 0, 0, 0, 491, 492, 5, 34, 0, 0, 492, 493, 5, 66, 0, 0, 493, 494, 5, 111, 0, 0, 494, 495, 5, 111, 0, 0, 495, 496, 5, 108, 0, 0, 496, 497, 5, 101, 0, 0, 497, 498, 5, 97, 0, 0, 498, 499, 5, 110, 0, 0, 499, 500, 5, 69, 0, 0, 500, 501, 5, 113, 0, 0, 501, 502, 5, 117, 0, 0, 502, 503, 5, 97, 0, 0, 503, 504, 5, 108, 0, 0, 504, 505, 5, 115, 0, 0, 505, 506, 5, 80, 0, 0, 506, 507, 5, 97, 0, 0, 507, 508, 5, 116, 0, 0, 508, 509, 5, 104, 0, 0, 509, 510, 5, 34, 0, 0, 510, 60, 1, 0, 0, 0, 511, 512, 5, 34, 0, 0, 512, 513, 5, 73, 0, 0, 513, 514, 5, 115, 0, 0, 514, 515, 5, 66, 0, 0, 515, 516, 5, 111, 0, 0, 516, 517, 5, 111, 0, 0, 517, 518, 5, 108, 0, 0, 518, 519, 5, 101, 0, 0, 519, 520, 5, 97, 0, 0, 520, 521, 5, 110, 0, 0, 521, 522, 5, 34, 0, 0, 522, 62, 1, 0, 0, 0, 523, 524, 5, 34, 0, 0, 524, 525, 5, 73, 0, 0, 525, 526, 5, 115, 0, 0, 526, 527, 5, 78, 0, 0, 527, 528, 5, 117, 0, 0, 528, 529, 5, 108, 0, 0, 529, 530, 5, 108, 0, 0, 530, 531, 5, 34, 0, 0, 531, 64, 1, 0, 0, 0, 532, 533, 5, 34, 0, 0, 533, 534, 5, 73, 0, 0, 534, 535, 5, 115, 0, 0, 535, 536, 5, 78, 0, 0, 536, 537, 5, 117, 0, 0, 537, 538, 5, 109, 0, 0, 538, 539, 5, 101, 0, 0, 539, 540, 5, 114, 0, 0, 540, 541, 5, 105, 0, 0, 541, 542, 5, 99, 0, 0, 542, 543, 5, 34, 0, 0, 543, 66, 1, 0, 0, 0, 544, 545, 5, 34, 0, 0, 545, 546, 5, 73, 0, 0, 546, 547, 5, 115, 0, 0, 547, 548, 5, 80, 0, 0, 548, 549, 5, 114, 0, 0, 549, 550, 5, 101, 0, 0, 550, 551, 5, 115, 0, 0, 551, 552, 5, 101, 0, 0, 552, 553, 5, 110, 0, 0, 553, 554, 5, 116, 0, 0, 554, 555, 5, 34, 0, 0, 555, 68, 1, 0, 0, 0, 556, 557, 5, 34, 0, 0, 557, 558, 5, 73, 0, 0, 558, 559, 5, 115, 0, 0, 559, 560, 5, 83, 0, 0, 560, 561, 5, 116, 0, 0, 561, 562, 5, 114, 0, 0, 562, 563, 5, 105, 0, 0, 563, 564, 5, 110, 0, 0, 564, 565, 5, 103, 0, 0, 565, 566, 5, 34, 0, 0, 566, 70, 1, 0, 0, 0, 567, 568, 5, 34, 0, 0, 568, 569, 5, 73, 0, 0, 569, 570, 5, 115, 0, 0, 570, 571, 5, 84, 0, 0, 571, 572, 5, 105, 0, 0, 572, 573, 5, 109, 0, 0, 573, 574, 5, 101, 0, 0, 574, 575, 5, 115, 0, 0, 575, 576, 5, 116, 0, 0, 576, 577, 5, 97, 0, 0, 577, 578, 5, 109, 0, 0, 578, 579, 5, 112, 0, 0, 579, 580, 5, 34, 0, 0, 580, 72, 1, 0, 0, 0, 581, 582, 5, 34, 0, 0, 582, 583, 5, 78, 0, 0, 583, 584, 5, 111, 0, 0, 584, 585, 5, 116, 0, 0, 585, 586, 5, 34, 0, 0, 586, 74, 1, 0, 0, 0, 587, 588, 5, 34, 0, 0, 588, 589, 5, 78, 0, 0, 589, 590, 5, 117, 0, 0, 590, 591, 5, 109, 0, 0, 591, 592, 5, 101, 0, 0, 592, 593, 5, 114, 0, 0, 593, 594, 5, 105, 0, 0, 594, 595, 5, 99, 0, 0, 595, 596, 5, 69, 0, 0, 596, 597, 5, 113, 0, 0, 597, 598, 5, 117, 0, 0, 598, 599, 5, 97, 0, 0, 599, 600, 5, 108, 0, 0, 600, 601, 5, 115, 0, 0, 601, 602, 5, 34, 0, 0, 602, 76, 1, 0, 0, 0, 603, 604, 5, 34, 0, 0, 604, 605, 5, 78, 0, 0, 605, 606, 5, 117, 0, 0, 606, 607, 5, 109, 0, 0, 607, 608, 5, 101, 0, 0, 608, 609, 5, 114, 0, 0, 609, 610, 5, 105, 0, 0, 610, 611, 5, 99, 0, 0, 611, 612, 5, 69, 0, 0, 612, 613, 5, 113, 0, 0, 613, 614, 5, 117, 0, 0, 614, 615, 5, 97, 0, 0, 615, 616, 5, 108, 0, 0, 616, 617, 5, 115, 0, 0, 617, 618, 5, 80, 0, 0, 618, 619, 5, 97, 0, 0, 619, 620, 5, 116, 0, 0, 620, 621, 5, 104, 0, 0, 621, 622, 5, 34, 0, 0, 622, 78, 1, 0, 0, 0, 623, 624, 5, 34, 0, 0, 624, 625, 5, 78, 0, 0, 625, 626, 5, 117, 0, 0, 626, 627, 5, 109, 0, 0, 627, 628, 5, 101, 0, 0, 628, 629, 5, 114, 0, 0, 629, 630, 5, 105, 0, 0, 630, 631, 5, 99, 0, 0, 631, 632, 5, 71, 0, 0, 632, 633, 5, 114, 0, 0, 633, 634, 5, 101, 0, 0, 634, 635, 5, 97, 0, 0, 635, 636, 5, 116, 0, 0, 636, 637, 5, 101, 0, 0, 637, 638, 5, 114, 0, 0, 638, 639, 5, 84, 0, 0, 639, 640, 5, 104, 0, 0, 640, 641, 5, 97, 0, 0, 641, 642, 5, 110, 0, 0, 642, 643, 5, 34, 0, 0, 643, 80, 1, 0, 0, 0, 644, 645, 5, 34, 0, 0, 645, 646, 5, 78, 0, 0, 646, 647, 5, 117, 0, 0, 647, 648, 5, 109, 0, 0, 648, 649, 5, 101, 0, 0, 649, 650, 5, 114, 0, 0, 650, 651, 5, 105, 0, 0, 651, 652, 5, 99, 0, 0, 652, 653, 5, 71, 0, 0, 653, 654, 5, 114, 0, 0, 654, 655, 5, 101, 0, 0, 655, 656, 5, 97, 0, 0, 656, 657, 5, 116, 0, 0, 657, 658, 5, 101, 0, 0, 658, 659, 5, 114, 0, 0, 659, 660, 5, 84, 0, 0, 660, 661, 5, 104, 0, 0, 661, 662, 5, 97, 0, 0, 662, 663, 5, 110, 0, 0, 663, 664, 5, 80, 0, 0, 664, 665, 5, 97, 0, 0, 665, 666, 5, 116, 0, 0, 666, 667, 5, 104, 0, 0, 667, 668, 5, 34, 0, 0, 668, 82, 1, 0, 0, 0, 669, 670, 5, 34, 0, 0, 670, 671, 5, 78, 0, 0, 671, 672, 5, 117, 0, 0, 672, 673, 5, 109, 0, 0, 673, 674, 5, 101, 0, 0, 674, 675, 5, 114, 0, 0, 675, 676, 5, 105, 0, 0, 676, 677, 5, 99, 0, 0, 677, 678, 5, 71, 0, 0, 678, 679, 5, 114, 0, 0, 679, 680, 5, 101, 0, 0, 680, 681, 5, 97, 0, 0, 681, 682, 5, 116, 0, 0, 682, 683, 5, 101, 0, 0, 683, 684, 5, 114, 0, 0, 684, 685, 5, 84, 0, 0, 685, 686, 5, 104, 0, 0, 686, 687, 5, 97, 0, 0, 687, 688, 5, 110, 0, 0, 688, 689, 5, 69, 0, 0, 689, 690, 5, 113, 0, 0, 690, 691, 5, 117, 0, 0, 691, 692, 5, 97, 0, 0, 692, 693, 5, 108, 0, 0, 693, 694, 5, 115, 0, 0, 694, 695, 5, 34, 0, 0, 695, 84, 1, 0, 0, 0, 696, 697, 5, 34, 0, 0, 697, 698, 5, 78, 0, 0, 698, 699, 5, 117, 0, 0, 699, 700, 5, 109, 0, 0, 700, 701, 5, 101, 0, 0, 701, 702, 5, 114, 0, 0, 702, 703, 5, 105, 0, 0, 703, 704, 5, 99, 0, 0, 704, 705, 5, 71, 0, 0, 705, 706, 5, 114, 0, 0, 706, 707, 5, 101, 0, 0, 707, 708, 5, 97, 0, 0, 708, 709, 5, 116, 0, 0, 709, 710, 5, 101, 0, 0, 710, 711, 5, 114, 0, 0, 711, 712, 5, 84, 0, 0, 712, 713, 5, 104, 0, 0, 713, 714, 5, 97, 0, 0, 714, 715, 5, 110, 0, 0, 715, 716, 5, 69, 0, 0, 716, 717, 5, 113, 0, 0, 717, 718, 5, 117, 0, 0, 718, 719, 5, 97, 0, 0, 719, 720, 5, 108, 0, 0, 720, 721, 5, 115, 0, 0, 721, 722, 5, 80, 0, 0, 722, 723, 5, 97, 0, 0, 723, 724, 5, 116, 0, 0, 724, 725, 5, 104, 0, 0, 725, 726, 5, 34, 0, 0, 726, 86, 1, 0, 0, 0, 727, 728, 5, 34, 0, 0, 728, 729, 5, 78, 0, 0, 729, 730, 5, 117, 0, 0, 730, 731, 5, 109, 0, 0, 731, 732, 5, 101, 0, 0, 732, 733, 5, 114, 0, 0, 733, 734, 5, 105, 0, 0, 734, 735, 5, 99, 0, 0, 735, 736, 5, 76, 0, 0, 736, 737, 5, 101, 0, 0, 737, 738, 5, 115, 0, 0, 738, 739, 5, 115, 0, 0, 739, 740, 5, 84, 0, 0, 740, 741, 5, 104, 0, 0, 741, 742, 5, 97, 0, 0, 742, 743, 5, 110, 0, 0, 743, 744, 5, 34, 0, 0, 744, 88, 1, 0, 0, 0, 745, 746, 5, 34, 0, 0, 746, 747, 5, 78, 0, 0, 747, 748, 5, 117, 0, 0, 748, 749, 5, 109, 0, 0, 749, 750, 5, 101, 0, 0, 750, 751, 5, 114, 0, 0, 751, 752, 5, 105, 0, 0, 752, 753, 5, 99, 0, 0, 753, 754, 5, 76, 0, 0, 754, 755, 5, 101, 0, 0, 755, 756, 5, 115, 0, 0, 756, 757, 5, 115, 0, 0, 757, 758, 5, 84, 0, 0, 758, 759, 5, 104, 0, 0, 759, 760, 5, 97, 0, 0, 760, 761, 5, 110, 0, 0, 761, 762, 5, 80, 0, 0, 762, 763, 5, 97, 0, 0, 763, 764, 5, 116, 0, 0, 764, 765, 5, 104, 0, 0, 765, 766, 5, 34, 0, 0, 766, 90, 1, 0, 0, 0, 767, 768, 5, 34, 0, 0, 768, 769, 5, 78, 0, 0, 769, 770, 5, 117, 0, 0, 770, 771, 5, 109, 0, 0, 771, 772, 5, 101, 0, 0, 772, 773, 5, 114, 0, 0, 773, 774, 5, 105, 0, 0, 774, 775, 5, 99, 0, 0, 775, 776, 5, 76, 0, 0, 776, 777, 5, 101, 0, 0, 777, 778, 5, 115, 0, 0, 778, 779, 5, 115, 0, 0, 779, 780, 5, 84, 0, 0, 780, 781, 5, 104, 0, 0, 781, 782, 5, 97, 0, 0, 782, 783, 5, 110, 0, 0, 783, 784, 5, 69, 0, 0, 784, 785, 5, 113, 0, 0, 785, 786, 5, 117, 0, 0, 786, 787, 5, 97, 0, 0, 787, 788, 5, 108, 0, 0, 788, 789, 5, 115, 0, 0, 789, 790, 5, 34, 0, 0, 790, 92, 1, 0, 0, 0, 791, 792, 5, 34, 0, 0, 792, 793, 5, 78, 0, 0, 793, 794, 5, 117, 0, 0, 794, 795, 5, 109, 0, 0, 795, 796, 5, 101, 0, 0, 796, 797, 5, 114, 0, 0, 797, 798, 5, 105, 0, 0, 798, 799, 5, 99, 0, 0, 799, 800, 5, 76, 0, 0, 800, 801, 5, 101, 0, 0, 801, 802, 5, 115, 0, 0, 802, 803, 5, 115, 0, 0, 803, 804, 5, 84, 0, 0, 804, 805, 5, 104, 0, 0, 805, 806, 5, 97, 0, 0, 806, 807, 5, 110, 0, 0, 807, 808, 5, 69, 0, 0, 808, 809, 5, 113, 0, 0, 809, 810, 5, 117, 0, 0, 810, 811, 5, 97, 0, 0, 811, 812, 5, 108, 0, 0, 812, 813, 5, 115, 0, 0, 813, 814, 5, 80, 0, 0, 814, 815, 5, 97, 0, 0, 815, 816, 5, 116, 0, 0, 816, 817, 5, 104, 0, 0, 817, 818, 5, 34, 0, 0, 818, 94, 1, 0, 0, 0, 819, 820, 5, 34, 0, 0, 820, 821, 5, 79, 0, 0, 821, 822, 5, 114, 0, 0, 822, 823, 5, 34, 0, 0, 823, 96, 1, 0, 0, 0, 824, 825, 5, 34, 0, 0, 825, 826, 5, 83, 0, 0, 826, 827, 5, 116, 0, 0, 827, 828, 5, 114, 0, 0, 828, 829, 5, 105, 0, 0, 829, 830, 5, 110, 0, 0, 830, 831, 5, 103, 0, 0, 831, 832, 5, 69, 0, 0, 832, 833, 5, 113, 0, 0, 833, 834, 5, 117, 0, 0, 834, 835, 5, 97, 0, 0, 835, 836, 5, 108, 0, 0, 836, 837, 5, 115, 0, 0, 837, 838, 5, 34, 0, 0, 838, 98, 1, 0, 0, 0, 839, 840, 5, 34, 0, 0, 840, 841, 5, 83, 0, 0, 841, 842, 5, 116, 0, 0, 842, 843, 5, 114, 0, 0, 843, 844, 5, 105, 0, 0, 844, 845, 5, 110, 0, 0, 845, 846, 5, 103, 0, 0, 846, 847, 5, 69, 0, 0, 847, 848, 5, 113, 0, 0, 848, 849, 5, 117, 0, 0, 849, 850, 5, 97, 0, 0, 850, 851, 5, 108, 0, 0, 851, 852, 5, 115, 0, 0, 852, 853, 5, 80, 0, 0, 853, 854, 5, 97, 0, 0, 854, 855, 5, 116, 0, 0, 855, 856, 5, 104, 0, 0, 856, 857, 5, 34, 0, 0, 857, 100, 1, 0, 0, 0, 858, 859, 5, 34, 0, 0, 859, 860, 5, 83, 0, 0, 860, 861, 5, 116, 0, 0, 861, 862, 5, 114, 0, 0, 862, 863, 5, 105, 0, 0, 863, 864, 5, 110, 0, 0, 864, 865, 5, 103, 0, 0, 865, 866, 5, 71, 0, 0, 866, 867, 5, 114, 0, 0, 867, 868, 5, 101, 0, 0, 868, 869, 5, 97, 0, 0, 869, 870, 5, 116, 0, 0, 870, 871, 5, 101, 0, 0, 871, 872, 5, 114, 0, 0, 872, 873, 5, 84, 0, 0, 873, 874, 5, 104, 0, 0, 874, 875, 5, 97, 0, 0, 875, 876, 5, 110, 0, 0, 876, 877, 5, 34, 0, 0, 877, 102, 1, 0, 0, 0, 878, 879, 5, 34, 0, 0, 879, 880, 5, 83, 0, 0, 880, 881, 5, 116, 0, 0, 881, 882, 5, 114, 0, 0, 882, 883, 5, 105, 0, 0, 883, 884, 5, 110, 0, 0, 884, 885, 5, 103, 0, 0, 885, 886, 5, 71, 0, 0, 886, 887, 5, 114, 0, 0, 887, 888, 5, 101, 0, 0, 888, 889, 5, 97, 0, 0, 889, 890, 5, 116, 0, 0, 890, 891, 5, 101, 0, 0, 891, 892, 5, 114, 0, 0, 892, 893, 5, 84, 0, 0, 893, 894, 5, 104, 0, 0, 894, 895, 5, 97, 0, 0, 895, 896, 5, 110, 0, 0, 896, 897, 5, 80, 0, 0, 897, 898, 5, 97, 0, 0, 898, 899, 5, 116, 0, 0, 899, 900, 5, 104, 0, 0, 900, 901, 5, 34, 0, 0, 901, 104, 1, 0, 0, 0, 902, 903, 5, 34, 0, 0, 903, 904, 5, 83, 0, 0, 904, 905, 5, 116, 0, 0, 905, 906, 5, 114, 0, 0, 906, 907, 5, 105, 0, 0, 907, 908, 5, 110, 0, 0, 908, 909, 5, 103, 0, 0, 909, 910, 5, 71, 0, 0, 910, 911, 5, 114, 0, 0, 911, 912, 5, 101, 0, 0, 912, 913, 5, 97, 0, 0, 913, 914, 5, 116, 0, 0, 914, 915, 5, 101, 0, 0, 915, 916, 5, 114, 0, 0, 916, 917, 5, 84, 0, 0, 917, 918, 5, 104, 0, 0, 918, 919, 5, 97, 0, 0, 919, 920, 5, 110, 0, 0, 920, 921, 5, 69, 0, 0, 921, 922, 5, 113, 0, 0, 922, 923, 5, 117, 0, 0, 923, 924, 5, 97, 0, 0, 924, 925, 5, 108, 0, 0, 925, 926, 5, 115, 0, 0, 926, 927, 5, 34, 0, 0, 927, 106, 1, 0, 0, 0, 928, 929, 5, 34, 0, 0, 929, 930, 5, 83, 0, 0, 930, 931, 5, 116, 0, 0, 931, 932, 5, 114, 0, 0, 932, 933, 5, 105, 0, 0, 933, 934, 5, 110, 0, 0, 934, 935, 5, 103, 0, 0, 935, 936, 5, 71, 0, 0, 936, 937, 5, 114, 0, 0, 937, 938, 5, 101, 0, 0, 938, 939, 5, 97, 0, 0, 939, 940, 5, 116, 0, 0, 940, 941, 5, 101, 0, 0, 941, 942, 5, 114, 0, 0, 942, 943, 5, 84, 0, 0, 943, 944, 5, 104, 0, 0, 944, 945, 5, 97, 0, 0, 945, 946, 5, 110, 0, 0, 946, 947, 5, 69, 0, 0, 947, 948, 5, 113, 0, 0, 948, 949, 5, 117, 0, 0, 949, 950, 5, 97, 0, 0, 950, 951, 5, 108, 0, 0, 951, 952, 5, 115, 0, 0, 952, 953, 5, 80, 0, 0, 953, 954, 5, 97, 0, 0, 954, 955, 5, 116, 0, 0, 955, 956, 5, 104, 0, 0, 956, 957, 5, 34, 0, 0, 957, 108, 1, 0, 0, 0, 958, 959, 5, 34, 0, 0, 959, 960, 5, 83, 0, 0, 960, 961, 5, 116, 0, 0, 961, 962, 5, 114, 0, 0, 962, 963, 5, 105, 0, 0, 963, 964, 5, 110, 0, 0, 964, 965, 5, 103, 0, 0, 965, 966, 5, 76, 0, 0, 966, 967, 5, 101, 0, 0, 967, 968, 5, 115, 0, 0, 968, 969, 5, 115, 0, 0, 969, 970, 5, 84, 0, 0, 970, 971, 5, 104, 0, 0, 971, 972, 5, 97, 0, 0, 972, 973, 5, 110, 0, 0, 973, 974, 5, 34, 0, 0, 974, 110, 1, 0, 0, 0, 975, 976, 5, 34, 0, 0, 976, 977, 5, 83, 0, 0, 977, 978, 5, 116, 0, 0, 978, 979, 5, 114, 0, 0, 979, 980, 5, 105, 0, 0, 980, 981, 5, 110, 0, 0, 981, 982, 5, 103, 0, 0, 982, 983, 5, 76, 0, 0, 983, 984, 5, 101, 0, 0, 984, 985, 5, 115, 0, 0, 985, 986, 5, 115, 0, 0, 986, 987, 5, 84, 0, 0, 987, 988, 5, 104, 0, 0, 988, 989, 5, 97, 0, 0, 989, 990, 5, 110, 0, 0, 990, 991, 5, 80, 0, 0, 991, 992, 5, 97, 0, 0, 992, 993, 5, 116, 0, 0, 993, 994, 5, 104, 0, 0, 994, 995, 5, 34, 0, 0, 995, 112, 1, 0, 0, 0, 996, 997, 5, 34, 0, 0, 997, 998, 5, 83, 0, 0, 998, 999, 5, 116, 0, 0, 999, 1000, 5, 114, 0, 0, 1000, 1001, 5, 105, 0, 0, 1001, 1002, 5, 110, 0, 0, 1002, 1003, 5, 103, 0, 0, 1003, 1004, 5, 76, 0, 0, 1004, 1005, 5, 101, 0, 0, 1005, 1006, 5, 115, 0, 0, 1006, 1007, 5, 115, 0, 0, 1007, 1008, 5, 84, 0, 0, 1008, 1009, 5, 104, 0, 0, 1009, 1010, 5, 97, 0, 0, 1010, 1011, 5, 110, 0, 0, 1011, 1012, 5, 69, 0, 0, 1012, 1013, 5, 113, 0, 0, 1013, 1014, 5, 117, 0, 0, 1014, 1015, 5, 97, 0, 0, 1015, 1016, 5, 108, 0, 0, 1016, 1017, 5, 115, 0, 0, 1017, 1018, 5, 34, 0, 0, 1018, 114, 1, 0, 0, 0, 1019, 1020, 5, 34, 0, 0, 1020, 1021, 5, 83, 0, 0, 1021, 1022, 5, 116, 0, 0, 1022, 1023, 5, 114, 0, 0, 1023, 1024, 5, 105, 0, 0, 1024, 1025, 5, 110, 0, 0, 1025, 1026, 5, 103, 0, 0, 1026, 1027, 5, 76, 0, 0, 1027, 1028, 5, 101, 0, 0, 1028, 1029, 5, 115, 0, 0, 1029, 1030, 5, 115, 0, 0, 1030, 1031, 5, 84, 0, 0, 1031, 1032, 5, 104, 0, 0, 1032, 1033, 5, 97, 0, 0, 1033, 1034, 5, 110, 0, 0, 1034, 1035, 5, 69, 0, 0, 1035, 1036, 5, 113, 0, 0, 1036, 1037, 5, 117, 0, 0, 1037, 1038, 5, 97, 0, 0, 1038, 1039, 5, 108, 0, 0, 1039, 1040, 5, 115, 0, 0, 1040, 1041, 5, 80, 0, 0, 1041, 1042, 5, 97, 0, 0, 1042, 1043, 5, 116, 0, 0, 1043, 1044, 5, 104, 0, 0, 1044, 1045, 5, 34, 0, 0, 1045, 116, 1, 0, 0, 0, 1046, 1047, 5, 34, 0, 0, 1047, 1048, 5, 83, 0, 0, 1048, 1049, 5, 116, 0, 0, 1049, 1050, 5, 114, 0, 0, 1050, 1051, 5, 105, 0, 0, 1051, 1052, 5, 110, 0, 0, 1052, 1053, 5, 103, 0, 0, 1053, 1054, 5, 77, 0, 0, 1054, 1055, 5, 97, 0, 0, 1055, 1056, 5, 116, 0, 0, 1056, 1057, 5, 99, 0, 0, 1057, 1058, 5, 104, 0, 0, 1058, 1059, 5, 101, 0, 0, 1059, 1060, 5, 115, 0, 0, 1060, 1061, 5, 34, 0, 0, 1061, 118, 1, 0, 0, 0, 1062, 1063, 5, 34, 0, 0, 1063, 1064, 5, 84, 0, 0, 1064, 1065, 5, 105, 0, 0, 1065, 1066, 5, 109, 0, 0, 1066, 1067, 5, 101, 0, 0, 1067, 1068, 5, 115, 0, 0, 1068, 1069, 5, 116, 0, 0, 1069, 1070, 5, 97, 0, 0, 1070, 1071, 5, 109, 0, 0, 1071, 1072, 5, 112, 0, 0, 1072, 1073, 5, 69, 0, 0, 1073, 1074, 5, 113, 0, 0, 1074, 1075, 5, 117, 0, 0, 1075, 1076, 5, 97, 0, 0, 1076, 1077, 5, 108, 0, 0, 1077, 1078, 5, 115, 0, 0, 1078, 1079, 5, 34, 0, 0, 1079, 120, 1, 0, 0, 0, 1080, 1081, 5, 34, 0, 0, 1081, 1082, 5, 84, 0, 0, 1082, 1083, 5, 105, 0, 0, 1083, 1084, 5, 109, 0, 0, 1084, 1085, 5, 101, 0, 0, 1085, 1086, 5, 115, 0, 0, 1086, 1087, 5, 116, 0, 0, 1087, 1088, 5, 97, 0, 0, 1088, 1089, 5, 109, 0, 0, 1089, 1090, 5, 112, 0, 0, 1090, 1091, 5, 69, 0, 0, 1091, 1092, 5, 113, 0, 0, 1092, 1093, 5, 117, 0, 0, 1093, 1094, 5, 97, 0, 0, 1094, 1095, 5, 108, 0, 0, 1095, 1096, 5, 115, 0, 0, 1096, 1097, 5, 80, 0, 0, 1097, 1098, 5, 97, 0, 0, 1098, 1099, 5, 116, 0, 0, 1099, 1100, 5, 104, 0, 0, 1100, 1101, 5, 34, 0, 0, 1101, 122, 1, 0, 0, 0, 1102, 1103, 5, 34, 0, 0, 1103, 1104, 5, 84, 0, 0, 1104, 1105, 5, 105, 0, 0, 1105, 1106, 5, 109, 0, 0, 1106, 1107, 5, 101, 0, 0, 1107, 1108, 5, 115, 0, 0, 1108, 1109, 5, 116, 0, 0, 1109, 1110, 5, 97, 0, 0, 1110, 1111, 5, 109, 0, 0, 1111, 1112, 5, 112, 0, 0, 1112, 1113, 5, 71, 0, 0, 1113, 1114, 5, 114, 0, 0, 1114, 1115, 5, 101, 0, 0, 1115, 1116, 5, 97, 0, 0, 1116, 1117, 5, 116, 0, 0, 1117, 1118, 5, 101, 0, 0, 1118, 1119, 5, 114, 0, 0, 1119, 1120, 5, 84, 0, 0, 1120, 1121, 5, 104, 0, 0, 1121, 1122, 5, 97, 0, 0, 1122, 1123, 5, 110, 0, 0, 1123, 1124, 5, 34, 0, 0, 1124, 124, 1, 0, 0, 0, 1125, 1126, 5, 34, 0, 0, 1126, 1127, 5, 84, 0, 0, 1127, 1128, 5, 105, 0, 0, 1128, 1129, 5, 109, 0, 0, 1129, 1130, 5, 101, 0, 0, 1130, 1131, 5, 115, 0, 0, 1131, 1132, 5, 116, 0, 0, 1132, 1133, 5, 97, 0, 0, 1133, 1134, 5, 109, 0, 0, 1134, 1135, 5, 112, 0, 0, 1135, 1136, 5, 71, 0, 0, 1136, 1137, 5, 114, 0, 0, 1137, 1138, 5, 101, 0, 0, 1138, 1139, 5, 97, 0, 0, 1139, 1140, 5, 116, 0, 0, 1140, 1141, 5, 101, 0, 0, 1141, 1142, 5, 114, 0, 0, 1142, 1143, 5, 84, 0, 0, 1143, 1144, 5, 104, 0, 0, 1144, 1145, 5, 97, 0, 0, 1145, 1146, 5, 110, 0, 0, 1146, 1147, 5, 80, 0, 0, 1147, 1148, 5, 97, 0, 0, 1148, 1149, 5, 116, 0, 0, 1149, 1150, 5, 104, 0, 0, 1150, 1151, 5, 34, 0, 0, 1151, 126, 1, 0, 0, 0, 1152, 1153, 5, 34, 0, 0, 1153, 1154, 5, 84, 0, 0, 1154, 1155, 5, 105, 0, 0, 1155, 1156, 5, 109, 0, 0, 1156, 1157, 5, 101, 0, 0, 1157, 1158, 5, 115, 0, 0, 1158, 1159, 5, 116, 0, 0, 1159, 1160, 5, 97, 0, 0, 1160, 1161, 5, 109, 0, 0, 1161, 1162, 5, 112, 0, 0, 1162, 1163, 5, 71, 0, 0, 1163, 1164, 5, 114, 0, 0, 1164, 1165, 5, 101, 0, 0, 1165, 1166, 5, 97, 0, 0, 1166, 1167, 5, 116, 0, 0, 1167, 1168, 5, 101, 0, 0, 1168, 1169, 5, 114, 0, 0, 1169, 1170, 5, 84, 0, 0, 1170, 1171, 5, 104, 0, 0, 1171, 1172, 5, 97, 0, 0, 1172, 1173, 5, 110, 0, 0, 1173, 1174, 5, 69, 0, 0, 1174, 1175, 5, 113, 0, 0, 1175, 1176, 5, 117, 0, 0, 1176, 1177, 5, 97, 0, 0, 1177, 1178, 5, 108, 0, 0, 1178, 1179, 5, 115, 0, 0, 1179, 1180, 5, 34, 0, 0, 1180, 128, 1, 0, 0, 0, 1181, 1182, 5, 34, 0, 0, 1182, 1183, 5, 84, 0, 0, 1183, 1184, 5, 105, 0, 0, 1184, 1185, 5, 109, 0, 0, 1185, 1186, 5, 101, 0, 0, 1186, 1187, 5, 115, 0, 0, 1187, 1188, 5, 116, 0, 0, 1188, 1189, 5, 97, 0, 0, 1189, 1190, 5, 109, 0, 0, 1190, 1191, 5, 112, 0, 0, 1191, 1192, 5, 71, 0, 0, 1192, 1193, 5, 114, 0, 0, 1193, 1194, 5, 101, 0, 0, 1194, 1195, 5, 97, 0, 0, 1195, 1196, 5, 116, 0, 0, 1196, 1197, 5, 101, 0, 0, 1197, 1198, 5, 114, 0, 0, 1198, 1199, 5, 84, 0, 0, 1199, 1200, 5, 104, 0, 0, 1200, 1201, 5, 97, 0, 0, 1201, 1202, 5, 110, 0, 0, 1202, 1203, 5, 69, 0, 0, 1203, 1204, 5, 113, 0, 0, 1204, 1205, 5, 117, 0, 0, 1205, 1206, 5, 97, 0, 0, 1206, 1207, 5, 108, 0, 0, 1207, 1208, 5, 115, 0, 0, 1208, 1209, 5, 80, 0, 0, 1209, 1210, 5, 97, 0, 0, 1210, 1211, 5, 116, 0, 0, 1211, 1212, 5, 104, 0, 0, 1212, 1213, 5, 34, 0, 0, 1213, 130, 1, 0, 0, 0, 1214, 1215, 5, 34, 0, 0, 1215, 1216, 5, 84, 0, 0, 1216, 1217, 5, 105, 0, 0, 1217, 1218, 5, 109, 0, 0, 1218, 1219, 5, 101, 0, 0, 1219, 1220, 5, 115, 0, 0, 1220, 1221, 5, 116, 0, 0, 1221, 1222, 5, 97, 0, 0, 1222, 1223, 5, 109, 0, 0, 1223, 1224, 5, 112, 0, 0, 1224, 1225, 5, 76, 0, 0, 1225, 1226, 5, 101, 0, 0, 1226, 1227, 5, 115, 0, 0, 1227, 1228, 5, 115, 0, 0, 1228, 1229, 5, 84, 0, 0, 1229, 1230, 5, 104, 0, 0, 1230, 1231, 5, 97, 0, 0, 1231, 1232, 5, 110, 0, 0, 1232, 1233, 5, 34, 0, 0, 1233, 132, 1, 0, 0, 0, 1234, 1235, 5, 34, 0, 0, 1235, 1236, 5, 84, 0, 0, 1236, 1237, 5, 105, 0, 0, 1237, 1238, 5, 109, 0, 0, 1238, 1239, 5, 101, 0, 0, 1239, 1240, 5, 115, 0, 0, 1240, 1241, 5, 116, 0, 0, 1241, 1242, 5, 97, 0, 0, 1242, 1243, 5, 109, 0, 0, 1243, 1244, 5, 112, 0, 0, 1244, 1245, 5, 76, 0, 0, 1245, 1246, 5, 101, 0, 0, 1246, 1247, 5, 115, 0, 0, 1247, 1248, 5, 115, 0, 0, 1248, 1249, 5, 84, 0, 0, 1249, 1250, 5, 104, 0, 0, 1250, 1251, 5, 97, 0, 0, 1251, 1252, 5, 110, 0, 0, 1252, 1253, 5, 80, 0, 0, 1253, 1254, 5, 97, 0, 0, 1254, 1255, 5, 116, 0, 0, 1255, 1256, 5, 104, 0, 0, 1256, 1257, 5, 34, 0, 0, 1257, 134, 1, 0, 0, 0, 1258, 1259, 5, 34, 0, 0, 1259, 1260, 5, 84, 0, 0, 1260, 1261, 5, 105, 0, 0, 1261, 1262, 5, 109, 0, 0, 1262, 1263, 5, 101, 0, 0, 1263, 1264, 5, 115, 0, 0, 1264, 1265, 5, 116, 0, 0, 1265, 1266, 5, 97, 0, 0, 1266, 1267, 5, 109, 0, 0, 1267, 1268, 5, 112, 0, 0, 1268, 1269, 5, 76, 0, 0, 1269, 1270, 5, 101, 0, 0, 1270, 1271, 5, 115, 0, 0, 1271, 1272, 5, 115, 0, 0, 1272, 1273, 5, 84, 0, 0, 1273, 1274, 5, 104, 0, 0, 1274, 1275, 5, 97, 0, 0, 1275, 1276, 5, 110, 0, 0, 1276, 1277, 5, 69, 0, 0, 1277, 1278, 5, 113, 0, 0, 1278, 1279, 5, 117, 0, 0, 1279, 1280, 5, 97, 0, 0, 1280, 1281, 5, 108, 0, 0, 1281, 1282, 5, 115, 0, 0, 1282, 1283, 5, 34, 0, 0, 1283, 136, 1, 0, 0, 0, 1284, 1285, 5, 34, 0, 0, 1285, 1286, 5, 84, 0, 0, 1286, 1287, 5, 105, 0, 0, 1287, 1288, 5, 109, 0, 0, 1288, 1289, 5, 101, 0, 0, 1289, 1290, 5, 115, 0, 0, 1290, 1291, 5, 116, 0, 0, 1291, 1292, 5, 97, 0, 0, 1292, 1293, 5, 109, 0, 0, 1293, 1294, 5, 112, 0, 0, 1294, 1295, 5, 76, 0, 0, 1295, 1296, 5, 101, 0, 0, 1296, 1297, 5, 115, 0, 0, 1297, 1298, 5, 115, 0, 0, 1298, 1299, 5, 84, 0, 0, 1299, 1300, 5, 104, 0, 0, 1300, 1301, 5, 97, 0, 0, 1301, 1302, 5, 110, 0, 0, 1302, 1303, 5, 69, 0, 0, 1303, 1304, 5, 113, 0, 0, 1304, 1305, 5, 117, 0, 0, 1305, 1306, 5, 97, 0, 0, 1306, 1307, 5, 108, 0, 0, 1307, 1308, 5, 115, 0, 0, 1308, 1309, 5, 80, 0, 0, 1309, 1310, 5, 97, 0, 0, 1310, 1311, 5, 116, 0, 0, 1311, 1312, 5, 104, 0, 0, 1312, 1313, 5, 34, 0, 0, 1313, 138, 1, 0, 0, 0, 1314, 1315, 5, 34, 0, 0, 1315, 1316, 5, 83, 0, 0, 1316, 1317, 5, 101, 0, 0, 1317, 1318, 5, 99, 0, 0, 1318, 1319, 5, 111, 0, 0, 1319, 1320, 5, 110, 0, 0, 1320, 1321, 5, 100, 0, 0, 1321, 1322, 5, 115, 0, 0, 1322, 1323, 5, 80, 0, 0, 1323, 1324, 5, 97, 0, 0, 1324, 1325, 5, 116, 0, 0, 1325, 1326, 5, 104, 0, 0, 1326, 1327, 5, 34, 0, 0, 1327, 140, 1, 0, 0, 0, 1328, 1329, 5, 34, 0, 0, 1329, 1330, 5, 83, 0, 0, 1330, 1331, 5, 101, 0, 0, 1331, 1332, 5, 99, 0, 0, 1332, 1333, 5, 111, 0, 0, 1333, 1334, 5, 110, 0, 0, 1334, 1335, 5, 100, 0, 0, 1335, 1336, 5, 115, 0, 0, 1336, 1337, 5, 34, 0, 0, 1337, 142, 1, 0, 0, 0, 1338, 1339, 5, 34, 0, 0, 1339, 1340, 5, 84, 0, 0, 1340, 1341, 5, 105, 0, 0, 1341, 1342, 5, 109, 0, 0, 1342, 1343, 5, 101, 0, 0, 1343, 1344, 5, 115, 0, 0, 1344, 1345, 5, 116, 0, 0, 1345, 1346, 5, 97, 0, 0, 1346, 1347, 5, 109, 0, 0, 1347, 1348, 5, 112, 0, 0, 1348, 1349, 5, 80, 0, 0, 1349, 1350, 5, 97, 0, 0, 1350, 1351, 5, 116, 0, 0, 1351, 1352, 5, 104, 0, 0, 1352, 1353, 5, 34, 0, 0, 1353, 144, 1, 0, 0, 0, 1354, 1355, 5, 34, 0, 0, 1355, 1356, 5, 84, 0, 0, 1356, 1357, 5, 105, 0, 0, 1357, 1358, 5, 109, 0, 0, 1358, 1359, 5, 101, 0, 0, 1359, 1360, 5, 115, 0, 0, 1360, 1361, 5, 116, 0, 0, 1361, 1362, 5, 97, 0, 0, 1362, 1363, 5, 109, 0, 0, 1363, 1364, 5, 112, 0, 0, 1364, 1365, 5, 34, 0, 0, 1365, 146, 1, 0, 0, 0, 1366, 1367, 5, 34, 0, 0, 1367, 1368, 5, 84, 0, 0, 1368, 1369, 5, 105, 0, 0, 1369, 1370, 5, 109, 0, 0, 1370, 1371, 5, 101, 0, 0, 1371, 1372, 5, 111, 0, 0, 1372, 1373, 5, 117, 0, 0, 1373, 1374, 5, 116, 0, 0, 1374, 1375, 5, 83, 0, 0, 1375, 1376, 5, 101, 0, 0, 1376, 1377, 5, 99, 0, 0, 1377, 1378, 5, 111, 0, 0, 1378, 1379, 5, 110, 0, 0, 1379, 1380, 5, 100, 0, 0, 1380, 1381, 5, 115, 0, 0, 1381, 1382, 5, 34, 0, 0, 1382, 148, 1, 0, 0, 0, 1383, 1384, 5, 34, 0, 0, 1384, 1385, 5, 84, 0, 0, 1385, 1386, 5, 105, 0, 0, 1386, 1387, 5, 109, 0, 0, 1387, 1388, 5, 101, 0, 0, 1388, 1389, 5, 111, 0, 0, 1389, 1390, 5, 117, 0, 0, 1390, 1391, 5, 116, 0, 0, 1391, 1392, 5, 83, 0, 0, 1392, 1393, 5, 101, 0, 0, 1393, 1394, 5, 99, 0, 0, 1394, 1395, 5, 111, 0, 0, 1395, 1396, 5, 110, 0, 0, 1396, 1397, 5, 100, 0, 0, 1397, 1398, 5, 115, 0, 0, 1398, 1399, 5, 80, 0, 0, 1399, 1400, 5, 97, 0, 0, 1400, 1401, 5, 116, 0, 0, 1401, 1402, 5, 104, 0, 0, 1402, 1403, 5, 34, 0, 0, 1403, 150, 1, 0, 0, 0, 1404, 1405, 5, 34, 0, 0, 1405, 1406, 5, 72, 0, 0, 1406, 1407, 5, 101, 0, 0, 1407, 1408, 5, 97, 0, 0, 1408, 1409, 5, 114, 0, 0, 1409, 1410, 5, 116, 0, 0, 1410, 1411, 5, 98, 0, 0, 1411, 1412, 5, 101, 0, 0, 1412, 1413, 5, 97, 0, 0, 1413, 1414, 5, 116, 0, 0, 1414, 1415, 5, 83, 0, 0, 1415, 1416, 5, 101, 0, 0, 1416, 1417, 5, 99, 0, 0, 1417, 1418, 5, 111, 0, 0, 1418, 1419, 5, 110, 0, 0, 1419, 1420, 5, 100, 0, 0, 1420, 1421, 5, 115, 0, 0, 1421, 1422, 5, 34, 0, 0, 1422, 152, 1, 0, 0, 0, 1423, 1424, 5, 34, 0, 0, 1424, 1425, 5, 72, 0, 0, 1425, 1426, 5, 101, 0, 0, 1426, 1427, 5, 97, 0, 0, 1427, 1428, 5, 114, 0, 0, 1428, 1429, 5, 116, 0, 0, 1429, 1430, 5, 98, 0, 0, 1430, 1431, 5, 101, 0, 0, 1431, 1432, 5, 97, 0, 0, 1432, 1433, 5, 116, 0, 0, 1433, 1434, 5, 83, 0, 0, 1434, 1435, 5, 101, 0, 0, 1435, 1436, 5, 99, 0, 0, 1436, 1437, 5, 111, 0, 0, 1437, 1438, 5, 110, 0, 0, 1438, 1439, 5, 100, 0, 0, 1439, 1440, 5, 115, 0, 0, 1440, 1441, 5, 80, 0, 0, 1441, 1442, 5, 97, 0, 0, 1442, 1443, 5, 116, 0, 0, 1443, 1444, 5, 104, 0, 0, 1444, 1445, 5, 34, 0, 0, 1445, 154, 1, 0, 0, 0, 1446, 1447, 5, 34, 0, 0, 1447, 1448, 5, 80, 0, 0, 1448, 1449, 5, 114, 0, 0, 1449, 1450, 5, 111, 0, 0, 1450, 1451, 5, 99, 0, 0, 1451, 1452, 5, 101, 0, 0, 1452, 1453, 5, 115, 0, 0, 1453, 1454, 5, 115, 0, 0, 1454, 1455, 5, 111, 0, 0, 1455, 1456, 5, 114, 0, 0, 1456, 1457, 5, 67, 0, 0, 1457, 1458, 5, 111, 0, 0, 1458, 1459, 5, 110, 0, 0, 1459, 1460, 5, 102, 0, 0, 1460, 1461, 5, 105, 0, 0, 1461, 1462, 5, 103, 0, 0, 1462, 1463, 5, 34, 0, 0, 1463, 156, 1, 0, 0, 0, 1464, 1465, 5, 34, 0, 0, 1465, 1466, 5, 77, 0, 0, 1466, 1467, 5, 111, 0, 0, 1467, 1468, 5, 100, 0, 0, 1468, 1469, 5, 101, 0, 0, 1469, 1470, 5, 34, 0, 0, 1470, 158, 1, 0, 0, 0, 1471, 1472, 5, 34, 0, 0, 1472, 1473, 5, 73, 0, 0, 1473, 1474, 5, 78, 0, 0, 1474, 1475, 5, 76, 0, 0, 1475, 1476, 5, 73, 0, 0, 1476, 1477, 5, 78, 0, 0, 1477, 1478, 5, 69, 0, 0, 1478, 1479, 5, 34, 0, 0, 1479, 160, 1, 0, 0, 0, 1480, 1481, 5, 34, 0, 0, 1481, 1482, 5, 68, 0, 0, 1482, 1483, 5, 73, 0, 0, 1483, 1484, 5, 83, 0, 0, 1484, 1485, 5, 84, 0, 0, 1485, 1486, 5, 82, 0, 0, 1486, 1487, 5, 73, 0, 0, 1487, 1488, 5, 66, 0, 0, 1488, 1489, 5, 85, 0, 0, 1489, 1490, 5, 84, 0, 0, 1490, 1491, 5, 69, 0, 0, 1491, 1492, 5, 68, 0, 0, 1492, 1493, 5, 34, 0, 0, 1493, 162, 1, 0, 0, 0, 1494, 1495, 5, 34, 0, 0, 1495, 1496, 5, 69, 0, 0, 1496, 1497, 5, 120, 0, 0, 1497, 1498, 5, 101, 0, 0, 1498, 1499, 5, 99, 0, 0, 1499, 1500, 5, 117, 0, 0, 1500, 1501, 5, 116, 0, 0, 1501, 1502, 5, 105, 0, 0, 1502, 1503, 5, 111, 0, 0, 1503, 1504, 5, 110, 0, 0, 1504, 1505, 5, 84, 0, 0, 1505, 1506, 5, 121, 0, 0, 1506, 1507, 5, 112, 0, 0, 1507, 1508, 5, 101, 0, 0, 1508, 1509, 5, 34, 0, 0, 1509, 164, 1, 0, 0, 0, 1510, 1511, 5, 34, 0, 0, 1511, 1512, 5, 83, 0, 0, 1512, 1513, 5, 84, 0, 0, 1513, 1514, 5, 65, 0, 0, 1514, 1515, 5, 78, 0, 0, 1515, 1516, 5, 68, 0, 0, 1516, 1517, 5, 65, 0, 0, 1517, 1518, 5, 82, 0, 0, 1518, 1519, 5, 68, 0, 0, 1519, 1520, 5, 34, 0, 0, 1520, 166, 1, 0, 0, 0, 1521, 1522, 5, 34, 0, 0, 1522, 1523, 5, 73, 0, 0, 1523, 1524, 5, 116, 0, 0, 1524, 1525, 5, 101, 0, 0, 1525, 1526, 5, 109, 0, 0, 1526, 1527, 5, 80, 0, 0, 1527, 1528, 5, 114, 0, 0, 1528, 1529, 5, 111, 0, 0, 1529, 1530, 5, 99, 0, 0, 1530, 1531, 5, 101, 0, 0, 1531, 1532, 5, 115, 0, 0, 1532, 1533, 5, 115, 0, 0, 1533, 1534, 5, 111, 0, 0, 1534, 1535, 5, 114, 0, 0, 1535, 1536, 5, 34, 0, 0, 1536, 168, 1, 0, 0, 0, 1537, 1538, 5, 34, 0, 0, 1538, 1539, 5, 73, 0, 0, 1539, 1540, 5, 116, 0, 0, 1540, 1541, 5, 101, 0, 0, 1541, 1542, 5, 114, 0, 0, 1542, 1543, 5, 97, 0, 0, 1543, 1544, 5, 116, 0, 0, 1544, 1545, 5, 111, 0, 0, 1545, 1546, 5, 114, 0, 0, 1546, 1547, 5, 34, 0, 0, 1547, 170, 1, 0, 0, 0, 1548, 1549, 5, 34, 0, 0, 1549, 1550, 5, 73, 0, 0, 1550, 1551, 5, 116, 0, 0, 1551, 1552, 5, 101, 0, 0, 1552, 1553, 5, 109, 0, 0, 1553, 1554, 5, 83, 0, 0, 1554, 1555, 5, 101, 0, 0, 1555, 1556, 5, 108, 0, 0, 1556, 1557, 5, 101, 0, 0, 1557, 1558, 5, 99, 0, 0, 1558, 1559, 5, 116, 0, 0, 1559, 1560, 5, 111, 0, 0, 1560, 1561, 5, 114, 0, 0, 1561, 1562, 5, 34, 0, 0, 1562, 172, 1, 0, 0, 0, 1563, 1564, 5, 34, 0, 0, 1564, 1565, 5, 77, 0, 0, 1565, 1566, 5, 97, 0, 0, 1566, 1567, 5, 120, 0, 0, 1567, 1568, 5, 67, 0, 0, 1568, 1569, 5, 111, 0, 0, 1569, 1570, 5, 110, 0, 0, 1570, 1571, 5, 99, 0, 0, 1571, 1572, 5, 117, 0, 0, 1572, 1573, 5, 114, 0, 0, 1573, 1574, 5, 114, 0, 0, 1574, 1575, 5, 101, 0, 0, 1575, 1576, 5, 110, 0, 0, 1576, 1577, 5, 99, 0, 0, 1577, 1578, 5, 121, 0, 0, 1578, 1579, 5, 34, 0, 0, 1579, 174, 1, 0, 0, 0, 1580, 1581, 5, 34, 0, 0, 1581, 1582, 5, 82, 0, 0, 1582, 1583, 5, 101, 0, 0, 1583, 1584, 5, 115, 0, 0, 1584, 1585, 5, 111, 0, 0, 1585, 1586, 5, 117, 0, 0, 1586, 1587, 5, 114, 0, 0, 1587, 1588, 5, 99, 0, 0, 1588, 1589, 5, 101, 0, 0, 1589, 1590, 5, 34, 0, 0, 1590, 176, 1, 0, 0, 0, 1591, 1592, 5, 34, 0, 0, 1592, 1593, 5, 73, 0, 0, 1593, 1594, 5, 110, 0, 0, 1594, 1595, 5, 112, 0, 0, 1595, 1596, 5, 117, 0, 0, 1596, 1597, 5, 116, 0, 0, 1597, 1598, 5, 80, 0, 0, 1598, 1599, 5, 97, 0, 0, 1599, 1600, 5, 116, 0, 0, 1600, 1601, 5, 104, 0, 0, 1601, 1602, 5, 34, 0, 0, 1602, 178, 1, 0, 0, 0, 1603, 1604, 5, 34, 0, 0, 1604, 1605, 5, 79, 0, 0, 1605, 1606, 5, 117, 0, 0, 1606, 1607, 5, 116, 0, 0, 1607, 1608, 5, 112, 0, 0, 1608, 1609, 5, 117, 0, 0, 1609, 1610, 5, 116, 0, 0, 1610, 1611, 5, 80, 0, 0, 1611, 1612, 5, 97, 0, 0, 1612, 1613, 5, 116, 0, 0, 1613, 1614, 5, 104, 0, 0, 1614, 1615, 5, 34, 0, 0, 1615, 180, 1, 0, 0, 0, 1616, 1617, 5, 34, 0, 0, 1617, 1618, 5, 73, 0, 0, 1618, 1619, 5, 116, 0, 0, 1619, 1620, 5, 101, 0, 0, 1620, 1621, 5, 109, 0, 0, 1621, 1622, 5, 115, 0, 0, 1622, 1623, 5, 80, 0, 0, 1623, 1624, 5, 97, 0, 0, 1624, 1625, 5, 116, 0, 0, 1625, 1626, 5, 104, 0, 0, 1626, 1627, 5, 34, 0, 0, 1627, 182, 1, 0, 0, 0, 1628, 1629, 5, 34, 0, 0, 1629, 1630, 5, 82, 0, 0, 1630, 1631, 5, 101, 0, 0, 1631, 1632, 5, 115, 0, 0, 1632, 1633, 5, 117, 0, 0, 1633, 1634, 5, 108, 0, 0, 1634, 1635, 5, 116, 0, 0, 1635, 1636, 5, 80, 0, 0, 1636, 1637, 5, 97, 0, 0, 1637, 1638, 5, 116, 0, 0, 1638, 1639, 5, 104, 0, 0, 1639, 1640, 5, 34, 0, 0, 1640, 184, 1, 0, 0, 0, 1641, 1642, 5, 34, 0, 0, 1642, 1643, 5, 82, 0, 0, 1643, 1644, 5, 101, 0, 0, 1644, 1645, 5, 115, 0, 0, 1645, 1646, 5, 117, 0, 0, 1646, 1647, 5, 108, 0, 0, 1647, 1648, 5, 116, 0, 0, 1648, 1649, 5, 34, 0, 0, 1649, 186, 1, 0, 0, 0, 1650, 1651, 5, 34, 0, 0, 1651, 1652, 5, 80, 0, 0, 1652, 1653, 5, 97, 0, 0, 1653, 1654, 5, 114, 0, 0, 1654, 1655, 5, 97, 0, 0, 1655, 1656, 5, 109, 0, 0, 1656, 1657, 5, 101, 0, 0, 1657, 1658, 5, 116, 0, 0, 1658, 1659, 5, 101, 0, 0, 1659, 1660, 5, 114, 0, 0, 1660, 1661, 5, 115, 0, 0, 1661, 1662, 5, 34, 0, 0, 1662, 188, 1, 0, 0, 0, 1663, 1664, 5, 34, 0, 0, 1664, 1665, 5, 82, 0, 0, 1665, 1666, 5, 101, 0, 0, 1666, 1667, 5, 115, 0, 0, 1667, 1668, 5, 117, 0, 0, 1668, 1669, 5, 108, 0, 0, 1669, 1670, 5, 116, 0, 0, 1670, 1671, 5, 83, 0, 0, 1671, 1672, 5, 101, 0, 0, 1672, 1673, 5, 108, 0, 0, 1673, 1674, 5, 101, 0, 0, 1674, 1675, 5, 99, 0, 0, 1675, 1676, 5, 116, 0, 0, 1676, 1677, 5, 111, 0, 0, 1677, 1678, 5, 114, 0, 0, 1678, 1679, 5, 34, 0, 0, 1679, 190, 1, 0, 0, 0, 1680, 1681, 5, 34, 0, 0, 1681, 1682, 5, 73, 0, 0, 1682, 1683, 5, 116, 0, 0, 1683, 1684, 5, 101, 0, 0, 1684, 1685, 5, 109, 0, 0, 1685, 1686, 5, 82, 0, 0, 1686, 1687, 5, 101, 0, 0, 1687, 1688, 5, 97, 0, 0, 1688, 1689, 5, 100, 0, 0, 1689, 1690, 5, 101, 0, 0, 1690, 1691, 5, 114, 0, 0, 1691, 1692, 5, 34, 0, 0, 1692, 192, 1, 0, 0, 0, 1693, 1694, 5, 34, 0, 0, 1694, 1695, 5, 82, 0, 0, 1695, 1696, 5, 101, 0, 0, 1696, 1697, 5, 97, 0, 0, 1697, 1698, 5, 100, 0, 0, 1698, 1699, 5, 101, 0, 0, 1699, 1700, 5, 114, 0, 0, 1700, 1701, 5, 67, 0, 0, 1701, 1702, 5, 111, 0, 0, 1702, 1703, 5, 110, 0, 0, 1703, 1704, 5, 102, 0, 0, 1704, 1705, 5, 105, 0, 0, 1705, 1706, 5, 103, 0, 0, 1706, 1707, 5, 34, 0, 0, 1707, 194, 1, 0, 0, 0, 1708, 1709, 5, 34, 0, 0, 1709, 1710, 5, 73, 0, 0, 1710, 1711, 5, 110, 0, 0, 1711, 1712, 5, 112, 0, 0, 1712, 1713, 5, 117, 0, 0, 1713, 1714, 5, 116, 0, 0, 1714, 1715, 5, 84, 0, 0, 1715, 1716, 5, 121, 0, 0, 1716, 1717, 5, 112, 0, 0, 1717, 1718, 5, 101, 0, 0, 1718, 1719, 5, 34, 0, 0, 1719, 196, 1, 0, 0, 0, 1720, 1721, 5, 34, 0, 0, 1721, 1722, 5, 67, 0, 0, 1722, 1723, 5, 83, 0, 0, 1723, 1724, 5, 86, 0, 0, 1724, 1725, 5, 72, 0, 0, 1725, 1726, 5, 101, 0, 0, 1726, 1727, 5, 97, 0, 0, 1727, 1728, 5, 100, 0, 0, 1728, 1729, 5, 101, 0, 0, 1729, 1730, 5, 114, 0, 0, 1730, 1731, 5, 76, 0, 0, 1731, 1732, 5, 111, 0, 0, 1732, 1733, 5, 99, 0, 0, 1733, 1734, 5, 97, 0, 0, 1734, 1735, 5, 116, 0, 0, 1735, 1736, 5, 105, 0, 0, 1736, 1737, 5, 111, 0, 0, 1737, 1738, 5, 110, 0, 0, 1738, 1739, 5, 34, 0, 0, 1739, 198, 1, 0, 0, 0, 1740, 1741, 5, 34, 0, 0, 1741, 1742, 5, 67, 0, 0, 1742, 1743, 5, 83, 0, 0, 1743, 1744, 5, 86, 0, 0, 1744, 1745, 5, 72, 0, 0, 1745, 1746, 5, 101, 0, 0, 1746, 1747, 5, 97, 0, 0, 1747, 1748, 5, 100, 0, 0, 1748, 1749, 5, 101, 0, 0, 1749, 1750, 5, 114, 0, 0, 1750, 1751, 5, 115, 0, 0, 1751, 1752, 5, 34, 0, 0, 1752, 200, 1, 0, 0, 0, 1753, 1754, 5, 34, 0, 0, 1754, 1755, 5, 77, 0, 0, 1755, 1756, 5, 97, 0, 0, 1756, 1757, 5, 120, 0, 0, 1757, 1758, 5, 73, 0, 0, 1758, 1759, 5, 116, 0, 0, 1759, 1760, 5, 101, 0, 0, 1760, 1761, 5, 109, 0, 0, 1761, 1762, 5, 115, 0, 0, 1762, 1763, 5, 34, 0, 0, 1763, 202, 1, 0, 0, 0, 1764, 1765, 5, 34, 0, 0, 1765, 1766, 5, 77, 0, 0, 1766, 1767, 5, 97, 0, 0, 1767, 1768, 5, 120, 0, 0, 1768, 1769, 5, 73, 0, 0, 1769, 1770, 5, 116, 0, 0, 1770, 1771, 5, 101, 0, 0, 1771, 1772, 5, 109, 0, 0, 1772, 1773, 5, 115, 0, 0, 1773, 1774, 5, 80, 0, 0, 1774, 1775, 5, 97, 0, 0, 1775, 1776, 5, 116, 0, 0, 1776, 1777, 5, 104, 0, 0, 1777, 1778, 5, 34, 0, 0, 1778, 204, 1, 0, 0, 0, 1779, 1780, 5, 34, 0, 0, 1780, 1781, 5, 78, 0, 0, 1781, 1782, 5, 101, 0, 0, 1782, 1783, 5, 120, 0, 0, 1783, 1784, 5, 116, 0, 0, 1784, 1785, 5, 34, 0, 0, 1785, 206, 1, 0, 0, 0, 1786, 1787, 5, 34, 0, 0, 1787, 1788, 5, 69, 0, 0, 1788, 1789, 5, 110, 0, 0, 1789, 1790, 5, 100, 0, 0, 1790, 1791, 5, 34, 0, 0, 1791, 208, 1, 0, 0, 0, 1792, 1793, 5, 34, 0, 0, 1793, 1794, 5, 67, 0, 0, 1794, 1795, 5, 97, 0, 0, 1795, 1796, 5, 117, 0, 0, 1796, 1797, 5, 115, 0, 0, 1797, 1798, 5, 101, 0, 0, 1798, 1799, 5, 34, 0, 0, 1799, 210, 1, 0, 0, 0, 1800, 1801, 5, 34, 0, 0, 1801, 1802, 5, 69, 0, 0, 1802, 1803, 5, 114, 0, 0, 1803, 1804, 5, 114, 0, 0, 1804, 1805, 5, 111, 0, 0, 1805, 1806, 5, 114, 0, 0, 1806, 1807, 5, 34, 0, 0, 1807, 212, 1, 0, 0, 0, 1808, 1809, 5, 34, 0, 0, 1809, 1810, 5, 82, 0, 0, 1810, 1811, 5, 101, 0, 0, 1811, 1812, 5, 116, 0, 0, 1812, 1813, 5, 114, 0, 0, 1813, 1814, 5, 121, 0, 0, 1814, 1815, 5, 34, 0, 0, 1815, 214, 1, 0, 0, 0, 1816, 1817, 5, 34, 0, 0, 1817, 1818, 5, 69, 0, 0, 1818, 1819, 5, 114, 0, 0, 1819, 1820, 5, 114, 0, 0, 1820, 1821, 5, 111, 0, 0, 1821, 1822, 5, 114, 0, 0, 1822, 1823, 5, 69, 0, 0, 1823, 1824, 5, 113, 0, 0, 1824, 1825, 5, 117, 0, 0, 1825, 1826, 5, 97, 0, 0, 1826, 1827, 5, 108, 0, 0, 1827, 1828, 5, 115, 0, 0, 1828, 1829, 5, 34, 0, 0, 1829, 216, 1, 0, 0, 0, 1830, 1831, 5, 34, 0, 0, 1831, 1832, 5, 73, 0, 0, 1832, 1833, 5, 110, 0, 0, 1833, 1834, 5, 116, 0, 0, 1834, 1835, 5, 101, 0, 0, 1835, 1836, 5, 114, 0, 0, 1836, 1837, 5, 118, 0, 0, 1837, 1838, 5, 97, 0, 0, 1838, 1839, 5, 108, 0, 0, 1839, 1840, 5, 83, 0, 0, 1840, 1841, 5, 101, 0, 0, 1841, 1842, 5, 99, 0, 0, 1842, 1843, 5, 111, 0, 0, 1843, 1844, 5, 110, 0, 0, 1844, 1845, 5, 100, 0, 0, 1845, 1846, 5, 115, 0, 0, 1846, 1847, 5, 34, 0, 0, 1847, 218, 1, 0, 0, 0, 1848, 1849, 5, 34, 0, 0, 1849, 1850, 5, 77, 0, 0, 1850, 1851, 5, 97, 0, 0, 1851, 1852, 5, 120, 0, 0, 1852, 1853, 5, 65, 0, 0, 1853, 1854, 5, 116, 0, 0, 1854, 1855, 5, 116, 0, 0, 1855, 1856, 5, 101, 0, 0, 1856, 1857, 5, 109, 0, 0, 1857, 1858, 5, 112, 0, 0, 1858, 1859, 5, 116, 0, 0, 1859, 1860, 5, 115, 0, 0, 1860, 1861, 5, 34, 0, 0, 1861, 220, 1, 0, 0, 0, 1862, 1863, 5, 34, 0, 0, 1863, 1864, 5, 66, 0, 0, 1864, 1865, 5, 97, 0, 0, 1865, 1866, 5, 99, 0, 0, 1866, 1867, 5, 107, 0, 0, 1867, 1868, 5, 111, 0, 0, 1868, 1869, 5, 102, 0, 0, 1869, 1870, 5, 102, 0, 0, 1870, 1871, 5, 82, 0, 0, 1871, 1872, 5, 97, 0, 0, 1872, 1873, 5, 116, 0, 0, 1873, 1874, 5, 101, 0, 0, 1874, 1875, 5, 34, 0, 0, 1875, 222, 1, 0, 0, 0, 1876, 1877, 5, 34, 0, 0, 1877, 1878, 5, 67, 0, 0, 1878, 1879, 5, 97, 0, 0, 1879, 1880, 5, 116, 0, 0, 1880, 1881, 5, 99, 0, 0, 1881, 1882, 5, 104, 0, 0, 1882, 1883, 5, 34, 0, 0, 1883, 224, 1, 0, 0, 0, 1884, 1885, 5, 34, 0, 0, 1885, 1886, 5, 83, 0, 0, 1886, 1887, 5, 116, 0, 0, 1887, 1888, 5, 97, 0, 0, 1888, 1889, 5, 116, 0, 0, 1889, 1890, 5, 101, 0, 0, 1890, 1891, 5, 115, 0, 0, 1891, 1892, 5, 46, 0, 0, 1892, 1893, 5, 65, 0, 0, 1893, 1894, 5, 76, 0, 0, 1894, 1895, 5, 76, 0, 0, 1895, 1896, 5, 34, 0, 0, 1896, 226, 1, 0, 0, 0, 1897, 1898, 5, 34, 0, 0, 1898, 1899, 5, 83, 0, 0, 1899, 1900, 5, 116, 0, 0, 1900, 1901, 5, 97, 0, 0, 1901, 1902, 5, 116, 0, 0, 1902, 1903, 5, 101, 0, 0, 1903, 1904, 5, 115, 0, 0, 1904, 1905, 5, 46, 0, 0, 1905, 1906, 5, 72, 0, 0, 1906, 1907, 5, 101, 0, 0, 1907, 1908, 5, 97, 0, 0, 1908, 1909, 5, 114, 0, 0, 1909, 1910, 5, 116, 0, 0, 1910, 1911, 5, 98, 0, 0, 1911, 1912, 5, 101, 0, 0, 1912, 1913, 5, 97, 0, 0, 1913, 1914, 5, 116, 0, 0, 1914, 1915, 5, 84, 0, 0, 1915, 1916, 5, 105, 0, 0, 1916, 1917, 5, 109, 0, 0, 1917, 1918, 5, 101, 0, 0, 1918, 1919, 5, 111, 0, 0, 1919, 1920, 5, 117, 0, 0, 1920, 1921, 5, 116, 0, 0, 1921, 1922, 5, 34, 0, 0, 1922, 228, 1, 0, 0, 0, 1923, 1924, 5, 34, 0, 0, 1924, 1925, 5, 83, 0, 0, 1925, 1926, 5, 116, 0, 0, 1926, 1927, 5, 97, 0, 0, 1927, 1928, 5, 116, 0, 0, 1928, 1929, 5, 101, 0, 0, 1929, 1930, 5, 115, 0, 0, 1930, 1931, 5, 46, 0, 0, 1931, 1932, 5, 84, 0, 0, 1932, 1933, 5, 105, 0, 0, 1933, 1934, 5, 109, 0, 0, 1934, 1935, 5, 101, 0, 0, 1935, 1936, 5, 111, 0, 0, 1936, 1937, 5, 117, 0, 0, 1937, 1938, 5, 116, 0, 0, 1938, 1939, 5, 34, 0, 0, 1939, 230, 1, 0, 0, 0, 1940, 1941, 5, 34, 0, 0, 1941, 1942, 5, 83, 0, 0, 1942, 1943, 5, 116, 0, 0, 1943, 1944, 5, 97, 0, 0, 1944, 1945, 5, 116, 0, 0, 1945, 1946, 5, 101, 0, 0, 1946, 1947, 5, 115, 0, 0, 1947, 1948, 5, 46, 0, 0, 1948, 1949, 5, 84, 0, 0, 1949, 1950, 5, 97, 0, 0, 1950, 1951, 5, 115, 0, 0, 1951, 1952, 5, 107, 0, 0, 1952, 1953, 5, 70, 0, 0, 1953, 1954, 5, 97, 0, 0, 1954, 1955, 5, 105, 0, 0, 1955, 1956, 5, 108, 0, 0, 1956, 1957, 5, 101, 0, 0, 1957, 1958, 5, 100, 0, 0, 1958, 1959, 5, 34, 0, 0, 1959, 232, 1, 0, 0, 0, 1960, 1961, 5, 34, 0, 0, 1961, 1962, 5, 83, 0, 0, 1962, 1963, 5, 116, 0, 0, 1963, 1964, 5, 97, 0, 0, 1964, 1965, 5, 116, 0, 0, 1965, 1966, 5, 101, 0, 0, 1966, 1967, 5, 115, 0, 0, 1967, 1968, 5, 46, 0, 0, 1968, 1969, 5, 80, 0, 0, 1969, 1970, 5, 101, 0, 0, 1970, 1971, 5, 114, 0, 0, 1971, 1972, 5, 109, 0, 0, 1972, 1973, 5, 105, 0, 0, 1973, 1974, 5, 115, 0, 0, 1974, 1975, 5, 115, 0, 0, 1975, 1976, 5, 105, 0, 0, 1976, 1977, 5, 111, 0, 0, 1977, 1978, 5, 110, 0, 0, 1978, 1979, 5, 115, 0, 0, 1979, 1980, 5, 34, 0, 0, 1980, 234, 1, 0, 0, 0, 1981, 1982, 5, 34, 0, 0, 1982, 1983, 5, 83, 0, 0, 1983, 1984, 5, 116, 0, 0, 1984, 1985, 5, 97, 0, 0, 1985, 1986, 5, 116, 0, 0, 1986, 1987, 5, 101, 0, 0, 1987, 1988, 5, 115, 0, 0, 1988, 1989, 5, 46, 0, 0, 1989, 1990, 5, 82, 0, 0, 1990, 1991, 5, 101, 0, 0, 1991, 1992, 5, 115, 0, 0, 1992, 1993, 5, 117, 0, 0, 1993, 1994, 5, 108, 0, 0, 1994, 1995, 5, 116, 0, 0, 1995, 1996, 5, 80, 0, 0, 1996, 1997, 5, 97, 0, 0, 1997, 1998, 5, 116, 0, 0, 1998, 1999, 5, 104, 0, 0, 1999, 2000, 5, 77, 0, 0, 2000, 2001, 5, 97, 0, 0, 2001, 2002, 5, 116, 0, 0, 2002, 2003, 5, 99, 0, 0, 2003, 2004, 5, 104, 0, 0, 2004, 2005, 5, 70, 0, 0, 2005, 2006, 5, 97, 0, 0, 2006, 2007, 5, 105, 0, 0, 2007, 2008, 5, 108, 0, 0, 2008, 2009, 5, 117, 0, 0, 2009, 2010, 5, 114, 0, 0, 2010, 2011, 5, 101, 0, 0, 2011, 2012, 5, 34, 0, 0, 2012, 236, 1, 0, 0, 0, 2013, 2014, 5, 34, 0, 0, 2014, 2015, 5, 83, 0, 0, 2015, 2016, 5, 116, 0, 0, 2016, 2017, 5, 97, 0, 0, 2017, 2018, 5, 116, 0, 0, 2018, 2019, 5, 101, 0, 0, 2019, 2020, 5, 115, 0, 0, 2020, 2021, 5, 46, 0, 0, 2021, 2022, 5, 80, 0, 0, 2022, 2023, 5, 97, 0, 0, 2023, 2024, 5, 114, 0, 0, 2024, 2025, 5, 97, 0, 0, 2025, 2026, 5, 109, 0, 0, 2026, 2027, 5, 101, 0, 0, 2027, 2028, 5, 116, 0, 0, 2028, 2029, 5, 101, 0, 0, 2029, 2030, 5, 114, 0, 0, 2030, 2031, 5, 80, 0, 0, 2031, 2032, 5, 97, 0, 0, 2032, 2033, 5, 116, 0, 0, 2033, 2034, 5, 104, 0, 0, 2034, 2035, 5, 70, 0, 0, 2035, 2036, 5, 97, 0, 0, 2036, 2037, 5, 105, 0, 0, 2037, 2038, 5, 108, 0, 0, 2038, 2039, 5, 117, 0, 0, 2039, 2040, 5, 114, 0, 0, 2040, 2041, 5, 101, 0, 0, 2041, 2042, 5, 34, 0, 0, 2042, 238, 1, 0, 0, 0, 2043, 2044, 5, 34, 0, 0, 2044, 2045, 5, 83, 0, 0, 2045, 2046, 5, 116, 0, 0, 2046, 2047, 5, 97, 0, 0, 2047, 2048, 5, 116, 0, 0, 2048, 2049, 5, 101, 0, 0, 2049, 2050, 5, 115, 0, 0, 2050, 2051, 5, 46, 0, 0, 2051, 2052, 5, 66, 0, 0, 2052, 2053, 5, 114, 0, 0, 2053, 2054, 5, 97, 0, 0, 2054, 2055, 5, 110, 0, 0, 2055, 2056, 5, 99, 0, 0, 2056, 2057, 5, 104, 0, 0, 2057, 2058, 5, 70, 0, 0, 2058, 2059, 5, 97, 0, 0, 2059, 2060, 5, 105, 0, 0, 2060, 2061, 5, 108, 0, 0, 2061, 2062, 5, 101, 0, 0, 2062, 2063, 5, 100, 0, 0, 2063, 2064, 5, 34, 0, 0, 2064, 240, 1, 0, 0, 0, 2065, 2066, 5, 34, 0, 0, 2066, 2067, 5, 83, 0, 0, 2067, 2068, 5, 116, 0, 0, 2068, 2069, 5, 97, 0, 0, 2069, 2070, 5, 116, 0, 0, 2070, 2071, 5, 101, 0, 0, 2071, 2072, 5, 115, 0, 0, 2072, 2073, 5, 46, 0, 0, 2073, 2074, 5, 78, 0, 0, 2074, 2075, 5, 111, 0, 0, 2075, 2076, 5, 67, 0, 0, 2076, 2077, 5, 104, 0, 0, 2077, 2078, 5, 111, 0, 0, 2078, 2079, 5, 105, 0, 0, 2079, 2080, 5, 99, 0, 0, 2080, 2081, 5, 101, 0, 0, 2081, 2082, 5, 77, 0, 0, 2082, 2083, 5, 97, 0, 0, 2083, 2084, 5, 116, 0, 0, 2084, 2085, 5, 99, 0, 0, 2085, 2086, 5, 104, 0, 0, 2086, 2087, 5, 101, 0, 0, 2087, 2088, 5, 100, 0, 0, 2088, 2089, 5, 34, 0, 0, 2089, 242, 1, 0, 0, 0, 2090, 2091, 5, 34, 0, 0, 2091, 2092, 5, 83, 0, 0, 2092, 2093, 5, 116, 0, 0, 2093, 2094, 5, 97, 0, 0, 2094, 2095, 5, 116, 0, 0, 2095, 2096, 5, 101, 0, 0, 2096, 2097, 5, 115, 0, 0, 2097, 2098, 5, 46, 0, 0, 2098, 2099, 5, 73, 0, 0, 2099, 2100, 5, 110, 0, 0, 2100, 2101, 5, 116, 0, 0, 2101, 2102, 5, 114, 0, 0, 2102, 2103, 5, 105, 0, 0, 2103, 2104, 5, 110, 0, 0, 2104, 2105, 5, 115, 0, 0, 2105, 2106, 5, 105, 0, 0, 2106, 2107, 5, 99, 0, 0, 2107, 2108, 5, 70, 0, 0, 2108, 2109, 5, 97, 0, 0, 2109, 2110, 5, 105, 0, 0, 2110, 2111, 5, 108, 0, 0, 2111, 2112, 5, 117, 0, 0, 2112, 2113, 5, 114, 0, 0, 2113, 2114, 5, 101, 0, 0, 2114, 2115, 5, 34, 0, 0, 2115, 244, 1, 0, 0, 0, 2116, 2117, 5, 34, 0, 0, 2117, 2118, 5, 83, 0, 0, 2118, 2119, 5, 116, 0, 0, 2119, 2120, 5, 97, 0, 0, 2120, 2121, 5, 116, 0, 0, 2121, 2122, 5, 101, 0, 0, 2122, 2123, 5, 115, 0, 0, 2123, 2124, 5, 46, 0, 0, 2124, 2125, 5, 69, 0, 0, 2125, 2126, 5, 120, 0, 0, 2126, 2127, 5, 99, 0, 0, 2127, 2128, 5, 101, 0, 0, 2128, 2129, 5, 101, 0, 0, 2129, 2130, 5, 100, 0, 0, 2130, 2131, 5, 84, 0, 0, 2131, 2132, 5, 111, 0, 0, 2132, 2133, 5, 108, 0, 0, 2133, 2134, 5, 101, 0, 0, 2134, 2135, 5, 114, 0, 0, 2135, 2136, 5, 97, 0, 0, 2136, 2137, 5, 116, 0, 0, 2137, 2138, 5, 101, 0, 0, 2138, 2139, 5, 100, 0, 0, 2139, 2140, 5, 70, 0, 0, 2140, 2141, 5, 97, 0, 0, 2141, 2142, 5, 105, 0, 0, 2142, 2143, 5, 108, 0, 0, 2143, 2144, 5, 117, 0, 0, 2144, 2145, 5, 114, 0, 0, 2145, 2146, 5, 101, 0, 0, 2146, 2147, 5, 84, 0, 0, 2147, 2148, 5, 104, 0, 0, 2148, 2149, 5, 114, 0, 0, 2149, 2150, 5, 101, 0, 0, 2150, 2151, 5, 115, 0, 0, 2151, 2152, 5, 104, 0, 0, 2152, 2153, 5, 111, 0, 0, 2153, 2154, 5, 108, 0, 0, 2154, 2155, 5, 100, 0, 0, 2155, 2156, 5, 34, 0, 0, 2156, 246, 1, 0, 0, 0, 2157, 2158, 5, 34, 0, 0, 2158, 2159, 5, 83, 0, 0, 2159, 2160, 5, 116, 0, 0, 2160, 2161, 5, 97, 0, 0, 2161, 2162, 5, 116, 0, 0, 2162, 2163, 5, 101, 0, 0, 2163, 2164, 5, 115, 0, 0, 2164, 2165, 5, 46, 0, 0, 2165, 2166, 5, 73, 0, 0, 2166, 2167, 5, 116, 0, 0, 2167, 2168, 5, 101, 0, 0, 2168, 2169, 5, 109, 0, 0, 2169, 2170, 5, 82, 0, 0, 2170, 2171, 5, 101, 0, 0, 2171, 2172, 5, 97, 0, 0, 2172, 2173, 5, 100, 0, 0, 2173, 2174, 5, 101, 0, 0, 2174, 2175, 5, 114, 0, 0, 2175, 2176, 5, 70, 0, 0, 2176, 2177, 5, 97, 0, 0, 2177, 2178, 5, 105, 0, 0, 2178, 2179, 5, 108, 0, 0, 2179, 2180, 5, 101, 0, 0, 2180, 2181, 5, 100, 0, 0, 2181, 2182, 5, 34, 0, 0, 2182, 248, 1, 0, 0, 0, 2183, 2184, 5, 34, 0, 0, 2184, 2185, 5, 83, 0, 0, 2185, 2186, 5, 116, 0, 0, 2186, 2187, 5, 97, 0, 0, 2187, 2188, 5, 116, 0, 0, 2188, 2189, 5, 101, 0, 0, 2189, 2190, 5, 115, 0, 0, 2190, 2191, 5, 46, 0, 0, 2191, 2192, 5, 82, 0, 0, 2192, 2193, 5, 101, 0, 0, 2193, 2194, 5, 115, 0, 0, 2194, 2195, 5, 117, 0, 0, 2195, 2196, 5, 108, 0, 0, 2196, 2197, 5, 116, 0, 0, 2197, 2198, 5, 87, 0, 0, 2198, 2199, 5, 114, 0, 0, 2199, 2200, 5, 105, 0, 0, 2200, 2201, 5, 116, 0, 0, 2201, 2202, 5, 101, 0, 0, 2202, 2203, 5, 114, 0, 0, 2203, 2204, 5, 70, 0, 0, 2204, 2205, 5, 97, 0, 0, 2205, 2206, 5, 105, 0, 0, 2206, 2207, 5, 108, 0, 0, 2207, 2208, 5, 101, 0, 0, 2208, 2209, 5, 100, 0, 0, 2209, 2210, 5, 34, 0, 0, 2210, 250, 1, 0, 0, 0, 2211, 2212, 5, 34, 0, 0, 2212, 2213, 5, 83, 0, 0, 2213, 2214, 5, 116, 0, 0, 2214, 2215, 5, 97, 0, 0, 2215, 2216, 5, 116, 0, 0, 2216, 2217, 5, 101, 0, 0, 2217, 2218, 5, 115, 0, 0, 2218, 2219, 5, 46, 0, 0, 2219, 2220, 5, 82, 0, 0, 2220, 2221, 5, 117, 0, 0, 2221, 2222, 5, 110, 0, 0, 2222, 2223, 5, 116, 0, 0, 2223, 2224, 5, 105, 0, 0, 2224, 2225, 5, 109, 0, 0, 2225, 2226, 5, 101, 0, 0, 2226, 2227, 5, 34, 0, 0, 2227, 252, 1, 0, 0, 0, 2228, 2233, 5, 34, 0, 0, 2229, 2232, 3, 261, 130, 0, 2230, 2232, 3, 267, 133, 0, 2231, 2229, 1, 0, 0, 0, 2231, 2230, 1, 0, 0, 0, 2232, 2235, 1, 0, 0, 0, 2233, 2231, 1, 0, 0, 0, 2233, 2234, 1, 0, 0, 0, 2234, 2236, 1, 0, 0, 0, 2235, 2233, 1, 0, 0, 0, 2236, 2237, 5, 46, 0, 0, 2237, 2238, 5, 36, 0, 0, 2238, 2239, 5, 34, 0, 0, 2239, 254, 1, 0, 0, 0, 2240, 2241, 5, 34, 0, 0, 2241, 2242, 5, 36, 0, 0, 2242, 2243, 5, 36, 0, 0, 2243, 2248, 1, 0, 0, 0, 2244, 2247, 3, 261, 130, 0, 2245, 2247, 3, 267, 133, 0, 2246, 2244, 1, 0, 0, 0, 2246, 2245, 1, 0, 0, 0, 2247, 2250, 1, 0, 0, 0, 2248, 2246, 1, 0, 0, 0, 2248, 2249, 1, 0, 0, 0, 2249, 2251, 1, 0, 0, 0, 2250, 2248, 1, 0, 0, 0, 2251, 2252, 5, 34, 0, 0, 2252, 256, 1, 0, 0, 0, 2253, 2254, 5, 34, 0, 0, 2254, 2255, 5, 36, 0, 0, 2255, 2260, 1, 0, 0, 0, 2256, 2259, 3, 261, 130, 0, 2257, 2259, 3, 267, 133, 0, 2258, 2256, 1, 0, 0, 0, 2258, 2257, 1, 0, 0, 0, 2259, 2262, 1, 0, 0, 0, 2260, 2258, 1, 0, 0, 0, 2260, 2261, 1, 0, 0, 0, 2261, 2263, 1, 0, 0, 0, 2262, 2260, 1, 0, 0, 0, 2263, 2264, 5, 34, 0, 0, 2264, 258, 1, 0, 0, 0, 2265, 2270, 5, 34, 0, 0, 2266, 2269, 3, 261, 130, 0, 2267, 2269, 3, 267, 133, 0, 2268, 2266, 1, 0, 0, 0, 2268, 2267, 1, 0, 0, 0, 2269, 2272, 1, 0, 0, 0, 2270, 2268, 1, 0, 0, 0, 2270, 2271, 1, 0, 0, 0, 2271, 2273, 1, 0, 0, 0, 2272, 2270, 1, 0, 0, 0, 2273, 2274, 5, 34, 0, 0, 2274, 260, 1, 0, 0, 0, 2275, 2278, 5, 92, 0, 0, 2276, 2279, 7, 0, 0, 0, 2277, 2279, 3, 263, 131, 0, 2278, 2276, 1, 0, 0, 0, 2278, 2277, 1, 0, 0, 0, 2279, 262, 1, 0, 0, 0, 2280, 2281, 5, 117, 0, 0, 2281, 2282, 3, 265, 132, 0, 2282, 2283, 3, 265, 132, 0, 2283, 2284, 3, 265, 132, 0, 2284, 2285, 3, 265, 132, 0, 2285, 264, 1, 0, 0, 0, 2286, 2287, 7, 1, 0, 0, 2287, 266, 1, 0, 0, 0, 2288, 2289, 8, 2, 0, 0, 2289, 268, 1, 0, 0, 0, 2290, 2299, 5, 48, 0, 0, 2291, 2295, 7, 3, 0, 0, 2292, 2294, 7, 4, 0, 0, 2293, 2292, 1, 0, 0, 0, 2294, 2297, 1, 0, 0, 0, 2295, 2293, 1, 0, 0, 0, 2295, 2296, 1, 0, 0, 0, 2296, 2299, 1, 0, 0, 0, 2297, 2295, 1, 0, 0, 0, 2298, 2290, 1, 0, 0, 0, 2298, 2291, 1, 0, 0, 0, 2299, 270, 1, 0, 0, 0, 2300, 2302, 5, 45, 0, 0, 2301, 2300, 1, 0, 0, 0, 2301, 2302, 1, 0, 0, 0, 2302, 2303, 1, 0, 0, 0, 2303, 2310, 3, 269, 134, 0, 2304, 2306, 5, 46, 0, 0, 2305, 2307, 7, 4, 0, 0, 2306, 2305, 1, 0, 0, 0, 2307, 2308, 1, 0, 0, 0, 2308, 2306, 1, 0, 0, 0, 2308, 2309, 1, 0, 0, 0, 2309, 2311, 1, 0, 0, 0, 2310, 2304, 1, 0, 0, 0, 2310, 2311, 1, 0, 0, 0, 2311, 2313, 1, 0, 0, 0, 2312, 2314, 3, 273, 136, 0, 2313, 2312, 1, 0, 0, 0, 2313, 2314, 1, 0, 0, 0, 2314, 272, 1, 0, 0, 0, 2315, 2317, 7, 5, 0, 0, 2316, 2318, 7, 6, 0, 0, 2317, 2316, 1, 0, 0, 0, 2317, 2318, 1, 0, 0, 0, 2318, 2319, 1, 0, 0, 0, 2319, 2320, 3, 269, 134, 0, 2320, 274, 1, 0, 0, 0, 2321, 2323, 7, 7, 0, 0, 2322, 2321, 1, 0, 0, 0, 2323, 2324, 1, 0, 0, 0, 2324, 2322, 1, 0, 0, 0, 2324, 2325, 1, 0, 0, 0, 2325, 2326, 1, 0, 0, 0, 2326, 2327, 6, 137, 0, 0, 2327, 276, 1, 0, 0, 0, 18, 0, 2231, 2233, 2246, 2248, 2258, 2260, 2268, 2270, 2278, 2295, 2298, 2301, 2308, 2310, 2313, 2317, 2324, 1, 6, 0, 0] \ No newline at end of file diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLLexer.py b/moto/stepfunctions/parser/asl/antlr/runtime/ASLLexer.py new file mode 100644 index 000000000..197664fd1 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLLexer.py @@ -0,0 +1,19662 @@ +# Generated from /Users/mep/LocalStack/localstack/localstack/services/stepfunctions/asl/antlr/ASLLexer.g4 by ANTLR 4.13.1 +import sys +from typing import TextIO + +from antlr4 import ( + DFA, + ATNDeserializer, + Lexer, + LexerATNSimulator, + PredictionContextCache, +) + + +def serializedATN(): + return [ + 4, + 0, + 133, + 2328, + 6, + -1, + 2, + 0, + 7, + 0, + 2, + 1, + 7, + 1, + 2, + 2, + 7, + 2, + 2, + 3, + 7, + 3, + 2, + 4, + 7, + 4, + 2, + 5, + 7, + 5, + 2, + 6, + 7, + 6, + 2, + 7, + 7, + 7, + 2, + 8, + 7, + 8, + 2, + 9, + 7, + 9, + 2, + 10, + 7, + 10, + 2, + 11, + 7, + 11, + 2, + 12, + 7, + 12, + 2, + 13, + 7, + 13, + 2, + 14, + 7, + 14, + 2, + 15, + 7, + 15, + 2, + 16, + 7, + 16, + 2, + 17, + 7, + 17, + 2, + 18, + 7, + 18, + 2, + 19, + 7, + 19, + 2, + 20, + 7, + 20, + 2, + 21, + 7, + 21, + 2, + 22, + 7, + 22, + 2, + 23, + 7, + 23, + 2, + 24, + 7, + 24, + 2, + 25, + 7, + 25, + 2, + 26, + 7, + 26, + 2, + 27, + 7, + 27, + 2, + 28, + 7, + 28, + 2, + 29, + 7, + 29, + 2, + 30, + 7, + 30, + 2, + 31, + 7, + 31, + 2, + 32, + 7, + 32, + 2, + 33, + 7, + 33, + 2, + 34, + 7, + 34, + 2, + 35, + 7, + 35, + 2, + 36, + 7, + 36, + 2, + 37, + 7, + 37, + 2, + 38, + 7, + 38, + 2, + 39, + 7, + 39, + 2, + 40, + 7, + 40, + 2, + 41, + 7, + 41, + 2, + 42, + 7, + 42, + 2, + 43, + 7, + 43, + 2, + 44, + 7, + 44, + 2, + 45, + 7, + 45, + 2, + 46, + 7, + 46, + 2, + 47, + 7, + 47, + 2, + 48, + 7, + 48, + 2, + 49, + 7, + 49, + 2, + 50, + 7, + 50, + 2, + 51, + 7, + 51, + 2, + 52, + 7, + 52, + 2, + 53, + 7, + 53, + 2, + 54, + 7, + 54, + 2, + 55, + 7, + 55, + 2, + 56, + 7, + 56, + 2, + 57, + 7, + 57, + 2, + 58, + 7, + 58, + 2, + 59, + 7, + 59, + 2, + 60, + 7, + 60, + 2, + 61, + 7, + 61, + 2, + 62, + 7, + 62, + 2, + 63, + 7, + 63, + 2, + 64, + 7, + 64, + 2, + 65, + 7, + 65, + 2, + 66, + 7, + 66, + 2, + 67, + 7, + 67, + 2, + 68, + 7, + 68, + 2, + 69, + 7, + 69, + 2, + 70, + 7, + 70, + 2, + 71, + 7, + 71, + 2, + 72, + 7, + 72, + 2, + 73, + 7, + 73, + 2, + 74, + 7, + 74, + 2, + 75, + 7, + 75, + 2, + 76, + 7, + 76, + 2, + 77, + 7, + 77, + 2, + 78, + 7, + 78, + 2, + 79, + 7, + 79, + 2, + 80, + 7, + 80, + 2, + 81, + 7, + 81, + 2, + 82, + 7, + 82, + 2, + 83, + 7, + 83, + 2, + 84, + 7, + 84, + 2, + 85, + 7, + 85, + 2, + 86, + 7, + 86, + 2, + 87, + 7, + 87, + 2, + 88, + 7, + 88, + 2, + 89, + 7, + 89, + 2, + 90, + 7, + 90, + 2, + 91, + 7, + 91, + 2, + 92, + 7, + 92, + 2, + 93, + 7, + 93, + 2, + 94, + 7, + 94, + 2, + 95, + 7, + 95, + 2, + 96, + 7, + 96, + 2, + 97, + 7, + 97, + 2, + 98, + 7, + 98, + 2, + 99, + 7, + 99, + 2, + 100, + 7, + 100, + 2, + 101, + 7, + 101, + 2, + 102, + 7, + 102, + 2, + 103, + 7, + 103, + 2, + 104, + 7, + 104, + 2, + 105, + 7, + 105, + 2, + 106, + 7, + 106, + 2, + 107, + 7, + 107, + 2, + 108, + 7, + 108, + 2, + 109, + 7, + 109, + 2, + 110, + 7, + 110, + 2, + 111, + 7, + 111, + 2, + 112, + 7, + 112, + 2, + 113, + 7, + 113, + 2, + 114, + 7, + 114, + 2, + 115, + 7, + 115, + 2, + 116, + 7, + 116, + 2, + 117, + 7, + 117, + 2, + 118, + 7, + 118, + 2, + 119, + 7, + 119, + 2, + 120, + 7, + 120, + 2, + 121, + 7, + 121, + 2, + 122, + 7, + 122, + 2, + 123, + 7, + 123, + 2, + 124, + 7, + 124, + 2, + 125, + 7, + 125, + 2, + 126, + 7, + 126, + 2, + 127, + 7, + 127, + 2, + 128, + 7, + 128, + 2, + 129, + 7, + 129, + 2, + 130, + 7, + 130, + 2, + 131, + 7, + 131, + 2, + 132, + 7, + 132, + 2, + 133, + 7, + 133, + 2, + 134, + 7, + 134, + 2, + 135, + 7, + 135, + 2, + 136, + 7, + 136, + 2, + 137, + 7, + 137, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 1, + 2, + 1, + 3, + 1, + 3, + 1, + 4, + 1, + 4, + 1, + 5, + 1, + 5, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 7, + 1, + 7, + 1, + 7, + 1, + 7, + 1, + 7, + 1, + 7, + 1, + 8, + 1, + 8, + 1, + 8, + 1, + 8, + 1, + 8, + 1, + 9, + 1, + 9, + 1, + 9, + 1, + 9, + 1, + 9, + 1, + 9, + 1, + 9, + 1, + 9, + 1, + 9, + 1, + 9, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 13, + 1, + 13, + 1, + 13, + 1, + 13, + 1, + 13, + 1, + 13, + 1, + 13, + 1, + 13, + 1, + 13, + 1, + 13, + 1, + 14, + 1, + 14, + 1, + 14, + 1, + 14, + 1, + 14, + 1, + 14, + 1, + 14, + 1, + 15, + 1, + 15, + 1, + 15, + 1, + 15, + 1, + 15, + 1, + 15, + 1, + 15, + 1, + 16, + 1, + 16, + 1, + 16, + 1, + 16, + 1, + 16, + 1, + 16, + 1, + 16, + 1, + 16, + 1, + 16, + 1, + 17, + 1, + 17, + 1, + 17, + 1, + 17, + 1, + 17, + 1, + 17, + 1, + 17, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 19, + 1, + 19, + 1, + 19, + 1, + 19, + 1, + 19, + 1, + 19, + 1, + 19, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 22, + 1, + 22, + 1, + 22, + 1, + 22, + 1, + 22, + 1, + 22, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 31, + 1, + 31, + 1, + 31, + 1, + 31, + 1, + 31, + 1, + 31, + 1, + 31, + 1, + 31, + 1, + 31, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 34, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 36, + 1, + 36, + 1, + 36, + 1, + 36, + 1, + 36, + 1, + 36, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 39, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 42, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 43, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 47, + 1, + 47, + 1, + 47, + 1, + 47, + 1, + 47, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 51, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 53, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 55, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 57, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 60, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 70, + 1, + 70, + 1, + 70, + 1, + 70, + 1, + 70, + 1, + 70, + 1, + 70, + 1, + 70, + 1, + 70, + 1, + 70, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 72, + 1, + 72, + 1, + 72, + 1, + 72, + 1, + 72, + 1, + 72, + 1, + 72, + 1, + 72, + 1, + 72, + 1, + 72, + 1, + 72, + 1, + 72, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 77, + 1, + 78, + 1, + 78, + 1, + 78, + 1, + 78, + 1, + 78, + 1, + 78, + 1, + 78, + 1, + 79, + 1, + 79, + 1, + 79, + 1, + 79, + 1, + 79, + 1, + 79, + 1, + 79, + 1, + 79, + 1, + 79, + 1, + 80, + 1, + 80, + 1, + 80, + 1, + 80, + 1, + 80, + 1, + 80, + 1, + 80, + 1, + 80, + 1, + 80, + 1, + 80, + 1, + 80, + 1, + 80, + 1, + 80, + 1, + 80, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 81, + 1, + 82, + 1, + 82, + 1, + 82, + 1, + 82, + 1, + 82, + 1, + 82, + 1, + 82, + 1, + 82, + 1, + 82, + 1, + 82, + 1, + 82, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 84, + 1, + 84, + 1, + 84, + 1, + 84, + 1, + 84, + 1, + 84, + 1, + 84, + 1, + 84, + 1, + 84, + 1, + 84, + 1, + 84, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 86, + 1, + 87, + 1, + 87, + 1, + 87, + 1, + 87, + 1, + 87, + 1, + 87, + 1, + 87, + 1, + 87, + 1, + 87, + 1, + 87, + 1, + 87, + 1, + 88, + 1, + 88, + 1, + 88, + 1, + 88, + 1, + 88, + 1, + 88, + 1, + 88, + 1, + 88, + 1, + 88, + 1, + 88, + 1, + 88, + 1, + 88, + 1, + 89, + 1, + 89, + 1, + 89, + 1, + 89, + 1, + 89, + 1, + 89, + 1, + 89, + 1, + 89, + 1, + 89, + 1, + 89, + 1, + 89, + 1, + 89, + 1, + 89, + 1, + 90, + 1, + 90, + 1, + 90, + 1, + 90, + 1, + 90, + 1, + 90, + 1, + 90, + 1, + 90, + 1, + 90, + 1, + 90, + 1, + 90, + 1, + 90, + 1, + 91, + 1, + 91, + 1, + 91, + 1, + 91, + 1, + 91, + 1, + 91, + 1, + 91, + 1, + 91, + 1, + 91, + 1, + 91, + 1, + 91, + 1, + 91, + 1, + 91, + 1, + 92, + 1, + 92, + 1, + 92, + 1, + 92, + 1, + 92, + 1, + 92, + 1, + 92, + 1, + 92, + 1, + 92, + 1, + 93, + 1, + 93, + 1, + 93, + 1, + 93, + 1, + 93, + 1, + 93, + 1, + 93, + 1, + 93, + 1, + 93, + 1, + 93, + 1, + 93, + 1, + 93, + 1, + 93, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 94, + 1, + 95, + 1, + 95, + 1, + 95, + 1, + 95, + 1, + 95, + 1, + 95, + 1, + 95, + 1, + 95, + 1, + 95, + 1, + 95, + 1, + 95, + 1, + 95, + 1, + 95, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 96, + 1, + 97, + 1, + 97, + 1, + 97, + 1, + 97, + 1, + 97, + 1, + 97, + 1, + 97, + 1, + 97, + 1, + 97, + 1, + 97, + 1, + 97, + 1, + 97, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 98, + 1, + 99, + 1, + 99, + 1, + 99, + 1, + 99, + 1, + 99, + 1, + 99, + 1, + 99, + 1, + 99, + 1, + 99, + 1, + 99, + 1, + 99, + 1, + 99, + 1, + 99, + 1, + 100, + 1, + 100, + 1, + 100, + 1, + 100, + 1, + 100, + 1, + 100, + 1, + 100, + 1, + 100, + 1, + 100, + 1, + 100, + 1, + 100, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 101, + 1, + 102, + 1, + 102, + 1, + 102, + 1, + 102, + 1, + 102, + 1, + 102, + 1, + 102, + 1, + 103, + 1, + 103, + 1, + 103, + 1, + 103, + 1, + 103, + 1, + 103, + 1, + 104, + 1, + 104, + 1, + 104, + 1, + 104, + 1, + 104, + 1, + 104, + 1, + 104, + 1, + 104, + 1, + 105, + 1, + 105, + 1, + 105, + 1, + 105, + 1, + 105, + 1, + 105, + 1, + 105, + 1, + 105, + 1, + 106, + 1, + 106, + 1, + 106, + 1, + 106, + 1, + 106, + 1, + 106, + 1, + 106, + 1, + 106, + 1, + 107, + 1, + 107, + 1, + 107, + 1, + 107, + 1, + 107, + 1, + 107, + 1, + 107, + 1, + 107, + 1, + 107, + 1, + 107, + 1, + 107, + 1, + 107, + 1, + 107, + 1, + 107, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 108, + 1, + 109, + 1, + 109, + 1, + 109, + 1, + 109, + 1, + 109, + 1, + 109, + 1, + 109, + 1, + 109, + 1, + 109, + 1, + 109, + 1, + 109, + 1, + 109, + 1, + 109, + 1, + 109, + 1, + 110, + 1, + 110, + 1, + 110, + 1, + 110, + 1, + 110, + 1, + 110, + 1, + 110, + 1, + 110, + 1, + 110, + 1, + 110, + 1, + 110, + 1, + 110, + 1, + 110, + 1, + 110, + 1, + 111, + 1, + 111, + 1, + 111, + 1, + 111, + 1, + 111, + 1, + 111, + 1, + 111, + 1, + 111, + 1, + 112, + 1, + 112, + 1, + 112, + 1, + 112, + 1, + 112, + 1, + 112, + 1, + 112, + 1, + 112, + 1, + 112, + 1, + 112, + 1, + 112, + 1, + 112, + 1, + 112, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 113, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 114, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 115, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 116, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 117, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 118, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 119, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 120, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 121, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 122, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 123, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 124, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 125, + 1, + 126, + 1, + 126, + 1, + 126, + 5, + 126, + 2232, + 8, + 126, + 10, + 126, + 12, + 126, + 2235, + 9, + 126, + 1, + 126, + 1, + 126, + 1, + 126, + 1, + 126, + 1, + 127, + 1, + 127, + 1, + 127, + 1, + 127, + 1, + 127, + 1, + 127, + 5, + 127, + 2247, + 8, + 127, + 10, + 127, + 12, + 127, + 2250, + 9, + 127, + 1, + 127, + 1, + 127, + 1, + 128, + 1, + 128, + 1, + 128, + 1, + 128, + 1, + 128, + 5, + 128, + 2259, + 8, + 128, + 10, + 128, + 12, + 128, + 2262, + 9, + 128, + 1, + 128, + 1, + 128, + 1, + 129, + 1, + 129, + 1, + 129, + 5, + 129, + 2269, + 8, + 129, + 10, + 129, + 12, + 129, + 2272, + 9, + 129, + 1, + 129, + 1, + 129, + 1, + 130, + 1, + 130, + 1, + 130, + 3, + 130, + 2279, + 8, + 130, + 1, + 131, + 1, + 131, + 1, + 131, + 1, + 131, + 1, + 131, + 1, + 131, + 1, + 132, + 1, + 132, + 1, + 133, + 1, + 133, + 1, + 134, + 1, + 134, + 1, + 134, + 5, + 134, + 2294, + 8, + 134, + 10, + 134, + 12, + 134, + 2297, + 9, + 134, + 3, + 134, + 2299, + 8, + 134, + 1, + 135, + 3, + 135, + 2302, + 8, + 135, + 1, + 135, + 1, + 135, + 1, + 135, + 4, + 135, + 2307, + 8, + 135, + 11, + 135, + 12, + 135, + 2308, + 3, + 135, + 2311, + 8, + 135, + 1, + 135, + 3, + 135, + 2314, + 8, + 135, + 1, + 136, + 1, + 136, + 3, + 136, + 2318, + 8, + 136, + 1, + 136, + 1, + 136, + 1, + 137, + 4, + 137, + 2323, + 8, + 137, + 11, + 137, + 12, + 137, + 2324, + 1, + 137, + 1, + 137, + 0, + 0, + 138, + 1, + 1, + 3, + 2, + 5, + 3, + 7, + 4, + 9, + 5, + 11, + 6, + 13, + 7, + 15, + 8, + 17, + 9, + 19, + 10, + 21, + 11, + 23, + 12, + 25, + 13, + 27, + 14, + 29, + 15, + 31, + 16, + 33, + 17, + 35, + 18, + 37, + 19, + 39, + 20, + 41, + 21, + 43, + 22, + 45, + 23, + 47, + 24, + 49, + 25, + 51, + 26, + 53, + 27, + 55, + 28, + 57, + 29, + 59, + 30, + 61, + 31, + 63, + 32, + 65, + 33, + 67, + 34, + 69, + 35, + 71, + 36, + 73, + 37, + 75, + 38, + 77, + 39, + 79, + 40, + 81, + 41, + 83, + 42, + 85, + 43, + 87, + 44, + 89, + 45, + 91, + 46, + 93, + 47, + 95, + 48, + 97, + 49, + 99, + 50, + 101, + 51, + 103, + 52, + 105, + 53, + 107, + 54, + 109, + 55, + 111, + 56, + 113, + 57, + 115, + 58, + 117, + 59, + 119, + 60, + 121, + 61, + 123, + 62, + 125, + 63, + 127, + 64, + 129, + 65, + 131, + 66, + 133, + 67, + 135, + 68, + 137, + 69, + 139, + 70, + 141, + 71, + 143, + 72, + 145, + 73, + 147, + 74, + 149, + 75, + 151, + 76, + 153, + 77, + 155, + 78, + 157, + 79, + 159, + 80, + 161, + 81, + 163, + 82, + 165, + 83, + 167, + 84, + 169, + 85, + 171, + 86, + 173, + 87, + 175, + 88, + 177, + 89, + 179, + 90, + 181, + 91, + 183, + 92, + 185, + 93, + 187, + 94, + 189, + 95, + 191, + 96, + 193, + 97, + 195, + 98, + 197, + 99, + 199, + 100, + 201, + 101, + 203, + 102, + 205, + 103, + 207, + 104, + 209, + 105, + 211, + 106, + 213, + 107, + 215, + 108, + 217, + 109, + 219, + 110, + 221, + 111, + 223, + 112, + 225, + 113, + 227, + 114, + 229, + 115, + 231, + 116, + 233, + 117, + 235, + 118, + 237, + 119, + 239, + 120, + 241, + 121, + 243, + 122, + 245, + 123, + 247, + 124, + 249, + 125, + 251, + 126, + 253, + 127, + 255, + 128, + 257, + 129, + 259, + 130, + 261, + 0, + 263, + 0, + 265, + 0, + 267, + 0, + 269, + 131, + 271, + 132, + 273, + 0, + 275, + 133, + 1, + 0, + 8, + 8, + 0, + 34, + 34, + 47, + 47, + 92, + 92, + 98, + 98, + 102, + 102, + 110, + 110, + 114, + 114, + 116, + 116, + 3, + 0, + 48, + 57, + 65, + 70, + 97, + 102, + 3, + 0, + 0, + 31, + 34, + 34, + 92, + 92, + 1, + 0, + 49, + 57, + 1, + 0, + 48, + 57, + 2, + 0, + 69, + 69, + 101, + 101, + 2, + 0, + 43, + 43, + 45, + 45, + 3, + 0, + 9, + 10, + 13, + 13, + 32, + 32, + 2339, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 3, + 1, + 0, + 0, + 0, + 0, + 5, + 1, + 0, + 0, + 0, + 0, + 7, + 1, + 0, + 0, + 0, + 0, + 9, + 1, + 0, + 0, + 0, + 0, + 11, + 1, + 0, + 0, + 0, + 0, + 13, + 1, + 0, + 0, + 0, + 0, + 15, + 1, + 0, + 0, + 0, + 0, + 17, + 1, + 0, + 0, + 0, + 0, + 19, + 1, + 0, + 0, + 0, + 0, + 21, + 1, + 0, + 0, + 0, + 0, + 23, + 1, + 0, + 0, + 0, + 0, + 25, + 1, + 0, + 0, + 0, + 0, + 27, + 1, + 0, + 0, + 0, + 0, + 29, + 1, + 0, + 0, + 0, + 0, + 31, + 1, + 0, + 0, + 0, + 0, + 33, + 1, + 0, + 0, + 0, + 0, + 35, + 1, + 0, + 0, + 0, + 0, + 37, + 1, + 0, + 0, + 0, + 0, + 39, + 1, + 0, + 0, + 0, + 0, + 41, + 1, + 0, + 0, + 0, + 0, + 43, + 1, + 0, + 0, + 0, + 0, + 45, + 1, + 0, + 0, + 0, + 0, + 47, + 1, + 0, + 0, + 0, + 0, + 49, + 1, + 0, + 0, + 0, + 0, + 51, + 1, + 0, + 0, + 0, + 0, + 53, + 1, + 0, + 0, + 0, + 0, + 55, + 1, + 0, + 0, + 0, + 0, + 57, + 1, + 0, + 0, + 0, + 0, + 59, + 1, + 0, + 0, + 0, + 0, + 61, + 1, + 0, + 0, + 0, + 0, + 63, + 1, + 0, + 0, + 0, + 0, + 65, + 1, + 0, + 0, + 0, + 0, + 67, + 1, + 0, + 0, + 0, + 0, + 69, + 1, + 0, + 0, + 0, + 0, + 71, + 1, + 0, + 0, + 0, + 0, + 73, + 1, + 0, + 0, + 0, + 0, + 75, + 1, + 0, + 0, + 0, + 0, + 77, + 1, + 0, + 0, + 0, + 0, + 79, + 1, + 0, + 0, + 0, + 0, + 81, + 1, + 0, + 0, + 0, + 0, + 83, + 1, + 0, + 0, + 0, + 0, + 85, + 1, + 0, + 0, + 0, + 0, + 87, + 1, + 0, + 0, + 0, + 0, + 89, + 1, + 0, + 0, + 0, + 0, + 91, + 1, + 0, + 0, + 0, + 0, + 93, + 1, + 0, + 0, + 0, + 0, + 95, + 1, + 0, + 0, + 0, + 0, + 97, + 1, + 0, + 0, + 0, + 0, + 99, + 1, + 0, + 0, + 0, + 0, + 101, + 1, + 0, + 0, + 0, + 0, + 103, + 1, + 0, + 0, + 0, + 0, + 105, + 1, + 0, + 0, + 0, + 0, + 107, + 1, + 0, + 0, + 0, + 0, + 109, + 1, + 0, + 0, + 0, + 0, + 111, + 1, + 0, + 0, + 0, + 0, + 113, + 1, + 0, + 0, + 0, + 0, + 115, + 1, + 0, + 0, + 0, + 0, + 117, + 1, + 0, + 0, + 0, + 0, + 119, + 1, + 0, + 0, + 0, + 0, + 121, + 1, + 0, + 0, + 0, + 0, + 123, + 1, + 0, + 0, + 0, + 0, + 125, + 1, + 0, + 0, + 0, + 0, + 127, + 1, + 0, + 0, + 0, + 0, + 129, + 1, + 0, + 0, + 0, + 0, + 131, + 1, + 0, + 0, + 0, + 0, + 133, + 1, + 0, + 0, + 0, + 0, + 135, + 1, + 0, + 0, + 0, + 0, + 137, + 1, + 0, + 0, + 0, + 0, + 139, + 1, + 0, + 0, + 0, + 0, + 141, + 1, + 0, + 0, + 0, + 0, + 143, + 1, + 0, + 0, + 0, + 0, + 145, + 1, + 0, + 0, + 0, + 0, + 147, + 1, + 0, + 0, + 0, + 0, + 149, + 1, + 0, + 0, + 0, + 0, + 151, + 1, + 0, + 0, + 0, + 0, + 153, + 1, + 0, + 0, + 0, + 0, + 155, + 1, + 0, + 0, + 0, + 0, + 157, + 1, + 0, + 0, + 0, + 0, + 159, + 1, + 0, + 0, + 0, + 0, + 161, + 1, + 0, + 0, + 0, + 0, + 163, + 1, + 0, + 0, + 0, + 0, + 165, + 1, + 0, + 0, + 0, + 0, + 167, + 1, + 0, + 0, + 0, + 0, + 169, + 1, + 0, + 0, + 0, + 0, + 171, + 1, + 0, + 0, + 0, + 0, + 173, + 1, + 0, + 0, + 0, + 0, + 175, + 1, + 0, + 0, + 0, + 0, + 177, + 1, + 0, + 0, + 0, + 0, + 179, + 1, + 0, + 0, + 0, + 0, + 181, + 1, + 0, + 0, + 0, + 0, + 183, + 1, + 0, + 0, + 0, + 0, + 185, + 1, + 0, + 0, + 0, + 0, + 187, + 1, + 0, + 0, + 0, + 0, + 189, + 1, + 0, + 0, + 0, + 0, + 191, + 1, + 0, + 0, + 0, + 0, + 193, + 1, + 0, + 0, + 0, + 0, + 195, + 1, + 0, + 0, + 0, + 0, + 197, + 1, + 0, + 0, + 0, + 0, + 199, + 1, + 0, + 0, + 0, + 0, + 201, + 1, + 0, + 0, + 0, + 0, + 203, + 1, + 0, + 0, + 0, + 0, + 205, + 1, + 0, + 0, + 0, + 0, + 207, + 1, + 0, + 0, + 0, + 0, + 209, + 1, + 0, + 0, + 0, + 0, + 211, + 1, + 0, + 0, + 0, + 0, + 213, + 1, + 0, + 0, + 0, + 0, + 215, + 1, + 0, + 0, + 0, + 0, + 217, + 1, + 0, + 0, + 0, + 0, + 219, + 1, + 0, + 0, + 0, + 0, + 221, + 1, + 0, + 0, + 0, + 0, + 223, + 1, + 0, + 0, + 0, + 0, + 225, + 1, + 0, + 0, + 0, + 0, + 227, + 1, + 0, + 0, + 0, + 0, + 229, + 1, + 0, + 0, + 0, + 0, + 231, + 1, + 0, + 0, + 0, + 0, + 233, + 1, + 0, + 0, + 0, + 0, + 235, + 1, + 0, + 0, + 0, + 0, + 237, + 1, + 0, + 0, + 0, + 0, + 239, + 1, + 0, + 0, + 0, + 0, + 241, + 1, + 0, + 0, + 0, + 0, + 243, + 1, + 0, + 0, + 0, + 0, + 245, + 1, + 0, + 0, + 0, + 0, + 247, + 1, + 0, + 0, + 0, + 0, + 249, + 1, + 0, + 0, + 0, + 0, + 251, + 1, + 0, + 0, + 0, + 0, + 253, + 1, + 0, + 0, + 0, + 0, + 255, + 1, + 0, + 0, + 0, + 0, + 257, + 1, + 0, + 0, + 0, + 0, + 259, + 1, + 0, + 0, + 0, + 0, + 269, + 1, + 0, + 0, + 0, + 0, + 271, + 1, + 0, + 0, + 0, + 0, + 275, + 1, + 0, + 0, + 0, + 1, + 277, + 1, + 0, + 0, + 0, + 3, + 279, + 1, + 0, + 0, + 0, + 5, + 281, + 1, + 0, + 0, + 0, + 7, + 283, + 1, + 0, + 0, + 0, + 9, + 285, + 1, + 0, + 0, + 0, + 11, + 287, + 1, + 0, + 0, + 0, + 13, + 289, + 1, + 0, + 0, + 0, + 15, + 294, + 1, + 0, + 0, + 0, + 17, + 300, + 1, + 0, + 0, + 0, + 19, + 305, + 1, + 0, + 0, + 0, + 21, + 315, + 1, + 0, + 0, + 0, + 23, + 324, + 1, + 0, + 0, + 0, + 25, + 334, + 1, + 0, + 0, + 0, + 27, + 346, + 1, + 0, + 0, + 0, + 29, + 356, + 1, + 0, + 0, + 0, + 31, + 363, + 1, + 0, + 0, + 0, + 33, + 370, + 1, + 0, + 0, + 0, + 35, + 379, + 1, + 0, + 0, + 0, + 37, + 386, + 1, + 0, + 0, + 0, + 39, + 396, + 1, + 0, + 0, + 0, + 41, + 403, + 1, + 0, + 0, + 0, + 43, + 410, + 1, + 0, + 0, + 0, + 45, + 421, + 1, + 0, + 0, + 0, + 47, + 427, + 1, + 0, + 0, + 0, + 49, + 437, + 1, + 0, + 0, + 0, + 51, + 448, + 1, + 0, + 0, + 0, + 53, + 458, + 1, + 0, + 0, + 0, + 55, + 469, + 1, + 0, + 0, + 0, + 57, + 475, + 1, + 0, + 0, + 0, + 59, + 491, + 1, + 0, + 0, + 0, + 61, + 511, + 1, + 0, + 0, + 0, + 63, + 523, + 1, + 0, + 0, + 0, + 65, + 532, + 1, + 0, + 0, + 0, + 67, + 544, + 1, + 0, + 0, + 0, + 69, + 556, + 1, + 0, + 0, + 0, + 71, + 567, + 1, + 0, + 0, + 0, + 73, + 581, + 1, + 0, + 0, + 0, + 75, + 587, + 1, + 0, + 0, + 0, + 77, + 603, + 1, + 0, + 0, + 0, + 79, + 623, + 1, + 0, + 0, + 0, + 81, + 644, + 1, + 0, + 0, + 0, + 83, + 669, + 1, + 0, + 0, + 0, + 85, + 696, + 1, + 0, + 0, + 0, + 87, + 727, + 1, + 0, + 0, + 0, + 89, + 745, + 1, + 0, + 0, + 0, + 91, + 767, + 1, + 0, + 0, + 0, + 93, + 791, + 1, + 0, + 0, + 0, + 95, + 819, + 1, + 0, + 0, + 0, + 97, + 824, + 1, + 0, + 0, + 0, + 99, + 839, + 1, + 0, + 0, + 0, + 101, + 858, + 1, + 0, + 0, + 0, + 103, + 878, + 1, + 0, + 0, + 0, + 105, + 902, + 1, + 0, + 0, + 0, + 107, + 928, + 1, + 0, + 0, + 0, + 109, + 958, + 1, + 0, + 0, + 0, + 111, + 975, + 1, + 0, + 0, + 0, + 113, + 996, + 1, + 0, + 0, + 0, + 115, + 1019, + 1, + 0, + 0, + 0, + 117, + 1046, + 1, + 0, + 0, + 0, + 119, + 1062, + 1, + 0, + 0, + 0, + 121, + 1080, + 1, + 0, + 0, + 0, + 123, + 1102, + 1, + 0, + 0, + 0, + 125, + 1125, + 1, + 0, + 0, + 0, + 127, + 1152, + 1, + 0, + 0, + 0, + 129, + 1181, + 1, + 0, + 0, + 0, + 131, + 1214, + 1, + 0, + 0, + 0, + 133, + 1234, + 1, + 0, + 0, + 0, + 135, + 1258, + 1, + 0, + 0, + 0, + 137, + 1284, + 1, + 0, + 0, + 0, + 139, + 1314, + 1, + 0, + 0, + 0, + 141, + 1328, + 1, + 0, + 0, + 0, + 143, + 1338, + 1, + 0, + 0, + 0, + 145, + 1354, + 1, + 0, + 0, + 0, + 147, + 1366, + 1, + 0, + 0, + 0, + 149, + 1383, + 1, + 0, + 0, + 0, + 151, + 1404, + 1, + 0, + 0, + 0, + 153, + 1423, + 1, + 0, + 0, + 0, + 155, + 1446, + 1, + 0, + 0, + 0, + 157, + 1464, + 1, + 0, + 0, + 0, + 159, + 1471, + 1, + 0, + 0, + 0, + 161, + 1480, + 1, + 0, + 0, + 0, + 163, + 1494, + 1, + 0, + 0, + 0, + 165, + 1510, + 1, + 0, + 0, + 0, + 167, + 1521, + 1, + 0, + 0, + 0, + 169, + 1537, + 1, + 0, + 0, + 0, + 171, + 1548, + 1, + 0, + 0, + 0, + 173, + 1563, + 1, + 0, + 0, + 0, + 175, + 1580, + 1, + 0, + 0, + 0, + 177, + 1591, + 1, + 0, + 0, + 0, + 179, + 1603, + 1, + 0, + 0, + 0, + 181, + 1616, + 1, + 0, + 0, + 0, + 183, + 1628, + 1, + 0, + 0, + 0, + 185, + 1641, + 1, + 0, + 0, + 0, + 187, + 1650, + 1, + 0, + 0, + 0, + 189, + 1663, + 1, + 0, + 0, + 0, + 191, + 1680, + 1, + 0, + 0, + 0, + 193, + 1693, + 1, + 0, + 0, + 0, + 195, + 1708, + 1, + 0, + 0, + 0, + 197, + 1720, + 1, + 0, + 0, + 0, + 199, + 1740, + 1, + 0, + 0, + 0, + 201, + 1753, + 1, + 0, + 0, + 0, + 203, + 1764, + 1, + 0, + 0, + 0, + 205, + 1779, + 1, + 0, + 0, + 0, + 207, + 1786, + 1, + 0, + 0, + 0, + 209, + 1792, + 1, + 0, + 0, + 0, + 211, + 1800, + 1, + 0, + 0, + 0, + 213, + 1808, + 1, + 0, + 0, + 0, + 215, + 1816, + 1, + 0, + 0, + 0, + 217, + 1830, + 1, + 0, + 0, + 0, + 219, + 1848, + 1, + 0, + 0, + 0, + 221, + 1862, + 1, + 0, + 0, + 0, + 223, + 1876, + 1, + 0, + 0, + 0, + 225, + 1884, + 1, + 0, + 0, + 0, + 227, + 1897, + 1, + 0, + 0, + 0, + 229, + 1923, + 1, + 0, + 0, + 0, + 231, + 1940, + 1, + 0, + 0, + 0, + 233, + 1960, + 1, + 0, + 0, + 0, + 235, + 1981, + 1, + 0, + 0, + 0, + 237, + 2013, + 1, + 0, + 0, + 0, + 239, + 2043, + 1, + 0, + 0, + 0, + 241, + 2065, + 1, + 0, + 0, + 0, + 243, + 2090, + 1, + 0, + 0, + 0, + 245, + 2116, + 1, + 0, + 0, + 0, + 247, + 2157, + 1, + 0, + 0, + 0, + 249, + 2183, + 1, + 0, + 0, + 0, + 251, + 2211, + 1, + 0, + 0, + 0, + 253, + 2228, + 1, + 0, + 0, + 0, + 255, + 2240, + 1, + 0, + 0, + 0, + 257, + 2253, + 1, + 0, + 0, + 0, + 259, + 2265, + 1, + 0, + 0, + 0, + 261, + 2275, + 1, + 0, + 0, + 0, + 263, + 2280, + 1, + 0, + 0, + 0, + 265, + 2286, + 1, + 0, + 0, + 0, + 267, + 2288, + 1, + 0, + 0, + 0, + 269, + 2298, + 1, + 0, + 0, + 0, + 271, + 2301, + 1, + 0, + 0, + 0, + 273, + 2315, + 1, + 0, + 0, + 0, + 275, + 2322, + 1, + 0, + 0, + 0, + 277, + 278, + 5, + 44, + 0, + 0, + 278, + 2, + 1, + 0, + 0, + 0, + 279, + 280, + 5, + 58, + 0, + 0, + 280, + 4, + 1, + 0, + 0, + 0, + 281, + 282, + 5, + 91, + 0, + 0, + 282, + 6, + 1, + 0, + 0, + 0, + 283, + 284, + 5, + 93, + 0, + 0, + 284, + 8, + 1, + 0, + 0, + 0, + 285, + 286, + 5, + 123, + 0, + 0, + 286, + 10, + 1, + 0, + 0, + 0, + 287, + 288, + 5, + 125, + 0, + 0, + 288, + 12, + 1, + 0, + 0, + 0, + 289, + 290, + 5, + 116, + 0, + 0, + 290, + 291, + 5, + 114, + 0, + 0, + 291, + 292, + 5, + 117, + 0, + 0, + 292, + 293, + 5, + 101, + 0, + 0, + 293, + 14, + 1, + 0, + 0, + 0, + 294, + 295, + 5, + 102, + 0, + 0, + 295, + 296, + 5, + 97, + 0, + 0, + 296, + 297, + 5, + 108, + 0, + 0, + 297, + 298, + 5, + 115, + 0, + 0, + 298, + 299, + 5, + 101, + 0, + 0, + 299, + 16, + 1, + 0, + 0, + 0, + 300, + 301, + 5, + 110, + 0, + 0, + 301, + 302, + 5, + 117, + 0, + 0, + 302, + 303, + 5, + 108, + 0, + 0, + 303, + 304, + 5, + 108, + 0, + 0, + 304, + 18, + 1, + 0, + 0, + 0, + 305, + 306, + 5, + 34, + 0, + 0, + 306, + 307, + 5, + 67, + 0, + 0, + 307, + 308, + 5, + 111, + 0, + 0, + 308, + 309, + 5, + 109, + 0, + 0, + 309, + 310, + 5, + 109, + 0, + 0, + 310, + 311, + 5, + 101, + 0, + 0, + 311, + 312, + 5, + 110, + 0, + 0, + 312, + 313, + 5, + 116, + 0, + 0, + 313, + 314, + 5, + 34, + 0, + 0, + 314, + 20, + 1, + 0, + 0, + 0, + 315, + 316, + 5, + 34, + 0, + 0, + 316, + 317, + 5, + 83, + 0, + 0, + 317, + 318, + 5, + 116, + 0, + 0, + 318, + 319, + 5, + 97, + 0, + 0, + 319, + 320, + 5, + 116, + 0, + 0, + 320, + 321, + 5, + 101, + 0, + 0, + 321, + 322, + 5, + 115, + 0, + 0, + 322, + 323, + 5, + 34, + 0, + 0, + 323, + 22, + 1, + 0, + 0, + 0, + 324, + 325, + 5, + 34, + 0, + 0, + 325, + 326, + 5, + 83, + 0, + 0, + 326, + 327, + 5, + 116, + 0, + 0, + 327, + 328, + 5, + 97, + 0, + 0, + 328, + 329, + 5, + 114, + 0, + 0, + 329, + 330, + 5, + 116, + 0, + 0, + 330, + 331, + 5, + 65, + 0, + 0, + 331, + 332, + 5, + 116, + 0, + 0, + 332, + 333, + 5, + 34, + 0, + 0, + 333, + 24, + 1, + 0, + 0, + 0, + 334, + 335, + 5, + 34, + 0, + 0, + 335, + 336, + 5, + 78, + 0, + 0, + 336, + 337, + 5, + 101, + 0, + 0, + 337, + 338, + 5, + 120, + 0, + 0, + 338, + 339, + 5, + 116, + 0, + 0, + 339, + 340, + 5, + 83, + 0, + 0, + 340, + 341, + 5, + 116, + 0, + 0, + 341, + 342, + 5, + 97, + 0, + 0, + 342, + 343, + 5, + 116, + 0, + 0, + 343, + 344, + 5, + 101, + 0, + 0, + 344, + 345, + 5, + 34, + 0, + 0, + 345, + 26, + 1, + 0, + 0, + 0, + 346, + 347, + 5, + 34, + 0, + 0, + 347, + 348, + 5, + 86, + 0, + 0, + 348, + 349, + 5, + 101, + 0, + 0, + 349, + 350, + 5, + 114, + 0, + 0, + 350, + 351, + 5, + 115, + 0, + 0, + 351, + 352, + 5, + 105, + 0, + 0, + 352, + 353, + 5, + 111, + 0, + 0, + 353, + 354, + 5, + 110, + 0, + 0, + 354, + 355, + 5, + 34, + 0, + 0, + 355, + 28, + 1, + 0, + 0, + 0, + 356, + 357, + 5, + 34, + 0, + 0, + 357, + 358, + 5, + 84, + 0, + 0, + 358, + 359, + 5, + 121, + 0, + 0, + 359, + 360, + 5, + 112, + 0, + 0, + 360, + 361, + 5, + 101, + 0, + 0, + 361, + 362, + 5, + 34, + 0, + 0, + 362, + 30, + 1, + 0, + 0, + 0, + 363, + 364, + 5, + 34, + 0, + 0, + 364, + 365, + 5, + 84, + 0, + 0, + 365, + 366, + 5, + 97, + 0, + 0, + 366, + 367, + 5, + 115, + 0, + 0, + 367, + 368, + 5, + 107, + 0, + 0, + 368, + 369, + 5, + 34, + 0, + 0, + 369, + 32, + 1, + 0, + 0, + 0, + 370, + 371, + 5, + 34, + 0, + 0, + 371, + 372, + 5, + 67, + 0, + 0, + 372, + 373, + 5, + 104, + 0, + 0, + 373, + 374, + 5, + 111, + 0, + 0, + 374, + 375, + 5, + 105, + 0, + 0, + 375, + 376, + 5, + 99, + 0, + 0, + 376, + 377, + 5, + 101, + 0, + 0, + 377, + 378, + 5, + 34, + 0, + 0, + 378, + 34, + 1, + 0, + 0, + 0, + 379, + 380, + 5, + 34, + 0, + 0, + 380, + 381, + 5, + 70, + 0, + 0, + 381, + 382, + 5, + 97, + 0, + 0, + 382, + 383, + 5, + 105, + 0, + 0, + 383, + 384, + 5, + 108, + 0, + 0, + 384, + 385, + 5, + 34, + 0, + 0, + 385, + 36, + 1, + 0, + 0, + 0, + 386, + 387, + 5, + 34, + 0, + 0, + 387, + 388, + 5, + 83, + 0, + 0, + 388, + 389, + 5, + 117, + 0, + 0, + 389, + 390, + 5, + 99, + 0, + 0, + 390, + 391, + 5, + 99, + 0, + 0, + 391, + 392, + 5, + 101, + 0, + 0, + 392, + 393, + 5, + 101, + 0, + 0, + 393, + 394, + 5, + 100, + 0, + 0, + 394, + 395, + 5, + 34, + 0, + 0, + 395, + 38, + 1, + 0, + 0, + 0, + 396, + 397, + 5, + 34, + 0, + 0, + 397, + 398, + 5, + 80, + 0, + 0, + 398, + 399, + 5, + 97, + 0, + 0, + 399, + 400, + 5, + 115, + 0, + 0, + 400, + 401, + 5, + 115, + 0, + 0, + 401, + 402, + 5, + 34, + 0, + 0, + 402, + 40, + 1, + 0, + 0, + 0, + 403, + 404, + 5, + 34, + 0, + 0, + 404, + 405, + 5, + 87, + 0, + 0, + 405, + 406, + 5, + 97, + 0, + 0, + 406, + 407, + 5, + 105, + 0, + 0, + 407, + 408, + 5, + 116, + 0, + 0, + 408, + 409, + 5, + 34, + 0, + 0, + 409, + 42, + 1, + 0, + 0, + 0, + 410, + 411, + 5, + 34, + 0, + 0, + 411, + 412, + 5, + 80, + 0, + 0, + 412, + 413, + 5, + 97, + 0, + 0, + 413, + 414, + 5, + 114, + 0, + 0, + 414, + 415, + 5, + 97, + 0, + 0, + 415, + 416, + 5, + 108, + 0, + 0, + 416, + 417, + 5, + 108, + 0, + 0, + 417, + 418, + 5, + 101, + 0, + 0, + 418, + 419, + 5, + 108, + 0, + 0, + 419, + 420, + 5, + 34, + 0, + 0, + 420, + 44, + 1, + 0, + 0, + 0, + 421, + 422, + 5, + 34, + 0, + 0, + 422, + 423, + 5, + 77, + 0, + 0, + 423, + 424, + 5, + 97, + 0, + 0, + 424, + 425, + 5, + 112, + 0, + 0, + 425, + 426, + 5, + 34, + 0, + 0, + 426, + 46, + 1, + 0, + 0, + 0, + 427, + 428, + 5, + 34, + 0, + 0, + 428, + 429, + 5, + 67, + 0, + 0, + 429, + 430, + 5, + 104, + 0, + 0, + 430, + 431, + 5, + 111, + 0, + 0, + 431, + 432, + 5, + 105, + 0, + 0, + 432, + 433, + 5, + 99, + 0, + 0, + 433, + 434, + 5, + 101, + 0, + 0, + 434, + 435, + 5, + 115, + 0, + 0, + 435, + 436, + 5, + 34, + 0, + 0, + 436, + 48, + 1, + 0, + 0, + 0, + 437, + 438, + 5, + 34, + 0, + 0, + 438, + 439, + 5, + 86, + 0, + 0, + 439, + 440, + 5, + 97, + 0, + 0, + 440, + 441, + 5, + 114, + 0, + 0, + 441, + 442, + 5, + 105, + 0, + 0, + 442, + 443, + 5, + 97, + 0, + 0, + 443, + 444, + 5, + 98, + 0, + 0, + 444, + 445, + 5, + 108, + 0, + 0, + 445, + 446, + 5, + 101, + 0, + 0, + 446, + 447, + 5, + 34, + 0, + 0, + 447, + 50, + 1, + 0, + 0, + 0, + 448, + 449, + 5, + 34, + 0, + 0, + 449, + 450, + 5, + 68, + 0, + 0, + 450, + 451, + 5, + 101, + 0, + 0, + 451, + 452, + 5, + 102, + 0, + 0, + 452, + 453, + 5, + 97, + 0, + 0, + 453, + 454, + 5, + 117, + 0, + 0, + 454, + 455, + 5, + 108, + 0, + 0, + 455, + 456, + 5, + 116, + 0, + 0, + 456, + 457, + 5, + 34, + 0, + 0, + 457, + 52, + 1, + 0, + 0, + 0, + 458, + 459, + 5, + 34, + 0, + 0, + 459, + 460, + 5, + 66, + 0, + 0, + 460, + 461, + 5, + 114, + 0, + 0, + 461, + 462, + 5, + 97, + 0, + 0, + 462, + 463, + 5, + 110, + 0, + 0, + 463, + 464, + 5, + 99, + 0, + 0, + 464, + 465, + 5, + 104, + 0, + 0, + 465, + 466, + 5, + 101, + 0, + 0, + 466, + 467, + 5, + 115, + 0, + 0, + 467, + 468, + 5, + 34, + 0, + 0, + 468, + 54, + 1, + 0, + 0, + 0, + 469, + 470, + 5, + 34, + 0, + 0, + 470, + 471, + 5, + 65, + 0, + 0, + 471, + 472, + 5, + 110, + 0, + 0, + 472, + 473, + 5, + 100, + 0, + 0, + 473, + 474, + 5, + 34, + 0, + 0, + 474, + 56, + 1, + 0, + 0, + 0, + 475, + 476, + 5, + 34, + 0, + 0, + 476, + 477, + 5, + 66, + 0, + 0, + 477, + 478, + 5, + 111, + 0, + 0, + 478, + 479, + 5, + 111, + 0, + 0, + 479, + 480, + 5, + 108, + 0, + 0, + 480, + 481, + 5, + 101, + 0, + 0, + 481, + 482, + 5, + 97, + 0, + 0, + 482, + 483, + 5, + 110, + 0, + 0, + 483, + 484, + 5, + 69, + 0, + 0, + 484, + 485, + 5, + 113, + 0, + 0, + 485, + 486, + 5, + 117, + 0, + 0, + 486, + 487, + 5, + 97, + 0, + 0, + 487, + 488, + 5, + 108, + 0, + 0, + 488, + 489, + 5, + 115, + 0, + 0, + 489, + 490, + 5, + 34, + 0, + 0, + 490, + 58, + 1, + 0, + 0, + 0, + 491, + 492, + 5, + 34, + 0, + 0, + 492, + 493, + 5, + 66, + 0, + 0, + 493, + 494, + 5, + 111, + 0, + 0, + 494, + 495, + 5, + 111, + 0, + 0, + 495, + 496, + 5, + 108, + 0, + 0, + 496, + 497, + 5, + 101, + 0, + 0, + 497, + 498, + 5, + 97, + 0, + 0, + 498, + 499, + 5, + 110, + 0, + 0, + 499, + 500, + 5, + 69, + 0, + 0, + 500, + 501, + 5, + 113, + 0, + 0, + 501, + 502, + 5, + 117, + 0, + 0, + 502, + 503, + 5, + 97, + 0, + 0, + 503, + 504, + 5, + 108, + 0, + 0, + 504, + 505, + 5, + 115, + 0, + 0, + 505, + 506, + 5, + 80, + 0, + 0, + 506, + 507, + 5, + 97, + 0, + 0, + 507, + 508, + 5, + 116, + 0, + 0, + 508, + 509, + 5, + 104, + 0, + 0, + 509, + 510, + 5, + 34, + 0, + 0, + 510, + 60, + 1, + 0, + 0, + 0, + 511, + 512, + 5, + 34, + 0, + 0, + 512, + 513, + 5, + 73, + 0, + 0, + 513, + 514, + 5, + 115, + 0, + 0, + 514, + 515, + 5, + 66, + 0, + 0, + 515, + 516, + 5, + 111, + 0, + 0, + 516, + 517, + 5, + 111, + 0, + 0, + 517, + 518, + 5, + 108, + 0, + 0, + 518, + 519, + 5, + 101, + 0, + 0, + 519, + 520, + 5, + 97, + 0, + 0, + 520, + 521, + 5, + 110, + 0, + 0, + 521, + 522, + 5, + 34, + 0, + 0, + 522, + 62, + 1, + 0, + 0, + 0, + 523, + 524, + 5, + 34, + 0, + 0, + 524, + 525, + 5, + 73, + 0, + 0, + 525, + 526, + 5, + 115, + 0, + 0, + 526, + 527, + 5, + 78, + 0, + 0, + 527, + 528, + 5, + 117, + 0, + 0, + 528, + 529, + 5, + 108, + 0, + 0, + 529, + 530, + 5, + 108, + 0, + 0, + 530, + 531, + 5, + 34, + 0, + 0, + 531, + 64, + 1, + 0, + 0, + 0, + 532, + 533, + 5, + 34, + 0, + 0, + 533, + 534, + 5, + 73, + 0, + 0, + 534, + 535, + 5, + 115, + 0, + 0, + 535, + 536, + 5, + 78, + 0, + 0, + 536, + 537, + 5, + 117, + 0, + 0, + 537, + 538, + 5, + 109, + 0, + 0, + 538, + 539, + 5, + 101, + 0, + 0, + 539, + 540, + 5, + 114, + 0, + 0, + 540, + 541, + 5, + 105, + 0, + 0, + 541, + 542, + 5, + 99, + 0, + 0, + 542, + 543, + 5, + 34, + 0, + 0, + 543, + 66, + 1, + 0, + 0, + 0, + 544, + 545, + 5, + 34, + 0, + 0, + 545, + 546, + 5, + 73, + 0, + 0, + 546, + 547, + 5, + 115, + 0, + 0, + 547, + 548, + 5, + 80, + 0, + 0, + 548, + 549, + 5, + 114, + 0, + 0, + 549, + 550, + 5, + 101, + 0, + 0, + 550, + 551, + 5, + 115, + 0, + 0, + 551, + 552, + 5, + 101, + 0, + 0, + 552, + 553, + 5, + 110, + 0, + 0, + 553, + 554, + 5, + 116, + 0, + 0, + 554, + 555, + 5, + 34, + 0, + 0, + 555, + 68, + 1, + 0, + 0, + 0, + 556, + 557, + 5, + 34, + 0, + 0, + 557, + 558, + 5, + 73, + 0, + 0, + 558, + 559, + 5, + 115, + 0, + 0, + 559, + 560, + 5, + 83, + 0, + 0, + 560, + 561, + 5, + 116, + 0, + 0, + 561, + 562, + 5, + 114, + 0, + 0, + 562, + 563, + 5, + 105, + 0, + 0, + 563, + 564, + 5, + 110, + 0, + 0, + 564, + 565, + 5, + 103, + 0, + 0, + 565, + 566, + 5, + 34, + 0, + 0, + 566, + 70, + 1, + 0, + 0, + 0, + 567, + 568, + 5, + 34, + 0, + 0, + 568, + 569, + 5, + 73, + 0, + 0, + 569, + 570, + 5, + 115, + 0, + 0, + 570, + 571, + 5, + 84, + 0, + 0, + 571, + 572, + 5, + 105, + 0, + 0, + 572, + 573, + 5, + 109, + 0, + 0, + 573, + 574, + 5, + 101, + 0, + 0, + 574, + 575, + 5, + 115, + 0, + 0, + 575, + 576, + 5, + 116, + 0, + 0, + 576, + 577, + 5, + 97, + 0, + 0, + 577, + 578, + 5, + 109, + 0, + 0, + 578, + 579, + 5, + 112, + 0, + 0, + 579, + 580, + 5, + 34, + 0, + 0, + 580, + 72, + 1, + 0, + 0, + 0, + 581, + 582, + 5, + 34, + 0, + 0, + 582, + 583, + 5, + 78, + 0, + 0, + 583, + 584, + 5, + 111, + 0, + 0, + 584, + 585, + 5, + 116, + 0, + 0, + 585, + 586, + 5, + 34, + 0, + 0, + 586, + 74, + 1, + 0, + 0, + 0, + 587, + 588, + 5, + 34, + 0, + 0, + 588, + 589, + 5, + 78, + 0, + 0, + 589, + 590, + 5, + 117, + 0, + 0, + 590, + 591, + 5, + 109, + 0, + 0, + 591, + 592, + 5, + 101, + 0, + 0, + 592, + 593, + 5, + 114, + 0, + 0, + 593, + 594, + 5, + 105, + 0, + 0, + 594, + 595, + 5, + 99, + 0, + 0, + 595, + 596, + 5, + 69, + 0, + 0, + 596, + 597, + 5, + 113, + 0, + 0, + 597, + 598, + 5, + 117, + 0, + 0, + 598, + 599, + 5, + 97, + 0, + 0, + 599, + 600, + 5, + 108, + 0, + 0, + 600, + 601, + 5, + 115, + 0, + 0, + 601, + 602, + 5, + 34, + 0, + 0, + 602, + 76, + 1, + 0, + 0, + 0, + 603, + 604, + 5, + 34, + 0, + 0, + 604, + 605, + 5, + 78, + 0, + 0, + 605, + 606, + 5, + 117, + 0, + 0, + 606, + 607, + 5, + 109, + 0, + 0, + 607, + 608, + 5, + 101, + 0, + 0, + 608, + 609, + 5, + 114, + 0, + 0, + 609, + 610, + 5, + 105, + 0, + 0, + 610, + 611, + 5, + 99, + 0, + 0, + 611, + 612, + 5, + 69, + 0, + 0, + 612, + 613, + 5, + 113, + 0, + 0, + 613, + 614, + 5, + 117, + 0, + 0, + 614, + 615, + 5, + 97, + 0, + 0, + 615, + 616, + 5, + 108, + 0, + 0, + 616, + 617, + 5, + 115, + 0, + 0, + 617, + 618, + 5, + 80, + 0, + 0, + 618, + 619, + 5, + 97, + 0, + 0, + 619, + 620, + 5, + 116, + 0, + 0, + 620, + 621, + 5, + 104, + 0, + 0, + 621, + 622, + 5, + 34, + 0, + 0, + 622, + 78, + 1, + 0, + 0, + 0, + 623, + 624, + 5, + 34, + 0, + 0, + 624, + 625, + 5, + 78, + 0, + 0, + 625, + 626, + 5, + 117, + 0, + 0, + 626, + 627, + 5, + 109, + 0, + 0, + 627, + 628, + 5, + 101, + 0, + 0, + 628, + 629, + 5, + 114, + 0, + 0, + 629, + 630, + 5, + 105, + 0, + 0, + 630, + 631, + 5, + 99, + 0, + 0, + 631, + 632, + 5, + 71, + 0, + 0, + 632, + 633, + 5, + 114, + 0, + 0, + 633, + 634, + 5, + 101, + 0, + 0, + 634, + 635, + 5, + 97, + 0, + 0, + 635, + 636, + 5, + 116, + 0, + 0, + 636, + 637, + 5, + 101, + 0, + 0, + 637, + 638, + 5, + 114, + 0, + 0, + 638, + 639, + 5, + 84, + 0, + 0, + 639, + 640, + 5, + 104, + 0, + 0, + 640, + 641, + 5, + 97, + 0, + 0, + 641, + 642, + 5, + 110, + 0, + 0, + 642, + 643, + 5, + 34, + 0, + 0, + 643, + 80, + 1, + 0, + 0, + 0, + 644, + 645, + 5, + 34, + 0, + 0, + 645, + 646, + 5, + 78, + 0, + 0, + 646, + 647, + 5, + 117, + 0, + 0, + 647, + 648, + 5, + 109, + 0, + 0, + 648, + 649, + 5, + 101, + 0, + 0, + 649, + 650, + 5, + 114, + 0, + 0, + 650, + 651, + 5, + 105, + 0, + 0, + 651, + 652, + 5, + 99, + 0, + 0, + 652, + 653, + 5, + 71, + 0, + 0, + 653, + 654, + 5, + 114, + 0, + 0, + 654, + 655, + 5, + 101, + 0, + 0, + 655, + 656, + 5, + 97, + 0, + 0, + 656, + 657, + 5, + 116, + 0, + 0, + 657, + 658, + 5, + 101, + 0, + 0, + 658, + 659, + 5, + 114, + 0, + 0, + 659, + 660, + 5, + 84, + 0, + 0, + 660, + 661, + 5, + 104, + 0, + 0, + 661, + 662, + 5, + 97, + 0, + 0, + 662, + 663, + 5, + 110, + 0, + 0, + 663, + 664, + 5, + 80, + 0, + 0, + 664, + 665, + 5, + 97, + 0, + 0, + 665, + 666, + 5, + 116, + 0, + 0, + 666, + 667, + 5, + 104, + 0, + 0, + 667, + 668, + 5, + 34, + 0, + 0, + 668, + 82, + 1, + 0, + 0, + 0, + 669, + 670, + 5, + 34, + 0, + 0, + 670, + 671, + 5, + 78, + 0, + 0, + 671, + 672, + 5, + 117, + 0, + 0, + 672, + 673, + 5, + 109, + 0, + 0, + 673, + 674, + 5, + 101, + 0, + 0, + 674, + 675, + 5, + 114, + 0, + 0, + 675, + 676, + 5, + 105, + 0, + 0, + 676, + 677, + 5, + 99, + 0, + 0, + 677, + 678, + 5, + 71, + 0, + 0, + 678, + 679, + 5, + 114, + 0, + 0, + 679, + 680, + 5, + 101, + 0, + 0, + 680, + 681, + 5, + 97, + 0, + 0, + 681, + 682, + 5, + 116, + 0, + 0, + 682, + 683, + 5, + 101, + 0, + 0, + 683, + 684, + 5, + 114, + 0, + 0, + 684, + 685, + 5, + 84, + 0, + 0, + 685, + 686, + 5, + 104, + 0, + 0, + 686, + 687, + 5, + 97, + 0, + 0, + 687, + 688, + 5, + 110, + 0, + 0, + 688, + 689, + 5, + 69, + 0, + 0, + 689, + 690, + 5, + 113, + 0, + 0, + 690, + 691, + 5, + 117, + 0, + 0, + 691, + 692, + 5, + 97, + 0, + 0, + 692, + 693, + 5, + 108, + 0, + 0, + 693, + 694, + 5, + 115, + 0, + 0, + 694, + 695, + 5, + 34, + 0, + 0, + 695, + 84, + 1, + 0, + 0, + 0, + 696, + 697, + 5, + 34, + 0, + 0, + 697, + 698, + 5, + 78, + 0, + 0, + 698, + 699, + 5, + 117, + 0, + 0, + 699, + 700, + 5, + 109, + 0, + 0, + 700, + 701, + 5, + 101, + 0, + 0, + 701, + 702, + 5, + 114, + 0, + 0, + 702, + 703, + 5, + 105, + 0, + 0, + 703, + 704, + 5, + 99, + 0, + 0, + 704, + 705, + 5, + 71, + 0, + 0, + 705, + 706, + 5, + 114, + 0, + 0, + 706, + 707, + 5, + 101, + 0, + 0, + 707, + 708, + 5, + 97, + 0, + 0, + 708, + 709, + 5, + 116, + 0, + 0, + 709, + 710, + 5, + 101, + 0, + 0, + 710, + 711, + 5, + 114, + 0, + 0, + 711, + 712, + 5, + 84, + 0, + 0, + 712, + 713, + 5, + 104, + 0, + 0, + 713, + 714, + 5, + 97, + 0, + 0, + 714, + 715, + 5, + 110, + 0, + 0, + 715, + 716, + 5, + 69, + 0, + 0, + 716, + 717, + 5, + 113, + 0, + 0, + 717, + 718, + 5, + 117, + 0, + 0, + 718, + 719, + 5, + 97, + 0, + 0, + 719, + 720, + 5, + 108, + 0, + 0, + 720, + 721, + 5, + 115, + 0, + 0, + 721, + 722, + 5, + 80, + 0, + 0, + 722, + 723, + 5, + 97, + 0, + 0, + 723, + 724, + 5, + 116, + 0, + 0, + 724, + 725, + 5, + 104, + 0, + 0, + 725, + 726, + 5, + 34, + 0, + 0, + 726, + 86, + 1, + 0, + 0, + 0, + 727, + 728, + 5, + 34, + 0, + 0, + 728, + 729, + 5, + 78, + 0, + 0, + 729, + 730, + 5, + 117, + 0, + 0, + 730, + 731, + 5, + 109, + 0, + 0, + 731, + 732, + 5, + 101, + 0, + 0, + 732, + 733, + 5, + 114, + 0, + 0, + 733, + 734, + 5, + 105, + 0, + 0, + 734, + 735, + 5, + 99, + 0, + 0, + 735, + 736, + 5, + 76, + 0, + 0, + 736, + 737, + 5, + 101, + 0, + 0, + 737, + 738, + 5, + 115, + 0, + 0, + 738, + 739, + 5, + 115, + 0, + 0, + 739, + 740, + 5, + 84, + 0, + 0, + 740, + 741, + 5, + 104, + 0, + 0, + 741, + 742, + 5, + 97, + 0, + 0, + 742, + 743, + 5, + 110, + 0, + 0, + 743, + 744, + 5, + 34, + 0, + 0, + 744, + 88, + 1, + 0, + 0, + 0, + 745, + 746, + 5, + 34, + 0, + 0, + 746, + 747, + 5, + 78, + 0, + 0, + 747, + 748, + 5, + 117, + 0, + 0, + 748, + 749, + 5, + 109, + 0, + 0, + 749, + 750, + 5, + 101, + 0, + 0, + 750, + 751, + 5, + 114, + 0, + 0, + 751, + 752, + 5, + 105, + 0, + 0, + 752, + 753, + 5, + 99, + 0, + 0, + 753, + 754, + 5, + 76, + 0, + 0, + 754, + 755, + 5, + 101, + 0, + 0, + 755, + 756, + 5, + 115, + 0, + 0, + 756, + 757, + 5, + 115, + 0, + 0, + 757, + 758, + 5, + 84, + 0, + 0, + 758, + 759, + 5, + 104, + 0, + 0, + 759, + 760, + 5, + 97, + 0, + 0, + 760, + 761, + 5, + 110, + 0, + 0, + 761, + 762, + 5, + 80, + 0, + 0, + 762, + 763, + 5, + 97, + 0, + 0, + 763, + 764, + 5, + 116, + 0, + 0, + 764, + 765, + 5, + 104, + 0, + 0, + 765, + 766, + 5, + 34, + 0, + 0, + 766, + 90, + 1, + 0, + 0, + 0, + 767, + 768, + 5, + 34, + 0, + 0, + 768, + 769, + 5, + 78, + 0, + 0, + 769, + 770, + 5, + 117, + 0, + 0, + 770, + 771, + 5, + 109, + 0, + 0, + 771, + 772, + 5, + 101, + 0, + 0, + 772, + 773, + 5, + 114, + 0, + 0, + 773, + 774, + 5, + 105, + 0, + 0, + 774, + 775, + 5, + 99, + 0, + 0, + 775, + 776, + 5, + 76, + 0, + 0, + 776, + 777, + 5, + 101, + 0, + 0, + 777, + 778, + 5, + 115, + 0, + 0, + 778, + 779, + 5, + 115, + 0, + 0, + 779, + 780, + 5, + 84, + 0, + 0, + 780, + 781, + 5, + 104, + 0, + 0, + 781, + 782, + 5, + 97, + 0, + 0, + 782, + 783, + 5, + 110, + 0, + 0, + 783, + 784, + 5, + 69, + 0, + 0, + 784, + 785, + 5, + 113, + 0, + 0, + 785, + 786, + 5, + 117, + 0, + 0, + 786, + 787, + 5, + 97, + 0, + 0, + 787, + 788, + 5, + 108, + 0, + 0, + 788, + 789, + 5, + 115, + 0, + 0, + 789, + 790, + 5, + 34, + 0, + 0, + 790, + 92, + 1, + 0, + 0, + 0, + 791, + 792, + 5, + 34, + 0, + 0, + 792, + 793, + 5, + 78, + 0, + 0, + 793, + 794, + 5, + 117, + 0, + 0, + 794, + 795, + 5, + 109, + 0, + 0, + 795, + 796, + 5, + 101, + 0, + 0, + 796, + 797, + 5, + 114, + 0, + 0, + 797, + 798, + 5, + 105, + 0, + 0, + 798, + 799, + 5, + 99, + 0, + 0, + 799, + 800, + 5, + 76, + 0, + 0, + 800, + 801, + 5, + 101, + 0, + 0, + 801, + 802, + 5, + 115, + 0, + 0, + 802, + 803, + 5, + 115, + 0, + 0, + 803, + 804, + 5, + 84, + 0, + 0, + 804, + 805, + 5, + 104, + 0, + 0, + 805, + 806, + 5, + 97, + 0, + 0, + 806, + 807, + 5, + 110, + 0, + 0, + 807, + 808, + 5, + 69, + 0, + 0, + 808, + 809, + 5, + 113, + 0, + 0, + 809, + 810, + 5, + 117, + 0, + 0, + 810, + 811, + 5, + 97, + 0, + 0, + 811, + 812, + 5, + 108, + 0, + 0, + 812, + 813, + 5, + 115, + 0, + 0, + 813, + 814, + 5, + 80, + 0, + 0, + 814, + 815, + 5, + 97, + 0, + 0, + 815, + 816, + 5, + 116, + 0, + 0, + 816, + 817, + 5, + 104, + 0, + 0, + 817, + 818, + 5, + 34, + 0, + 0, + 818, + 94, + 1, + 0, + 0, + 0, + 819, + 820, + 5, + 34, + 0, + 0, + 820, + 821, + 5, + 79, + 0, + 0, + 821, + 822, + 5, + 114, + 0, + 0, + 822, + 823, + 5, + 34, + 0, + 0, + 823, + 96, + 1, + 0, + 0, + 0, + 824, + 825, + 5, + 34, + 0, + 0, + 825, + 826, + 5, + 83, + 0, + 0, + 826, + 827, + 5, + 116, + 0, + 0, + 827, + 828, + 5, + 114, + 0, + 0, + 828, + 829, + 5, + 105, + 0, + 0, + 829, + 830, + 5, + 110, + 0, + 0, + 830, + 831, + 5, + 103, + 0, + 0, + 831, + 832, + 5, + 69, + 0, + 0, + 832, + 833, + 5, + 113, + 0, + 0, + 833, + 834, + 5, + 117, + 0, + 0, + 834, + 835, + 5, + 97, + 0, + 0, + 835, + 836, + 5, + 108, + 0, + 0, + 836, + 837, + 5, + 115, + 0, + 0, + 837, + 838, + 5, + 34, + 0, + 0, + 838, + 98, + 1, + 0, + 0, + 0, + 839, + 840, + 5, + 34, + 0, + 0, + 840, + 841, + 5, + 83, + 0, + 0, + 841, + 842, + 5, + 116, + 0, + 0, + 842, + 843, + 5, + 114, + 0, + 0, + 843, + 844, + 5, + 105, + 0, + 0, + 844, + 845, + 5, + 110, + 0, + 0, + 845, + 846, + 5, + 103, + 0, + 0, + 846, + 847, + 5, + 69, + 0, + 0, + 847, + 848, + 5, + 113, + 0, + 0, + 848, + 849, + 5, + 117, + 0, + 0, + 849, + 850, + 5, + 97, + 0, + 0, + 850, + 851, + 5, + 108, + 0, + 0, + 851, + 852, + 5, + 115, + 0, + 0, + 852, + 853, + 5, + 80, + 0, + 0, + 853, + 854, + 5, + 97, + 0, + 0, + 854, + 855, + 5, + 116, + 0, + 0, + 855, + 856, + 5, + 104, + 0, + 0, + 856, + 857, + 5, + 34, + 0, + 0, + 857, + 100, + 1, + 0, + 0, + 0, + 858, + 859, + 5, + 34, + 0, + 0, + 859, + 860, + 5, + 83, + 0, + 0, + 860, + 861, + 5, + 116, + 0, + 0, + 861, + 862, + 5, + 114, + 0, + 0, + 862, + 863, + 5, + 105, + 0, + 0, + 863, + 864, + 5, + 110, + 0, + 0, + 864, + 865, + 5, + 103, + 0, + 0, + 865, + 866, + 5, + 71, + 0, + 0, + 866, + 867, + 5, + 114, + 0, + 0, + 867, + 868, + 5, + 101, + 0, + 0, + 868, + 869, + 5, + 97, + 0, + 0, + 869, + 870, + 5, + 116, + 0, + 0, + 870, + 871, + 5, + 101, + 0, + 0, + 871, + 872, + 5, + 114, + 0, + 0, + 872, + 873, + 5, + 84, + 0, + 0, + 873, + 874, + 5, + 104, + 0, + 0, + 874, + 875, + 5, + 97, + 0, + 0, + 875, + 876, + 5, + 110, + 0, + 0, + 876, + 877, + 5, + 34, + 0, + 0, + 877, + 102, + 1, + 0, + 0, + 0, + 878, + 879, + 5, + 34, + 0, + 0, + 879, + 880, + 5, + 83, + 0, + 0, + 880, + 881, + 5, + 116, + 0, + 0, + 881, + 882, + 5, + 114, + 0, + 0, + 882, + 883, + 5, + 105, + 0, + 0, + 883, + 884, + 5, + 110, + 0, + 0, + 884, + 885, + 5, + 103, + 0, + 0, + 885, + 886, + 5, + 71, + 0, + 0, + 886, + 887, + 5, + 114, + 0, + 0, + 887, + 888, + 5, + 101, + 0, + 0, + 888, + 889, + 5, + 97, + 0, + 0, + 889, + 890, + 5, + 116, + 0, + 0, + 890, + 891, + 5, + 101, + 0, + 0, + 891, + 892, + 5, + 114, + 0, + 0, + 892, + 893, + 5, + 84, + 0, + 0, + 893, + 894, + 5, + 104, + 0, + 0, + 894, + 895, + 5, + 97, + 0, + 0, + 895, + 896, + 5, + 110, + 0, + 0, + 896, + 897, + 5, + 80, + 0, + 0, + 897, + 898, + 5, + 97, + 0, + 0, + 898, + 899, + 5, + 116, + 0, + 0, + 899, + 900, + 5, + 104, + 0, + 0, + 900, + 901, + 5, + 34, + 0, + 0, + 901, + 104, + 1, + 0, + 0, + 0, + 902, + 903, + 5, + 34, + 0, + 0, + 903, + 904, + 5, + 83, + 0, + 0, + 904, + 905, + 5, + 116, + 0, + 0, + 905, + 906, + 5, + 114, + 0, + 0, + 906, + 907, + 5, + 105, + 0, + 0, + 907, + 908, + 5, + 110, + 0, + 0, + 908, + 909, + 5, + 103, + 0, + 0, + 909, + 910, + 5, + 71, + 0, + 0, + 910, + 911, + 5, + 114, + 0, + 0, + 911, + 912, + 5, + 101, + 0, + 0, + 912, + 913, + 5, + 97, + 0, + 0, + 913, + 914, + 5, + 116, + 0, + 0, + 914, + 915, + 5, + 101, + 0, + 0, + 915, + 916, + 5, + 114, + 0, + 0, + 916, + 917, + 5, + 84, + 0, + 0, + 917, + 918, + 5, + 104, + 0, + 0, + 918, + 919, + 5, + 97, + 0, + 0, + 919, + 920, + 5, + 110, + 0, + 0, + 920, + 921, + 5, + 69, + 0, + 0, + 921, + 922, + 5, + 113, + 0, + 0, + 922, + 923, + 5, + 117, + 0, + 0, + 923, + 924, + 5, + 97, + 0, + 0, + 924, + 925, + 5, + 108, + 0, + 0, + 925, + 926, + 5, + 115, + 0, + 0, + 926, + 927, + 5, + 34, + 0, + 0, + 927, + 106, + 1, + 0, + 0, + 0, + 928, + 929, + 5, + 34, + 0, + 0, + 929, + 930, + 5, + 83, + 0, + 0, + 930, + 931, + 5, + 116, + 0, + 0, + 931, + 932, + 5, + 114, + 0, + 0, + 932, + 933, + 5, + 105, + 0, + 0, + 933, + 934, + 5, + 110, + 0, + 0, + 934, + 935, + 5, + 103, + 0, + 0, + 935, + 936, + 5, + 71, + 0, + 0, + 936, + 937, + 5, + 114, + 0, + 0, + 937, + 938, + 5, + 101, + 0, + 0, + 938, + 939, + 5, + 97, + 0, + 0, + 939, + 940, + 5, + 116, + 0, + 0, + 940, + 941, + 5, + 101, + 0, + 0, + 941, + 942, + 5, + 114, + 0, + 0, + 942, + 943, + 5, + 84, + 0, + 0, + 943, + 944, + 5, + 104, + 0, + 0, + 944, + 945, + 5, + 97, + 0, + 0, + 945, + 946, + 5, + 110, + 0, + 0, + 946, + 947, + 5, + 69, + 0, + 0, + 947, + 948, + 5, + 113, + 0, + 0, + 948, + 949, + 5, + 117, + 0, + 0, + 949, + 950, + 5, + 97, + 0, + 0, + 950, + 951, + 5, + 108, + 0, + 0, + 951, + 952, + 5, + 115, + 0, + 0, + 952, + 953, + 5, + 80, + 0, + 0, + 953, + 954, + 5, + 97, + 0, + 0, + 954, + 955, + 5, + 116, + 0, + 0, + 955, + 956, + 5, + 104, + 0, + 0, + 956, + 957, + 5, + 34, + 0, + 0, + 957, + 108, + 1, + 0, + 0, + 0, + 958, + 959, + 5, + 34, + 0, + 0, + 959, + 960, + 5, + 83, + 0, + 0, + 960, + 961, + 5, + 116, + 0, + 0, + 961, + 962, + 5, + 114, + 0, + 0, + 962, + 963, + 5, + 105, + 0, + 0, + 963, + 964, + 5, + 110, + 0, + 0, + 964, + 965, + 5, + 103, + 0, + 0, + 965, + 966, + 5, + 76, + 0, + 0, + 966, + 967, + 5, + 101, + 0, + 0, + 967, + 968, + 5, + 115, + 0, + 0, + 968, + 969, + 5, + 115, + 0, + 0, + 969, + 970, + 5, + 84, + 0, + 0, + 970, + 971, + 5, + 104, + 0, + 0, + 971, + 972, + 5, + 97, + 0, + 0, + 972, + 973, + 5, + 110, + 0, + 0, + 973, + 974, + 5, + 34, + 0, + 0, + 974, + 110, + 1, + 0, + 0, + 0, + 975, + 976, + 5, + 34, + 0, + 0, + 976, + 977, + 5, + 83, + 0, + 0, + 977, + 978, + 5, + 116, + 0, + 0, + 978, + 979, + 5, + 114, + 0, + 0, + 979, + 980, + 5, + 105, + 0, + 0, + 980, + 981, + 5, + 110, + 0, + 0, + 981, + 982, + 5, + 103, + 0, + 0, + 982, + 983, + 5, + 76, + 0, + 0, + 983, + 984, + 5, + 101, + 0, + 0, + 984, + 985, + 5, + 115, + 0, + 0, + 985, + 986, + 5, + 115, + 0, + 0, + 986, + 987, + 5, + 84, + 0, + 0, + 987, + 988, + 5, + 104, + 0, + 0, + 988, + 989, + 5, + 97, + 0, + 0, + 989, + 990, + 5, + 110, + 0, + 0, + 990, + 991, + 5, + 80, + 0, + 0, + 991, + 992, + 5, + 97, + 0, + 0, + 992, + 993, + 5, + 116, + 0, + 0, + 993, + 994, + 5, + 104, + 0, + 0, + 994, + 995, + 5, + 34, + 0, + 0, + 995, + 112, + 1, + 0, + 0, + 0, + 996, + 997, + 5, + 34, + 0, + 0, + 997, + 998, + 5, + 83, + 0, + 0, + 998, + 999, + 5, + 116, + 0, + 0, + 999, + 1000, + 5, + 114, + 0, + 0, + 1000, + 1001, + 5, + 105, + 0, + 0, + 1001, + 1002, + 5, + 110, + 0, + 0, + 1002, + 1003, + 5, + 103, + 0, + 0, + 1003, + 1004, + 5, + 76, + 0, + 0, + 1004, + 1005, + 5, + 101, + 0, + 0, + 1005, + 1006, + 5, + 115, + 0, + 0, + 1006, + 1007, + 5, + 115, + 0, + 0, + 1007, + 1008, + 5, + 84, + 0, + 0, + 1008, + 1009, + 5, + 104, + 0, + 0, + 1009, + 1010, + 5, + 97, + 0, + 0, + 1010, + 1011, + 5, + 110, + 0, + 0, + 1011, + 1012, + 5, + 69, + 0, + 0, + 1012, + 1013, + 5, + 113, + 0, + 0, + 1013, + 1014, + 5, + 117, + 0, + 0, + 1014, + 1015, + 5, + 97, + 0, + 0, + 1015, + 1016, + 5, + 108, + 0, + 0, + 1016, + 1017, + 5, + 115, + 0, + 0, + 1017, + 1018, + 5, + 34, + 0, + 0, + 1018, + 114, + 1, + 0, + 0, + 0, + 1019, + 1020, + 5, + 34, + 0, + 0, + 1020, + 1021, + 5, + 83, + 0, + 0, + 1021, + 1022, + 5, + 116, + 0, + 0, + 1022, + 1023, + 5, + 114, + 0, + 0, + 1023, + 1024, + 5, + 105, + 0, + 0, + 1024, + 1025, + 5, + 110, + 0, + 0, + 1025, + 1026, + 5, + 103, + 0, + 0, + 1026, + 1027, + 5, + 76, + 0, + 0, + 1027, + 1028, + 5, + 101, + 0, + 0, + 1028, + 1029, + 5, + 115, + 0, + 0, + 1029, + 1030, + 5, + 115, + 0, + 0, + 1030, + 1031, + 5, + 84, + 0, + 0, + 1031, + 1032, + 5, + 104, + 0, + 0, + 1032, + 1033, + 5, + 97, + 0, + 0, + 1033, + 1034, + 5, + 110, + 0, + 0, + 1034, + 1035, + 5, + 69, + 0, + 0, + 1035, + 1036, + 5, + 113, + 0, + 0, + 1036, + 1037, + 5, + 117, + 0, + 0, + 1037, + 1038, + 5, + 97, + 0, + 0, + 1038, + 1039, + 5, + 108, + 0, + 0, + 1039, + 1040, + 5, + 115, + 0, + 0, + 1040, + 1041, + 5, + 80, + 0, + 0, + 1041, + 1042, + 5, + 97, + 0, + 0, + 1042, + 1043, + 5, + 116, + 0, + 0, + 1043, + 1044, + 5, + 104, + 0, + 0, + 1044, + 1045, + 5, + 34, + 0, + 0, + 1045, + 116, + 1, + 0, + 0, + 0, + 1046, + 1047, + 5, + 34, + 0, + 0, + 1047, + 1048, + 5, + 83, + 0, + 0, + 1048, + 1049, + 5, + 116, + 0, + 0, + 1049, + 1050, + 5, + 114, + 0, + 0, + 1050, + 1051, + 5, + 105, + 0, + 0, + 1051, + 1052, + 5, + 110, + 0, + 0, + 1052, + 1053, + 5, + 103, + 0, + 0, + 1053, + 1054, + 5, + 77, + 0, + 0, + 1054, + 1055, + 5, + 97, + 0, + 0, + 1055, + 1056, + 5, + 116, + 0, + 0, + 1056, + 1057, + 5, + 99, + 0, + 0, + 1057, + 1058, + 5, + 104, + 0, + 0, + 1058, + 1059, + 5, + 101, + 0, + 0, + 1059, + 1060, + 5, + 115, + 0, + 0, + 1060, + 1061, + 5, + 34, + 0, + 0, + 1061, + 118, + 1, + 0, + 0, + 0, + 1062, + 1063, + 5, + 34, + 0, + 0, + 1063, + 1064, + 5, + 84, + 0, + 0, + 1064, + 1065, + 5, + 105, + 0, + 0, + 1065, + 1066, + 5, + 109, + 0, + 0, + 1066, + 1067, + 5, + 101, + 0, + 0, + 1067, + 1068, + 5, + 115, + 0, + 0, + 1068, + 1069, + 5, + 116, + 0, + 0, + 1069, + 1070, + 5, + 97, + 0, + 0, + 1070, + 1071, + 5, + 109, + 0, + 0, + 1071, + 1072, + 5, + 112, + 0, + 0, + 1072, + 1073, + 5, + 69, + 0, + 0, + 1073, + 1074, + 5, + 113, + 0, + 0, + 1074, + 1075, + 5, + 117, + 0, + 0, + 1075, + 1076, + 5, + 97, + 0, + 0, + 1076, + 1077, + 5, + 108, + 0, + 0, + 1077, + 1078, + 5, + 115, + 0, + 0, + 1078, + 1079, + 5, + 34, + 0, + 0, + 1079, + 120, + 1, + 0, + 0, + 0, + 1080, + 1081, + 5, + 34, + 0, + 0, + 1081, + 1082, + 5, + 84, + 0, + 0, + 1082, + 1083, + 5, + 105, + 0, + 0, + 1083, + 1084, + 5, + 109, + 0, + 0, + 1084, + 1085, + 5, + 101, + 0, + 0, + 1085, + 1086, + 5, + 115, + 0, + 0, + 1086, + 1087, + 5, + 116, + 0, + 0, + 1087, + 1088, + 5, + 97, + 0, + 0, + 1088, + 1089, + 5, + 109, + 0, + 0, + 1089, + 1090, + 5, + 112, + 0, + 0, + 1090, + 1091, + 5, + 69, + 0, + 0, + 1091, + 1092, + 5, + 113, + 0, + 0, + 1092, + 1093, + 5, + 117, + 0, + 0, + 1093, + 1094, + 5, + 97, + 0, + 0, + 1094, + 1095, + 5, + 108, + 0, + 0, + 1095, + 1096, + 5, + 115, + 0, + 0, + 1096, + 1097, + 5, + 80, + 0, + 0, + 1097, + 1098, + 5, + 97, + 0, + 0, + 1098, + 1099, + 5, + 116, + 0, + 0, + 1099, + 1100, + 5, + 104, + 0, + 0, + 1100, + 1101, + 5, + 34, + 0, + 0, + 1101, + 122, + 1, + 0, + 0, + 0, + 1102, + 1103, + 5, + 34, + 0, + 0, + 1103, + 1104, + 5, + 84, + 0, + 0, + 1104, + 1105, + 5, + 105, + 0, + 0, + 1105, + 1106, + 5, + 109, + 0, + 0, + 1106, + 1107, + 5, + 101, + 0, + 0, + 1107, + 1108, + 5, + 115, + 0, + 0, + 1108, + 1109, + 5, + 116, + 0, + 0, + 1109, + 1110, + 5, + 97, + 0, + 0, + 1110, + 1111, + 5, + 109, + 0, + 0, + 1111, + 1112, + 5, + 112, + 0, + 0, + 1112, + 1113, + 5, + 71, + 0, + 0, + 1113, + 1114, + 5, + 114, + 0, + 0, + 1114, + 1115, + 5, + 101, + 0, + 0, + 1115, + 1116, + 5, + 97, + 0, + 0, + 1116, + 1117, + 5, + 116, + 0, + 0, + 1117, + 1118, + 5, + 101, + 0, + 0, + 1118, + 1119, + 5, + 114, + 0, + 0, + 1119, + 1120, + 5, + 84, + 0, + 0, + 1120, + 1121, + 5, + 104, + 0, + 0, + 1121, + 1122, + 5, + 97, + 0, + 0, + 1122, + 1123, + 5, + 110, + 0, + 0, + 1123, + 1124, + 5, + 34, + 0, + 0, + 1124, + 124, + 1, + 0, + 0, + 0, + 1125, + 1126, + 5, + 34, + 0, + 0, + 1126, + 1127, + 5, + 84, + 0, + 0, + 1127, + 1128, + 5, + 105, + 0, + 0, + 1128, + 1129, + 5, + 109, + 0, + 0, + 1129, + 1130, + 5, + 101, + 0, + 0, + 1130, + 1131, + 5, + 115, + 0, + 0, + 1131, + 1132, + 5, + 116, + 0, + 0, + 1132, + 1133, + 5, + 97, + 0, + 0, + 1133, + 1134, + 5, + 109, + 0, + 0, + 1134, + 1135, + 5, + 112, + 0, + 0, + 1135, + 1136, + 5, + 71, + 0, + 0, + 1136, + 1137, + 5, + 114, + 0, + 0, + 1137, + 1138, + 5, + 101, + 0, + 0, + 1138, + 1139, + 5, + 97, + 0, + 0, + 1139, + 1140, + 5, + 116, + 0, + 0, + 1140, + 1141, + 5, + 101, + 0, + 0, + 1141, + 1142, + 5, + 114, + 0, + 0, + 1142, + 1143, + 5, + 84, + 0, + 0, + 1143, + 1144, + 5, + 104, + 0, + 0, + 1144, + 1145, + 5, + 97, + 0, + 0, + 1145, + 1146, + 5, + 110, + 0, + 0, + 1146, + 1147, + 5, + 80, + 0, + 0, + 1147, + 1148, + 5, + 97, + 0, + 0, + 1148, + 1149, + 5, + 116, + 0, + 0, + 1149, + 1150, + 5, + 104, + 0, + 0, + 1150, + 1151, + 5, + 34, + 0, + 0, + 1151, + 126, + 1, + 0, + 0, + 0, + 1152, + 1153, + 5, + 34, + 0, + 0, + 1153, + 1154, + 5, + 84, + 0, + 0, + 1154, + 1155, + 5, + 105, + 0, + 0, + 1155, + 1156, + 5, + 109, + 0, + 0, + 1156, + 1157, + 5, + 101, + 0, + 0, + 1157, + 1158, + 5, + 115, + 0, + 0, + 1158, + 1159, + 5, + 116, + 0, + 0, + 1159, + 1160, + 5, + 97, + 0, + 0, + 1160, + 1161, + 5, + 109, + 0, + 0, + 1161, + 1162, + 5, + 112, + 0, + 0, + 1162, + 1163, + 5, + 71, + 0, + 0, + 1163, + 1164, + 5, + 114, + 0, + 0, + 1164, + 1165, + 5, + 101, + 0, + 0, + 1165, + 1166, + 5, + 97, + 0, + 0, + 1166, + 1167, + 5, + 116, + 0, + 0, + 1167, + 1168, + 5, + 101, + 0, + 0, + 1168, + 1169, + 5, + 114, + 0, + 0, + 1169, + 1170, + 5, + 84, + 0, + 0, + 1170, + 1171, + 5, + 104, + 0, + 0, + 1171, + 1172, + 5, + 97, + 0, + 0, + 1172, + 1173, + 5, + 110, + 0, + 0, + 1173, + 1174, + 5, + 69, + 0, + 0, + 1174, + 1175, + 5, + 113, + 0, + 0, + 1175, + 1176, + 5, + 117, + 0, + 0, + 1176, + 1177, + 5, + 97, + 0, + 0, + 1177, + 1178, + 5, + 108, + 0, + 0, + 1178, + 1179, + 5, + 115, + 0, + 0, + 1179, + 1180, + 5, + 34, + 0, + 0, + 1180, + 128, + 1, + 0, + 0, + 0, + 1181, + 1182, + 5, + 34, + 0, + 0, + 1182, + 1183, + 5, + 84, + 0, + 0, + 1183, + 1184, + 5, + 105, + 0, + 0, + 1184, + 1185, + 5, + 109, + 0, + 0, + 1185, + 1186, + 5, + 101, + 0, + 0, + 1186, + 1187, + 5, + 115, + 0, + 0, + 1187, + 1188, + 5, + 116, + 0, + 0, + 1188, + 1189, + 5, + 97, + 0, + 0, + 1189, + 1190, + 5, + 109, + 0, + 0, + 1190, + 1191, + 5, + 112, + 0, + 0, + 1191, + 1192, + 5, + 71, + 0, + 0, + 1192, + 1193, + 5, + 114, + 0, + 0, + 1193, + 1194, + 5, + 101, + 0, + 0, + 1194, + 1195, + 5, + 97, + 0, + 0, + 1195, + 1196, + 5, + 116, + 0, + 0, + 1196, + 1197, + 5, + 101, + 0, + 0, + 1197, + 1198, + 5, + 114, + 0, + 0, + 1198, + 1199, + 5, + 84, + 0, + 0, + 1199, + 1200, + 5, + 104, + 0, + 0, + 1200, + 1201, + 5, + 97, + 0, + 0, + 1201, + 1202, + 5, + 110, + 0, + 0, + 1202, + 1203, + 5, + 69, + 0, + 0, + 1203, + 1204, + 5, + 113, + 0, + 0, + 1204, + 1205, + 5, + 117, + 0, + 0, + 1205, + 1206, + 5, + 97, + 0, + 0, + 1206, + 1207, + 5, + 108, + 0, + 0, + 1207, + 1208, + 5, + 115, + 0, + 0, + 1208, + 1209, + 5, + 80, + 0, + 0, + 1209, + 1210, + 5, + 97, + 0, + 0, + 1210, + 1211, + 5, + 116, + 0, + 0, + 1211, + 1212, + 5, + 104, + 0, + 0, + 1212, + 1213, + 5, + 34, + 0, + 0, + 1213, + 130, + 1, + 0, + 0, + 0, + 1214, + 1215, + 5, + 34, + 0, + 0, + 1215, + 1216, + 5, + 84, + 0, + 0, + 1216, + 1217, + 5, + 105, + 0, + 0, + 1217, + 1218, + 5, + 109, + 0, + 0, + 1218, + 1219, + 5, + 101, + 0, + 0, + 1219, + 1220, + 5, + 115, + 0, + 0, + 1220, + 1221, + 5, + 116, + 0, + 0, + 1221, + 1222, + 5, + 97, + 0, + 0, + 1222, + 1223, + 5, + 109, + 0, + 0, + 1223, + 1224, + 5, + 112, + 0, + 0, + 1224, + 1225, + 5, + 76, + 0, + 0, + 1225, + 1226, + 5, + 101, + 0, + 0, + 1226, + 1227, + 5, + 115, + 0, + 0, + 1227, + 1228, + 5, + 115, + 0, + 0, + 1228, + 1229, + 5, + 84, + 0, + 0, + 1229, + 1230, + 5, + 104, + 0, + 0, + 1230, + 1231, + 5, + 97, + 0, + 0, + 1231, + 1232, + 5, + 110, + 0, + 0, + 1232, + 1233, + 5, + 34, + 0, + 0, + 1233, + 132, + 1, + 0, + 0, + 0, + 1234, + 1235, + 5, + 34, + 0, + 0, + 1235, + 1236, + 5, + 84, + 0, + 0, + 1236, + 1237, + 5, + 105, + 0, + 0, + 1237, + 1238, + 5, + 109, + 0, + 0, + 1238, + 1239, + 5, + 101, + 0, + 0, + 1239, + 1240, + 5, + 115, + 0, + 0, + 1240, + 1241, + 5, + 116, + 0, + 0, + 1241, + 1242, + 5, + 97, + 0, + 0, + 1242, + 1243, + 5, + 109, + 0, + 0, + 1243, + 1244, + 5, + 112, + 0, + 0, + 1244, + 1245, + 5, + 76, + 0, + 0, + 1245, + 1246, + 5, + 101, + 0, + 0, + 1246, + 1247, + 5, + 115, + 0, + 0, + 1247, + 1248, + 5, + 115, + 0, + 0, + 1248, + 1249, + 5, + 84, + 0, + 0, + 1249, + 1250, + 5, + 104, + 0, + 0, + 1250, + 1251, + 5, + 97, + 0, + 0, + 1251, + 1252, + 5, + 110, + 0, + 0, + 1252, + 1253, + 5, + 80, + 0, + 0, + 1253, + 1254, + 5, + 97, + 0, + 0, + 1254, + 1255, + 5, + 116, + 0, + 0, + 1255, + 1256, + 5, + 104, + 0, + 0, + 1256, + 1257, + 5, + 34, + 0, + 0, + 1257, + 134, + 1, + 0, + 0, + 0, + 1258, + 1259, + 5, + 34, + 0, + 0, + 1259, + 1260, + 5, + 84, + 0, + 0, + 1260, + 1261, + 5, + 105, + 0, + 0, + 1261, + 1262, + 5, + 109, + 0, + 0, + 1262, + 1263, + 5, + 101, + 0, + 0, + 1263, + 1264, + 5, + 115, + 0, + 0, + 1264, + 1265, + 5, + 116, + 0, + 0, + 1265, + 1266, + 5, + 97, + 0, + 0, + 1266, + 1267, + 5, + 109, + 0, + 0, + 1267, + 1268, + 5, + 112, + 0, + 0, + 1268, + 1269, + 5, + 76, + 0, + 0, + 1269, + 1270, + 5, + 101, + 0, + 0, + 1270, + 1271, + 5, + 115, + 0, + 0, + 1271, + 1272, + 5, + 115, + 0, + 0, + 1272, + 1273, + 5, + 84, + 0, + 0, + 1273, + 1274, + 5, + 104, + 0, + 0, + 1274, + 1275, + 5, + 97, + 0, + 0, + 1275, + 1276, + 5, + 110, + 0, + 0, + 1276, + 1277, + 5, + 69, + 0, + 0, + 1277, + 1278, + 5, + 113, + 0, + 0, + 1278, + 1279, + 5, + 117, + 0, + 0, + 1279, + 1280, + 5, + 97, + 0, + 0, + 1280, + 1281, + 5, + 108, + 0, + 0, + 1281, + 1282, + 5, + 115, + 0, + 0, + 1282, + 1283, + 5, + 34, + 0, + 0, + 1283, + 136, + 1, + 0, + 0, + 0, + 1284, + 1285, + 5, + 34, + 0, + 0, + 1285, + 1286, + 5, + 84, + 0, + 0, + 1286, + 1287, + 5, + 105, + 0, + 0, + 1287, + 1288, + 5, + 109, + 0, + 0, + 1288, + 1289, + 5, + 101, + 0, + 0, + 1289, + 1290, + 5, + 115, + 0, + 0, + 1290, + 1291, + 5, + 116, + 0, + 0, + 1291, + 1292, + 5, + 97, + 0, + 0, + 1292, + 1293, + 5, + 109, + 0, + 0, + 1293, + 1294, + 5, + 112, + 0, + 0, + 1294, + 1295, + 5, + 76, + 0, + 0, + 1295, + 1296, + 5, + 101, + 0, + 0, + 1296, + 1297, + 5, + 115, + 0, + 0, + 1297, + 1298, + 5, + 115, + 0, + 0, + 1298, + 1299, + 5, + 84, + 0, + 0, + 1299, + 1300, + 5, + 104, + 0, + 0, + 1300, + 1301, + 5, + 97, + 0, + 0, + 1301, + 1302, + 5, + 110, + 0, + 0, + 1302, + 1303, + 5, + 69, + 0, + 0, + 1303, + 1304, + 5, + 113, + 0, + 0, + 1304, + 1305, + 5, + 117, + 0, + 0, + 1305, + 1306, + 5, + 97, + 0, + 0, + 1306, + 1307, + 5, + 108, + 0, + 0, + 1307, + 1308, + 5, + 115, + 0, + 0, + 1308, + 1309, + 5, + 80, + 0, + 0, + 1309, + 1310, + 5, + 97, + 0, + 0, + 1310, + 1311, + 5, + 116, + 0, + 0, + 1311, + 1312, + 5, + 104, + 0, + 0, + 1312, + 1313, + 5, + 34, + 0, + 0, + 1313, + 138, + 1, + 0, + 0, + 0, + 1314, + 1315, + 5, + 34, + 0, + 0, + 1315, + 1316, + 5, + 83, + 0, + 0, + 1316, + 1317, + 5, + 101, + 0, + 0, + 1317, + 1318, + 5, + 99, + 0, + 0, + 1318, + 1319, + 5, + 111, + 0, + 0, + 1319, + 1320, + 5, + 110, + 0, + 0, + 1320, + 1321, + 5, + 100, + 0, + 0, + 1321, + 1322, + 5, + 115, + 0, + 0, + 1322, + 1323, + 5, + 80, + 0, + 0, + 1323, + 1324, + 5, + 97, + 0, + 0, + 1324, + 1325, + 5, + 116, + 0, + 0, + 1325, + 1326, + 5, + 104, + 0, + 0, + 1326, + 1327, + 5, + 34, + 0, + 0, + 1327, + 140, + 1, + 0, + 0, + 0, + 1328, + 1329, + 5, + 34, + 0, + 0, + 1329, + 1330, + 5, + 83, + 0, + 0, + 1330, + 1331, + 5, + 101, + 0, + 0, + 1331, + 1332, + 5, + 99, + 0, + 0, + 1332, + 1333, + 5, + 111, + 0, + 0, + 1333, + 1334, + 5, + 110, + 0, + 0, + 1334, + 1335, + 5, + 100, + 0, + 0, + 1335, + 1336, + 5, + 115, + 0, + 0, + 1336, + 1337, + 5, + 34, + 0, + 0, + 1337, + 142, + 1, + 0, + 0, + 0, + 1338, + 1339, + 5, + 34, + 0, + 0, + 1339, + 1340, + 5, + 84, + 0, + 0, + 1340, + 1341, + 5, + 105, + 0, + 0, + 1341, + 1342, + 5, + 109, + 0, + 0, + 1342, + 1343, + 5, + 101, + 0, + 0, + 1343, + 1344, + 5, + 115, + 0, + 0, + 1344, + 1345, + 5, + 116, + 0, + 0, + 1345, + 1346, + 5, + 97, + 0, + 0, + 1346, + 1347, + 5, + 109, + 0, + 0, + 1347, + 1348, + 5, + 112, + 0, + 0, + 1348, + 1349, + 5, + 80, + 0, + 0, + 1349, + 1350, + 5, + 97, + 0, + 0, + 1350, + 1351, + 5, + 116, + 0, + 0, + 1351, + 1352, + 5, + 104, + 0, + 0, + 1352, + 1353, + 5, + 34, + 0, + 0, + 1353, + 144, + 1, + 0, + 0, + 0, + 1354, + 1355, + 5, + 34, + 0, + 0, + 1355, + 1356, + 5, + 84, + 0, + 0, + 1356, + 1357, + 5, + 105, + 0, + 0, + 1357, + 1358, + 5, + 109, + 0, + 0, + 1358, + 1359, + 5, + 101, + 0, + 0, + 1359, + 1360, + 5, + 115, + 0, + 0, + 1360, + 1361, + 5, + 116, + 0, + 0, + 1361, + 1362, + 5, + 97, + 0, + 0, + 1362, + 1363, + 5, + 109, + 0, + 0, + 1363, + 1364, + 5, + 112, + 0, + 0, + 1364, + 1365, + 5, + 34, + 0, + 0, + 1365, + 146, + 1, + 0, + 0, + 0, + 1366, + 1367, + 5, + 34, + 0, + 0, + 1367, + 1368, + 5, + 84, + 0, + 0, + 1368, + 1369, + 5, + 105, + 0, + 0, + 1369, + 1370, + 5, + 109, + 0, + 0, + 1370, + 1371, + 5, + 101, + 0, + 0, + 1371, + 1372, + 5, + 111, + 0, + 0, + 1372, + 1373, + 5, + 117, + 0, + 0, + 1373, + 1374, + 5, + 116, + 0, + 0, + 1374, + 1375, + 5, + 83, + 0, + 0, + 1375, + 1376, + 5, + 101, + 0, + 0, + 1376, + 1377, + 5, + 99, + 0, + 0, + 1377, + 1378, + 5, + 111, + 0, + 0, + 1378, + 1379, + 5, + 110, + 0, + 0, + 1379, + 1380, + 5, + 100, + 0, + 0, + 1380, + 1381, + 5, + 115, + 0, + 0, + 1381, + 1382, + 5, + 34, + 0, + 0, + 1382, + 148, + 1, + 0, + 0, + 0, + 1383, + 1384, + 5, + 34, + 0, + 0, + 1384, + 1385, + 5, + 84, + 0, + 0, + 1385, + 1386, + 5, + 105, + 0, + 0, + 1386, + 1387, + 5, + 109, + 0, + 0, + 1387, + 1388, + 5, + 101, + 0, + 0, + 1388, + 1389, + 5, + 111, + 0, + 0, + 1389, + 1390, + 5, + 117, + 0, + 0, + 1390, + 1391, + 5, + 116, + 0, + 0, + 1391, + 1392, + 5, + 83, + 0, + 0, + 1392, + 1393, + 5, + 101, + 0, + 0, + 1393, + 1394, + 5, + 99, + 0, + 0, + 1394, + 1395, + 5, + 111, + 0, + 0, + 1395, + 1396, + 5, + 110, + 0, + 0, + 1396, + 1397, + 5, + 100, + 0, + 0, + 1397, + 1398, + 5, + 115, + 0, + 0, + 1398, + 1399, + 5, + 80, + 0, + 0, + 1399, + 1400, + 5, + 97, + 0, + 0, + 1400, + 1401, + 5, + 116, + 0, + 0, + 1401, + 1402, + 5, + 104, + 0, + 0, + 1402, + 1403, + 5, + 34, + 0, + 0, + 1403, + 150, + 1, + 0, + 0, + 0, + 1404, + 1405, + 5, + 34, + 0, + 0, + 1405, + 1406, + 5, + 72, + 0, + 0, + 1406, + 1407, + 5, + 101, + 0, + 0, + 1407, + 1408, + 5, + 97, + 0, + 0, + 1408, + 1409, + 5, + 114, + 0, + 0, + 1409, + 1410, + 5, + 116, + 0, + 0, + 1410, + 1411, + 5, + 98, + 0, + 0, + 1411, + 1412, + 5, + 101, + 0, + 0, + 1412, + 1413, + 5, + 97, + 0, + 0, + 1413, + 1414, + 5, + 116, + 0, + 0, + 1414, + 1415, + 5, + 83, + 0, + 0, + 1415, + 1416, + 5, + 101, + 0, + 0, + 1416, + 1417, + 5, + 99, + 0, + 0, + 1417, + 1418, + 5, + 111, + 0, + 0, + 1418, + 1419, + 5, + 110, + 0, + 0, + 1419, + 1420, + 5, + 100, + 0, + 0, + 1420, + 1421, + 5, + 115, + 0, + 0, + 1421, + 1422, + 5, + 34, + 0, + 0, + 1422, + 152, + 1, + 0, + 0, + 0, + 1423, + 1424, + 5, + 34, + 0, + 0, + 1424, + 1425, + 5, + 72, + 0, + 0, + 1425, + 1426, + 5, + 101, + 0, + 0, + 1426, + 1427, + 5, + 97, + 0, + 0, + 1427, + 1428, + 5, + 114, + 0, + 0, + 1428, + 1429, + 5, + 116, + 0, + 0, + 1429, + 1430, + 5, + 98, + 0, + 0, + 1430, + 1431, + 5, + 101, + 0, + 0, + 1431, + 1432, + 5, + 97, + 0, + 0, + 1432, + 1433, + 5, + 116, + 0, + 0, + 1433, + 1434, + 5, + 83, + 0, + 0, + 1434, + 1435, + 5, + 101, + 0, + 0, + 1435, + 1436, + 5, + 99, + 0, + 0, + 1436, + 1437, + 5, + 111, + 0, + 0, + 1437, + 1438, + 5, + 110, + 0, + 0, + 1438, + 1439, + 5, + 100, + 0, + 0, + 1439, + 1440, + 5, + 115, + 0, + 0, + 1440, + 1441, + 5, + 80, + 0, + 0, + 1441, + 1442, + 5, + 97, + 0, + 0, + 1442, + 1443, + 5, + 116, + 0, + 0, + 1443, + 1444, + 5, + 104, + 0, + 0, + 1444, + 1445, + 5, + 34, + 0, + 0, + 1445, + 154, + 1, + 0, + 0, + 0, + 1446, + 1447, + 5, + 34, + 0, + 0, + 1447, + 1448, + 5, + 80, + 0, + 0, + 1448, + 1449, + 5, + 114, + 0, + 0, + 1449, + 1450, + 5, + 111, + 0, + 0, + 1450, + 1451, + 5, + 99, + 0, + 0, + 1451, + 1452, + 5, + 101, + 0, + 0, + 1452, + 1453, + 5, + 115, + 0, + 0, + 1453, + 1454, + 5, + 115, + 0, + 0, + 1454, + 1455, + 5, + 111, + 0, + 0, + 1455, + 1456, + 5, + 114, + 0, + 0, + 1456, + 1457, + 5, + 67, + 0, + 0, + 1457, + 1458, + 5, + 111, + 0, + 0, + 1458, + 1459, + 5, + 110, + 0, + 0, + 1459, + 1460, + 5, + 102, + 0, + 0, + 1460, + 1461, + 5, + 105, + 0, + 0, + 1461, + 1462, + 5, + 103, + 0, + 0, + 1462, + 1463, + 5, + 34, + 0, + 0, + 1463, + 156, + 1, + 0, + 0, + 0, + 1464, + 1465, + 5, + 34, + 0, + 0, + 1465, + 1466, + 5, + 77, + 0, + 0, + 1466, + 1467, + 5, + 111, + 0, + 0, + 1467, + 1468, + 5, + 100, + 0, + 0, + 1468, + 1469, + 5, + 101, + 0, + 0, + 1469, + 1470, + 5, + 34, + 0, + 0, + 1470, + 158, + 1, + 0, + 0, + 0, + 1471, + 1472, + 5, + 34, + 0, + 0, + 1472, + 1473, + 5, + 73, + 0, + 0, + 1473, + 1474, + 5, + 78, + 0, + 0, + 1474, + 1475, + 5, + 76, + 0, + 0, + 1475, + 1476, + 5, + 73, + 0, + 0, + 1476, + 1477, + 5, + 78, + 0, + 0, + 1477, + 1478, + 5, + 69, + 0, + 0, + 1478, + 1479, + 5, + 34, + 0, + 0, + 1479, + 160, + 1, + 0, + 0, + 0, + 1480, + 1481, + 5, + 34, + 0, + 0, + 1481, + 1482, + 5, + 68, + 0, + 0, + 1482, + 1483, + 5, + 73, + 0, + 0, + 1483, + 1484, + 5, + 83, + 0, + 0, + 1484, + 1485, + 5, + 84, + 0, + 0, + 1485, + 1486, + 5, + 82, + 0, + 0, + 1486, + 1487, + 5, + 73, + 0, + 0, + 1487, + 1488, + 5, + 66, + 0, + 0, + 1488, + 1489, + 5, + 85, + 0, + 0, + 1489, + 1490, + 5, + 84, + 0, + 0, + 1490, + 1491, + 5, + 69, + 0, + 0, + 1491, + 1492, + 5, + 68, + 0, + 0, + 1492, + 1493, + 5, + 34, + 0, + 0, + 1493, + 162, + 1, + 0, + 0, + 0, + 1494, + 1495, + 5, + 34, + 0, + 0, + 1495, + 1496, + 5, + 69, + 0, + 0, + 1496, + 1497, + 5, + 120, + 0, + 0, + 1497, + 1498, + 5, + 101, + 0, + 0, + 1498, + 1499, + 5, + 99, + 0, + 0, + 1499, + 1500, + 5, + 117, + 0, + 0, + 1500, + 1501, + 5, + 116, + 0, + 0, + 1501, + 1502, + 5, + 105, + 0, + 0, + 1502, + 1503, + 5, + 111, + 0, + 0, + 1503, + 1504, + 5, + 110, + 0, + 0, + 1504, + 1505, + 5, + 84, + 0, + 0, + 1505, + 1506, + 5, + 121, + 0, + 0, + 1506, + 1507, + 5, + 112, + 0, + 0, + 1507, + 1508, + 5, + 101, + 0, + 0, + 1508, + 1509, + 5, + 34, + 0, + 0, + 1509, + 164, + 1, + 0, + 0, + 0, + 1510, + 1511, + 5, + 34, + 0, + 0, + 1511, + 1512, + 5, + 83, + 0, + 0, + 1512, + 1513, + 5, + 84, + 0, + 0, + 1513, + 1514, + 5, + 65, + 0, + 0, + 1514, + 1515, + 5, + 78, + 0, + 0, + 1515, + 1516, + 5, + 68, + 0, + 0, + 1516, + 1517, + 5, + 65, + 0, + 0, + 1517, + 1518, + 5, + 82, + 0, + 0, + 1518, + 1519, + 5, + 68, + 0, + 0, + 1519, + 1520, + 5, + 34, + 0, + 0, + 1520, + 166, + 1, + 0, + 0, + 0, + 1521, + 1522, + 5, + 34, + 0, + 0, + 1522, + 1523, + 5, + 73, + 0, + 0, + 1523, + 1524, + 5, + 116, + 0, + 0, + 1524, + 1525, + 5, + 101, + 0, + 0, + 1525, + 1526, + 5, + 109, + 0, + 0, + 1526, + 1527, + 5, + 80, + 0, + 0, + 1527, + 1528, + 5, + 114, + 0, + 0, + 1528, + 1529, + 5, + 111, + 0, + 0, + 1529, + 1530, + 5, + 99, + 0, + 0, + 1530, + 1531, + 5, + 101, + 0, + 0, + 1531, + 1532, + 5, + 115, + 0, + 0, + 1532, + 1533, + 5, + 115, + 0, + 0, + 1533, + 1534, + 5, + 111, + 0, + 0, + 1534, + 1535, + 5, + 114, + 0, + 0, + 1535, + 1536, + 5, + 34, + 0, + 0, + 1536, + 168, + 1, + 0, + 0, + 0, + 1537, + 1538, + 5, + 34, + 0, + 0, + 1538, + 1539, + 5, + 73, + 0, + 0, + 1539, + 1540, + 5, + 116, + 0, + 0, + 1540, + 1541, + 5, + 101, + 0, + 0, + 1541, + 1542, + 5, + 114, + 0, + 0, + 1542, + 1543, + 5, + 97, + 0, + 0, + 1543, + 1544, + 5, + 116, + 0, + 0, + 1544, + 1545, + 5, + 111, + 0, + 0, + 1545, + 1546, + 5, + 114, + 0, + 0, + 1546, + 1547, + 5, + 34, + 0, + 0, + 1547, + 170, + 1, + 0, + 0, + 0, + 1548, + 1549, + 5, + 34, + 0, + 0, + 1549, + 1550, + 5, + 73, + 0, + 0, + 1550, + 1551, + 5, + 116, + 0, + 0, + 1551, + 1552, + 5, + 101, + 0, + 0, + 1552, + 1553, + 5, + 109, + 0, + 0, + 1553, + 1554, + 5, + 83, + 0, + 0, + 1554, + 1555, + 5, + 101, + 0, + 0, + 1555, + 1556, + 5, + 108, + 0, + 0, + 1556, + 1557, + 5, + 101, + 0, + 0, + 1557, + 1558, + 5, + 99, + 0, + 0, + 1558, + 1559, + 5, + 116, + 0, + 0, + 1559, + 1560, + 5, + 111, + 0, + 0, + 1560, + 1561, + 5, + 114, + 0, + 0, + 1561, + 1562, + 5, + 34, + 0, + 0, + 1562, + 172, + 1, + 0, + 0, + 0, + 1563, + 1564, + 5, + 34, + 0, + 0, + 1564, + 1565, + 5, + 77, + 0, + 0, + 1565, + 1566, + 5, + 97, + 0, + 0, + 1566, + 1567, + 5, + 120, + 0, + 0, + 1567, + 1568, + 5, + 67, + 0, + 0, + 1568, + 1569, + 5, + 111, + 0, + 0, + 1569, + 1570, + 5, + 110, + 0, + 0, + 1570, + 1571, + 5, + 99, + 0, + 0, + 1571, + 1572, + 5, + 117, + 0, + 0, + 1572, + 1573, + 5, + 114, + 0, + 0, + 1573, + 1574, + 5, + 114, + 0, + 0, + 1574, + 1575, + 5, + 101, + 0, + 0, + 1575, + 1576, + 5, + 110, + 0, + 0, + 1576, + 1577, + 5, + 99, + 0, + 0, + 1577, + 1578, + 5, + 121, + 0, + 0, + 1578, + 1579, + 5, + 34, + 0, + 0, + 1579, + 174, + 1, + 0, + 0, + 0, + 1580, + 1581, + 5, + 34, + 0, + 0, + 1581, + 1582, + 5, + 82, + 0, + 0, + 1582, + 1583, + 5, + 101, + 0, + 0, + 1583, + 1584, + 5, + 115, + 0, + 0, + 1584, + 1585, + 5, + 111, + 0, + 0, + 1585, + 1586, + 5, + 117, + 0, + 0, + 1586, + 1587, + 5, + 114, + 0, + 0, + 1587, + 1588, + 5, + 99, + 0, + 0, + 1588, + 1589, + 5, + 101, + 0, + 0, + 1589, + 1590, + 5, + 34, + 0, + 0, + 1590, + 176, + 1, + 0, + 0, + 0, + 1591, + 1592, + 5, + 34, + 0, + 0, + 1592, + 1593, + 5, + 73, + 0, + 0, + 1593, + 1594, + 5, + 110, + 0, + 0, + 1594, + 1595, + 5, + 112, + 0, + 0, + 1595, + 1596, + 5, + 117, + 0, + 0, + 1596, + 1597, + 5, + 116, + 0, + 0, + 1597, + 1598, + 5, + 80, + 0, + 0, + 1598, + 1599, + 5, + 97, + 0, + 0, + 1599, + 1600, + 5, + 116, + 0, + 0, + 1600, + 1601, + 5, + 104, + 0, + 0, + 1601, + 1602, + 5, + 34, + 0, + 0, + 1602, + 178, + 1, + 0, + 0, + 0, + 1603, + 1604, + 5, + 34, + 0, + 0, + 1604, + 1605, + 5, + 79, + 0, + 0, + 1605, + 1606, + 5, + 117, + 0, + 0, + 1606, + 1607, + 5, + 116, + 0, + 0, + 1607, + 1608, + 5, + 112, + 0, + 0, + 1608, + 1609, + 5, + 117, + 0, + 0, + 1609, + 1610, + 5, + 116, + 0, + 0, + 1610, + 1611, + 5, + 80, + 0, + 0, + 1611, + 1612, + 5, + 97, + 0, + 0, + 1612, + 1613, + 5, + 116, + 0, + 0, + 1613, + 1614, + 5, + 104, + 0, + 0, + 1614, + 1615, + 5, + 34, + 0, + 0, + 1615, + 180, + 1, + 0, + 0, + 0, + 1616, + 1617, + 5, + 34, + 0, + 0, + 1617, + 1618, + 5, + 73, + 0, + 0, + 1618, + 1619, + 5, + 116, + 0, + 0, + 1619, + 1620, + 5, + 101, + 0, + 0, + 1620, + 1621, + 5, + 109, + 0, + 0, + 1621, + 1622, + 5, + 115, + 0, + 0, + 1622, + 1623, + 5, + 80, + 0, + 0, + 1623, + 1624, + 5, + 97, + 0, + 0, + 1624, + 1625, + 5, + 116, + 0, + 0, + 1625, + 1626, + 5, + 104, + 0, + 0, + 1626, + 1627, + 5, + 34, + 0, + 0, + 1627, + 182, + 1, + 0, + 0, + 0, + 1628, + 1629, + 5, + 34, + 0, + 0, + 1629, + 1630, + 5, + 82, + 0, + 0, + 1630, + 1631, + 5, + 101, + 0, + 0, + 1631, + 1632, + 5, + 115, + 0, + 0, + 1632, + 1633, + 5, + 117, + 0, + 0, + 1633, + 1634, + 5, + 108, + 0, + 0, + 1634, + 1635, + 5, + 116, + 0, + 0, + 1635, + 1636, + 5, + 80, + 0, + 0, + 1636, + 1637, + 5, + 97, + 0, + 0, + 1637, + 1638, + 5, + 116, + 0, + 0, + 1638, + 1639, + 5, + 104, + 0, + 0, + 1639, + 1640, + 5, + 34, + 0, + 0, + 1640, + 184, + 1, + 0, + 0, + 0, + 1641, + 1642, + 5, + 34, + 0, + 0, + 1642, + 1643, + 5, + 82, + 0, + 0, + 1643, + 1644, + 5, + 101, + 0, + 0, + 1644, + 1645, + 5, + 115, + 0, + 0, + 1645, + 1646, + 5, + 117, + 0, + 0, + 1646, + 1647, + 5, + 108, + 0, + 0, + 1647, + 1648, + 5, + 116, + 0, + 0, + 1648, + 1649, + 5, + 34, + 0, + 0, + 1649, + 186, + 1, + 0, + 0, + 0, + 1650, + 1651, + 5, + 34, + 0, + 0, + 1651, + 1652, + 5, + 80, + 0, + 0, + 1652, + 1653, + 5, + 97, + 0, + 0, + 1653, + 1654, + 5, + 114, + 0, + 0, + 1654, + 1655, + 5, + 97, + 0, + 0, + 1655, + 1656, + 5, + 109, + 0, + 0, + 1656, + 1657, + 5, + 101, + 0, + 0, + 1657, + 1658, + 5, + 116, + 0, + 0, + 1658, + 1659, + 5, + 101, + 0, + 0, + 1659, + 1660, + 5, + 114, + 0, + 0, + 1660, + 1661, + 5, + 115, + 0, + 0, + 1661, + 1662, + 5, + 34, + 0, + 0, + 1662, + 188, + 1, + 0, + 0, + 0, + 1663, + 1664, + 5, + 34, + 0, + 0, + 1664, + 1665, + 5, + 82, + 0, + 0, + 1665, + 1666, + 5, + 101, + 0, + 0, + 1666, + 1667, + 5, + 115, + 0, + 0, + 1667, + 1668, + 5, + 117, + 0, + 0, + 1668, + 1669, + 5, + 108, + 0, + 0, + 1669, + 1670, + 5, + 116, + 0, + 0, + 1670, + 1671, + 5, + 83, + 0, + 0, + 1671, + 1672, + 5, + 101, + 0, + 0, + 1672, + 1673, + 5, + 108, + 0, + 0, + 1673, + 1674, + 5, + 101, + 0, + 0, + 1674, + 1675, + 5, + 99, + 0, + 0, + 1675, + 1676, + 5, + 116, + 0, + 0, + 1676, + 1677, + 5, + 111, + 0, + 0, + 1677, + 1678, + 5, + 114, + 0, + 0, + 1678, + 1679, + 5, + 34, + 0, + 0, + 1679, + 190, + 1, + 0, + 0, + 0, + 1680, + 1681, + 5, + 34, + 0, + 0, + 1681, + 1682, + 5, + 73, + 0, + 0, + 1682, + 1683, + 5, + 116, + 0, + 0, + 1683, + 1684, + 5, + 101, + 0, + 0, + 1684, + 1685, + 5, + 109, + 0, + 0, + 1685, + 1686, + 5, + 82, + 0, + 0, + 1686, + 1687, + 5, + 101, + 0, + 0, + 1687, + 1688, + 5, + 97, + 0, + 0, + 1688, + 1689, + 5, + 100, + 0, + 0, + 1689, + 1690, + 5, + 101, + 0, + 0, + 1690, + 1691, + 5, + 114, + 0, + 0, + 1691, + 1692, + 5, + 34, + 0, + 0, + 1692, + 192, + 1, + 0, + 0, + 0, + 1693, + 1694, + 5, + 34, + 0, + 0, + 1694, + 1695, + 5, + 82, + 0, + 0, + 1695, + 1696, + 5, + 101, + 0, + 0, + 1696, + 1697, + 5, + 97, + 0, + 0, + 1697, + 1698, + 5, + 100, + 0, + 0, + 1698, + 1699, + 5, + 101, + 0, + 0, + 1699, + 1700, + 5, + 114, + 0, + 0, + 1700, + 1701, + 5, + 67, + 0, + 0, + 1701, + 1702, + 5, + 111, + 0, + 0, + 1702, + 1703, + 5, + 110, + 0, + 0, + 1703, + 1704, + 5, + 102, + 0, + 0, + 1704, + 1705, + 5, + 105, + 0, + 0, + 1705, + 1706, + 5, + 103, + 0, + 0, + 1706, + 1707, + 5, + 34, + 0, + 0, + 1707, + 194, + 1, + 0, + 0, + 0, + 1708, + 1709, + 5, + 34, + 0, + 0, + 1709, + 1710, + 5, + 73, + 0, + 0, + 1710, + 1711, + 5, + 110, + 0, + 0, + 1711, + 1712, + 5, + 112, + 0, + 0, + 1712, + 1713, + 5, + 117, + 0, + 0, + 1713, + 1714, + 5, + 116, + 0, + 0, + 1714, + 1715, + 5, + 84, + 0, + 0, + 1715, + 1716, + 5, + 121, + 0, + 0, + 1716, + 1717, + 5, + 112, + 0, + 0, + 1717, + 1718, + 5, + 101, + 0, + 0, + 1718, + 1719, + 5, + 34, + 0, + 0, + 1719, + 196, + 1, + 0, + 0, + 0, + 1720, + 1721, + 5, + 34, + 0, + 0, + 1721, + 1722, + 5, + 67, + 0, + 0, + 1722, + 1723, + 5, + 83, + 0, + 0, + 1723, + 1724, + 5, + 86, + 0, + 0, + 1724, + 1725, + 5, + 72, + 0, + 0, + 1725, + 1726, + 5, + 101, + 0, + 0, + 1726, + 1727, + 5, + 97, + 0, + 0, + 1727, + 1728, + 5, + 100, + 0, + 0, + 1728, + 1729, + 5, + 101, + 0, + 0, + 1729, + 1730, + 5, + 114, + 0, + 0, + 1730, + 1731, + 5, + 76, + 0, + 0, + 1731, + 1732, + 5, + 111, + 0, + 0, + 1732, + 1733, + 5, + 99, + 0, + 0, + 1733, + 1734, + 5, + 97, + 0, + 0, + 1734, + 1735, + 5, + 116, + 0, + 0, + 1735, + 1736, + 5, + 105, + 0, + 0, + 1736, + 1737, + 5, + 111, + 0, + 0, + 1737, + 1738, + 5, + 110, + 0, + 0, + 1738, + 1739, + 5, + 34, + 0, + 0, + 1739, + 198, + 1, + 0, + 0, + 0, + 1740, + 1741, + 5, + 34, + 0, + 0, + 1741, + 1742, + 5, + 67, + 0, + 0, + 1742, + 1743, + 5, + 83, + 0, + 0, + 1743, + 1744, + 5, + 86, + 0, + 0, + 1744, + 1745, + 5, + 72, + 0, + 0, + 1745, + 1746, + 5, + 101, + 0, + 0, + 1746, + 1747, + 5, + 97, + 0, + 0, + 1747, + 1748, + 5, + 100, + 0, + 0, + 1748, + 1749, + 5, + 101, + 0, + 0, + 1749, + 1750, + 5, + 114, + 0, + 0, + 1750, + 1751, + 5, + 115, + 0, + 0, + 1751, + 1752, + 5, + 34, + 0, + 0, + 1752, + 200, + 1, + 0, + 0, + 0, + 1753, + 1754, + 5, + 34, + 0, + 0, + 1754, + 1755, + 5, + 77, + 0, + 0, + 1755, + 1756, + 5, + 97, + 0, + 0, + 1756, + 1757, + 5, + 120, + 0, + 0, + 1757, + 1758, + 5, + 73, + 0, + 0, + 1758, + 1759, + 5, + 116, + 0, + 0, + 1759, + 1760, + 5, + 101, + 0, + 0, + 1760, + 1761, + 5, + 109, + 0, + 0, + 1761, + 1762, + 5, + 115, + 0, + 0, + 1762, + 1763, + 5, + 34, + 0, + 0, + 1763, + 202, + 1, + 0, + 0, + 0, + 1764, + 1765, + 5, + 34, + 0, + 0, + 1765, + 1766, + 5, + 77, + 0, + 0, + 1766, + 1767, + 5, + 97, + 0, + 0, + 1767, + 1768, + 5, + 120, + 0, + 0, + 1768, + 1769, + 5, + 73, + 0, + 0, + 1769, + 1770, + 5, + 116, + 0, + 0, + 1770, + 1771, + 5, + 101, + 0, + 0, + 1771, + 1772, + 5, + 109, + 0, + 0, + 1772, + 1773, + 5, + 115, + 0, + 0, + 1773, + 1774, + 5, + 80, + 0, + 0, + 1774, + 1775, + 5, + 97, + 0, + 0, + 1775, + 1776, + 5, + 116, + 0, + 0, + 1776, + 1777, + 5, + 104, + 0, + 0, + 1777, + 1778, + 5, + 34, + 0, + 0, + 1778, + 204, + 1, + 0, + 0, + 0, + 1779, + 1780, + 5, + 34, + 0, + 0, + 1780, + 1781, + 5, + 78, + 0, + 0, + 1781, + 1782, + 5, + 101, + 0, + 0, + 1782, + 1783, + 5, + 120, + 0, + 0, + 1783, + 1784, + 5, + 116, + 0, + 0, + 1784, + 1785, + 5, + 34, + 0, + 0, + 1785, + 206, + 1, + 0, + 0, + 0, + 1786, + 1787, + 5, + 34, + 0, + 0, + 1787, + 1788, + 5, + 69, + 0, + 0, + 1788, + 1789, + 5, + 110, + 0, + 0, + 1789, + 1790, + 5, + 100, + 0, + 0, + 1790, + 1791, + 5, + 34, + 0, + 0, + 1791, + 208, + 1, + 0, + 0, + 0, + 1792, + 1793, + 5, + 34, + 0, + 0, + 1793, + 1794, + 5, + 67, + 0, + 0, + 1794, + 1795, + 5, + 97, + 0, + 0, + 1795, + 1796, + 5, + 117, + 0, + 0, + 1796, + 1797, + 5, + 115, + 0, + 0, + 1797, + 1798, + 5, + 101, + 0, + 0, + 1798, + 1799, + 5, + 34, + 0, + 0, + 1799, + 210, + 1, + 0, + 0, + 0, + 1800, + 1801, + 5, + 34, + 0, + 0, + 1801, + 1802, + 5, + 69, + 0, + 0, + 1802, + 1803, + 5, + 114, + 0, + 0, + 1803, + 1804, + 5, + 114, + 0, + 0, + 1804, + 1805, + 5, + 111, + 0, + 0, + 1805, + 1806, + 5, + 114, + 0, + 0, + 1806, + 1807, + 5, + 34, + 0, + 0, + 1807, + 212, + 1, + 0, + 0, + 0, + 1808, + 1809, + 5, + 34, + 0, + 0, + 1809, + 1810, + 5, + 82, + 0, + 0, + 1810, + 1811, + 5, + 101, + 0, + 0, + 1811, + 1812, + 5, + 116, + 0, + 0, + 1812, + 1813, + 5, + 114, + 0, + 0, + 1813, + 1814, + 5, + 121, + 0, + 0, + 1814, + 1815, + 5, + 34, + 0, + 0, + 1815, + 214, + 1, + 0, + 0, + 0, + 1816, + 1817, + 5, + 34, + 0, + 0, + 1817, + 1818, + 5, + 69, + 0, + 0, + 1818, + 1819, + 5, + 114, + 0, + 0, + 1819, + 1820, + 5, + 114, + 0, + 0, + 1820, + 1821, + 5, + 111, + 0, + 0, + 1821, + 1822, + 5, + 114, + 0, + 0, + 1822, + 1823, + 5, + 69, + 0, + 0, + 1823, + 1824, + 5, + 113, + 0, + 0, + 1824, + 1825, + 5, + 117, + 0, + 0, + 1825, + 1826, + 5, + 97, + 0, + 0, + 1826, + 1827, + 5, + 108, + 0, + 0, + 1827, + 1828, + 5, + 115, + 0, + 0, + 1828, + 1829, + 5, + 34, + 0, + 0, + 1829, + 216, + 1, + 0, + 0, + 0, + 1830, + 1831, + 5, + 34, + 0, + 0, + 1831, + 1832, + 5, + 73, + 0, + 0, + 1832, + 1833, + 5, + 110, + 0, + 0, + 1833, + 1834, + 5, + 116, + 0, + 0, + 1834, + 1835, + 5, + 101, + 0, + 0, + 1835, + 1836, + 5, + 114, + 0, + 0, + 1836, + 1837, + 5, + 118, + 0, + 0, + 1837, + 1838, + 5, + 97, + 0, + 0, + 1838, + 1839, + 5, + 108, + 0, + 0, + 1839, + 1840, + 5, + 83, + 0, + 0, + 1840, + 1841, + 5, + 101, + 0, + 0, + 1841, + 1842, + 5, + 99, + 0, + 0, + 1842, + 1843, + 5, + 111, + 0, + 0, + 1843, + 1844, + 5, + 110, + 0, + 0, + 1844, + 1845, + 5, + 100, + 0, + 0, + 1845, + 1846, + 5, + 115, + 0, + 0, + 1846, + 1847, + 5, + 34, + 0, + 0, + 1847, + 218, + 1, + 0, + 0, + 0, + 1848, + 1849, + 5, + 34, + 0, + 0, + 1849, + 1850, + 5, + 77, + 0, + 0, + 1850, + 1851, + 5, + 97, + 0, + 0, + 1851, + 1852, + 5, + 120, + 0, + 0, + 1852, + 1853, + 5, + 65, + 0, + 0, + 1853, + 1854, + 5, + 116, + 0, + 0, + 1854, + 1855, + 5, + 116, + 0, + 0, + 1855, + 1856, + 5, + 101, + 0, + 0, + 1856, + 1857, + 5, + 109, + 0, + 0, + 1857, + 1858, + 5, + 112, + 0, + 0, + 1858, + 1859, + 5, + 116, + 0, + 0, + 1859, + 1860, + 5, + 115, + 0, + 0, + 1860, + 1861, + 5, + 34, + 0, + 0, + 1861, + 220, + 1, + 0, + 0, + 0, + 1862, + 1863, + 5, + 34, + 0, + 0, + 1863, + 1864, + 5, + 66, + 0, + 0, + 1864, + 1865, + 5, + 97, + 0, + 0, + 1865, + 1866, + 5, + 99, + 0, + 0, + 1866, + 1867, + 5, + 107, + 0, + 0, + 1867, + 1868, + 5, + 111, + 0, + 0, + 1868, + 1869, + 5, + 102, + 0, + 0, + 1869, + 1870, + 5, + 102, + 0, + 0, + 1870, + 1871, + 5, + 82, + 0, + 0, + 1871, + 1872, + 5, + 97, + 0, + 0, + 1872, + 1873, + 5, + 116, + 0, + 0, + 1873, + 1874, + 5, + 101, + 0, + 0, + 1874, + 1875, + 5, + 34, + 0, + 0, + 1875, + 222, + 1, + 0, + 0, + 0, + 1876, + 1877, + 5, + 34, + 0, + 0, + 1877, + 1878, + 5, + 67, + 0, + 0, + 1878, + 1879, + 5, + 97, + 0, + 0, + 1879, + 1880, + 5, + 116, + 0, + 0, + 1880, + 1881, + 5, + 99, + 0, + 0, + 1881, + 1882, + 5, + 104, + 0, + 0, + 1882, + 1883, + 5, + 34, + 0, + 0, + 1883, + 224, + 1, + 0, + 0, + 0, + 1884, + 1885, + 5, + 34, + 0, + 0, + 1885, + 1886, + 5, + 83, + 0, + 0, + 1886, + 1887, + 5, + 116, + 0, + 0, + 1887, + 1888, + 5, + 97, + 0, + 0, + 1888, + 1889, + 5, + 116, + 0, + 0, + 1889, + 1890, + 5, + 101, + 0, + 0, + 1890, + 1891, + 5, + 115, + 0, + 0, + 1891, + 1892, + 5, + 46, + 0, + 0, + 1892, + 1893, + 5, + 65, + 0, + 0, + 1893, + 1894, + 5, + 76, + 0, + 0, + 1894, + 1895, + 5, + 76, + 0, + 0, + 1895, + 1896, + 5, + 34, + 0, + 0, + 1896, + 226, + 1, + 0, + 0, + 0, + 1897, + 1898, + 5, + 34, + 0, + 0, + 1898, + 1899, + 5, + 83, + 0, + 0, + 1899, + 1900, + 5, + 116, + 0, + 0, + 1900, + 1901, + 5, + 97, + 0, + 0, + 1901, + 1902, + 5, + 116, + 0, + 0, + 1902, + 1903, + 5, + 101, + 0, + 0, + 1903, + 1904, + 5, + 115, + 0, + 0, + 1904, + 1905, + 5, + 46, + 0, + 0, + 1905, + 1906, + 5, + 72, + 0, + 0, + 1906, + 1907, + 5, + 101, + 0, + 0, + 1907, + 1908, + 5, + 97, + 0, + 0, + 1908, + 1909, + 5, + 114, + 0, + 0, + 1909, + 1910, + 5, + 116, + 0, + 0, + 1910, + 1911, + 5, + 98, + 0, + 0, + 1911, + 1912, + 5, + 101, + 0, + 0, + 1912, + 1913, + 5, + 97, + 0, + 0, + 1913, + 1914, + 5, + 116, + 0, + 0, + 1914, + 1915, + 5, + 84, + 0, + 0, + 1915, + 1916, + 5, + 105, + 0, + 0, + 1916, + 1917, + 5, + 109, + 0, + 0, + 1917, + 1918, + 5, + 101, + 0, + 0, + 1918, + 1919, + 5, + 111, + 0, + 0, + 1919, + 1920, + 5, + 117, + 0, + 0, + 1920, + 1921, + 5, + 116, + 0, + 0, + 1921, + 1922, + 5, + 34, + 0, + 0, + 1922, + 228, + 1, + 0, + 0, + 0, + 1923, + 1924, + 5, + 34, + 0, + 0, + 1924, + 1925, + 5, + 83, + 0, + 0, + 1925, + 1926, + 5, + 116, + 0, + 0, + 1926, + 1927, + 5, + 97, + 0, + 0, + 1927, + 1928, + 5, + 116, + 0, + 0, + 1928, + 1929, + 5, + 101, + 0, + 0, + 1929, + 1930, + 5, + 115, + 0, + 0, + 1930, + 1931, + 5, + 46, + 0, + 0, + 1931, + 1932, + 5, + 84, + 0, + 0, + 1932, + 1933, + 5, + 105, + 0, + 0, + 1933, + 1934, + 5, + 109, + 0, + 0, + 1934, + 1935, + 5, + 101, + 0, + 0, + 1935, + 1936, + 5, + 111, + 0, + 0, + 1936, + 1937, + 5, + 117, + 0, + 0, + 1937, + 1938, + 5, + 116, + 0, + 0, + 1938, + 1939, + 5, + 34, + 0, + 0, + 1939, + 230, + 1, + 0, + 0, + 0, + 1940, + 1941, + 5, + 34, + 0, + 0, + 1941, + 1942, + 5, + 83, + 0, + 0, + 1942, + 1943, + 5, + 116, + 0, + 0, + 1943, + 1944, + 5, + 97, + 0, + 0, + 1944, + 1945, + 5, + 116, + 0, + 0, + 1945, + 1946, + 5, + 101, + 0, + 0, + 1946, + 1947, + 5, + 115, + 0, + 0, + 1947, + 1948, + 5, + 46, + 0, + 0, + 1948, + 1949, + 5, + 84, + 0, + 0, + 1949, + 1950, + 5, + 97, + 0, + 0, + 1950, + 1951, + 5, + 115, + 0, + 0, + 1951, + 1952, + 5, + 107, + 0, + 0, + 1952, + 1953, + 5, + 70, + 0, + 0, + 1953, + 1954, + 5, + 97, + 0, + 0, + 1954, + 1955, + 5, + 105, + 0, + 0, + 1955, + 1956, + 5, + 108, + 0, + 0, + 1956, + 1957, + 5, + 101, + 0, + 0, + 1957, + 1958, + 5, + 100, + 0, + 0, + 1958, + 1959, + 5, + 34, + 0, + 0, + 1959, + 232, + 1, + 0, + 0, + 0, + 1960, + 1961, + 5, + 34, + 0, + 0, + 1961, + 1962, + 5, + 83, + 0, + 0, + 1962, + 1963, + 5, + 116, + 0, + 0, + 1963, + 1964, + 5, + 97, + 0, + 0, + 1964, + 1965, + 5, + 116, + 0, + 0, + 1965, + 1966, + 5, + 101, + 0, + 0, + 1966, + 1967, + 5, + 115, + 0, + 0, + 1967, + 1968, + 5, + 46, + 0, + 0, + 1968, + 1969, + 5, + 80, + 0, + 0, + 1969, + 1970, + 5, + 101, + 0, + 0, + 1970, + 1971, + 5, + 114, + 0, + 0, + 1971, + 1972, + 5, + 109, + 0, + 0, + 1972, + 1973, + 5, + 105, + 0, + 0, + 1973, + 1974, + 5, + 115, + 0, + 0, + 1974, + 1975, + 5, + 115, + 0, + 0, + 1975, + 1976, + 5, + 105, + 0, + 0, + 1976, + 1977, + 5, + 111, + 0, + 0, + 1977, + 1978, + 5, + 110, + 0, + 0, + 1978, + 1979, + 5, + 115, + 0, + 0, + 1979, + 1980, + 5, + 34, + 0, + 0, + 1980, + 234, + 1, + 0, + 0, + 0, + 1981, + 1982, + 5, + 34, + 0, + 0, + 1982, + 1983, + 5, + 83, + 0, + 0, + 1983, + 1984, + 5, + 116, + 0, + 0, + 1984, + 1985, + 5, + 97, + 0, + 0, + 1985, + 1986, + 5, + 116, + 0, + 0, + 1986, + 1987, + 5, + 101, + 0, + 0, + 1987, + 1988, + 5, + 115, + 0, + 0, + 1988, + 1989, + 5, + 46, + 0, + 0, + 1989, + 1990, + 5, + 82, + 0, + 0, + 1990, + 1991, + 5, + 101, + 0, + 0, + 1991, + 1992, + 5, + 115, + 0, + 0, + 1992, + 1993, + 5, + 117, + 0, + 0, + 1993, + 1994, + 5, + 108, + 0, + 0, + 1994, + 1995, + 5, + 116, + 0, + 0, + 1995, + 1996, + 5, + 80, + 0, + 0, + 1996, + 1997, + 5, + 97, + 0, + 0, + 1997, + 1998, + 5, + 116, + 0, + 0, + 1998, + 1999, + 5, + 104, + 0, + 0, + 1999, + 2000, + 5, + 77, + 0, + 0, + 2000, + 2001, + 5, + 97, + 0, + 0, + 2001, + 2002, + 5, + 116, + 0, + 0, + 2002, + 2003, + 5, + 99, + 0, + 0, + 2003, + 2004, + 5, + 104, + 0, + 0, + 2004, + 2005, + 5, + 70, + 0, + 0, + 2005, + 2006, + 5, + 97, + 0, + 0, + 2006, + 2007, + 5, + 105, + 0, + 0, + 2007, + 2008, + 5, + 108, + 0, + 0, + 2008, + 2009, + 5, + 117, + 0, + 0, + 2009, + 2010, + 5, + 114, + 0, + 0, + 2010, + 2011, + 5, + 101, + 0, + 0, + 2011, + 2012, + 5, + 34, + 0, + 0, + 2012, + 236, + 1, + 0, + 0, + 0, + 2013, + 2014, + 5, + 34, + 0, + 0, + 2014, + 2015, + 5, + 83, + 0, + 0, + 2015, + 2016, + 5, + 116, + 0, + 0, + 2016, + 2017, + 5, + 97, + 0, + 0, + 2017, + 2018, + 5, + 116, + 0, + 0, + 2018, + 2019, + 5, + 101, + 0, + 0, + 2019, + 2020, + 5, + 115, + 0, + 0, + 2020, + 2021, + 5, + 46, + 0, + 0, + 2021, + 2022, + 5, + 80, + 0, + 0, + 2022, + 2023, + 5, + 97, + 0, + 0, + 2023, + 2024, + 5, + 114, + 0, + 0, + 2024, + 2025, + 5, + 97, + 0, + 0, + 2025, + 2026, + 5, + 109, + 0, + 0, + 2026, + 2027, + 5, + 101, + 0, + 0, + 2027, + 2028, + 5, + 116, + 0, + 0, + 2028, + 2029, + 5, + 101, + 0, + 0, + 2029, + 2030, + 5, + 114, + 0, + 0, + 2030, + 2031, + 5, + 80, + 0, + 0, + 2031, + 2032, + 5, + 97, + 0, + 0, + 2032, + 2033, + 5, + 116, + 0, + 0, + 2033, + 2034, + 5, + 104, + 0, + 0, + 2034, + 2035, + 5, + 70, + 0, + 0, + 2035, + 2036, + 5, + 97, + 0, + 0, + 2036, + 2037, + 5, + 105, + 0, + 0, + 2037, + 2038, + 5, + 108, + 0, + 0, + 2038, + 2039, + 5, + 117, + 0, + 0, + 2039, + 2040, + 5, + 114, + 0, + 0, + 2040, + 2041, + 5, + 101, + 0, + 0, + 2041, + 2042, + 5, + 34, + 0, + 0, + 2042, + 238, + 1, + 0, + 0, + 0, + 2043, + 2044, + 5, + 34, + 0, + 0, + 2044, + 2045, + 5, + 83, + 0, + 0, + 2045, + 2046, + 5, + 116, + 0, + 0, + 2046, + 2047, + 5, + 97, + 0, + 0, + 2047, + 2048, + 5, + 116, + 0, + 0, + 2048, + 2049, + 5, + 101, + 0, + 0, + 2049, + 2050, + 5, + 115, + 0, + 0, + 2050, + 2051, + 5, + 46, + 0, + 0, + 2051, + 2052, + 5, + 66, + 0, + 0, + 2052, + 2053, + 5, + 114, + 0, + 0, + 2053, + 2054, + 5, + 97, + 0, + 0, + 2054, + 2055, + 5, + 110, + 0, + 0, + 2055, + 2056, + 5, + 99, + 0, + 0, + 2056, + 2057, + 5, + 104, + 0, + 0, + 2057, + 2058, + 5, + 70, + 0, + 0, + 2058, + 2059, + 5, + 97, + 0, + 0, + 2059, + 2060, + 5, + 105, + 0, + 0, + 2060, + 2061, + 5, + 108, + 0, + 0, + 2061, + 2062, + 5, + 101, + 0, + 0, + 2062, + 2063, + 5, + 100, + 0, + 0, + 2063, + 2064, + 5, + 34, + 0, + 0, + 2064, + 240, + 1, + 0, + 0, + 0, + 2065, + 2066, + 5, + 34, + 0, + 0, + 2066, + 2067, + 5, + 83, + 0, + 0, + 2067, + 2068, + 5, + 116, + 0, + 0, + 2068, + 2069, + 5, + 97, + 0, + 0, + 2069, + 2070, + 5, + 116, + 0, + 0, + 2070, + 2071, + 5, + 101, + 0, + 0, + 2071, + 2072, + 5, + 115, + 0, + 0, + 2072, + 2073, + 5, + 46, + 0, + 0, + 2073, + 2074, + 5, + 78, + 0, + 0, + 2074, + 2075, + 5, + 111, + 0, + 0, + 2075, + 2076, + 5, + 67, + 0, + 0, + 2076, + 2077, + 5, + 104, + 0, + 0, + 2077, + 2078, + 5, + 111, + 0, + 0, + 2078, + 2079, + 5, + 105, + 0, + 0, + 2079, + 2080, + 5, + 99, + 0, + 0, + 2080, + 2081, + 5, + 101, + 0, + 0, + 2081, + 2082, + 5, + 77, + 0, + 0, + 2082, + 2083, + 5, + 97, + 0, + 0, + 2083, + 2084, + 5, + 116, + 0, + 0, + 2084, + 2085, + 5, + 99, + 0, + 0, + 2085, + 2086, + 5, + 104, + 0, + 0, + 2086, + 2087, + 5, + 101, + 0, + 0, + 2087, + 2088, + 5, + 100, + 0, + 0, + 2088, + 2089, + 5, + 34, + 0, + 0, + 2089, + 242, + 1, + 0, + 0, + 0, + 2090, + 2091, + 5, + 34, + 0, + 0, + 2091, + 2092, + 5, + 83, + 0, + 0, + 2092, + 2093, + 5, + 116, + 0, + 0, + 2093, + 2094, + 5, + 97, + 0, + 0, + 2094, + 2095, + 5, + 116, + 0, + 0, + 2095, + 2096, + 5, + 101, + 0, + 0, + 2096, + 2097, + 5, + 115, + 0, + 0, + 2097, + 2098, + 5, + 46, + 0, + 0, + 2098, + 2099, + 5, + 73, + 0, + 0, + 2099, + 2100, + 5, + 110, + 0, + 0, + 2100, + 2101, + 5, + 116, + 0, + 0, + 2101, + 2102, + 5, + 114, + 0, + 0, + 2102, + 2103, + 5, + 105, + 0, + 0, + 2103, + 2104, + 5, + 110, + 0, + 0, + 2104, + 2105, + 5, + 115, + 0, + 0, + 2105, + 2106, + 5, + 105, + 0, + 0, + 2106, + 2107, + 5, + 99, + 0, + 0, + 2107, + 2108, + 5, + 70, + 0, + 0, + 2108, + 2109, + 5, + 97, + 0, + 0, + 2109, + 2110, + 5, + 105, + 0, + 0, + 2110, + 2111, + 5, + 108, + 0, + 0, + 2111, + 2112, + 5, + 117, + 0, + 0, + 2112, + 2113, + 5, + 114, + 0, + 0, + 2113, + 2114, + 5, + 101, + 0, + 0, + 2114, + 2115, + 5, + 34, + 0, + 0, + 2115, + 244, + 1, + 0, + 0, + 0, + 2116, + 2117, + 5, + 34, + 0, + 0, + 2117, + 2118, + 5, + 83, + 0, + 0, + 2118, + 2119, + 5, + 116, + 0, + 0, + 2119, + 2120, + 5, + 97, + 0, + 0, + 2120, + 2121, + 5, + 116, + 0, + 0, + 2121, + 2122, + 5, + 101, + 0, + 0, + 2122, + 2123, + 5, + 115, + 0, + 0, + 2123, + 2124, + 5, + 46, + 0, + 0, + 2124, + 2125, + 5, + 69, + 0, + 0, + 2125, + 2126, + 5, + 120, + 0, + 0, + 2126, + 2127, + 5, + 99, + 0, + 0, + 2127, + 2128, + 5, + 101, + 0, + 0, + 2128, + 2129, + 5, + 101, + 0, + 0, + 2129, + 2130, + 5, + 100, + 0, + 0, + 2130, + 2131, + 5, + 84, + 0, + 0, + 2131, + 2132, + 5, + 111, + 0, + 0, + 2132, + 2133, + 5, + 108, + 0, + 0, + 2133, + 2134, + 5, + 101, + 0, + 0, + 2134, + 2135, + 5, + 114, + 0, + 0, + 2135, + 2136, + 5, + 97, + 0, + 0, + 2136, + 2137, + 5, + 116, + 0, + 0, + 2137, + 2138, + 5, + 101, + 0, + 0, + 2138, + 2139, + 5, + 100, + 0, + 0, + 2139, + 2140, + 5, + 70, + 0, + 0, + 2140, + 2141, + 5, + 97, + 0, + 0, + 2141, + 2142, + 5, + 105, + 0, + 0, + 2142, + 2143, + 5, + 108, + 0, + 0, + 2143, + 2144, + 5, + 117, + 0, + 0, + 2144, + 2145, + 5, + 114, + 0, + 0, + 2145, + 2146, + 5, + 101, + 0, + 0, + 2146, + 2147, + 5, + 84, + 0, + 0, + 2147, + 2148, + 5, + 104, + 0, + 0, + 2148, + 2149, + 5, + 114, + 0, + 0, + 2149, + 2150, + 5, + 101, + 0, + 0, + 2150, + 2151, + 5, + 115, + 0, + 0, + 2151, + 2152, + 5, + 104, + 0, + 0, + 2152, + 2153, + 5, + 111, + 0, + 0, + 2153, + 2154, + 5, + 108, + 0, + 0, + 2154, + 2155, + 5, + 100, + 0, + 0, + 2155, + 2156, + 5, + 34, + 0, + 0, + 2156, + 246, + 1, + 0, + 0, + 0, + 2157, + 2158, + 5, + 34, + 0, + 0, + 2158, + 2159, + 5, + 83, + 0, + 0, + 2159, + 2160, + 5, + 116, + 0, + 0, + 2160, + 2161, + 5, + 97, + 0, + 0, + 2161, + 2162, + 5, + 116, + 0, + 0, + 2162, + 2163, + 5, + 101, + 0, + 0, + 2163, + 2164, + 5, + 115, + 0, + 0, + 2164, + 2165, + 5, + 46, + 0, + 0, + 2165, + 2166, + 5, + 73, + 0, + 0, + 2166, + 2167, + 5, + 116, + 0, + 0, + 2167, + 2168, + 5, + 101, + 0, + 0, + 2168, + 2169, + 5, + 109, + 0, + 0, + 2169, + 2170, + 5, + 82, + 0, + 0, + 2170, + 2171, + 5, + 101, + 0, + 0, + 2171, + 2172, + 5, + 97, + 0, + 0, + 2172, + 2173, + 5, + 100, + 0, + 0, + 2173, + 2174, + 5, + 101, + 0, + 0, + 2174, + 2175, + 5, + 114, + 0, + 0, + 2175, + 2176, + 5, + 70, + 0, + 0, + 2176, + 2177, + 5, + 97, + 0, + 0, + 2177, + 2178, + 5, + 105, + 0, + 0, + 2178, + 2179, + 5, + 108, + 0, + 0, + 2179, + 2180, + 5, + 101, + 0, + 0, + 2180, + 2181, + 5, + 100, + 0, + 0, + 2181, + 2182, + 5, + 34, + 0, + 0, + 2182, + 248, + 1, + 0, + 0, + 0, + 2183, + 2184, + 5, + 34, + 0, + 0, + 2184, + 2185, + 5, + 83, + 0, + 0, + 2185, + 2186, + 5, + 116, + 0, + 0, + 2186, + 2187, + 5, + 97, + 0, + 0, + 2187, + 2188, + 5, + 116, + 0, + 0, + 2188, + 2189, + 5, + 101, + 0, + 0, + 2189, + 2190, + 5, + 115, + 0, + 0, + 2190, + 2191, + 5, + 46, + 0, + 0, + 2191, + 2192, + 5, + 82, + 0, + 0, + 2192, + 2193, + 5, + 101, + 0, + 0, + 2193, + 2194, + 5, + 115, + 0, + 0, + 2194, + 2195, + 5, + 117, + 0, + 0, + 2195, + 2196, + 5, + 108, + 0, + 0, + 2196, + 2197, + 5, + 116, + 0, + 0, + 2197, + 2198, + 5, + 87, + 0, + 0, + 2198, + 2199, + 5, + 114, + 0, + 0, + 2199, + 2200, + 5, + 105, + 0, + 0, + 2200, + 2201, + 5, + 116, + 0, + 0, + 2201, + 2202, + 5, + 101, + 0, + 0, + 2202, + 2203, + 5, + 114, + 0, + 0, + 2203, + 2204, + 5, + 70, + 0, + 0, + 2204, + 2205, + 5, + 97, + 0, + 0, + 2205, + 2206, + 5, + 105, + 0, + 0, + 2206, + 2207, + 5, + 108, + 0, + 0, + 2207, + 2208, + 5, + 101, + 0, + 0, + 2208, + 2209, + 5, + 100, + 0, + 0, + 2209, + 2210, + 5, + 34, + 0, + 0, + 2210, + 250, + 1, + 0, + 0, + 0, + 2211, + 2212, + 5, + 34, + 0, + 0, + 2212, + 2213, + 5, + 83, + 0, + 0, + 2213, + 2214, + 5, + 116, + 0, + 0, + 2214, + 2215, + 5, + 97, + 0, + 0, + 2215, + 2216, + 5, + 116, + 0, + 0, + 2216, + 2217, + 5, + 101, + 0, + 0, + 2217, + 2218, + 5, + 115, + 0, + 0, + 2218, + 2219, + 5, + 46, + 0, + 0, + 2219, + 2220, + 5, + 82, + 0, + 0, + 2220, + 2221, + 5, + 117, + 0, + 0, + 2221, + 2222, + 5, + 110, + 0, + 0, + 2222, + 2223, + 5, + 116, + 0, + 0, + 2223, + 2224, + 5, + 105, + 0, + 0, + 2224, + 2225, + 5, + 109, + 0, + 0, + 2225, + 2226, + 5, + 101, + 0, + 0, + 2226, + 2227, + 5, + 34, + 0, + 0, + 2227, + 252, + 1, + 0, + 0, + 0, + 2228, + 2233, + 5, + 34, + 0, + 0, + 2229, + 2232, + 3, + 261, + 130, + 0, + 2230, + 2232, + 3, + 267, + 133, + 0, + 2231, + 2229, + 1, + 0, + 0, + 0, + 2231, + 2230, + 1, + 0, + 0, + 0, + 2232, + 2235, + 1, + 0, + 0, + 0, + 2233, + 2231, + 1, + 0, + 0, + 0, + 2233, + 2234, + 1, + 0, + 0, + 0, + 2234, + 2236, + 1, + 0, + 0, + 0, + 2235, + 2233, + 1, + 0, + 0, + 0, + 2236, + 2237, + 5, + 46, + 0, + 0, + 2237, + 2238, + 5, + 36, + 0, + 0, + 2238, + 2239, + 5, + 34, + 0, + 0, + 2239, + 254, + 1, + 0, + 0, + 0, + 2240, + 2241, + 5, + 34, + 0, + 0, + 2241, + 2242, + 5, + 36, + 0, + 0, + 2242, + 2243, + 5, + 36, + 0, + 0, + 2243, + 2248, + 1, + 0, + 0, + 0, + 2244, + 2247, + 3, + 261, + 130, + 0, + 2245, + 2247, + 3, + 267, + 133, + 0, + 2246, + 2244, + 1, + 0, + 0, + 0, + 2246, + 2245, + 1, + 0, + 0, + 0, + 2247, + 2250, + 1, + 0, + 0, + 0, + 2248, + 2246, + 1, + 0, + 0, + 0, + 2248, + 2249, + 1, + 0, + 0, + 0, + 2249, + 2251, + 1, + 0, + 0, + 0, + 2250, + 2248, + 1, + 0, + 0, + 0, + 2251, + 2252, + 5, + 34, + 0, + 0, + 2252, + 256, + 1, + 0, + 0, + 0, + 2253, + 2254, + 5, + 34, + 0, + 0, + 2254, + 2255, + 5, + 36, + 0, + 0, + 2255, + 2260, + 1, + 0, + 0, + 0, + 2256, + 2259, + 3, + 261, + 130, + 0, + 2257, + 2259, + 3, + 267, + 133, + 0, + 2258, + 2256, + 1, + 0, + 0, + 0, + 2258, + 2257, + 1, + 0, + 0, + 0, + 2259, + 2262, + 1, + 0, + 0, + 0, + 2260, + 2258, + 1, + 0, + 0, + 0, + 2260, + 2261, + 1, + 0, + 0, + 0, + 2261, + 2263, + 1, + 0, + 0, + 0, + 2262, + 2260, + 1, + 0, + 0, + 0, + 2263, + 2264, + 5, + 34, + 0, + 0, + 2264, + 258, + 1, + 0, + 0, + 0, + 2265, + 2270, + 5, + 34, + 0, + 0, + 2266, + 2269, + 3, + 261, + 130, + 0, + 2267, + 2269, + 3, + 267, + 133, + 0, + 2268, + 2266, + 1, + 0, + 0, + 0, + 2268, + 2267, + 1, + 0, + 0, + 0, + 2269, + 2272, + 1, + 0, + 0, + 0, + 2270, + 2268, + 1, + 0, + 0, + 0, + 2270, + 2271, + 1, + 0, + 0, + 0, + 2271, + 2273, + 1, + 0, + 0, + 0, + 2272, + 2270, + 1, + 0, + 0, + 0, + 2273, + 2274, + 5, + 34, + 0, + 0, + 2274, + 260, + 1, + 0, + 0, + 0, + 2275, + 2278, + 5, + 92, + 0, + 0, + 2276, + 2279, + 7, + 0, + 0, + 0, + 2277, + 2279, + 3, + 263, + 131, + 0, + 2278, + 2276, + 1, + 0, + 0, + 0, + 2278, + 2277, + 1, + 0, + 0, + 0, + 2279, + 262, + 1, + 0, + 0, + 0, + 2280, + 2281, + 5, + 117, + 0, + 0, + 2281, + 2282, + 3, + 265, + 132, + 0, + 2282, + 2283, + 3, + 265, + 132, + 0, + 2283, + 2284, + 3, + 265, + 132, + 0, + 2284, + 2285, + 3, + 265, + 132, + 0, + 2285, + 264, + 1, + 0, + 0, + 0, + 2286, + 2287, + 7, + 1, + 0, + 0, + 2287, + 266, + 1, + 0, + 0, + 0, + 2288, + 2289, + 8, + 2, + 0, + 0, + 2289, + 268, + 1, + 0, + 0, + 0, + 2290, + 2299, + 5, + 48, + 0, + 0, + 2291, + 2295, + 7, + 3, + 0, + 0, + 2292, + 2294, + 7, + 4, + 0, + 0, + 2293, + 2292, + 1, + 0, + 0, + 0, + 2294, + 2297, + 1, + 0, + 0, + 0, + 2295, + 2293, + 1, + 0, + 0, + 0, + 2295, + 2296, + 1, + 0, + 0, + 0, + 2296, + 2299, + 1, + 0, + 0, + 0, + 2297, + 2295, + 1, + 0, + 0, + 0, + 2298, + 2290, + 1, + 0, + 0, + 0, + 2298, + 2291, + 1, + 0, + 0, + 0, + 2299, + 270, + 1, + 0, + 0, + 0, + 2300, + 2302, + 5, + 45, + 0, + 0, + 2301, + 2300, + 1, + 0, + 0, + 0, + 2301, + 2302, + 1, + 0, + 0, + 0, + 2302, + 2303, + 1, + 0, + 0, + 0, + 2303, + 2310, + 3, + 269, + 134, + 0, + 2304, + 2306, + 5, + 46, + 0, + 0, + 2305, + 2307, + 7, + 4, + 0, + 0, + 2306, + 2305, + 1, + 0, + 0, + 0, + 2307, + 2308, + 1, + 0, + 0, + 0, + 2308, + 2306, + 1, + 0, + 0, + 0, + 2308, + 2309, + 1, + 0, + 0, + 0, + 2309, + 2311, + 1, + 0, + 0, + 0, + 2310, + 2304, + 1, + 0, + 0, + 0, + 2310, + 2311, + 1, + 0, + 0, + 0, + 2311, + 2313, + 1, + 0, + 0, + 0, + 2312, + 2314, + 3, + 273, + 136, + 0, + 2313, + 2312, + 1, + 0, + 0, + 0, + 2313, + 2314, + 1, + 0, + 0, + 0, + 2314, + 272, + 1, + 0, + 0, + 0, + 2315, + 2317, + 7, + 5, + 0, + 0, + 2316, + 2318, + 7, + 6, + 0, + 0, + 2317, + 2316, + 1, + 0, + 0, + 0, + 2317, + 2318, + 1, + 0, + 0, + 0, + 2318, + 2319, + 1, + 0, + 0, + 0, + 2319, + 2320, + 3, + 269, + 134, + 0, + 2320, + 274, + 1, + 0, + 0, + 0, + 2321, + 2323, + 7, + 7, + 0, + 0, + 2322, + 2321, + 1, + 0, + 0, + 0, + 2323, + 2324, + 1, + 0, + 0, + 0, + 2324, + 2322, + 1, + 0, + 0, + 0, + 2324, + 2325, + 1, + 0, + 0, + 0, + 2325, + 2326, + 1, + 0, + 0, + 0, + 2326, + 2327, + 6, + 137, + 0, + 0, + 2327, + 276, + 1, + 0, + 0, + 0, + 18, + 0, + 2231, + 2233, + 2246, + 2248, + 2258, + 2260, + 2268, + 2270, + 2278, + 2295, + 2298, + 2301, + 2308, + 2310, + 2313, + 2317, + 2324, + 1, + 6, + 0, + 0, + ] + + +class ASLLexer(Lexer): + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [DFA(ds, i) for i, ds in enumerate(atn.decisionToState)] + + COMMA = 1 + COLON = 2 + LBRACK = 3 + RBRACK = 4 + LBRACE = 5 + RBRACE = 6 + TRUE = 7 + FALSE = 8 + NULL = 9 + COMMENT = 10 + STATES = 11 + STARTAT = 12 + NEXTSTATE = 13 + VERSION = 14 + TYPE = 15 + TASK = 16 + CHOICE = 17 + FAIL = 18 + SUCCEED = 19 + PASS = 20 + WAIT = 21 + PARALLEL = 22 + MAP = 23 + CHOICES = 24 + VARIABLE = 25 + DEFAULT = 26 + BRANCHES = 27 + AND = 28 + BOOLEANEQUALS = 29 + BOOLEANQUALSPATH = 30 + ISBOOLEAN = 31 + ISNULL = 32 + ISNUMERIC = 33 + ISPRESENT = 34 + ISSTRING = 35 + ISTIMESTAMP = 36 + NOT = 37 + NUMERICEQUALS = 38 + NUMERICEQUALSPATH = 39 + NUMERICGREATERTHAN = 40 + NUMERICGREATERTHANPATH = 41 + NUMERICGREATERTHANEQUALS = 42 + NUMERICGREATERTHANEQUALSPATH = 43 + NUMERICLESSTHAN = 44 + NUMERICLESSTHANPATH = 45 + NUMERICLESSTHANEQUALS = 46 + NUMERICLESSTHANEQUALSPATH = 47 + OR = 48 + STRINGEQUALS = 49 + STRINGEQUALSPATH = 50 + STRINGGREATERTHAN = 51 + STRINGGREATERTHANPATH = 52 + STRINGGREATERTHANEQUALS = 53 + STRINGGREATERTHANEQUALSPATH = 54 + STRINGLESSTHAN = 55 + STRINGLESSTHANPATH = 56 + STRINGLESSTHANEQUALS = 57 + STRINGLESSTHANEQUALSPATH = 58 + STRINGMATCHES = 59 + TIMESTAMPEQUALS = 60 + TIMESTAMPEQUALSPATH = 61 + TIMESTAMPGREATERTHAN = 62 + TIMESTAMPGREATERTHANPATH = 63 + TIMESTAMPGREATERTHANEQUALS = 64 + TIMESTAMPGREATERTHANEQUALSPATH = 65 + TIMESTAMPLESSTHAN = 66 + TIMESTAMPLESSTHANPATH = 67 + TIMESTAMPLESSTHANEQUALS = 68 + TIMESTAMPLESSTHANEQUALSPATH = 69 + SECONDSPATH = 70 + SECONDS = 71 + TIMESTAMPPATH = 72 + TIMESTAMP = 73 + TIMEOUTSECONDS = 74 + TIMEOUTSECONDSPATH = 75 + HEARTBEATSECONDS = 76 + HEARTBEATSECONDSPATH = 77 + PROCESSORCONFIG = 78 + MODE = 79 + INLINE = 80 + DISTRIBUTED = 81 + EXECUTIONTYPE = 82 + STANDARD = 83 + ITEMPROCESSOR = 84 + ITERATOR = 85 + ITEMSELECTOR = 86 + MAXCONCURRENCY = 87 + RESOURCE = 88 + INPUTPATH = 89 + OUTPUTPATH = 90 + ITEMSPATH = 91 + RESULTPATH = 92 + RESULT = 93 + PARAMETERS = 94 + RESULTSELECTOR = 95 + ITEMREADER = 96 + READERCONFIG = 97 + INPUTTYPE = 98 + CSVHEADERLOCATION = 99 + CSVHEADERS = 100 + MAXITEMS = 101 + MAXITEMSPATH = 102 + NEXT = 103 + END = 104 + CAUSE = 105 + ERROR = 106 + RETRY = 107 + ERROREQUALS = 108 + INTERVALSECONDS = 109 + MAXATTEMPTS = 110 + BACKOFFRATE = 111 + CATCH = 112 + ERRORNAMEStatesALL = 113 + ERRORNAMEStatesHeartbeatTimeout = 114 + ERRORNAMEStatesTimeout = 115 + ERRORNAMEStatesTaskFailed = 116 + ERRORNAMEStatesPermissions = 117 + ERRORNAMEStatesResultPathMatchFailure = 118 + ERRORNAMEStatesParameterPathFailure = 119 + ERRORNAMEStatesBranchFailed = 120 + ERRORNAMEStatesNoChoiceMatched = 121 + ERRORNAMEStatesIntrinsicFailure = 122 + ERRORNAMEStatesExceedToleratedFailureThreshold = 123 + ERRORNAMEStatesItemReaderFailed = 124 + ERRORNAMEStatesResultWriterFailed = 125 + ERRORNAMEStatesRuntime = 126 + STRINGDOLLAR = 127 + STRINGPATHCONTEXTOBJ = 128 + STRINGPATH = 129 + STRING = 130 + INT = 131 + NUMBER = 132 + WS = 133 + + channelNames = ["DEFAULT_TOKEN_CHANNEL", "HIDDEN"] + + modeNames = ["DEFAULT_MODE"] + + literalNames = [ + "", + "','", + "':'", + "'['", + "']'", + "'{'", + "'}'", + "'true'", + "'false'", + "'null'", + "'\"Comment\"'", + "'\"States\"'", + "'\"StartAt\"'", + "'\"NextState\"'", + "'\"Version\"'", + "'\"Type\"'", + "'\"Task\"'", + "'\"Choice\"'", + "'\"Fail\"'", + "'\"Succeed\"'", + "'\"Pass\"'", + "'\"Wait\"'", + "'\"Parallel\"'", + "'\"Map\"'", + "'\"Choices\"'", + "'\"Variable\"'", + "'\"Default\"'", + "'\"Branches\"'", + "'\"And\"'", + "'\"BooleanEquals\"'", + "'\"BooleanEqualsPath\"'", + "'\"IsBoolean\"'", + "'\"IsNull\"'", + "'\"IsNumeric\"'", + "'\"IsPresent\"'", + "'\"IsString\"'", + "'\"IsTimestamp\"'", + "'\"Not\"'", + "'\"NumericEquals\"'", + "'\"NumericEqualsPath\"'", + "'\"NumericGreaterThan\"'", + "'\"NumericGreaterThanPath\"'", + "'\"NumericGreaterThanEquals\"'", + "'\"NumericGreaterThanEqualsPath\"'", + "'\"NumericLessThan\"'", + "'\"NumericLessThanPath\"'", + "'\"NumericLessThanEquals\"'", + "'\"NumericLessThanEqualsPath\"'", + "'\"Or\"'", + "'\"StringEquals\"'", + "'\"StringEqualsPath\"'", + "'\"StringGreaterThan\"'", + "'\"StringGreaterThanPath\"'", + "'\"StringGreaterThanEquals\"'", + "'\"StringGreaterThanEqualsPath\"'", + "'\"StringLessThan\"'", + "'\"StringLessThanPath\"'", + "'\"StringLessThanEquals\"'", + "'\"StringLessThanEqualsPath\"'", + "'\"StringMatches\"'", + "'\"TimestampEquals\"'", + "'\"TimestampEqualsPath\"'", + "'\"TimestampGreaterThan\"'", + "'\"TimestampGreaterThanPath\"'", + "'\"TimestampGreaterThanEquals\"'", + "'\"TimestampGreaterThanEqualsPath\"'", + "'\"TimestampLessThan\"'", + "'\"TimestampLessThanPath\"'", + "'\"TimestampLessThanEquals\"'", + "'\"TimestampLessThanEqualsPath\"'", + "'\"SecondsPath\"'", + "'\"Seconds\"'", + "'\"TimestampPath\"'", + "'\"Timestamp\"'", + "'\"TimeoutSeconds\"'", + "'\"TimeoutSecondsPath\"'", + "'\"HeartbeatSeconds\"'", + "'\"HeartbeatSecondsPath\"'", + "'\"ProcessorConfig\"'", + "'\"Mode\"'", + "'\"INLINE\"'", + "'\"DISTRIBUTED\"'", + "'\"ExecutionType\"'", + "'\"STANDARD\"'", + "'\"ItemProcessor\"'", + "'\"Iterator\"'", + "'\"ItemSelector\"'", + "'\"MaxConcurrency\"'", + "'\"Resource\"'", + "'\"InputPath\"'", + "'\"OutputPath\"'", + "'\"ItemsPath\"'", + "'\"ResultPath\"'", + "'\"Result\"'", + "'\"Parameters\"'", + "'\"ResultSelector\"'", + "'\"ItemReader\"'", + "'\"ReaderConfig\"'", + "'\"InputType\"'", + "'\"CSVHeaderLocation\"'", + "'\"CSVHeaders\"'", + "'\"MaxItems\"'", + "'\"MaxItemsPath\"'", + "'\"Next\"'", + "'\"End\"'", + "'\"Cause\"'", + "'\"Error\"'", + "'\"Retry\"'", + "'\"ErrorEquals\"'", + "'\"IntervalSeconds\"'", + "'\"MaxAttempts\"'", + "'\"BackoffRate\"'", + "'\"Catch\"'", + "'\"States.ALL\"'", + "'\"States.HeartbeatTimeout\"'", + "'\"States.Timeout\"'", + "'\"States.TaskFailed\"'", + "'\"States.Permissions\"'", + "'\"States.ResultPathMatchFailure\"'", + "'\"States.ParameterPathFailure\"'", + "'\"States.BranchFailed\"'", + "'\"States.NoChoiceMatched\"'", + "'\"States.IntrinsicFailure\"'", + "'\"States.ExceedToleratedFailureThreshold\"'", + "'\"States.ItemReaderFailed\"'", + "'\"States.ResultWriterFailed\"'", + "'\"States.Runtime\"'", + ] + + symbolicNames = [ + "", + "COMMA", + "COLON", + "LBRACK", + "RBRACK", + "LBRACE", + "RBRACE", + "TRUE", + "FALSE", + "NULL", + "COMMENT", + "STATES", + "STARTAT", + "NEXTSTATE", + "VERSION", + "TYPE", + "TASK", + "CHOICE", + "FAIL", + "SUCCEED", + "PASS", + "WAIT", + "PARALLEL", + "MAP", + "CHOICES", + "VARIABLE", + "DEFAULT", + "BRANCHES", + "AND", + "BOOLEANEQUALS", + "BOOLEANQUALSPATH", + "ISBOOLEAN", + "ISNULL", + "ISNUMERIC", + "ISPRESENT", + "ISSTRING", + "ISTIMESTAMP", + "NOT", + "NUMERICEQUALS", + "NUMERICEQUALSPATH", + "NUMERICGREATERTHAN", + "NUMERICGREATERTHANPATH", + "NUMERICGREATERTHANEQUALS", + "NUMERICGREATERTHANEQUALSPATH", + "NUMERICLESSTHAN", + "NUMERICLESSTHANPATH", + "NUMERICLESSTHANEQUALS", + "NUMERICLESSTHANEQUALSPATH", + "OR", + "STRINGEQUALS", + "STRINGEQUALSPATH", + "STRINGGREATERTHAN", + "STRINGGREATERTHANPATH", + "STRINGGREATERTHANEQUALS", + "STRINGGREATERTHANEQUALSPATH", + "STRINGLESSTHAN", + "STRINGLESSTHANPATH", + "STRINGLESSTHANEQUALS", + "STRINGLESSTHANEQUALSPATH", + "STRINGMATCHES", + "TIMESTAMPEQUALS", + "TIMESTAMPEQUALSPATH", + "TIMESTAMPGREATERTHAN", + "TIMESTAMPGREATERTHANPATH", + "TIMESTAMPGREATERTHANEQUALS", + "TIMESTAMPGREATERTHANEQUALSPATH", + "TIMESTAMPLESSTHAN", + "TIMESTAMPLESSTHANPATH", + "TIMESTAMPLESSTHANEQUALS", + "TIMESTAMPLESSTHANEQUALSPATH", + "SECONDSPATH", + "SECONDS", + "TIMESTAMPPATH", + "TIMESTAMP", + "TIMEOUTSECONDS", + "TIMEOUTSECONDSPATH", + "HEARTBEATSECONDS", + "HEARTBEATSECONDSPATH", + "PROCESSORCONFIG", + "MODE", + "INLINE", + "DISTRIBUTED", + "EXECUTIONTYPE", + "STANDARD", + "ITEMPROCESSOR", + "ITERATOR", + "ITEMSELECTOR", + "MAXCONCURRENCY", + "RESOURCE", + "INPUTPATH", + "OUTPUTPATH", + "ITEMSPATH", + "RESULTPATH", + "RESULT", + "PARAMETERS", + "RESULTSELECTOR", + "ITEMREADER", + "READERCONFIG", + "INPUTTYPE", + "CSVHEADERLOCATION", + "CSVHEADERS", + "MAXITEMS", + "MAXITEMSPATH", + "NEXT", + "END", + "CAUSE", + "ERROR", + "RETRY", + "ERROREQUALS", + "INTERVALSECONDS", + "MAXATTEMPTS", + "BACKOFFRATE", + "CATCH", + "ERRORNAMEStatesALL", + "ERRORNAMEStatesHeartbeatTimeout", + "ERRORNAMEStatesTimeout", + "ERRORNAMEStatesTaskFailed", + "ERRORNAMEStatesPermissions", + "ERRORNAMEStatesResultPathMatchFailure", + "ERRORNAMEStatesParameterPathFailure", + "ERRORNAMEStatesBranchFailed", + "ERRORNAMEStatesNoChoiceMatched", + "ERRORNAMEStatesIntrinsicFailure", + "ERRORNAMEStatesExceedToleratedFailureThreshold", + "ERRORNAMEStatesItemReaderFailed", + "ERRORNAMEStatesResultWriterFailed", + "ERRORNAMEStatesRuntime", + "STRINGDOLLAR", + "STRINGPATHCONTEXTOBJ", + "STRINGPATH", + "STRING", + "INT", + "NUMBER", + "WS", + ] + + ruleNames = [ + "COMMA", + "COLON", + "LBRACK", + "RBRACK", + "LBRACE", + "RBRACE", + "TRUE", + "FALSE", + "NULL", + "COMMENT", + "STATES", + "STARTAT", + "NEXTSTATE", + "VERSION", + "TYPE", + "TASK", + "CHOICE", + "FAIL", + "SUCCEED", + "PASS", + "WAIT", + "PARALLEL", + "MAP", + "CHOICES", + "VARIABLE", + "DEFAULT", + "BRANCHES", + "AND", + "BOOLEANEQUALS", + "BOOLEANQUALSPATH", + "ISBOOLEAN", + "ISNULL", + "ISNUMERIC", + "ISPRESENT", + "ISSTRING", + "ISTIMESTAMP", + "NOT", + "NUMERICEQUALS", + "NUMERICEQUALSPATH", + "NUMERICGREATERTHAN", + "NUMERICGREATERTHANPATH", + "NUMERICGREATERTHANEQUALS", + "NUMERICGREATERTHANEQUALSPATH", + "NUMERICLESSTHAN", + "NUMERICLESSTHANPATH", + "NUMERICLESSTHANEQUALS", + "NUMERICLESSTHANEQUALSPATH", + "OR", + "STRINGEQUALS", + "STRINGEQUALSPATH", + "STRINGGREATERTHAN", + "STRINGGREATERTHANPATH", + "STRINGGREATERTHANEQUALS", + "STRINGGREATERTHANEQUALSPATH", + "STRINGLESSTHAN", + "STRINGLESSTHANPATH", + "STRINGLESSTHANEQUALS", + "STRINGLESSTHANEQUALSPATH", + "STRINGMATCHES", + "TIMESTAMPEQUALS", + "TIMESTAMPEQUALSPATH", + "TIMESTAMPGREATERTHAN", + "TIMESTAMPGREATERTHANPATH", + "TIMESTAMPGREATERTHANEQUALS", + "TIMESTAMPGREATERTHANEQUALSPATH", + "TIMESTAMPLESSTHAN", + "TIMESTAMPLESSTHANPATH", + "TIMESTAMPLESSTHANEQUALS", + "TIMESTAMPLESSTHANEQUALSPATH", + "SECONDSPATH", + "SECONDS", + "TIMESTAMPPATH", + "TIMESTAMP", + "TIMEOUTSECONDS", + "TIMEOUTSECONDSPATH", + "HEARTBEATSECONDS", + "HEARTBEATSECONDSPATH", + "PROCESSORCONFIG", + "MODE", + "INLINE", + "DISTRIBUTED", + "EXECUTIONTYPE", + "STANDARD", + "ITEMPROCESSOR", + "ITERATOR", + "ITEMSELECTOR", + "MAXCONCURRENCY", + "RESOURCE", + "INPUTPATH", + "OUTPUTPATH", + "ITEMSPATH", + "RESULTPATH", + "RESULT", + "PARAMETERS", + "RESULTSELECTOR", + "ITEMREADER", + "READERCONFIG", + "INPUTTYPE", + "CSVHEADERLOCATION", + "CSVHEADERS", + "MAXITEMS", + "MAXITEMSPATH", + "NEXT", + "END", + "CAUSE", + "ERROR", + "RETRY", + "ERROREQUALS", + "INTERVALSECONDS", + "MAXATTEMPTS", + "BACKOFFRATE", + "CATCH", + "ERRORNAMEStatesALL", + "ERRORNAMEStatesHeartbeatTimeout", + "ERRORNAMEStatesTimeout", + "ERRORNAMEStatesTaskFailed", + "ERRORNAMEStatesPermissions", + "ERRORNAMEStatesResultPathMatchFailure", + "ERRORNAMEStatesParameterPathFailure", + "ERRORNAMEStatesBranchFailed", + "ERRORNAMEStatesNoChoiceMatched", + "ERRORNAMEStatesIntrinsicFailure", + "ERRORNAMEStatesExceedToleratedFailureThreshold", + "ERRORNAMEStatesItemReaderFailed", + "ERRORNAMEStatesResultWriterFailed", + "ERRORNAMEStatesRuntime", + "STRINGDOLLAR", + "STRINGPATHCONTEXTOBJ", + "STRINGPATH", + "STRING", + "ESC", + "UNICODE", + "HEX", + "SAFECODEPOINT", + "INT", + "NUMBER", + "EXP", + "WS", + ] + + grammarFileName = "ASLLexer.g4" + + def __init__(self, input=None, output: TextIO = sys.stdout): + super().__init__(input, output) + self.checkVersion("4.13.1") + self._interp = LexerATNSimulator( + self, self.atn, self.decisionsToDFA, PredictionContextCache() + ) + self._actions = None + self._predicates = None diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLLexer.tokens b/moto/stepfunctions/parser/asl/antlr/runtime/ASLLexer.tokens new file mode 100644 index 000000000..7f35b74e8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLLexer.tokens @@ -0,0 +1,259 @@ +COMMA=1 +COLON=2 +LBRACK=3 +RBRACK=4 +LBRACE=5 +RBRACE=6 +TRUE=7 +FALSE=8 +NULL=9 +COMMENT=10 +STATES=11 +STARTAT=12 +NEXTSTATE=13 +VERSION=14 +TYPE=15 +TASK=16 +CHOICE=17 +FAIL=18 +SUCCEED=19 +PASS=20 +WAIT=21 +PARALLEL=22 +MAP=23 +CHOICES=24 +VARIABLE=25 +DEFAULT=26 +BRANCHES=27 +AND=28 +BOOLEANEQUALS=29 +BOOLEANQUALSPATH=30 +ISBOOLEAN=31 +ISNULL=32 +ISNUMERIC=33 +ISPRESENT=34 +ISSTRING=35 +ISTIMESTAMP=36 +NOT=37 +NUMERICEQUALS=38 +NUMERICEQUALSPATH=39 +NUMERICGREATERTHAN=40 +NUMERICGREATERTHANPATH=41 +NUMERICGREATERTHANEQUALS=42 +NUMERICGREATERTHANEQUALSPATH=43 +NUMERICLESSTHAN=44 +NUMERICLESSTHANPATH=45 +NUMERICLESSTHANEQUALS=46 +NUMERICLESSTHANEQUALSPATH=47 +OR=48 +STRINGEQUALS=49 +STRINGEQUALSPATH=50 +STRINGGREATERTHAN=51 +STRINGGREATERTHANPATH=52 +STRINGGREATERTHANEQUALS=53 +STRINGGREATERTHANEQUALSPATH=54 +STRINGLESSTHAN=55 +STRINGLESSTHANPATH=56 +STRINGLESSTHANEQUALS=57 +STRINGLESSTHANEQUALSPATH=58 +STRINGMATCHES=59 +TIMESTAMPEQUALS=60 +TIMESTAMPEQUALSPATH=61 +TIMESTAMPGREATERTHAN=62 +TIMESTAMPGREATERTHANPATH=63 +TIMESTAMPGREATERTHANEQUALS=64 +TIMESTAMPGREATERTHANEQUALSPATH=65 +TIMESTAMPLESSTHAN=66 +TIMESTAMPLESSTHANPATH=67 +TIMESTAMPLESSTHANEQUALS=68 +TIMESTAMPLESSTHANEQUALSPATH=69 +SECONDSPATH=70 +SECONDS=71 +TIMESTAMPPATH=72 +TIMESTAMP=73 +TIMEOUTSECONDS=74 +TIMEOUTSECONDSPATH=75 +HEARTBEATSECONDS=76 +HEARTBEATSECONDSPATH=77 +PROCESSORCONFIG=78 +MODE=79 +INLINE=80 +DISTRIBUTED=81 +EXECUTIONTYPE=82 +STANDARD=83 +ITEMPROCESSOR=84 +ITERATOR=85 +ITEMSELECTOR=86 +MAXCONCURRENCY=87 +RESOURCE=88 +INPUTPATH=89 +OUTPUTPATH=90 +ITEMSPATH=91 +RESULTPATH=92 +RESULT=93 +PARAMETERS=94 +RESULTSELECTOR=95 +ITEMREADER=96 +READERCONFIG=97 +INPUTTYPE=98 +CSVHEADERLOCATION=99 +CSVHEADERS=100 +MAXITEMS=101 +MAXITEMSPATH=102 +NEXT=103 +END=104 +CAUSE=105 +ERROR=106 +RETRY=107 +ERROREQUALS=108 +INTERVALSECONDS=109 +MAXATTEMPTS=110 +BACKOFFRATE=111 +CATCH=112 +ERRORNAMEStatesALL=113 +ERRORNAMEStatesHeartbeatTimeout=114 +ERRORNAMEStatesTimeout=115 +ERRORNAMEStatesTaskFailed=116 +ERRORNAMEStatesPermissions=117 +ERRORNAMEStatesResultPathMatchFailure=118 +ERRORNAMEStatesParameterPathFailure=119 +ERRORNAMEStatesBranchFailed=120 +ERRORNAMEStatesNoChoiceMatched=121 +ERRORNAMEStatesIntrinsicFailure=122 +ERRORNAMEStatesExceedToleratedFailureThreshold=123 +ERRORNAMEStatesItemReaderFailed=124 +ERRORNAMEStatesResultWriterFailed=125 +ERRORNAMEStatesRuntime=126 +STRINGDOLLAR=127 +STRINGPATHCONTEXTOBJ=128 +STRINGPATH=129 +STRING=130 +INT=131 +NUMBER=132 +WS=133 +','=1 +':'=2 +'['=3 +']'=4 +'{'=5 +'}'=6 +'true'=7 +'false'=8 +'null'=9 +'"Comment"'=10 +'"States"'=11 +'"StartAt"'=12 +'"NextState"'=13 +'"Version"'=14 +'"Type"'=15 +'"Task"'=16 +'"Choice"'=17 +'"Fail"'=18 +'"Succeed"'=19 +'"Pass"'=20 +'"Wait"'=21 +'"Parallel"'=22 +'"Map"'=23 +'"Choices"'=24 +'"Variable"'=25 +'"Default"'=26 +'"Branches"'=27 +'"And"'=28 +'"BooleanEquals"'=29 +'"BooleanEqualsPath"'=30 +'"IsBoolean"'=31 +'"IsNull"'=32 +'"IsNumeric"'=33 +'"IsPresent"'=34 +'"IsString"'=35 +'"IsTimestamp"'=36 +'"Not"'=37 +'"NumericEquals"'=38 +'"NumericEqualsPath"'=39 +'"NumericGreaterThan"'=40 +'"NumericGreaterThanPath"'=41 +'"NumericGreaterThanEquals"'=42 +'"NumericGreaterThanEqualsPath"'=43 +'"NumericLessThan"'=44 +'"NumericLessThanPath"'=45 +'"NumericLessThanEquals"'=46 +'"NumericLessThanEqualsPath"'=47 +'"Or"'=48 +'"StringEquals"'=49 +'"StringEqualsPath"'=50 +'"StringGreaterThan"'=51 +'"StringGreaterThanPath"'=52 +'"StringGreaterThanEquals"'=53 +'"StringGreaterThanEqualsPath"'=54 +'"StringLessThan"'=55 +'"StringLessThanPath"'=56 +'"StringLessThanEquals"'=57 +'"StringLessThanEqualsPath"'=58 +'"StringMatches"'=59 +'"TimestampEquals"'=60 +'"TimestampEqualsPath"'=61 +'"TimestampGreaterThan"'=62 +'"TimestampGreaterThanPath"'=63 +'"TimestampGreaterThanEquals"'=64 +'"TimestampGreaterThanEqualsPath"'=65 +'"TimestampLessThan"'=66 +'"TimestampLessThanPath"'=67 +'"TimestampLessThanEquals"'=68 +'"TimestampLessThanEqualsPath"'=69 +'"SecondsPath"'=70 +'"Seconds"'=71 +'"TimestampPath"'=72 +'"Timestamp"'=73 +'"TimeoutSeconds"'=74 +'"TimeoutSecondsPath"'=75 +'"HeartbeatSeconds"'=76 +'"HeartbeatSecondsPath"'=77 +'"ProcessorConfig"'=78 +'"Mode"'=79 +'"INLINE"'=80 +'"DISTRIBUTED"'=81 +'"ExecutionType"'=82 +'"STANDARD"'=83 +'"ItemProcessor"'=84 +'"Iterator"'=85 +'"ItemSelector"'=86 +'"MaxConcurrency"'=87 +'"Resource"'=88 +'"InputPath"'=89 +'"OutputPath"'=90 +'"ItemsPath"'=91 +'"ResultPath"'=92 +'"Result"'=93 +'"Parameters"'=94 +'"ResultSelector"'=95 +'"ItemReader"'=96 +'"ReaderConfig"'=97 +'"InputType"'=98 +'"CSVHeaderLocation"'=99 +'"CSVHeaders"'=100 +'"MaxItems"'=101 +'"MaxItemsPath"'=102 +'"Next"'=103 +'"End"'=104 +'"Cause"'=105 +'"Error"'=106 +'"Retry"'=107 +'"ErrorEquals"'=108 +'"IntervalSeconds"'=109 +'"MaxAttempts"'=110 +'"BackoffRate"'=111 +'"Catch"'=112 +'"States.ALL"'=113 +'"States.HeartbeatTimeout"'=114 +'"States.Timeout"'=115 +'"States.TaskFailed"'=116 +'"States.Permissions"'=117 +'"States.ResultPathMatchFailure"'=118 +'"States.ParameterPathFailure"'=119 +'"States.BranchFailed"'=120 +'"States.NoChoiceMatched"'=121 +'"States.IntrinsicFailure"'=122 +'"States.ExceedToleratedFailureThreshold"'=123 +'"States.ItemReaderFailed"'=124 +'"States.ResultWriterFailed"'=125 +'"States.Runtime"'=126 diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLParser.interp b/moto/stepfunctions/parser/asl/antlr/runtime/ASLParser.interp new file mode 100644 index 000000000..d3ff6e468 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLParser.interp @@ -0,0 +1,364 @@ +token literal names: +null +',' +':' +'[' +']' +'{' +'}' +'true' +'false' +'null' +'"Comment"' +'"States"' +'"StartAt"' +'"NextState"' +'"Version"' +'"Type"' +'"Task"' +'"Choice"' +'"Fail"' +'"Succeed"' +'"Pass"' +'"Wait"' +'"Parallel"' +'"Map"' +'"Choices"' +'"Variable"' +'"Default"' +'"Branches"' +'"And"' +'"BooleanEquals"' +'"BooleanEqualsPath"' +'"IsBoolean"' +'"IsNull"' +'"IsNumeric"' +'"IsPresent"' +'"IsString"' +'"IsTimestamp"' +'"Not"' +'"NumericEquals"' +'"NumericEqualsPath"' +'"NumericGreaterThan"' +'"NumericGreaterThanPath"' +'"NumericGreaterThanEquals"' +'"NumericGreaterThanEqualsPath"' +'"NumericLessThan"' +'"NumericLessThanPath"' +'"NumericLessThanEquals"' +'"NumericLessThanEqualsPath"' +'"Or"' +'"StringEquals"' +'"StringEqualsPath"' +'"StringGreaterThan"' +'"StringGreaterThanPath"' +'"StringGreaterThanEquals"' +'"StringGreaterThanEqualsPath"' +'"StringLessThan"' +'"StringLessThanPath"' +'"StringLessThanEquals"' +'"StringLessThanEqualsPath"' +'"StringMatches"' +'"TimestampEquals"' +'"TimestampEqualsPath"' +'"TimestampGreaterThan"' +'"TimestampGreaterThanPath"' +'"TimestampGreaterThanEquals"' +'"TimestampGreaterThanEqualsPath"' +'"TimestampLessThan"' +'"TimestampLessThanPath"' +'"TimestampLessThanEquals"' +'"TimestampLessThanEqualsPath"' +'"SecondsPath"' +'"Seconds"' +'"TimestampPath"' +'"Timestamp"' +'"TimeoutSeconds"' +'"TimeoutSecondsPath"' +'"HeartbeatSeconds"' +'"HeartbeatSecondsPath"' +'"ProcessorConfig"' +'"Mode"' +'"INLINE"' +'"DISTRIBUTED"' +'"ExecutionType"' +'"STANDARD"' +'"ItemProcessor"' +'"Iterator"' +'"ItemSelector"' +'"MaxConcurrency"' +'"Resource"' +'"InputPath"' +'"OutputPath"' +'"ItemsPath"' +'"ResultPath"' +'"Result"' +'"Parameters"' +'"ResultSelector"' +'"ItemReader"' +'"ReaderConfig"' +'"InputType"' +'"CSVHeaderLocation"' +'"CSVHeaders"' +'"MaxItems"' +'"MaxItemsPath"' +'"Next"' +'"End"' +'"Cause"' +'"Error"' +'"Retry"' +'"ErrorEquals"' +'"IntervalSeconds"' +'"MaxAttempts"' +'"BackoffRate"' +'"Catch"' +'"States.ALL"' +'"States.HeartbeatTimeout"' +'"States.Timeout"' +'"States.TaskFailed"' +'"States.Permissions"' +'"States.ResultPathMatchFailure"' +'"States.ParameterPathFailure"' +'"States.BranchFailed"' +'"States.NoChoiceMatched"' +'"States.IntrinsicFailure"' +'"States.ExceedToleratedFailureThreshold"' +'"States.ItemReaderFailed"' +'"States.ResultWriterFailed"' +'"States.Runtime"' +null +null +null +null +null +null +null + +token symbolic names: +null +COMMA +COLON +LBRACK +RBRACK +LBRACE +RBRACE +TRUE +FALSE +NULL +COMMENT +STATES +STARTAT +NEXTSTATE +VERSION +TYPE +TASK +CHOICE +FAIL +SUCCEED +PASS +WAIT +PARALLEL +MAP +CHOICES +VARIABLE +DEFAULT +BRANCHES +AND +BOOLEANEQUALS +BOOLEANQUALSPATH +ISBOOLEAN +ISNULL +ISNUMERIC +ISPRESENT +ISSTRING +ISTIMESTAMP +NOT +NUMERICEQUALS +NUMERICEQUALSPATH +NUMERICGREATERTHAN +NUMERICGREATERTHANPATH +NUMERICGREATERTHANEQUALS +NUMERICGREATERTHANEQUALSPATH +NUMERICLESSTHAN +NUMERICLESSTHANPATH +NUMERICLESSTHANEQUALS +NUMERICLESSTHANEQUALSPATH +OR +STRINGEQUALS +STRINGEQUALSPATH +STRINGGREATERTHAN +STRINGGREATERTHANPATH +STRINGGREATERTHANEQUALS +STRINGGREATERTHANEQUALSPATH +STRINGLESSTHAN +STRINGLESSTHANPATH +STRINGLESSTHANEQUALS +STRINGLESSTHANEQUALSPATH +STRINGMATCHES +TIMESTAMPEQUALS +TIMESTAMPEQUALSPATH +TIMESTAMPGREATERTHAN +TIMESTAMPGREATERTHANPATH +TIMESTAMPGREATERTHANEQUALS +TIMESTAMPGREATERTHANEQUALSPATH +TIMESTAMPLESSTHAN +TIMESTAMPLESSTHANPATH +TIMESTAMPLESSTHANEQUALS +TIMESTAMPLESSTHANEQUALSPATH +SECONDSPATH +SECONDS +TIMESTAMPPATH +TIMESTAMP +TIMEOUTSECONDS +TIMEOUTSECONDSPATH +HEARTBEATSECONDS +HEARTBEATSECONDSPATH +PROCESSORCONFIG +MODE +INLINE +DISTRIBUTED +EXECUTIONTYPE +STANDARD +ITEMPROCESSOR +ITERATOR +ITEMSELECTOR +MAXCONCURRENCY +RESOURCE +INPUTPATH +OUTPUTPATH +ITEMSPATH +RESULTPATH +RESULT +PARAMETERS +RESULTSELECTOR +ITEMREADER +READERCONFIG +INPUTTYPE +CSVHEADERLOCATION +CSVHEADERS +MAXITEMS +MAXITEMSPATH +NEXT +END +CAUSE +ERROR +RETRY +ERROREQUALS +INTERVALSECONDS +MAXATTEMPTS +BACKOFFRATE +CATCH +ERRORNAMEStatesALL +ERRORNAMEStatesHeartbeatTimeout +ERRORNAMEStatesTimeout +ERRORNAMEStatesTaskFailed +ERRORNAMEStatesPermissions +ERRORNAMEStatesResultPathMatchFailure +ERRORNAMEStatesParameterPathFailure +ERRORNAMEStatesBranchFailed +ERRORNAMEStatesNoChoiceMatched +ERRORNAMEStatesIntrinsicFailure +ERRORNAMEStatesExceedToleratedFailureThreshold +ERRORNAMEStatesItemReaderFailed +ERRORNAMEStatesResultWriterFailed +ERRORNAMEStatesRuntime +STRINGDOLLAR +STRINGPATHCONTEXTOBJ +STRINGPATH +STRING +INT +NUMBER +WS + +rule names: +program_decl +top_layer_stmt +startat_decl +comment_decl +version_decl +state_stmt +states_decl +state_name +state_decl +state_decl_body +type_decl +next_decl +resource_decl +input_path_decl +result_decl +result_path_decl +output_path_decl +end_decl +default_decl +error_decl +cause_decl +seconds_decl +seconds_path_decl +timestamp_decl +timestamp_path_decl +items_path_decl +max_concurrency_decl +parameters_decl +timeout_seconds_decl +timeout_seconds_path_decl +heartbeat_seconds_decl +heartbeat_seconds_path_decl +payload_tmpl_decl +payload_binding +intrinsic_func +payload_arr_decl +payload_value_decl +payload_value_lit +result_selector_decl +state_type +choices_decl +choice_rule +comparison_variable_stmt +comparison_composite_stmt +comparison_composite +variable_decl +comparison_func +branches_decl +item_processor_decl +item_processor_item +processor_config_decl +processor_config_field +mode_decl +mode_type +execution_decl +execution_type +iterator_decl +iterator_decl_item +item_selector_decl +item_reader_decl +items_reader_field +reader_config_decl +reader_config_field +input_type_decl +csv_header_location_decl +csv_headers_decl +max_items_decl +max_items_path_decl +retry_decl +retrier_decl +retrier_stmt +error_equals_decl +interval_seconds_decl +max_attempts_decl +backoff_rate_decl +catch_decl +catcher_decl +catcher_stmt +comparison_op +choice_operator +states_error_name +error_name +json_obj_decl +json_binding +json_arr_decl +json_value_decl +keyword_or_string + + +atn: +[4, 1, 133, 793, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 1, 0, 1, 0, 1, 0, 1, 0, 5, 0, 179, 8, 0, 10, 0, 12, 0, 182, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 191, 8, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 237, 8, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 5, 6, 245, 8, 6, 10, 6, 12, 6, 248, 9, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 5, 9, 262, 8, 9, 10, 9, 12, 9, 265, 9, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 3, 13, 285, 8, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 3, 15, 295, 8, 15, 1, 16, 1, 16, 1, 16, 1, 16, 3, 16, 301, 8, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 5, 32, 367, 8, 32, 10, 32, 12, 32, 370, 9, 32, 1, 32, 1, 32, 1, 32, 1, 32, 3, 32, 376, 8, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 3, 33, 391, 8, 33, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 5, 35, 399, 8, 35, 10, 35, 12, 35, 402, 9, 35, 1, 35, 1, 35, 1, 35, 1, 35, 3, 35, 408, 8, 35, 1, 36, 1, 36, 1, 36, 1, 36, 3, 36, 414, 8, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 3, 37, 421, 8, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 1, 40, 5, 40, 435, 8, 40, 10, 40, 12, 40, 438, 9, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 41, 4, 41, 446, 8, 41, 11, 41, 12, 41, 447, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 5, 41, 456, 8, 41, 10, 41, 12, 41, 459, 9, 41, 1, 41, 1, 41, 3, 41, 463, 8, 41, 1, 42, 1, 42, 1, 42, 3, 42, 468, 8, 42, 1, 43, 1, 43, 3, 43, 472, 8, 43, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 1, 44, 5, 44, 481, 8, 44, 10, 44, 12, 44, 484, 9, 44, 1, 44, 1, 44, 3, 44, 488, 8, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 1, 47, 5, 47, 504, 8, 47, 10, 47, 12, 47, 507, 9, 47, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 1, 48, 5, 48, 517, 8, 48, 10, 48, 12, 48, 520, 9, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 49, 3, 49, 528, 8, 49, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 1, 50, 5, 50, 536, 8, 50, 10, 50, 12, 50, 539, 9, 50, 1, 50, 1, 50, 1, 51, 1, 51, 3, 51, 545, 8, 51, 1, 52, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 1, 56, 5, 56, 565, 8, 56, 10, 56, 12, 56, 568, 9, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 3, 57, 575, 8, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 1, 59, 5, 59, 587, 8, 59, 10, 59, 12, 59, 590, 9, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 3, 60, 597, 8, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 5, 61, 605, 8, 61, 10, 61, 12, 61, 608, 9, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 3, 62, 617, 8, 62, 1, 63, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 5, 65, 633, 8, 65, 10, 65, 12, 65, 636, 9, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 1, 68, 5, 68, 654, 8, 68, 10, 68, 12, 68, 657, 9, 68, 3, 68, 659, 8, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 69, 5, 69, 667, 8, 69, 10, 69, 12, 69, 670, 9, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 70, 3, 70, 678, 8, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 5, 71, 686, 8, 71, 10, 71, 12, 71, 689, 9, 71, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 1, 75, 5, 75, 711, 8, 75, 10, 75, 12, 75, 714, 9, 75, 3, 75, 716, 8, 75, 1, 75, 1, 75, 1, 76, 1, 76, 1, 76, 1, 76, 5, 76, 724, 8, 76, 10, 76, 12, 76, 727, 9, 76, 1, 76, 1, 76, 1, 77, 1, 77, 1, 77, 3, 77, 734, 8, 77, 1, 78, 1, 78, 1, 79, 1, 79, 1, 80, 1, 80, 1, 81, 1, 81, 3, 81, 744, 8, 81, 1, 82, 1, 82, 1, 82, 1, 82, 5, 82, 750, 8, 82, 10, 82, 12, 82, 753, 9, 82, 1, 82, 1, 82, 1, 82, 1, 82, 3, 82, 759, 8, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 5, 84, 769, 8, 84, 10, 84, 12, 84, 772, 9, 84, 1, 84, 1, 84, 1, 84, 1, 84, 3, 84, 778, 8, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 3, 85, 789, 8, 85, 1, 86, 1, 86, 1, 86, 0, 0, 87, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 0, 8, 1, 0, 7, 8, 1, 0, 16, 23, 1, 0, 80, 81, 1, 0, 131, 132, 3, 0, 29, 36, 38, 47, 49, 69, 3, 0, 28, 28, 37, 37, 48, 48, 1, 0, 113, 126, 2, 0, 10, 13, 15, 130, 813, 0, 174, 1, 0, 0, 0, 2, 190, 1, 0, 0, 0, 4, 192, 1, 0, 0, 0, 6, 196, 1, 0, 0, 0, 8, 200, 1, 0, 0, 0, 10, 236, 1, 0, 0, 0, 12, 238, 1, 0, 0, 0, 14, 251, 1, 0, 0, 0, 16, 253, 1, 0, 0, 0, 18, 257, 1, 0, 0, 0, 20, 268, 1, 0, 0, 0, 22, 272, 1, 0, 0, 0, 24, 276, 1, 0, 0, 0, 26, 280, 1, 0, 0, 0, 28, 286, 1, 0, 0, 0, 30, 290, 1, 0, 0, 0, 32, 296, 1, 0, 0, 0, 34, 302, 1, 0, 0, 0, 36, 306, 1, 0, 0, 0, 38, 310, 1, 0, 0, 0, 40, 314, 1, 0, 0, 0, 42, 318, 1, 0, 0, 0, 44, 322, 1, 0, 0, 0, 46, 326, 1, 0, 0, 0, 48, 330, 1, 0, 0, 0, 50, 334, 1, 0, 0, 0, 52, 338, 1, 0, 0, 0, 54, 342, 1, 0, 0, 0, 56, 346, 1, 0, 0, 0, 58, 350, 1, 0, 0, 0, 60, 354, 1, 0, 0, 0, 62, 358, 1, 0, 0, 0, 64, 375, 1, 0, 0, 0, 66, 390, 1, 0, 0, 0, 68, 392, 1, 0, 0, 0, 70, 407, 1, 0, 0, 0, 72, 413, 1, 0, 0, 0, 74, 420, 1, 0, 0, 0, 76, 422, 1, 0, 0, 0, 78, 426, 1, 0, 0, 0, 80, 428, 1, 0, 0, 0, 82, 462, 1, 0, 0, 0, 84, 467, 1, 0, 0, 0, 86, 471, 1, 0, 0, 0, 88, 473, 1, 0, 0, 0, 90, 489, 1, 0, 0, 0, 92, 493, 1, 0, 0, 0, 94, 497, 1, 0, 0, 0, 96, 510, 1, 0, 0, 0, 98, 527, 1, 0, 0, 0, 100, 529, 1, 0, 0, 0, 102, 544, 1, 0, 0, 0, 104, 546, 1, 0, 0, 0, 106, 550, 1, 0, 0, 0, 108, 552, 1, 0, 0, 0, 110, 556, 1, 0, 0, 0, 112, 558, 1, 0, 0, 0, 114, 574, 1, 0, 0, 0, 116, 576, 1, 0, 0, 0, 118, 580, 1, 0, 0, 0, 120, 596, 1, 0, 0, 0, 122, 598, 1, 0, 0, 0, 124, 616, 1, 0, 0, 0, 126, 618, 1, 0, 0, 0, 128, 622, 1, 0, 0, 0, 130, 626, 1, 0, 0, 0, 132, 639, 1, 0, 0, 0, 134, 643, 1, 0, 0, 0, 136, 647, 1, 0, 0, 0, 138, 662, 1, 0, 0, 0, 140, 677, 1, 0, 0, 0, 142, 679, 1, 0, 0, 0, 144, 692, 1, 0, 0, 0, 146, 696, 1, 0, 0, 0, 148, 700, 1, 0, 0, 0, 150, 704, 1, 0, 0, 0, 152, 719, 1, 0, 0, 0, 154, 733, 1, 0, 0, 0, 156, 735, 1, 0, 0, 0, 158, 737, 1, 0, 0, 0, 160, 739, 1, 0, 0, 0, 162, 743, 1, 0, 0, 0, 164, 758, 1, 0, 0, 0, 166, 760, 1, 0, 0, 0, 168, 777, 1, 0, 0, 0, 170, 788, 1, 0, 0, 0, 172, 790, 1, 0, 0, 0, 174, 175, 5, 5, 0, 0, 175, 180, 3, 2, 1, 0, 176, 177, 5, 1, 0, 0, 177, 179, 3, 2, 1, 0, 178, 176, 1, 0, 0, 0, 179, 182, 1, 0, 0, 0, 180, 178, 1, 0, 0, 0, 180, 181, 1, 0, 0, 0, 181, 183, 1, 0, 0, 0, 182, 180, 1, 0, 0, 0, 183, 184, 5, 6, 0, 0, 184, 1, 1, 0, 0, 0, 185, 191, 3, 6, 3, 0, 186, 191, 3, 8, 4, 0, 187, 191, 3, 4, 2, 0, 188, 191, 3, 12, 6, 0, 189, 191, 3, 56, 28, 0, 190, 185, 1, 0, 0, 0, 190, 186, 1, 0, 0, 0, 190, 187, 1, 0, 0, 0, 190, 188, 1, 0, 0, 0, 190, 189, 1, 0, 0, 0, 191, 3, 1, 0, 0, 0, 192, 193, 5, 12, 0, 0, 193, 194, 5, 2, 0, 0, 194, 195, 3, 172, 86, 0, 195, 5, 1, 0, 0, 0, 196, 197, 5, 10, 0, 0, 197, 198, 5, 2, 0, 0, 198, 199, 3, 172, 86, 0, 199, 7, 1, 0, 0, 0, 200, 201, 5, 14, 0, 0, 201, 202, 5, 2, 0, 0, 202, 203, 3, 172, 86, 0, 203, 9, 1, 0, 0, 0, 204, 237, 3, 6, 3, 0, 205, 237, 3, 20, 10, 0, 206, 237, 3, 26, 13, 0, 207, 237, 3, 24, 12, 0, 208, 237, 3, 22, 11, 0, 209, 237, 3, 28, 14, 0, 210, 237, 3, 30, 15, 0, 211, 237, 3, 32, 16, 0, 212, 237, 3, 34, 17, 0, 213, 237, 3, 36, 18, 0, 214, 237, 3, 80, 40, 0, 215, 237, 3, 38, 19, 0, 216, 237, 3, 40, 20, 0, 217, 237, 3, 42, 21, 0, 218, 237, 3, 44, 22, 0, 219, 237, 3, 46, 23, 0, 220, 237, 3, 48, 24, 0, 221, 237, 3, 50, 25, 0, 222, 237, 3, 96, 48, 0, 223, 237, 3, 112, 56, 0, 224, 237, 3, 116, 58, 0, 225, 237, 3, 118, 59, 0, 226, 237, 3, 52, 26, 0, 227, 237, 3, 56, 28, 0, 228, 237, 3, 58, 29, 0, 229, 237, 3, 60, 30, 0, 230, 237, 3, 62, 31, 0, 231, 237, 3, 94, 47, 0, 232, 237, 3, 54, 27, 0, 233, 237, 3, 136, 68, 0, 234, 237, 3, 150, 75, 0, 235, 237, 3, 76, 38, 0, 236, 204, 1, 0, 0, 0, 236, 205, 1, 0, 0, 0, 236, 206, 1, 0, 0, 0, 236, 207, 1, 0, 0, 0, 236, 208, 1, 0, 0, 0, 236, 209, 1, 0, 0, 0, 236, 210, 1, 0, 0, 0, 236, 211, 1, 0, 0, 0, 236, 212, 1, 0, 0, 0, 236, 213, 1, 0, 0, 0, 236, 214, 1, 0, 0, 0, 236, 215, 1, 0, 0, 0, 236, 216, 1, 0, 0, 0, 236, 217, 1, 0, 0, 0, 236, 218, 1, 0, 0, 0, 236, 219, 1, 0, 0, 0, 236, 220, 1, 0, 0, 0, 236, 221, 1, 0, 0, 0, 236, 222, 1, 0, 0, 0, 236, 223, 1, 0, 0, 0, 236, 224, 1, 0, 0, 0, 236, 225, 1, 0, 0, 0, 236, 226, 1, 0, 0, 0, 236, 227, 1, 0, 0, 0, 236, 228, 1, 0, 0, 0, 236, 229, 1, 0, 0, 0, 236, 230, 1, 0, 0, 0, 236, 231, 1, 0, 0, 0, 236, 232, 1, 0, 0, 0, 236, 233, 1, 0, 0, 0, 236, 234, 1, 0, 0, 0, 236, 235, 1, 0, 0, 0, 237, 11, 1, 0, 0, 0, 238, 239, 5, 11, 0, 0, 239, 240, 5, 2, 0, 0, 240, 241, 5, 5, 0, 0, 241, 246, 3, 16, 8, 0, 242, 243, 5, 1, 0, 0, 243, 245, 3, 16, 8, 0, 244, 242, 1, 0, 0, 0, 245, 248, 1, 0, 0, 0, 246, 244, 1, 0, 0, 0, 246, 247, 1, 0, 0, 0, 247, 249, 1, 0, 0, 0, 248, 246, 1, 0, 0, 0, 249, 250, 5, 6, 0, 0, 250, 13, 1, 0, 0, 0, 251, 252, 3, 172, 86, 0, 252, 15, 1, 0, 0, 0, 253, 254, 3, 14, 7, 0, 254, 255, 5, 2, 0, 0, 255, 256, 3, 18, 9, 0, 256, 17, 1, 0, 0, 0, 257, 258, 5, 5, 0, 0, 258, 263, 3, 10, 5, 0, 259, 260, 5, 1, 0, 0, 260, 262, 3, 10, 5, 0, 261, 259, 1, 0, 0, 0, 262, 265, 1, 0, 0, 0, 263, 261, 1, 0, 0, 0, 263, 264, 1, 0, 0, 0, 264, 266, 1, 0, 0, 0, 265, 263, 1, 0, 0, 0, 266, 267, 5, 6, 0, 0, 267, 19, 1, 0, 0, 0, 268, 269, 5, 15, 0, 0, 269, 270, 5, 2, 0, 0, 270, 271, 3, 78, 39, 0, 271, 21, 1, 0, 0, 0, 272, 273, 5, 103, 0, 0, 273, 274, 5, 2, 0, 0, 274, 275, 3, 172, 86, 0, 275, 23, 1, 0, 0, 0, 276, 277, 5, 88, 0, 0, 277, 278, 5, 2, 0, 0, 278, 279, 3, 172, 86, 0, 279, 25, 1, 0, 0, 0, 280, 281, 5, 89, 0, 0, 281, 284, 5, 2, 0, 0, 282, 285, 5, 9, 0, 0, 283, 285, 3, 172, 86, 0, 284, 282, 1, 0, 0, 0, 284, 283, 1, 0, 0, 0, 285, 27, 1, 0, 0, 0, 286, 287, 5, 93, 0, 0, 287, 288, 5, 2, 0, 0, 288, 289, 3, 170, 85, 0, 289, 29, 1, 0, 0, 0, 290, 291, 5, 92, 0, 0, 291, 294, 5, 2, 0, 0, 292, 295, 5, 9, 0, 0, 293, 295, 3, 172, 86, 0, 294, 292, 1, 0, 0, 0, 294, 293, 1, 0, 0, 0, 295, 31, 1, 0, 0, 0, 296, 297, 5, 90, 0, 0, 297, 300, 5, 2, 0, 0, 298, 301, 5, 9, 0, 0, 299, 301, 3, 172, 86, 0, 300, 298, 1, 0, 0, 0, 300, 299, 1, 0, 0, 0, 301, 33, 1, 0, 0, 0, 302, 303, 5, 104, 0, 0, 303, 304, 5, 2, 0, 0, 304, 305, 7, 0, 0, 0, 305, 35, 1, 0, 0, 0, 306, 307, 5, 26, 0, 0, 307, 308, 5, 2, 0, 0, 308, 309, 3, 172, 86, 0, 309, 37, 1, 0, 0, 0, 310, 311, 5, 106, 0, 0, 311, 312, 5, 2, 0, 0, 312, 313, 3, 172, 86, 0, 313, 39, 1, 0, 0, 0, 314, 315, 5, 105, 0, 0, 315, 316, 5, 2, 0, 0, 316, 317, 3, 172, 86, 0, 317, 41, 1, 0, 0, 0, 318, 319, 5, 71, 0, 0, 319, 320, 5, 2, 0, 0, 320, 321, 5, 131, 0, 0, 321, 43, 1, 0, 0, 0, 322, 323, 5, 70, 0, 0, 323, 324, 5, 2, 0, 0, 324, 325, 3, 172, 86, 0, 325, 45, 1, 0, 0, 0, 326, 327, 5, 73, 0, 0, 327, 328, 5, 2, 0, 0, 328, 329, 3, 172, 86, 0, 329, 47, 1, 0, 0, 0, 330, 331, 5, 72, 0, 0, 331, 332, 5, 2, 0, 0, 332, 333, 3, 172, 86, 0, 333, 49, 1, 0, 0, 0, 334, 335, 5, 91, 0, 0, 335, 336, 5, 2, 0, 0, 336, 337, 3, 172, 86, 0, 337, 51, 1, 0, 0, 0, 338, 339, 5, 87, 0, 0, 339, 340, 5, 2, 0, 0, 340, 341, 5, 131, 0, 0, 341, 53, 1, 0, 0, 0, 342, 343, 5, 94, 0, 0, 343, 344, 5, 2, 0, 0, 344, 345, 3, 64, 32, 0, 345, 55, 1, 0, 0, 0, 346, 347, 5, 74, 0, 0, 347, 348, 5, 2, 0, 0, 348, 349, 5, 131, 0, 0, 349, 57, 1, 0, 0, 0, 350, 351, 5, 75, 0, 0, 351, 352, 5, 2, 0, 0, 352, 353, 5, 129, 0, 0, 353, 59, 1, 0, 0, 0, 354, 355, 5, 76, 0, 0, 355, 356, 5, 2, 0, 0, 356, 357, 5, 131, 0, 0, 357, 61, 1, 0, 0, 0, 358, 359, 5, 77, 0, 0, 359, 360, 5, 2, 0, 0, 360, 361, 5, 129, 0, 0, 361, 63, 1, 0, 0, 0, 362, 363, 5, 5, 0, 0, 363, 368, 3, 66, 33, 0, 364, 365, 5, 1, 0, 0, 365, 367, 3, 66, 33, 0, 366, 364, 1, 0, 0, 0, 367, 370, 1, 0, 0, 0, 368, 366, 1, 0, 0, 0, 368, 369, 1, 0, 0, 0, 369, 371, 1, 0, 0, 0, 370, 368, 1, 0, 0, 0, 371, 372, 5, 6, 0, 0, 372, 376, 1, 0, 0, 0, 373, 374, 5, 5, 0, 0, 374, 376, 5, 6, 0, 0, 375, 362, 1, 0, 0, 0, 375, 373, 1, 0, 0, 0, 376, 65, 1, 0, 0, 0, 377, 378, 5, 127, 0, 0, 378, 379, 5, 2, 0, 0, 379, 391, 5, 129, 0, 0, 380, 381, 5, 127, 0, 0, 381, 382, 5, 2, 0, 0, 382, 391, 5, 128, 0, 0, 383, 384, 5, 127, 0, 0, 384, 385, 5, 2, 0, 0, 385, 391, 3, 68, 34, 0, 386, 387, 3, 172, 86, 0, 387, 388, 5, 2, 0, 0, 388, 389, 3, 72, 36, 0, 389, 391, 1, 0, 0, 0, 390, 377, 1, 0, 0, 0, 390, 380, 1, 0, 0, 0, 390, 383, 1, 0, 0, 0, 390, 386, 1, 0, 0, 0, 391, 67, 1, 0, 0, 0, 392, 393, 5, 130, 0, 0, 393, 69, 1, 0, 0, 0, 394, 395, 5, 3, 0, 0, 395, 400, 3, 72, 36, 0, 396, 397, 5, 1, 0, 0, 397, 399, 3, 72, 36, 0, 398, 396, 1, 0, 0, 0, 399, 402, 1, 0, 0, 0, 400, 398, 1, 0, 0, 0, 400, 401, 1, 0, 0, 0, 401, 403, 1, 0, 0, 0, 402, 400, 1, 0, 0, 0, 403, 404, 5, 4, 0, 0, 404, 408, 1, 0, 0, 0, 405, 406, 5, 3, 0, 0, 406, 408, 5, 4, 0, 0, 407, 394, 1, 0, 0, 0, 407, 405, 1, 0, 0, 0, 408, 71, 1, 0, 0, 0, 409, 414, 3, 66, 33, 0, 410, 414, 3, 70, 35, 0, 411, 414, 3, 64, 32, 0, 412, 414, 3, 74, 37, 0, 413, 409, 1, 0, 0, 0, 413, 410, 1, 0, 0, 0, 413, 411, 1, 0, 0, 0, 413, 412, 1, 0, 0, 0, 414, 73, 1, 0, 0, 0, 415, 421, 5, 132, 0, 0, 416, 421, 5, 131, 0, 0, 417, 421, 7, 0, 0, 0, 418, 421, 5, 9, 0, 0, 419, 421, 3, 172, 86, 0, 420, 415, 1, 0, 0, 0, 420, 416, 1, 0, 0, 0, 420, 417, 1, 0, 0, 0, 420, 418, 1, 0, 0, 0, 420, 419, 1, 0, 0, 0, 421, 75, 1, 0, 0, 0, 422, 423, 5, 95, 0, 0, 423, 424, 5, 2, 0, 0, 424, 425, 3, 64, 32, 0, 425, 77, 1, 0, 0, 0, 426, 427, 7, 1, 0, 0, 427, 79, 1, 0, 0, 0, 428, 429, 5, 24, 0, 0, 429, 430, 5, 2, 0, 0, 430, 431, 5, 3, 0, 0, 431, 436, 3, 82, 41, 0, 432, 433, 5, 1, 0, 0, 433, 435, 3, 82, 41, 0, 434, 432, 1, 0, 0, 0, 435, 438, 1, 0, 0, 0, 436, 434, 1, 0, 0, 0, 436, 437, 1, 0, 0, 0, 437, 439, 1, 0, 0, 0, 438, 436, 1, 0, 0, 0, 439, 440, 5, 4, 0, 0, 440, 81, 1, 0, 0, 0, 441, 442, 5, 5, 0, 0, 442, 445, 3, 84, 42, 0, 443, 444, 5, 1, 0, 0, 444, 446, 3, 84, 42, 0, 445, 443, 1, 0, 0, 0, 446, 447, 1, 0, 0, 0, 447, 445, 1, 0, 0, 0, 447, 448, 1, 0, 0, 0, 448, 449, 1, 0, 0, 0, 449, 450, 5, 6, 0, 0, 450, 463, 1, 0, 0, 0, 451, 452, 5, 5, 0, 0, 452, 457, 3, 86, 43, 0, 453, 454, 5, 1, 0, 0, 454, 456, 3, 86, 43, 0, 455, 453, 1, 0, 0, 0, 456, 459, 1, 0, 0, 0, 457, 455, 1, 0, 0, 0, 457, 458, 1, 0, 0, 0, 458, 460, 1, 0, 0, 0, 459, 457, 1, 0, 0, 0, 460, 461, 5, 6, 0, 0, 461, 463, 1, 0, 0, 0, 462, 441, 1, 0, 0, 0, 462, 451, 1, 0, 0, 0, 463, 83, 1, 0, 0, 0, 464, 468, 3, 90, 45, 0, 465, 468, 3, 92, 46, 0, 466, 468, 3, 22, 11, 0, 467, 464, 1, 0, 0, 0, 467, 465, 1, 0, 0, 0, 467, 466, 1, 0, 0, 0, 468, 85, 1, 0, 0, 0, 469, 472, 3, 88, 44, 0, 470, 472, 3, 22, 11, 0, 471, 469, 1, 0, 0, 0, 471, 470, 1, 0, 0, 0, 472, 87, 1, 0, 0, 0, 473, 474, 3, 158, 79, 0, 474, 487, 5, 2, 0, 0, 475, 488, 3, 82, 41, 0, 476, 477, 5, 3, 0, 0, 477, 482, 3, 82, 41, 0, 478, 479, 5, 1, 0, 0, 479, 481, 3, 82, 41, 0, 480, 478, 1, 0, 0, 0, 481, 484, 1, 0, 0, 0, 482, 480, 1, 0, 0, 0, 482, 483, 1, 0, 0, 0, 483, 485, 1, 0, 0, 0, 484, 482, 1, 0, 0, 0, 485, 486, 5, 4, 0, 0, 486, 488, 1, 0, 0, 0, 487, 475, 1, 0, 0, 0, 487, 476, 1, 0, 0, 0, 488, 89, 1, 0, 0, 0, 489, 490, 5, 25, 0, 0, 490, 491, 5, 2, 0, 0, 491, 492, 3, 172, 86, 0, 492, 91, 1, 0, 0, 0, 493, 494, 3, 156, 78, 0, 494, 495, 5, 2, 0, 0, 495, 496, 3, 170, 85, 0, 496, 93, 1, 0, 0, 0, 497, 498, 5, 27, 0, 0, 498, 499, 5, 2, 0, 0, 499, 500, 5, 3, 0, 0, 500, 505, 3, 0, 0, 0, 501, 502, 5, 1, 0, 0, 502, 504, 3, 0, 0, 0, 503, 501, 1, 0, 0, 0, 504, 507, 1, 0, 0, 0, 505, 503, 1, 0, 0, 0, 505, 506, 1, 0, 0, 0, 506, 508, 1, 0, 0, 0, 507, 505, 1, 0, 0, 0, 508, 509, 5, 4, 0, 0, 509, 95, 1, 0, 0, 0, 510, 511, 5, 84, 0, 0, 511, 512, 5, 2, 0, 0, 512, 513, 5, 5, 0, 0, 513, 518, 3, 98, 49, 0, 514, 515, 5, 1, 0, 0, 515, 517, 3, 98, 49, 0, 516, 514, 1, 0, 0, 0, 517, 520, 1, 0, 0, 0, 518, 516, 1, 0, 0, 0, 518, 519, 1, 0, 0, 0, 519, 521, 1, 0, 0, 0, 520, 518, 1, 0, 0, 0, 521, 522, 5, 6, 0, 0, 522, 97, 1, 0, 0, 0, 523, 528, 3, 100, 50, 0, 524, 528, 3, 4, 2, 0, 525, 528, 3, 12, 6, 0, 526, 528, 3, 6, 3, 0, 527, 523, 1, 0, 0, 0, 527, 524, 1, 0, 0, 0, 527, 525, 1, 0, 0, 0, 527, 526, 1, 0, 0, 0, 528, 99, 1, 0, 0, 0, 529, 530, 5, 78, 0, 0, 530, 531, 5, 2, 0, 0, 531, 532, 5, 5, 0, 0, 532, 537, 3, 102, 51, 0, 533, 534, 5, 1, 0, 0, 534, 536, 3, 102, 51, 0, 535, 533, 1, 0, 0, 0, 536, 539, 1, 0, 0, 0, 537, 535, 1, 0, 0, 0, 537, 538, 1, 0, 0, 0, 538, 540, 1, 0, 0, 0, 539, 537, 1, 0, 0, 0, 540, 541, 5, 6, 0, 0, 541, 101, 1, 0, 0, 0, 542, 545, 3, 104, 52, 0, 543, 545, 3, 108, 54, 0, 544, 542, 1, 0, 0, 0, 544, 543, 1, 0, 0, 0, 545, 103, 1, 0, 0, 0, 546, 547, 5, 79, 0, 0, 547, 548, 5, 2, 0, 0, 548, 549, 3, 106, 53, 0, 549, 105, 1, 0, 0, 0, 550, 551, 7, 2, 0, 0, 551, 107, 1, 0, 0, 0, 552, 553, 5, 82, 0, 0, 553, 554, 5, 2, 0, 0, 554, 555, 3, 110, 55, 0, 555, 109, 1, 0, 0, 0, 556, 557, 5, 83, 0, 0, 557, 111, 1, 0, 0, 0, 558, 559, 5, 85, 0, 0, 559, 560, 5, 2, 0, 0, 560, 561, 5, 5, 0, 0, 561, 566, 3, 114, 57, 0, 562, 563, 5, 1, 0, 0, 563, 565, 3, 114, 57, 0, 564, 562, 1, 0, 0, 0, 565, 568, 1, 0, 0, 0, 566, 564, 1, 0, 0, 0, 566, 567, 1, 0, 0, 0, 567, 569, 1, 0, 0, 0, 568, 566, 1, 0, 0, 0, 569, 570, 5, 6, 0, 0, 570, 113, 1, 0, 0, 0, 571, 575, 3, 4, 2, 0, 572, 575, 3, 12, 6, 0, 573, 575, 3, 6, 3, 0, 574, 571, 1, 0, 0, 0, 574, 572, 1, 0, 0, 0, 574, 573, 1, 0, 0, 0, 575, 115, 1, 0, 0, 0, 576, 577, 5, 86, 0, 0, 577, 578, 5, 2, 0, 0, 578, 579, 3, 64, 32, 0, 579, 117, 1, 0, 0, 0, 580, 581, 5, 96, 0, 0, 581, 582, 5, 2, 0, 0, 582, 583, 5, 5, 0, 0, 583, 588, 3, 120, 60, 0, 584, 585, 5, 1, 0, 0, 585, 587, 3, 120, 60, 0, 586, 584, 1, 0, 0, 0, 587, 590, 1, 0, 0, 0, 588, 586, 1, 0, 0, 0, 588, 589, 1, 0, 0, 0, 589, 591, 1, 0, 0, 0, 590, 588, 1, 0, 0, 0, 591, 592, 5, 6, 0, 0, 592, 119, 1, 0, 0, 0, 593, 597, 3, 24, 12, 0, 594, 597, 3, 54, 27, 0, 595, 597, 3, 122, 61, 0, 596, 593, 1, 0, 0, 0, 596, 594, 1, 0, 0, 0, 596, 595, 1, 0, 0, 0, 597, 121, 1, 0, 0, 0, 598, 599, 5, 97, 0, 0, 599, 600, 5, 2, 0, 0, 600, 601, 5, 5, 0, 0, 601, 606, 3, 124, 62, 0, 602, 603, 5, 1, 0, 0, 603, 605, 3, 124, 62, 0, 604, 602, 1, 0, 0, 0, 605, 608, 1, 0, 0, 0, 606, 604, 1, 0, 0, 0, 606, 607, 1, 0, 0, 0, 607, 609, 1, 0, 0, 0, 608, 606, 1, 0, 0, 0, 609, 610, 5, 6, 0, 0, 610, 123, 1, 0, 0, 0, 611, 617, 3, 126, 63, 0, 612, 617, 3, 128, 64, 0, 613, 617, 3, 130, 65, 0, 614, 617, 3, 132, 66, 0, 615, 617, 3, 134, 67, 0, 616, 611, 1, 0, 0, 0, 616, 612, 1, 0, 0, 0, 616, 613, 1, 0, 0, 0, 616, 614, 1, 0, 0, 0, 616, 615, 1, 0, 0, 0, 617, 125, 1, 0, 0, 0, 618, 619, 5, 98, 0, 0, 619, 620, 5, 2, 0, 0, 620, 621, 3, 172, 86, 0, 621, 127, 1, 0, 0, 0, 622, 623, 5, 99, 0, 0, 623, 624, 5, 2, 0, 0, 624, 625, 3, 172, 86, 0, 625, 129, 1, 0, 0, 0, 626, 627, 5, 100, 0, 0, 627, 628, 5, 2, 0, 0, 628, 629, 5, 3, 0, 0, 629, 634, 3, 172, 86, 0, 630, 631, 5, 1, 0, 0, 631, 633, 3, 172, 86, 0, 632, 630, 1, 0, 0, 0, 633, 636, 1, 0, 0, 0, 634, 632, 1, 0, 0, 0, 634, 635, 1, 0, 0, 0, 635, 637, 1, 0, 0, 0, 636, 634, 1, 0, 0, 0, 637, 638, 5, 4, 0, 0, 638, 131, 1, 0, 0, 0, 639, 640, 5, 101, 0, 0, 640, 641, 5, 2, 0, 0, 641, 642, 5, 131, 0, 0, 642, 133, 1, 0, 0, 0, 643, 644, 5, 102, 0, 0, 644, 645, 5, 2, 0, 0, 645, 646, 5, 129, 0, 0, 646, 135, 1, 0, 0, 0, 647, 648, 5, 107, 0, 0, 648, 649, 5, 2, 0, 0, 649, 658, 5, 3, 0, 0, 650, 655, 3, 138, 69, 0, 651, 652, 5, 1, 0, 0, 652, 654, 3, 138, 69, 0, 653, 651, 1, 0, 0, 0, 654, 657, 1, 0, 0, 0, 655, 653, 1, 0, 0, 0, 655, 656, 1, 0, 0, 0, 656, 659, 1, 0, 0, 0, 657, 655, 1, 0, 0, 0, 658, 650, 1, 0, 0, 0, 658, 659, 1, 0, 0, 0, 659, 660, 1, 0, 0, 0, 660, 661, 5, 4, 0, 0, 661, 137, 1, 0, 0, 0, 662, 663, 5, 5, 0, 0, 663, 668, 3, 140, 70, 0, 664, 665, 5, 1, 0, 0, 665, 667, 3, 140, 70, 0, 666, 664, 1, 0, 0, 0, 667, 670, 1, 0, 0, 0, 668, 666, 1, 0, 0, 0, 668, 669, 1, 0, 0, 0, 669, 671, 1, 0, 0, 0, 670, 668, 1, 0, 0, 0, 671, 672, 5, 6, 0, 0, 672, 139, 1, 0, 0, 0, 673, 678, 3, 142, 71, 0, 674, 678, 3, 144, 72, 0, 675, 678, 3, 146, 73, 0, 676, 678, 3, 148, 74, 0, 677, 673, 1, 0, 0, 0, 677, 674, 1, 0, 0, 0, 677, 675, 1, 0, 0, 0, 677, 676, 1, 0, 0, 0, 678, 141, 1, 0, 0, 0, 679, 680, 5, 108, 0, 0, 680, 681, 5, 2, 0, 0, 681, 682, 5, 3, 0, 0, 682, 687, 3, 162, 81, 0, 683, 684, 5, 1, 0, 0, 684, 686, 3, 162, 81, 0, 685, 683, 1, 0, 0, 0, 686, 689, 1, 0, 0, 0, 687, 685, 1, 0, 0, 0, 687, 688, 1, 0, 0, 0, 688, 690, 1, 0, 0, 0, 689, 687, 1, 0, 0, 0, 690, 691, 5, 4, 0, 0, 691, 143, 1, 0, 0, 0, 692, 693, 5, 109, 0, 0, 693, 694, 5, 2, 0, 0, 694, 695, 5, 131, 0, 0, 695, 145, 1, 0, 0, 0, 696, 697, 5, 110, 0, 0, 697, 698, 5, 2, 0, 0, 698, 699, 5, 131, 0, 0, 699, 147, 1, 0, 0, 0, 700, 701, 5, 111, 0, 0, 701, 702, 5, 2, 0, 0, 702, 703, 7, 3, 0, 0, 703, 149, 1, 0, 0, 0, 704, 705, 5, 112, 0, 0, 705, 706, 5, 2, 0, 0, 706, 715, 5, 3, 0, 0, 707, 712, 3, 152, 76, 0, 708, 709, 5, 1, 0, 0, 709, 711, 3, 152, 76, 0, 710, 708, 1, 0, 0, 0, 711, 714, 1, 0, 0, 0, 712, 710, 1, 0, 0, 0, 712, 713, 1, 0, 0, 0, 713, 716, 1, 0, 0, 0, 714, 712, 1, 0, 0, 0, 715, 707, 1, 0, 0, 0, 715, 716, 1, 0, 0, 0, 716, 717, 1, 0, 0, 0, 717, 718, 5, 4, 0, 0, 718, 151, 1, 0, 0, 0, 719, 720, 5, 5, 0, 0, 720, 725, 3, 154, 77, 0, 721, 722, 5, 1, 0, 0, 722, 724, 3, 154, 77, 0, 723, 721, 1, 0, 0, 0, 724, 727, 1, 0, 0, 0, 725, 723, 1, 0, 0, 0, 725, 726, 1, 0, 0, 0, 726, 728, 1, 0, 0, 0, 727, 725, 1, 0, 0, 0, 728, 729, 5, 6, 0, 0, 729, 153, 1, 0, 0, 0, 730, 734, 3, 142, 71, 0, 731, 734, 3, 30, 15, 0, 732, 734, 3, 22, 11, 0, 733, 730, 1, 0, 0, 0, 733, 731, 1, 0, 0, 0, 733, 732, 1, 0, 0, 0, 734, 155, 1, 0, 0, 0, 735, 736, 7, 4, 0, 0, 736, 157, 1, 0, 0, 0, 737, 738, 7, 5, 0, 0, 738, 159, 1, 0, 0, 0, 739, 740, 7, 6, 0, 0, 740, 161, 1, 0, 0, 0, 741, 744, 3, 160, 80, 0, 742, 744, 3, 172, 86, 0, 743, 741, 1, 0, 0, 0, 743, 742, 1, 0, 0, 0, 744, 163, 1, 0, 0, 0, 745, 746, 5, 5, 0, 0, 746, 751, 3, 166, 83, 0, 747, 748, 5, 1, 0, 0, 748, 750, 3, 166, 83, 0, 749, 747, 1, 0, 0, 0, 750, 753, 1, 0, 0, 0, 751, 749, 1, 0, 0, 0, 751, 752, 1, 0, 0, 0, 752, 754, 1, 0, 0, 0, 753, 751, 1, 0, 0, 0, 754, 755, 5, 6, 0, 0, 755, 759, 1, 0, 0, 0, 756, 757, 5, 5, 0, 0, 757, 759, 5, 6, 0, 0, 758, 745, 1, 0, 0, 0, 758, 756, 1, 0, 0, 0, 759, 165, 1, 0, 0, 0, 760, 761, 3, 172, 86, 0, 761, 762, 5, 2, 0, 0, 762, 763, 3, 170, 85, 0, 763, 167, 1, 0, 0, 0, 764, 765, 5, 3, 0, 0, 765, 770, 3, 170, 85, 0, 766, 767, 5, 1, 0, 0, 767, 769, 3, 170, 85, 0, 768, 766, 1, 0, 0, 0, 769, 772, 1, 0, 0, 0, 770, 768, 1, 0, 0, 0, 770, 771, 1, 0, 0, 0, 771, 773, 1, 0, 0, 0, 772, 770, 1, 0, 0, 0, 773, 774, 5, 4, 0, 0, 774, 778, 1, 0, 0, 0, 775, 776, 5, 3, 0, 0, 776, 778, 5, 4, 0, 0, 777, 764, 1, 0, 0, 0, 777, 775, 1, 0, 0, 0, 778, 169, 1, 0, 0, 0, 779, 789, 5, 132, 0, 0, 780, 789, 5, 131, 0, 0, 781, 789, 5, 7, 0, 0, 782, 789, 5, 8, 0, 0, 783, 789, 5, 9, 0, 0, 784, 789, 3, 166, 83, 0, 785, 789, 3, 168, 84, 0, 786, 789, 3, 164, 82, 0, 787, 789, 3, 172, 86, 0, 788, 779, 1, 0, 0, 0, 788, 780, 1, 0, 0, 0, 788, 781, 1, 0, 0, 0, 788, 782, 1, 0, 0, 0, 788, 783, 1, 0, 0, 0, 788, 784, 1, 0, 0, 0, 788, 785, 1, 0, 0, 0, 788, 786, 1, 0, 0, 0, 788, 787, 1, 0, 0, 0, 789, 171, 1, 0, 0, 0, 790, 791, 7, 7, 0, 0, 791, 173, 1, 0, 0, 0, 50, 180, 190, 236, 246, 263, 284, 294, 300, 368, 375, 390, 400, 407, 413, 420, 436, 447, 457, 462, 467, 471, 482, 487, 505, 518, 527, 537, 544, 566, 574, 588, 596, 606, 616, 634, 655, 658, 668, 677, 687, 712, 715, 725, 733, 743, 751, 758, 770, 777, 788] \ No newline at end of file diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLParser.py b/moto/stepfunctions/parser/asl/antlr/runtime/ASLParser.py new file mode 100644 index 000000000..2a19a5637 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLParser.py @@ -0,0 +1,14824 @@ +# Generated from /Users/mep/LocalStack/localstack/localstack/services/stepfunctions/asl/antlr/ASLParser.g4 by ANTLR 4.13.1 +# encoding: utf-8 +import sys +from typing import TextIO + +from antlr4 import ( + DFA, + ATNDeserializer, + NoViableAltException, + Parser, + ParserATNSimulator, + ParserRuleContext, + ParseTreeListener, + ParseTreeVisitor, + PredictionContextCache, + RecognitionException, + Token, + TokenStream, +) + + +def serializedATN(): + return [ + 4, + 1, + 133, + 793, + 2, + 0, + 7, + 0, + 2, + 1, + 7, + 1, + 2, + 2, + 7, + 2, + 2, + 3, + 7, + 3, + 2, + 4, + 7, + 4, + 2, + 5, + 7, + 5, + 2, + 6, + 7, + 6, + 2, + 7, + 7, + 7, + 2, + 8, + 7, + 8, + 2, + 9, + 7, + 9, + 2, + 10, + 7, + 10, + 2, + 11, + 7, + 11, + 2, + 12, + 7, + 12, + 2, + 13, + 7, + 13, + 2, + 14, + 7, + 14, + 2, + 15, + 7, + 15, + 2, + 16, + 7, + 16, + 2, + 17, + 7, + 17, + 2, + 18, + 7, + 18, + 2, + 19, + 7, + 19, + 2, + 20, + 7, + 20, + 2, + 21, + 7, + 21, + 2, + 22, + 7, + 22, + 2, + 23, + 7, + 23, + 2, + 24, + 7, + 24, + 2, + 25, + 7, + 25, + 2, + 26, + 7, + 26, + 2, + 27, + 7, + 27, + 2, + 28, + 7, + 28, + 2, + 29, + 7, + 29, + 2, + 30, + 7, + 30, + 2, + 31, + 7, + 31, + 2, + 32, + 7, + 32, + 2, + 33, + 7, + 33, + 2, + 34, + 7, + 34, + 2, + 35, + 7, + 35, + 2, + 36, + 7, + 36, + 2, + 37, + 7, + 37, + 2, + 38, + 7, + 38, + 2, + 39, + 7, + 39, + 2, + 40, + 7, + 40, + 2, + 41, + 7, + 41, + 2, + 42, + 7, + 42, + 2, + 43, + 7, + 43, + 2, + 44, + 7, + 44, + 2, + 45, + 7, + 45, + 2, + 46, + 7, + 46, + 2, + 47, + 7, + 47, + 2, + 48, + 7, + 48, + 2, + 49, + 7, + 49, + 2, + 50, + 7, + 50, + 2, + 51, + 7, + 51, + 2, + 52, + 7, + 52, + 2, + 53, + 7, + 53, + 2, + 54, + 7, + 54, + 2, + 55, + 7, + 55, + 2, + 56, + 7, + 56, + 2, + 57, + 7, + 57, + 2, + 58, + 7, + 58, + 2, + 59, + 7, + 59, + 2, + 60, + 7, + 60, + 2, + 61, + 7, + 61, + 2, + 62, + 7, + 62, + 2, + 63, + 7, + 63, + 2, + 64, + 7, + 64, + 2, + 65, + 7, + 65, + 2, + 66, + 7, + 66, + 2, + 67, + 7, + 67, + 2, + 68, + 7, + 68, + 2, + 69, + 7, + 69, + 2, + 70, + 7, + 70, + 2, + 71, + 7, + 71, + 2, + 72, + 7, + 72, + 2, + 73, + 7, + 73, + 2, + 74, + 7, + 74, + 2, + 75, + 7, + 75, + 2, + 76, + 7, + 76, + 2, + 77, + 7, + 77, + 2, + 78, + 7, + 78, + 2, + 79, + 7, + 79, + 2, + 80, + 7, + 80, + 2, + 81, + 7, + 81, + 2, + 82, + 7, + 82, + 2, + 83, + 7, + 83, + 2, + 84, + 7, + 84, + 2, + 85, + 7, + 85, + 2, + 86, + 7, + 86, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 5, + 0, + 179, + 8, + 0, + 10, + 0, + 12, + 0, + 182, + 9, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 3, + 1, + 191, + 8, + 1, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 2, + 1, + 3, + 1, + 3, + 1, + 3, + 1, + 3, + 1, + 4, + 1, + 4, + 1, + 4, + 1, + 4, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 1, + 5, + 3, + 5, + 237, + 8, + 5, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 1, + 6, + 5, + 6, + 245, + 8, + 6, + 10, + 6, + 12, + 6, + 248, + 9, + 6, + 1, + 6, + 1, + 6, + 1, + 7, + 1, + 7, + 1, + 8, + 1, + 8, + 1, + 8, + 1, + 8, + 1, + 9, + 1, + 9, + 1, + 9, + 1, + 9, + 5, + 9, + 262, + 8, + 9, + 10, + 9, + 12, + 9, + 265, + 9, + 9, + 1, + 9, + 1, + 9, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 10, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 11, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 12, + 1, + 13, + 1, + 13, + 1, + 13, + 1, + 13, + 3, + 13, + 285, + 8, + 13, + 1, + 14, + 1, + 14, + 1, + 14, + 1, + 14, + 1, + 15, + 1, + 15, + 1, + 15, + 1, + 15, + 3, + 15, + 295, + 8, + 15, + 1, + 16, + 1, + 16, + 1, + 16, + 1, + 16, + 3, + 16, + 301, + 8, + 16, + 1, + 17, + 1, + 17, + 1, + 17, + 1, + 17, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 18, + 1, + 19, + 1, + 19, + 1, + 19, + 1, + 19, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 20, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 21, + 1, + 22, + 1, + 22, + 1, + 22, + 1, + 22, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 23, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 24, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 25, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 26, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 27, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 28, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 29, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 30, + 1, + 31, + 1, + 31, + 1, + 31, + 1, + 31, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 5, + 32, + 367, + 8, + 32, + 10, + 32, + 12, + 32, + 370, + 9, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 1, + 32, + 3, + 32, + 376, + 8, + 32, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 1, + 33, + 3, + 33, + 391, + 8, + 33, + 1, + 34, + 1, + 34, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 5, + 35, + 399, + 8, + 35, + 10, + 35, + 12, + 35, + 402, + 9, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 1, + 35, + 3, + 35, + 408, + 8, + 35, + 1, + 36, + 1, + 36, + 1, + 36, + 1, + 36, + 3, + 36, + 414, + 8, + 36, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 1, + 37, + 3, + 37, + 421, + 8, + 37, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 38, + 1, + 39, + 1, + 39, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 1, + 40, + 5, + 40, + 435, + 8, + 40, + 10, + 40, + 12, + 40, + 438, + 9, + 40, + 1, + 40, + 1, + 40, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 4, + 41, + 446, + 8, + 41, + 11, + 41, + 12, + 41, + 447, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 1, + 41, + 5, + 41, + 456, + 8, + 41, + 10, + 41, + 12, + 41, + 459, + 9, + 41, + 1, + 41, + 1, + 41, + 3, + 41, + 463, + 8, + 41, + 1, + 42, + 1, + 42, + 1, + 42, + 3, + 42, + 468, + 8, + 42, + 1, + 43, + 1, + 43, + 3, + 43, + 472, + 8, + 43, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 1, + 44, + 5, + 44, + 481, + 8, + 44, + 10, + 44, + 12, + 44, + 484, + 9, + 44, + 1, + 44, + 1, + 44, + 3, + 44, + 488, + 8, + 44, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 45, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 46, + 1, + 47, + 1, + 47, + 1, + 47, + 1, + 47, + 1, + 47, + 1, + 47, + 5, + 47, + 504, + 8, + 47, + 10, + 47, + 12, + 47, + 507, + 9, + 47, + 1, + 47, + 1, + 47, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 1, + 48, + 5, + 48, + 517, + 8, + 48, + 10, + 48, + 12, + 48, + 520, + 9, + 48, + 1, + 48, + 1, + 48, + 1, + 49, + 1, + 49, + 1, + 49, + 1, + 49, + 3, + 49, + 528, + 8, + 49, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 1, + 50, + 5, + 50, + 536, + 8, + 50, + 10, + 50, + 12, + 50, + 539, + 9, + 50, + 1, + 50, + 1, + 50, + 1, + 51, + 1, + 51, + 3, + 51, + 545, + 8, + 51, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 52, + 1, + 53, + 1, + 53, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 54, + 1, + 55, + 1, + 55, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 1, + 56, + 5, + 56, + 565, + 8, + 56, + 10, + 56, + 12, + 56, + 568, + 9, + 56, + 1, + 56, + 1, + 56, + 1, + 57, + 1, + 57, + 1, + 57, + 3, + 57, + 575, + 8, + 57, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 58, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 1, + 59, + 5, + 59, + 587, + 8, + 59, + 10, + 59, + 12, + 59, + 590, + 9, + 59, + 1, + 59, + 1, + 59, + 1, + 60, + 1, + 60, + 1, + 60, + 3, + 60, + 597, + 8, + 60, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 1, + 61, + 5, + 61, + 605, + 8, + 61, + 10, + 61, + 12, + 61, + 608, + 9, + 61, + 1, + 61, + 1, + 61, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 1, + 62, + 3, + 62, + 617, + 8, + 62, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 63, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 64, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 1, + 65, + 5, + 65, + 633, + 8, + 65, + 10, + 65, + 12, + 65, + 636, + 9, + 65, + 1, + 65, + 1, + 65, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 66, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 67, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 1, + 68, + 5, + 68, + 654, + 8, + 68, + 10, + 68, + 12, + 68, + 657, + 9, + 68, + 3, + 68, + 659, + 8, + 68, + 1, + 68, + 1, + 68, + 1, + 69, + 1, + 69, + 1, + 69, + 1, + 69, + 5, + 69, + 667, + 8, + 69, + 10, + 69, + 12, + 69, + 670, + 9, + 69, + 1, + 69, + 1, + 69, + 1, + 70, + 1, + 70, + 1, + 70, + 1, + 70, + 3, + 70, + 678, + 8, + 70, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 1, + 71, + 5, + 71, + 686, + 8, + 71, + 10, + 71, + 12, + 71, + 689, + 9, + 71, + 1, + 71, + 1, + 71, + 1, + 72, + 1, + 72, + 1, + 72, + 1, + 72, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 73, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 74, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 1, + 75, + 5, + 75, + 711, + 8, + 75, + 10, + 75, + 12, + 75, + 714, + 9, + 75, + 3, + 75, + 716, + 8, + 75, + 1, + 75, + 1, + 75, + 1, + 76, + 1, + 76, + 1, + 76, + 1, + 76, + 5, + 76, + 724, + 8, + 76, + 10, + 76, + 12, + 76, + 727, + 9, + 76, + 1, + 76, + 1, + 76, + 1, + 77, + 1, + 77, + 1, + 77, + 3, + 77, + 734, + 8, + 77, + 1, + 78, + 1, + 78, + 1, + 79, + 1, + 79, + 1, + 80, + 1, + 80, + 1, + 81, + 1, + 81, + 3, + 81, + 744, + 8, + 81, + 1, + 82, + 1, + 82, + 1, + 82, + 1, + 82, + 5, + 82, + 750, + 8, + 82, + 10, + 82, + 12, + 82, + 753, + 9, + 82, + 1, + 82, + 1, + 82, + 1, + 82, + 1, + 82, + 3, + 82, + 759, + 8, + 82, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 83, + 1, + 84, + 1, + 84, + 1, + 84, + 1, + 84, + 5, + 84, + 769, + 8, + 84, + 10, + 84, + 12, + 84, + 772, + 9, + 84, + 1, + 84, + 1, + 84, + 1, + 84, + 1, + 84, + 3, + 84, + 778, + 8, + 84, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 1, + 85, + 3, + 85, + 789, + 8, + 85, + 1, + 86, + 1, + 86, + 1, + 86, + 0, + 0, + 87, + 0, + 2, + 4, + 6, + 8, + 10, + 12, + 14, + 16, + 18, + 20, + 22, + 24, + 26, + 28, + 30, + 32, + 34, + 36, + 38, + 40, + 42, + 44, + 46, + 48, + 50, + 52, + 54, + 56, + 58, + 60, + 62, + 64, + 66, + 68, + 70, + 72, + 74, + 76, + 78, + 80, + 82, + 84, + 86, + 88, + 90, + 92, + 94, + 96, + 98, + 100, + 102, + 104, + 106, + 108, + 110, + 112, + 114, + 116, + 118, + 120, + 122, + 124, + 126, + 128, + 130, + 132, + 134, + 136, + 138, + 140, + 142, + 144, + 146, + 148, + 150, + 152, + 154, + 156, + 158, + 160, + 162, + 164, + 166, + 168, + 170, + 172, + 0, + 8, + 1, + 0, + 7, + 8, + 1, + 0, + 16, + 23, + 1, + 0, + 80, + 81, + 1, + 0, + 131, + 132, + 3, + 0, + 29, + 36, + 38, + 47, + 49, + 69, + 3, + 0, + 28, + 28, + 37, + 37, + 48, + 48, + 1, + 0, + 113, + 126, + 2, + 0, + 10, + 13, + 15, + 130, + 813, + 0, + 174, + 1, + 0, + 0, + 0, + 2, + 190, + 1, + 0, + 0, + 0, + 4, + 192, + 1, + 0, + 0, + 0, + 6, + 196, + 1, + 0, + 0, + 0, + 8, + 200, + 1, + 0, + 0, + 0, + 10, + 236, + 1, + 0, + 0, + 0, + 12, + 238, + 1, + 0, + 0, + 0, + 14, + 251, + 1, + 0, + 0, + 0, + 16, + 253, + 1, + 0, + 0, + 0, + 18, + 257, + 1, + 0, + 0, + 0, + 20, + 268, + 1, + 0, + 0, + 0, + 22, + 272, + 1, + 0, + 0, + 0, + 24, + 276, + 1, + 0, + 0, + 0, + 26, + 280, + 1, + 0, + 0, + 0, + 28, + 286, + 1, + 0, + 0, + 0, + 30, + 290, + 1, + 0, + 0, + 0, + 32, + 296, + 1, + 0, + 0, + 0, + 34, + 302, + 1, + 0, + 0, + 0, + 36, + 306, + 1, + 0, + 0, + 0, + 38, + 310, + 1, + 0, + 0, + 0, + 40, + 314, + 1, + 0, + 0, + 0, + 42, + 318, + 1, + 0, + 0, + 0, + 44, + 322, + 1, + 0, + 0, + 0, + 46, + 326, + 1, + 0, + 0, + 0, + 48, + 330, + 1, + 0, + 0, + 0, + 50, + 334, + 1, + 0, + 0, + 0, + 52, + 338, + 1, + 0, + 0, + 0, + 54, + 342, + 1, + 0, + 0, + 0, + 56, + 346, + 1, + 0, + 0, + 0, + 58, + 350, + 1, + 0, + 0, + 0, + 60, + 354, + 1, + 0, + 0, + 0, + 62, + 358, + 1, + 0, + 0, + 0, + 64, + 375, + 1, + 0, + 0, + 0, + 66, + 390, + 1, + 0, + 0, + 0, + 68, + 392, + 1, + 0, + 0, + 0, + 70, + 407, + 1, + 0, + 0, + 0, + 72, + 413, + 1, + 0, + 0, + 0, + 74, + 420, + 1, + 0, + 0, + 0, + 76, + 422, + 1, + 0, + 0, + 0, + 78, + 426, + 1, + 0, + 0, + 0, + 80, + 428, + 1, + 0, + 0, + 0, + 82, + 462, + 1, + 0, + 0, + 0, + 84, + 467, + 1, + 0, + 0, + 0, + 86, + 471, + 1, + 0, + 0, + 0, + 88, + 473, + 1, + 0, + 0, + 0, + 90, + 489, + 1, + 0, + 0, + 0, + 92, + 493, + 1, + 0, + 0, + 0, + 94, + 497, + 1, + 0, + 0, + 0, + 96, + 510, + 1, + 0, + 0, + 0, + 98, + 527, + 1, + 0, + 0, + 0, + 100, + 529, + 1, + 0, + 0, + 0, + 102, + 544, + 1, + 0, + 0, + 0, + 104, + 546, + 1, + 0, + 0, + 0, + 106, + 550, + 1, + 0, + 0, + 0, + 108, + 552, + 1, + 0, + 0, + 0, + 110, + 556, + 1, + 0, + 0, + 0, + 112, + 558, + 1, + 0, + 0, + 0, + 114, + 574, + 1, + 0, + 0, + 0, + 116, + 576, + 1, + 0, + 0, + 0, + 118, + 580, + 1, + 0, + 0, + 0, + 120, + 596, + 1, + 0, + 0, + 0, + 122, + 598, + 1, + 0, + 0, + 0, + 124, + 616, + 1, + 0, + 0, + 0, + 126, + 618, + 1, + 0, + 0, + 0, + 128, + 622, + 1, + 0, + 0, + 0, + 130, + 626, + 1, + 0, + 0, + 0, + 132, + 639, + 1, + 0, + 0, + 0, + 134, + 643, + 1, + 0, + 0, + 0, + 136, + 647, + 1, + 0, + 0, + 0, + 138, + 662, + 1, + 0, + 0, + 0, + 140, + 677, + 1, + 0, + 0, + 0, + 142, + 679, + 1, + 0, + 0, + 0, + 144, + 692, + 1, + 0, + 0, + 0, + 146, + 696, + 1, + 0, + 0, + 0, + 148, + 700, + 1, + 0, + 0, + 0, + 150, + 704, + 1, + 0, + 0, + 0, + 152, + 719, + 1, + 0, + 0, + 0, + 154, + 733, + 1, + 0, + 0, + 0, + 156, + 735, + 1, + 0, + 0, + 0, + 158, + 737, + 1, + 0, + 0, + 0, + 160, + 739, + 1, + 0, + 0, + 0, + 162, + 743, + 1, + 0, + 0, + 0, + 164, + 758, + 1, + 0, + 0, + 0, + 166, + 760, + 1, + 0, + 0, + 0, + 168, + 777, + 1, + 0, + 0, + 0, + 170, + 788, + 1, + 0, + 0, + 0, + 172, + 790, + 1, + 0, + 0, + 0, + 174, + 175, + 5, + 5, + 0, + 0, + 175, + 180, + 3, + 2, + 1, + 0, + 176, + 177, + 5, + 1, + 0, + 0, + 177, + 179, + 3, + 2, + 1, + 0, + 178, + 176, + 1, + 0, + 0, + 0, + 179, + 182, + 1, + 0, + 0, + 0, + 180, + 178, + 1, + 0, + 0, + 0, + 180, + 181, + 1, + 0, + 0, + 0, + 181, + 183, + 1, + 0, + 0, + 0, + 182, + 180, + 1, + 0, + 0, + 0, + 183, + 184, + 5, + 6, + 0, + 0, + 184, + 1, + 1, + 0, + 0, + 0, + 185, + 191, + 3, + 6, + 3, + 0, + 186, + 191, + 3, + 8, + 4, + 0, + 187, + 191, + 3, + 4, + 2, + 0, + 188, + 191, + 3, + 12, + 6, + 0, + 189, + 191, + 3, + 56, + 28, + 0, + 190, + 185, + 1, + 0, + 0, + 0, + 190, + 186, + 1, + 0, + 0, + 0, + 190, + 187, + 1, + 0, + 0, + 0, + 190, + 188, + 1, + 0, + 0, + 0, + 190, + 189, + 1, + 0, + 0, + 0, + 191, + 3, + 1, + 0, + 0, + 0, + 192, + 193, + 5, + 12, + 0, + 0, + 193, + 194, + 5, + 2, + 0, + 0, + 194, + 195, + 3, + 172, + 86, + 0, + 195, + 5, + 1, + 0, + 0, + 0, + 196, + 197, + 5, + 10, + 0, + 0, + 197, + 198, + 5, + 2, + 0, + 0, + 198, + 199, + 3, + 172, + 86, + 0, + 199, + 7, + 1, + 0, + 0, + 0, + 200, + 201, + 5, + 14, + 0, + 0, + 201, + 202, + 5, + 2, + 0, + 0, + 202, + 203, + 3, + 172, + 86, + 0, + 203, + 9, + 1, + 0, + 0, + 0, + 204, + 237, + 3, + 6, + 3, + 0, + 205, + 237, + 3, + 20, + 10, + 0, + 206, + 237, + 3, + 26, + 13, + 0, + 207, + 237, + 3, + 24, + 12, + 0, + 208, + 237, + 3, + 22, + 11, + 0, + 209, + 237, + 3, + 28, + 14, + 0, + 210, + 237, + 3, + 30, + 15, + 0, + 211, + 237, + 3, + 32, + 16, + 0, + 212, + 237, + 3, + 34, + 17, + 0, + 213, + 237, + 3, + 36, + 18, + 0, + 214, + 237, + 3, + 80, + 40, + 0, + 215, + 237, + 3, + 38, + 19, + 0, + 216, + 237, + 3, + 40, + 20, + 0, + 217, + 237, + 3, + 42, + 21, + 0, + 218, + 237, + 3, + 44, + 22, + 0, + 219, + 237, + 3, + 46, + 23, + 0, + 220, + 237, + 3, + 48, + 24, + 0, + 221, + 237, + 3, + 50, + 25, + 0, + 222, + 237, + 3, + 96, + 48, + 0, + 223, + 237, + 3, + 112, + 56, + 0, + 224, + 237, + 3, + 116, + 58, + 0, + 225, + 237, + 3, + 118, + 59, + 0, + 226, + 237, + 3, + 52, + 26, + 0, + 227, + 237, + 3, + 56, + 28, + 0, + 228, + 237, + 3, + 58, + 29, + 0, + 229, + 237, + 3, + 60, + 30, + 0, + 230, + 237, + 3, + 62, + 31, + 0, + 231, + 237, + 3, + 94, + 47, + 0, + 232, + 237, + 3, + 54, + 27, + 0, + 233, + 237, + 3, + 136, + 68, + 0, + 234, + 237, + 3, + 150, + 75, + 0, + 235, + 237, + 3, + 76, + 38, + 0, + 236, + 204, + 1, + 0, + 0, + 0, + 236, + 205, + 1, + 0, + 0, + 0, + 236, + 206, + 1, + 0, + 0, + 0, + 236, + 207, + 1, + 0, + 0, + 0, + 236, + 208, + 1, + 0, + 0, + 0, + 236, + 209, + 1, + 0, + 0, + 0, + 236, + 210, + 1, + 0, + 0, + 0, + 236, + 211, + 1, + 0, + 0, + 0, + 236, + 212, + 1, + 0, + 0, + 0, + 236, + 213, + 1, + 0, + 0, + 0, + 236, + 214, + 1, + 0, + 0, + 0, + 236, + 215, + 1, + 0, + 0, + 0, + 236, + 216, + 1, + 0, + 0, + 0, + 236, + 217, + 1, + 0, + 0, + 0, + 236, + 218, + 1, + 0, + 0, + 0, + 236, + 219, + 1, + 0, + 0, + 0, + 236, + 220, + 1, + 0, + 0, + 0, + 236, + 221, + 1, + 0, + 0, + 0, + 236, + 222, + 1, + 0, + 0, + 0, + 236, + 223, + 1, + 0, + 0, + 0, + 236, + 224, + 1, + 0, + 0, + 0, + 236, + 225, + 1, + 0, + 0, + 0, + 236, + 226, + 1, + 0, + 0, + 0, + 236, + 227, + 1, + 0, + 0, + 0, + 236, + 228, + 1, + 0, + 0, + 0, + 236, + 229, + 1, + 0, + 0, + 0, + 236, + 230, + 1, + 0, + 0, + 0, + 236, + 231, + 1, + 0, + 0, + 0, + 236, + 232, + 1, + 0, + 0, + 0, + 236, + 233, + 1, + 0, + 0, + 0, + 236, + 234, + 1, + 0, + 0, + 0, + 236, + 235, + 1, + 0, + 0, + 0, + 237, + 11, + 1, + 0, + 0, + 0, + 238, + 239, + 5, + 11, + 0, + 0, + 239, + 240, + 5, + 2, + 0, + 0, + 240, + 241, + 5, + 5, + 0, + 0, + 241, + 246, + 3, + 16, + 8, + 0, + 242, + 243, + 5, + 1, + 0, + 0, + 243, + 245, + 3, + 16, + 8, + 0, + 244, + 242, + 1, + 0, + 0, + 0, + 245, + 248, + 1, + 0, + 0, + 0, + 246, + 244, + 1, + 0, + 0, + 0, + 246, + 247, + 1, + 0, + 0, + 0, + 247, + 249, + 1, + 0, + 0, + 0, + 248, + 246, + 1, + 0, + 0, + 0, + 249, + 250, + 5, + 6, + 0, + 0, + 250, + 13, + 1, + 0, + 0, + 0, + 251, + 252, + 3, + 172, + 86, + 0, + 252, + 15, + 1, + 0, + 0, + 0, + 253, + 254, + 3, + 14, + 7, + 0, + 254, + 255, + 5, + 2, + 0, + 0, + 255, + 256, + 3, + 18, + 9, + 0, + 256, + 17, + 1, + 0, + 0, + 0, + 257, + 258, + 5, + 5, + 0, + 0, + 258, + 263, + 3, + 10, + 5, + 0, + 259, + 260, + 5, + 1, + 0, + 0, + 260, + 262, + 3, + 10, + 5, + 0, + 261, + 259, + 1, + 0, + 0, + 0, + 262, + 265, + 1, + 0, + 0, + 0, + 263, + 261, + 1, + 0, + 0, + 0, + 263, + 264, + 1, + 0, + 0, + 0, + 264, + 266, + 1, + 0, + 0, + 0, + 265, + 263, + 1, + 0, + 0, + 0, + 266, + 267, + 5, + 6, + 0, + 0, + 267, + 19, + 1, + 0, + 0, + 0, + 268, + 269, + 5, + 15, + 0, + 0, + 269, + 270, + 5, + 2, + 0, + 0, + 270, + 271, + 3, + 78, + 39, + 0, + 271, + 21, + 1, + 0, + 0, + 0, + 272, + 273, + 5, + 103, + 0, + 0, + 273, + 274, + 5, + 2, + 0, + 0, + 274, + 275, + 3, + 172, + 86, + 0, + 275, + 23, + 1, + 0, + 0, + 0, + 276, + 277, + 5, + 88, + 0, + 0, + 277, + 278, + 5, + 2, + 0, + 0, + 278, + 279, + 3, + 172, + 86, + 0, + 279, + 25, + 1, + 0, + 0, + 0, + 280, + 281, + 5, + 89, + 0, + 0, + 281, + 284, + 5, + 2, + 0, + 0, + 282, + 285, + 5, + 9, + 0, + 0, + 283, + 285, + 3, + 172, + 86, + 0, + 284, + 282, + 1, + 0, + 0, + 0, + 284, + 283, + 1, + 0, + 0, + 0, + 285, + 27, + 1, + 0, + 0, + 0, + 286, + 287, + 5, + 93, + 0, + 0, + 287, + 288, + 5, + 2, + 0, + 0, + 288, + 289, + 3, + 170, + 85, + 0, + 289, + 29, + 1, + 0, + 0, + 0, + 290, + 291, + 5, + 92, + 0, + 0, + 291, + 294, + 5, + 2, + 0, + 0, + 292, + 295, + 5, + 9, + 0, + 0, + 293, + 295, + 3, + 172, + 86, + 0, + 294, + 292, + 1, + 0, + 0, + 0, + 294, + 293, + 1, + 0, + 0, + 0, + 295, + 31, + 1, + 0, + 0, + 0, + 296, + 297, + 5, + 90, + 0, + 0, + 297, + 300, + 5, + 2, + 0, + 0, + 298, + 301, + 5, + 9, + 0, + 0, + 299, + 301, + 3, + 172, + 86, + 0, + 300, + 298, + 1, + 0, + 0, + 0, + 300, + 299, + 1, + 0, + 0, + 0, + 301, + 33, + 1, + 0, + 0, + 0, + 302, + 303, + 5, + 104, + 0, + 0, + 303, + 304, + 5, + 2, + 0, + 0, + 304, + 305, + 7, + 0, + 0, + 0, + 305, + 35, + 1, + 0, + 0, + 0, + 306, + 307, + 5, + 26, + 0, + 0, + 307, + 308, + 5, + 2, + 0, + 0, + 308, + 309, + 3, + 172, + 86, + 0, + 309, + 37, + 1, + 0, + 0, + 0, + 310, + 311, + 5, + 106, + 0, + 0, + 311, + 312, + 5, + 2, + 0, + 0, + 312, + 313, + 3, + 172, + 86, + 0, + 313, + 39, + 1, + 0, + 0, + 0, + 314, + 315, + 5, + 105, + 0, + 0, + 315, + 316, + 5, + 2, + 0, + 0, + 316, + 317, + 3, + 172, + 86, + 0, + 317, + 41, + 1, + 0, + 0, + 0, + 318, + 319, + 5, + 71, + 0, + 0, + 319, + 320, + 5, + 2, + 0, + 0, + 320, + 321, + 5, + 131, + 0, + 0, + 321, + 43, + 1, + 0, + 0, + 0, + 322, + 323, + 5, + 70, + 0, + 0, + 323, + 324, + 5, + 2, + 0, + 0, + 324, + 325, + 3, + 172, + 86, + 0, + 325, + 45, + 1, + 0, + 0, + 0, + 326, + 327, + 5, + 73, + 0, + 0, + 327, + 328, + 5, + 2, + 0, + 0, + 328, + 329, + 3, + 172, + 86, + 0, + 329, + 47, + 1, + 0, + 0, + 0, + 330, + 331, + 5, + 72, + 0, + 0, + 331, + 332, + 5, + 2, + 0, + 0, + 332, + 333, + 3, + 172, + 86, + 0, + 333, + 49, + 1, + 0, + 0, + 0, + 334, + 335, + 5, + 91, + 0, + 0, + 335, + 336, + 5, + 2, + 0, + 0, + 336, + 337, + 3, + 172, + 86, + 0, + 337, + 51, + 1, + 0, + 0, + 0, + 338, + 339, + 5, + 87, + 0, + 0, + 339, + 340, + 5, + 2, + 0, + 0, + 340, + 341, + 5, + 131, + 0, + 0, + 341, + 53, + 1, + 0, + 0, + 0, + 342, + 343, + 5, + 94, + 0, + 0, + 343, + 344, + 5, + 2, + 0, + 0, + 344, + 345, + 3, + 64, + 32, + 0, + 345, + 55, + 1, + 0, + 0, + 0, + 346, + 347, + 5, + 74, + 0, + 0, + 347, + 348, + 5, + 2, + 0, + 0, + 348, + 349, + 5, + 131, + 0, + 0, + 349, + 57, + 1, + 0, + 0, + 0, + 350, + 351, + 5, + 75, + 0, + 0, + 351, + 352, + 5, + 2, + 0, + 0, + 352, + 353, + 5, + 129, + 0, + 0, + 353, + 59, + 1, + 0, + 0, + 0, + 354, + 355, + 5, + 76, + 0, + 0, + 355, + 356, + 5, + 2, + 0, + 0, + 356, + 357, + 5, + 131, + 0, + 0, + 357, + 61, + 1, + 0, + 0, + 0, + 358, + 359, + 5, + 77, + 0, + 0, + 359, + 360, + 5, + 2, + 0, + 0, + 360, + 361, + 5, + 129, + 0, + 0, + 361, + 63, + 1, + 0, + 0, + 0, + 362, + 363, + 5, + 5, + 0, + 0, + 363, + 368, + 3, + 66, + 33, + 0, + 364, + 365, + 5, + 1, + 0, + 0, + 365, + 367, + 3, + 66, + 33, + 0, + 366, + 364, + 1, + 0, + 0, + 0, + 367, + 370, + 1, + 0, + 0, + 0, + 368, + 366, + 1, + 0, + 0, + 0, + 368, + 369, + 1, + 0, + 0, + 0, + 369, + 371, + 1, + 0, + 0, + 0, + 370, + 368, + 1, + 0, + 0, + 0, + 371, + 372, + 5, + 6, + 0, + 0, + 372, + 376, + 1, + 0, + 0, + 0, + 373, + 374, + 5, + 5, + 0, + 0, + 374, + 376, + 5, + 6, + 0, + 0, + 375, + 362, + 1, + 0, + 0, + 0, + 375, + 373, + 1, + 0, + 0, + 0, + 376, + 65, + 1, + 0, + 0, + 0, + 377, + 378, + 5, + 127, + 0, + 0, + 378, + 379, + 5, + 2, + 0, + 0, + 379, + 391, + 5, + 129, + 0, + 0, + 380, + 381, + 5, + 127, + 0, + 0, + 381, + 382, + 5, + 2, + 0, + 0, + 382, + 391, + 5, + 128, + 0, + 0, + 383, + 384, + 5, + 127, + 0, + 0, + 384, + 385, + 5, + 2, + 0, + 0, + 385, + 391, + 3, + 68, + 34, + 0, + 386, + 387, + 3, + 172, + 86, + 0, + 387, + 388, + 5, + 2, + 0, + 0, + 388, + 389, + 3, + 72, + 36, + 0, + 389, + 391, + 1, + 0, + 0, + 0, + 390, + 377, + 1, + 0, + 0, + 0, + 390, + 380, + 1, + 0, + 0, + 0, + 390, + 383, + 1, + 0, + 0, + 0, + 390, + 386, + 1, + 0, + 0, + 0, + 391, + 67, + 1, + 0, + 0, + 0, + 392, + 393, + 5, + 130, + 0, + 0, + 393, + 69, + 1, + 0, + 0, + 0, + 394, + 395, + 5, + 3, + 0, + 0, + 395, + 400, + 3, + 72, + 36, + 0, + 396, + 397, + 5, + 1, + 0, + 0, + 397, + 399, + 3, + 72, + 36, + 0, + 398, + 396, + 1, + 0, + 0, + 0, + 399, + 402, + 1, + 0, + 0, + 0, + 400, + 398, + 1, + 0, + 0, + 0, + 400, + 401, + 1, + 0, + 0, + 0, + 401, + 403, + 1, + 0, + 0, + 0, + 402, + 400, + 1, + 0, + 0, + 0, + 403, + 404, + 5, + 4, + 0, + 0, + 404, + 408, + 1, + 0, + 0, + 0, + 405, + 406, + 5, + 3, + 0, + 0, + 406, + 408, + 5, + 4, + 0, + 0, + 407, + 394, + 1, + 0, + 0, + 0, + 407, + 405, + 1, + 0, + 0, + 0, + 408, + 71, + 1, + 0, + 0, + 0, + 409, + 414, + 3, + 66, + 33, + 0, + 410, + 414, + 3, + 70, + 35, + 0, + 411, + 414, + 3, + 64, + 32, + 0, + 412, + 414, + 3, + 74, + 37, + 0, + 413, + 409, + 1, + 0, + 0, + 0, + 413, + 410, + 1, + 0, + 0, + 0, + 413, + 411, + 1, + 0, + 0, + 0, + 413, + 412, + 1, + 0, + 0, + 0, + 414, + 73, + 1, + 0, + 0, + 0, + 415, + 421, + 5, + 132, + 0, + 0, + 416, + 421, + 5, + 131, + 0, + 0, + 417, + 421, + 7, + 0, + 0, + 0, + 418, + 421, + 5, + 9, + 0, + 0, + 419, + 421, + 3, + 172, + 86, + 0, + 420, + 415, + 1, + 0, + 0, + 0, + 420, + 416, + 1, + 0, + 0, + 0, + 420, + 417, + 1, + 0, + 0, + 0, + 420, + 418, + 1, + 0, + 0, + 0, + 420, + 419, + 1, + 0, + 0, + 0, + 421, + 75, + 1, + 0, + 0, + 0, + 422, + 423, + 5, + 95, + 0, + 0, + 423, + 424, + 5, + 2, + 0, + 0, + 424, + 425, + 3, + 64, + 32, + 0, + 425, + 77, + 1, + 0, + 0, + 0, + 426, + 427, + 7, + 1, + 0, + 0, + 427, + 79, + 1, + 0, + 0, + 0, + 428, + 429, + 5, + 24, + 0, + 0, + 429, + 430, + 5, + 2, + 0, + 0, + 430, + 431, + 5, + 3, + 0, + 0, + 431, + 436, + 3, + 82, + 41, + 0, + 432, + 433, + 5, + 1, + 0, + 0, + 433, + 435, + 3, + 82, + 41, + 0, + 434, + 432, + 1, + 0, + 0, + 0, + 435, + 438, + 1, + 0, + 0, + 0, + 436, + 434, + 1, + 0, + 0, + 0, + 436, + 437, + 1, + 0, + 0, + 0, + 437, + 439, + 1, + 0, + 0, + 0, + 438, + 436, + 1, + 0, + 0, + 0, + 439, + 440, + 5, + 4, + 0, + 0, + 440, + 81, + 1, + 0, + 0, + 0, + 441, + 442, + 5, + 5, + 0, + 0, + 442, + 445, + 3, + 84, + 42, + 0, + 443, + 444, + 5, + 1, + 0, + 0, + 444, + 446, + 3, + 84, + 42, + 0, + 445, + 443, + 1, + 0, + 0, + 0, + 446, + 447, + 1, + 0, + 0, + 0, + 447, + 445, + 1, + 0, + 0, + 0, + 447, + 448, + 1, + 0, + 0, + 0, + 448, + 449, + 1, + 0, + 0, + 0, + 449, + 450, + 5, + 6, + 0, + 0, + 450, + 463, + 1, + 0, + 0, + 0, + 451, + 452, + 5, + 5, + 0, + 0, + 452, + 457, + 3, + 86, + 43, + 0, + 453, + 454, + 5, + 1, + 0, + 0, + 454, + 456, + 3, + 86, + 43, + 0, + 455, + 453, + 1, + 0, + 0, + 0, + 456, + 459, + 1, + 0, + 0, + 0, + 457, + 455, + 1, + 0, + 0, + 0, + 457, + 458, + 1, + 0, + 0, + 0, + 458, + 460, + 1, + 0, + 0, + 0, + 459, + 457, + 1, + 0, + 0, + 0, + 460, + 461, + 5, + 6, + 0, + 0, + 461, + 463, + 1, + 0, + 0, + 0, + 462, + 441, + 1, + 0, + 0, + 0, + 462, + 451, + 1, + 0, + 0, + 0, + 463, + 83, + 1, + 0, + 0, + 0, + 464, + 468, + 3, + 90, + 45, + 0, + 465, + 468, + 3, + 92, + 46, + 0, + 466, + 468, + 3, + 22, + 11, + 0, + 467, + 464, + 1, + 0, + 0, + 0, + 467, + 465, + 1, + 0, + 0, + 0, + 467, + 466, + 1, + 0, + 0, + 0, + 468, + 85, + 1, + 0, + 0, + 0, + 469, + 472, + 3, + 88, + 44, + 0, + 470, + 472, + 3, + 22, + 11, + 0, + 471, + 469, + 1, + 0, + 0, + 0, + 471, + 470, + 1, + 0, + 0, + 0, + 472, + 87, + 1, + 0, + 0, + 0, + 473, + 474, + 3, + 158, + 79, + 0, + 474, + 487, + 5, + 2, + 0, + 0, + 475, + 488, + 3, + 82, + 41, + 0, + 476, + 477, + 5, + 3, + 0, + 0, + 477, + 482, + 3, + 82, + 41, + 0, + 478, + 479, + 5, + 1, + 0, + 0, + 479, + 481, + 3, + 82, + 41, + 0, + 480, + 478, + 1, + 0, + 0, + 0, + 481, + 484, + 1, + 0, + 0, + 0, + 482, + 480, + 1, + 0, + 0, + 0, + 482, + 483, + 1, + 0, + 0, + 0, + 483, + 485, + 1, + 0, + 0, + 0, + 484, + 482, + 1, + 0, + 0, + 0, + 485, + 486, + 5, + 4, + 0, + 0, + 486, + 488, + 1, + 0, + 0, + 0, + 487, + 475, + 1, + 0, + 0, + 0, + 487, + 476, + 1, + 0, + 0, + 0, + 488, + 89, + 1, + 0, + 0, + 0, + 489, + 490, + 5, + 25, + 0, + 0, + 490, + 491, + 5, + 2, + 0, + 0, + 491, + 492, + 3, + 172, + 86, + 0, + 492, + 91, + 1, + 0, + 0, + 0, + 493, + 494, + 3, + 156, + 78, + 0, + 494, + 495, + 5, + 2, + 0, + 0, + 495, + 496, + 3, + 170, + 85, + 0, + 496, + 93, + 1, + 0, + 0, + 0, + 497, + 498, + 5, + 27, + 0, + 0, + 498, + 499, + 5, + 2, + 0, + 0, + 499, + 500, + 5, + 3, + 0, + 0, + 500, + 505, + 3, + 0, + 0, + 0, + 501, + 502, + 5, + 1, + 0, + 0, + 502, + 504, + 3, + 0, + 0, + 0, + 503, + 501, + 1, + 0, + 0, + 0, + 504, + 507, + 1, + 0, + 0, + 0, + 505, + 503, + 1, + 0, + 0, + 0, + 505, + 506, + 1, + 0, + 0, + 0, + 506, + 508, + 1, + 0, + 0, + 0, + 507, + 505, + 1, + 0, + 0, + 0, + 508, + 509, + 5, + 4, + 0, + 0, + 509, + 95, + 1, + 0, + 0, + 0, + 510, + 511, + 5, + 84, + 0, + 0, + 511, + 512, + 5, + 2, + 0, + 0, + 512, + 513, + 5, + 5, + 0, + 0, + 513, + 518, + 3, + 98, + 49, + 0, + 514, + 515, + 5, + 1, + 0, + 0, + 515, + 517, + 3, + 98, + 49, + 0, + 516, + 514, + 1, + 0, + 0, + 0, + 517, + 520, + 1, + 0, + 0, + 0, + 518, + 516, + 1, + 0, + 0, + 0, + 518, + 519, + 1, + 0, + 0, + 0, + 519, + 521, + 1, + 0, + 0, + 0, + 520, + 518, + 1, + 0, + 0, + 0, + 521, + 522, + 5, + 6, + 0, + 0, + 522, + 97, + 1, + 0, + 0, + 0, + 523, + 528, + 3, + 100, + 50, + 0, + 524, + 528, + 3, + 4, + 2, + 0, + 525, + 528, + 3, + 12, + 6, + 0, + 526, + 528, + 3, + 6, + 3, + 0, + 527, + 523, + 1, + 0, + 0, + 0, + 527, + 524, + 1, + 0, + 0, + 0, + 527, + 525, + 1, + 0, + 0, + 0, + 527, + 526, + 1, + 0, + 0, + 0, + 528, + 99, + 1, + 0, + 0, + 0, + 529, + 530, + 5, + 78, + 0, + 0, + 530, + 531, + 5, + 2, + 0, + 0, + 531, + 532, + 5, + 5, + 0, + 0, + 532, + 537, + 3, + 102, + 51, + 0, + 533, + 534, + 5, + 1, + 0, + 0, + 534, + 536, + 3, + 102, + 51, + 0, + 535, + 533, + 1, + 0, + 0, + 0, + 536, + 539, + 1, + 0, + 0, + 0, + 537, + 535, + 1, + 0, + 0, + 0, + 537, + 538, + 1, + 0, + 0, + 0, + 538, + 540, + 1, + 0, + 0, + 0, + 539, + 537, + 1, + 0, + 0, + 0, + 540, + 541, + 5, + 6, + 0, + 0, + 541, + 101, + 1, + 0, + 0, + 0, + 542, + 545, + 3, + 104, + 52, + 0, + 543, + 545, + 3, + 108, + 54, + 0, + 544, + 542, + 1, + 0, + 0, + 0, + 544, + 543, + 1, + 0, + 0, + 0, + 545, + 103, + 1, + 0, + 0, + 0, + 546, + 547, + 5, + 79, + 0, + 0, + 547, + 548, + 5, + 2, + 0, + 0, + 548, + 549, + 3, + 106, + 53, + 0, + 549, + 105, + 1, + 0, + 0, + 0, + 550, + 551, + 7, + 2, + 0, + 0, + 551, + 107, + 1, + 0, + 0, + 0, + 552, + 553, + 5, + 82, + 0, + 0, + 553, + 554, + 5, + 2, + 0, + 0, + 554, + 555, + 3, + 110, + 55, + 0, + 555, + 109, + 1, + 0, + 0, + 0, + 556, + 557, + 5, + 83, + 0, + 0, + 557, + 111, + 1, + 0, + 0, + 0, + 558, + 559, + 5, + 85, + 0, + 0, + 559, + 560, + 5, + 2, + 0, + 0, + 560, + 561, + 5, + 5, + 0, + 0, + 561, + 566, + 3, + 114, + 57, + 0, + 562, + 563, + 5, + 1, + 0, + 0, + 563, + 565, + 3, + 114, + 57, + 0, + 564, + 562, + 1, + 0, + 0, + 0, + 565, + 568, + 1, + 0, + 0, + 0, + 566, + 564, + 1, + 0, + 0, + 0, + 566, + 567, + 1, + 0, + 0, + 0, + 567, + 569, + 1, + 0, + 0, + 0, + 568, + 566, + 1, + 0, + 0, + 0, + 569, + 570, + 5, + 6, + 0, + 0, + 570, + 113, + 1, + 0, + 0, + 0, + 571, + 575, + 3, + 4, + 2, + 0, + 572, + 575, + 3, + 12, + 6, + 0, + 573, + 575, + 3, + 6, + 3, + 0, + 574, + 571, + 1, + 0, + 0, + 0, + 574, + 572, + 1, + 0, + 0, + 0, + 574, + 573, + 1, + 0, + 0, + 0, + 575, + 115, + 1, + 0, + 0, + 0, + 576, + 577, + 5, + 86, + 0, + 0, + 577, + 578, + 5, + 2, + 0, + 0, + 578, + 579, + 3, + 64, + 32, + 0, + 579, + 117, + 1, + 0, + 0, + 0, + 580, + 581, + 5, + 96, + 0, + 0, + 581, + 582, + 5, + 2, + 0, + 0, + 582, + 583, + 5, + 5, + 0, + 0, + 583, + 588, + 3, + 120, + 60, + 0, + 584, + 585, + 5, + 1, + 0, + 0, + 585, + 587, + 3, + 120, + 60, + 0, + 586, + 584, + 1, + 0, + 0, + 0, + 587, + 590, + 1, + 0, + 0, + 0, + 588, + 586, + 1, + 0, + 0, + 0, + 588, + 589, + 1, + 0, + 0, + 0, + 589, + 591, + 1, + 0, + 0, + 0, + 590, + 588, + 1, + 0, + 0, + 0, + 591, + 592, + 5, + 6, + 0, + 0, + 592, + 119, + 1, + 0, + 0, + 0, + 593, + 597, + 3, + 24, + 12, + 0, + 594, + 597, + 3, + 54, + 27, + 0, + 595, + 597, + 3, + 122, + 61, + 0, + 596, + 593, + 1, + 0, + 0, + 0, + 596, + 594, + 1, + 0, + 0, + 0, + 596, + 595, + 1, + 0, + 0, + 0, + 597, + 121, + 1, + 0, + 0, + 0, + 598, + 599, + 5, + 97, + 0, + 0, + 599, + 600, + 5, + 2, + 0, + 0, + 600, + 601, + 5, + 5, + 0, + 0, + 601, + 606, + 3, + 124, + 62, + 0, + 602, + 603, + 5, + 1, + 0, + 0, + 603, + 605, + 3, + 124, + 62, + 0, + 604, + 602, + 1, + 0, + 0, + 0, + 605, + 608, + 1, + 0, + 0, + 0, + 606, + 604, + 1, + 0, + 0, + 0, + 606, + 607, + 1, + 0, + 0, + 0, + 607, + 609, + 1, + 0, + 0, + 0, + 608, + 606, + 1, + 0, + 0, + 0, + 609, + 610, + 5, + 6, + 0, + 0, + 610, + 123, + 1, + 0, + 0, + 0, + 611, + 617, + 3, + 126, + 63, + 0, + 612, + 617, + 3, + 128, + 64, + 0, + 613, + 617, + 3, + 130, + 65, + 0, + 614, + 617, + 3, + 132, + 66, + 0, + 615, + 617, + 3, + 134, + 67, + 0, + 616, + 611, + 1, + 0, + 0, + 0, + 616, + 612, + 1, + 0, + 0, + 0, + 616, + 613, + 1, + 0, + 0, + 0, + 616, + 614, + 1, + 0, + 0, + 0, + 616, + 615, + 1, + 0, + 0, + 0, + 617, + 125, + 1, + 0, + 0, + 0, + 618, + 619, + 5, + 98, + 0, + 0, + 619, + 620, + 5, + 2, + 0, + 0, + 620, + 621, + 3, + 172, + 86, + 0, + 621, + 127, + 1, + 0, + 0, + 0, + 622, + 623, + 5, + 99, + 0, + 0, + 623, + 624, + 5, + 2, + 0, + 0, + 624, + 625, + 3, + 172, + 86, + 0, + 625, + 129, + 1, + 0, + 0, + 0, + 626, + 627, + 5, + 100, + 0, + 0, + 627, + 628, + 5, + 2, + 0, + 0, + 628, + 629, + 5, + 3, + 0, + 0, + 629, + 634, + 3, + 172, + 86, + 0, + 630, + 631, + 5, + 1, + 0, + 0, + 631, + 633, + 3, + 172, + 86, + 0, + 632, + 630, + 1, + 0, + 0, + 0, + 633, + 636, + 1, + 0, + 0, + 0, + 634, + 632, + 1, + 0, + 0, + 0, + 634, + 635, + 1, + 0, + 0, + 0, + 635, + 637, + 1, + 0, + 0, + 0, + 636, + 634, + 1, + 0, + 0, + 0, + 637, + 638, + 5, + 4, + 0, + 0, + 638, + 131, + 1, + 0, + 0, + 0, + 639, + 640, + 5, + 101, + 0, + 0, + 640, + 641, + 5, + 2, + 0, + 0, + 641, + 642, + 5, + 131, + 0, + 0, + 642, + 133, + 1, + 0, + 0, + 0, + 643, + 644, + 5, + 102, + 0, + 0, + 644, + 645, + 5, + 2, + 0, + 0, + 645, + 646, + 5, + 129, + 0, + 0, + 646, + 135, + 1, + 0, + 0, + 0, + 647, + 648, + 5, + 107, + 0, + 0, + 648, + 649, + 5, + 2, + 0, + 0, + 649, + 658, + 5, + 3, + 0, + 0, + 650, + 655, + 3, + 138, + 69, + 0, + 651, + 652, + 5, + 1, + 0, + 0, + 652, + 654, + 3, + 138, + 69, + 0, + 653, + 651, + 1, + 0, + 0, + 0, + 654, + 657, + 1, + 0, + 0, + 0, + 655, + 653, + 1, + 0, + 0, + 0, + 655, + 656, + 1, + 0, + 0, + 0, + 656, + 659, + 1, + 0, + 0, + 0, + 657, + 655, + 1, + 0, + 0, + 0, + 658, + 650, + 1, + 0, + 0, + 0, + 658, + 659, + 1, + 0, + 0, + 0, + 659, + 660, + 1, + 0, + 0, + 0, + 660, + 661, + 5, + 4, + 0, + 0, + 661, + 137, + 1, + 0, + 0, + 0, + 662, + 663, + 5, + 5, + 0, + 0, + 663, + 668, + 3, + 140, + 70, + 0, + 664, + 665, + 5, + 1, + 0, + 0, + 665, + 667, + 3, + 140, + 70, + 0, + 666, + 664, + 1, + 0, + 0, + 0, + 667, + 670, + 1, + 0, + 0, + 0, + 668, + 666, + 1, + 0, + 0, + 0, + 668, + 669, + 1, + 0, + 0, + 0, + 669, + 671, + 1, + 0, + 0, + 0, + 670, + 668, + 1, + 0, + 0, + 0, + 671, + 672, + 5, + 6, + 0, + 0, + 672, + 139, + 1, + 0, + 0, + 0, + 673, + 678, + 3, + 142, + 71, + 0, + 674, + 678, + 3, + 144, + 72, + 0, + 675, + 678, + 3, + 146, + 73, + 0, + 676, + 678, + 3, + 148, + 74, + 0, + 677, + 673, + 1, + 0, + 0, + 0, + 677, + 674, + 1, + 0, + 0, + 0, + 677, + 675, + 1, + 0, + 0, + 0, + 677, + 676, + 1, + 0, + 0, + 0, + 678, + 141, + 1, + 0, + 0, + 0, + 679, + 680, + 5, + 108, + 0, + 0, + 680, + 681, + 5, + 2, + 0, + 0, + 681, + 682, + 5, + 3, + 0, + 0, + 682, + 687, + 3, + 162, + 81, + 0, + 683, + 684, + 5, + 1, + 0, + 0, + 684, + 686, + 3, + 162, + 81, + 0, + 685, + 683, + 1, + 0, + 0, + 0, + 686, + 689, + 1, + 0, + 0, + 0, + 687, + 685, + 1, + 0, + 0, + 0, + 687, + 688, + 1, + 0, + 0, + 0, + 688, + 690, + 1, + 0, + 0, + 0, + 689, + 687, + 1, + 0, + 0, + 0, + 690, + 691, + 5, + 4, + 0, + 0, + 691, + 143, + 1, + 0, + 0, + 0, + 692, + 693, + 5, + 109, + 0, + 0, + 693, + 694, + 5, + 2, + 0, + 0, + 694, + 695, + 5, + 131, + 0, + 0, + 695, + 145, + 1, + 0, + 0, + 0, + 696, + 697, + 5, + 110, + 0, + 0, + 697, + 698, + 5, + 2, + 0, + 0, + 698, + 699, + 5, + 131, + 0, + 0, + 699, + 147, + 1, + 0, + 0, + 0, + 700, + 701, + 5, + 111, + 0, + 0, + 701, + 702, + 5, + 2, + 0, + 0, + 702, + 703, + 7, + 3, + 0, + 0, + 703, + 149, + 1, + 0, + 0, + 0, + 704, + 705, + 5, + 112, + 0, + 0, + 705, + 706, + 5, + 2, + 0, + 0, + 706, + 715, + 5, + 3, + 0, + 0, + 707, + 712, + 3, + 152, + 76, + 0, + 708, + 709, + 5, + 1, + 0, + 0, + 709, + 711, + 3, + 152, + 76, + 0, + 710, + 708, + 1, + 0, + 0, + 0, + 711, + 714, + 1, + 0, + 0, + 0, + 712, + 710, + 1, + 0, + 0, + 0, + 712, + 713, + 1, + 0, + 0, + 0, + 713, + 716, + 1, + 0, + 0, + 0, + 714, + 712, + 1, + 0, + 0, + 0, + 715, + 707, + 1, + 0, + 0, + 0, + 715, + 716, + 1, + 0, + 0, + 0, + 716, + 717, + 1, + 0, + 0, + 0, + 717, + 718, + 5, + 4, + 0, + 0, + 718, + 151, + 1, + 0, + 0, + 0, + 719, + 720, + 5, + 5, + 0, + 0, + 720, + 725, + 3, + 154, + 77, + 0, + 721, + 722, + 5, + 1, + 0, + 0, + 722, + 724, + 3, + 154, + 77, + 0, + 723, + 721, + 1, + 0, + 0, + 0, + 724, + 727, + 1, + 0, + 0, + 0, + 725, + 723, + 1, + 0, + 0, + 0, + 725, + 726, + 1, + 0, + 0, + 0, + 726, + 728, + 1, + 0, + 0, + 0, + 727, + 725, + 1, + 0, + 0, + 0, + 728, + 729, + 5, + 6, + 0, + 0, + 729, + 153, + 1, + 0, + 0, + 0, + 730, + 734, + 3, + 142, + 71, + 0, + 731, + 734, + 3, + 30, + 15, + 0, + 732, + 734, + 3, + 22, + 11, + 0, + 733, + 730, + 1, + 0, + 0, + 0, + 733, + 731, + 1, + 0, + 0, + 0, + 733, + 732, + 1, + 0, + 0, + 0, + 734, + 155, + 1, + 0, + 0, + 0, + 735, + 736, + 7, + 4, + 0, + 0, + 736, + 157, + 1, + 0, + 0, + 0, + 737, + 738, + 7, + 5, + 0, + 0, + 738, + 159, + 1, + 0, + 0, + 0, + 739, + 740, + 7, + 6, + 0, + 0, + 740, + 161, + 1, + 0, + 0, + 0, + 741, + 744, + 3, + 160, + 80, + 0, + 742, + 744, + 3, + 172, + 86, + 0, + 743, + 741, + 1, + 0, + 0, + 0, + 743, + 742, + 1, + 0, + 0, + 0, + 744, + 163, + 1, + 0, + 0, + 0, + 745, + 746, + 5, + 5, + 0, + 0, + 746, + 751, + 3, + 166, + 83, + 0, + 747, + 748, + 5, + 1, + 0, + 0, + 748, + 750, + 3, + 166, + 83, + 0, + 749, + 747, + 1, + 0, + 0, + 0, + 750, + 753, + 1, + 0, + 0, + 0, + 751, + 749, + 1, + 0, + 0, + 0, + 751, + 752, + 1, + 0, + 0, + 0, + 752, + 754, + 1, + 0, + 0, + 0, + 753, + 751, + 1, + 0, + 0, + 0, + 754, + 755, + 5, + 6, + 0, + 0, + 755, + 759, + 1, + 0, + 0, + 0, + 756, + 757, + 5, + 5, + 0, + 0, + 757, + 759, + 5, + 6, + 0, + 0, + 758, + 745, + 1, + 0, + 0, + 0, + 758, + 756, + 1, + 0, + 0, + 0, + 759, + 165, + 1, + 0, + 0, + 0, + 760, + 761, + 3, + 172, + 86, + 0, + 761, + 762, + 5, + 2, + 0, + 0, + 762, + 763, + 3, + 170, + 85, + 0, + 763, + 167, + 1, + 0, + 0, + 0, + 764, + 765, + 5, + 3, + 0, + 0, + 765, + 770, + 3, + 170, + 85, + 0, + 766, + 767, + 5, + 1, + 0, + 0, + 767, + 769, + 3, + 170, + 85, + 0, + 768, + 766, + 1, + 0, + 0, + 0, + 769, + 772, + 1, + 0, + 0, + 0, + 770, + 768, + 1, + 0, + 0, + 0, + 770, + 771, + 1, + 0, + 0, + 0, + 771, + 773, + 1, + 0, + 0, + 0, + 772, + 770, + 1, + 0, + 0, + 0, + 773, + 774, + 5, + 4, + 0, + 0, + 774, + 778, + 1, + 0, + 0, + 0, + 775, + 776, + 5, + 3, + 0, + 0, + 776, + 778, + 5, + 4, + 0, + 0, + 777, + 764, + 1, + 0, + 0, + 0, + 777, + 775, + 1, + 0, + 0, + 0, + 778, + 169, + 1, + 0, + 0, + 0, + 779, + 789, + 5, + 132, + 0, + 0, + 780, + 789, + 5, + 131, + 0, + 0, + 781, + 789, + 5, + 7, + 0, + 0, + 782, + 789, + 5, + 8, + 0, + 0, + 783, + 789, + 5, + 9, + 0, + 0, + 784, + 789, + 3, + 166, + 83, + 0, + 785, + 789, + 3, + 168, + 84, + 0, + 786, + 789, + 3, + 164, + 82, + 0, + 787, + 789, + 3, + 172, + 86, + 0, + 788, + 779, + 1, + 0, + 0, + 0, + 788, + 780, + 1, + 0, + 0, + 0, + 788, + 781, + 1, + 0, + 0, + 0, + 788, + 782, + 1, + 0, + 0, + 0, + 788, + 783, + 1, + 0, + 0, + 0, + 788, + 784, + 1, + 0, + 0, + 0, + 788, + 785, + 1, + 0, + 0, + 0, + 788, + 786, + 1, + 0, + 0, + 0, + 788, + 787, + 1, + 0, + 0, + 0, + 789, + 171, + 1, + 0, + 0, + 0, + 790, + 791, + 7, + 7, + 0, + 0, + 791, + 173, + 1, + 0, + 0, + 0, + 50, + 180, + 190, + 236, + 246, + 263, + 284, + 294, + 300, + 368, + 375, + 390, + 400, + 407, + 413, + 420, + 436, + 447, + 457, + 462, + 467, + 471, + 482, + 487, + 505, + 518, + 527, + 537, + 544, + 566, + 574, + 588, + 596, + 606, + 616, + 634, + 655, + 658, + 668, + 677, + 687, + 712, + 715, + 725, + 733, + 743, + 751, + 758, + 770, + 777, + 788, + ] + + +class ASLParser(Parser): + + grammarFileName = "ASLParser.g4" + + atn = ATNDeserializer().deserialize(serializedATN()) + + decisionsToDFA = [DFA(ds, i) for i, ds in enumerate(atn.decisionToState)] + + sharedContextCache = PredictionContextCache() + + literalNames = [ + "", + "','", + "':'", + "'['", + "']'", + "'{'", + "'}'", + "'true'", + "'false'", + "'null'", + "'\"Comment\"'", + "'\"States\"'", + "'\"StartAt\"'", + "'\"NextState\"'", + "'\"Version\"'", + "'\"Type\"'", + "'\"Task\"'", + "'\"Choice\"'", + "'\"Fail\"'", + "'\"Succeed\"'", + "'\"Pass\"'", + "'\"Wait\"'", + "'\"Parallel\"'", + "'\"Map\"'", + "'\"Choices\"'", + "'\"Variable\"'", + "'\"Default\"'", + "'\"Branches\"'", + "'\"And\"'", + "'\"BooleanEquals\"'", + "'\"BooleanEqualsPath\"'", + "'\"IsBoolean\"'", + "'\"IsNull\"'", + "'\"IsNumeric\"'", + "'\"IsPresent\"'", + "'\"IsString\"'", + "'\"IsTimestamp\"'", + "'\"Not\"'", + "'\"NumericEquals\"'", + "'\"NumericEqualsPath\"'", + "'\"NumericGreaterThan\"'", + "'\"NumericGreaterThanPath\"'", + "'\"NumericGreaterThanEquals\"'", + "'\"NumericGreaterThanEqualsPath\"'", + "'\"NumericLessThan\"'", + "'\"NumericLessThanPath\"'", + "'\"NumericLessThanEquals\"'", + "'\"NumericLessThanEqualsPath\"'", + "'\"Or\"'", + "'\"StringEquals\"'", + "'\"StringEqualsPath\"'", + "'\"StringGreaterThan\"'", + "'\"StringGreaterThanPath\"'", + "'\"StringGreaterThanEquals\"'", + "'\"StringGreaterThanEqualsPath\"'", + "'\"StringLessThan\"'", + "'\"StringLessThanPath\"'", + "'\"StringLessThanEquals\"'", + "'\"StringLessThanEqualsPath\"'", + "'\"StringMatches\"'", + "'\"TimestampEquals\"'", + "'\"TimestampEqualsPath\"'", + "'\"TimestampGreaterThan\"'", + "'\"TimestampGreaterThanPath\"'", + "'\"TimestampGreaterThanEquals\"'", + "'\"TimestampGreaterThanEqualsPath\"'", + "'\"TimestampLessThan\"'", + "'\"TimestampLessThanPath\"'", + "'\"TimestampLessThanEquals\"'", + "'\"TimestampLessThanEqualsPath\"'", + "'\"SecondsPath\"'", + "'\"Seconds\"'", + "'\"TimestampPath\"'", + "'\"Timestamp\"'", + "'\"TimeoutSeconds\"'", + "'\"TimeoutSecondsPath\"'", + "'\"HeartbeatSeconds\"'", + "'\"HeartbeatSecondsPath\"'", + "'\"ProcessorConfig\"'", + "'\"Mode\"'", + "'\"INLINE\"'", + "'\"DISTRIBUTED\"'", + "'\"ExecutionType\"'", + "'\"STANDARD\"'", + "'\"ItemProcessor\"'", + "'\"Iterator\"'", + "'\"ItemSelector\"'", + "'\"MaxConcurrency\"'", + "'\"Resource\"'", + "'\"InputPath\"'", + "'\"OutputPath\"'", + "'\"ItemsPath\"'", + "'\"ResultPath\"'", + "'\"Result\"'", + "'\"Parameters\"'", + "'\"ResultSelector\"'", + "'\"ItemReader\"'", + "'\"ReaderConfig\"'", + "'\"InputType\"'", + "'\"CSVHeaderLocation\"'", + "'\"CSVHeaders\"'", + "'\"MaxItems\"'", + "'\"MaxItemsPath\"'", + "'\"Next\"'", + "'\"End\"'", + "'\"Cause\"'", + "'\"Error\"'", + "'\"Retry\"'", + "'\"ErrorEquals\"'", + "'\"IntervalSeconds\"'", + "'\"MaxAttempts\"'", + "'\"BackoffRate\"'", + "'\"Catch\"'", + "'\"States.ALL\"'", + "'\"States.HeartbeatTimeout\"'", + "'\"States.Timeout\"'", + "'\"States.TaskFailed\"'", + "'\"States.Permissions\"'", + "'\"States.ResultPathMatchFailure\"'", + "'\"States.ParameterPathFailure\"'", + "'\"States.BranchFailed\"'", + "'\"States.NoChoiceMatched\"'", + "'\"States.IntrinsicFailure\"'", + "'\"States.ExceedToleratedFailureThreshold\"'", + "'\"States.ItemReaderFailed\"'", + "'\"States.ResultWriterFailed\"'", + "'\"States.Runtime\"'", + ] + + symbolicNames = [ + "", + "COMMA", + "COLON", + "LBRACK", + "RBRACK", + "LBRACE", + "RBRACE", + "TRUE", + "FALSE", + "NULL", + "COMMENT", + "STATES", + "STARTAT", + "NEXTSTATE", + "VERSION", + "TYPE", + "TASK", + "CHOICE", + "FAIL", + "SUCCEED", + "PASS", + "WAIT", + "PARALLEL", + "MAP", + "CHOICES", + "VARIABLE", + "DEFAULT", + "BRANCHES", + "AND", + "BOOLEANEQUALS", + "BOOLEANQUALSPATH", + "ISBOOLEAN", + "ISNULL", + "ISNUMERIC", + "ISPRESENT", + "ISSTRING", + "ISTIMESTAMP", + "NOT", + "NUMERICEQUALS", + "NUMERICEQUALSPATH", + "NUMERICGREATERTHAN", + "NUMERICGREATERTHANPATH", + "NUMERICGREATERTHANEQUALS", + "NUMERICGREATERTHANEQUALSPATH", + "NUMERICLESSTHAN", + "NUMERICLESSTHANPATH", + "NUMERICLESSTHANEQUALS", + "NUMERICLESSTHANEQUALSPATH", + "OR", + "STRINGEQUALS", + "STRINGEQUALSPATH", + "STRINGGREATERTHAN", + "STRINGGREATERTHANPATH", + "STRINGGREATERTHANEQUALS", + "STRINGGREATERTHANEQUALSPATH", + "STRINGLESSTHAN", + "STRINGLESSTHANPATH", + "STRINGLESSTHANEQUALS", + "STRINGLESSTHANEQUALSPATH", + "STRINGMATCHES", + "TIMESTAMPEQUALS", + "TIMESTAMPEQUALSPATH", + "TIMESTAMPGREATERTHAN", + "TIMESTAMPGREATERTHANPATH", + "TIMESTAMPGREATERTHANEQUALS", + "TIMESTAMPGREATERTHANEQUALSPATH", + "TIMESTAMPLESSTHAN", + "TIMESTAMPLESSTHANPATH", + "TIMESTAMPLESSTHANEQUALS", + "TIMESTAMPLESSTHANEQUALSPATH", + "SECONDSPATH", + "SECONDS", + "TIMESTAMPPATH", + "TIMESTAMP", + "TIMEOUTSECONDS", + "TIMEOUTSECONDSPATH", + "HEARTBEATSECONDS", + "HEARTBEATSECONDSPATH", + "PROCESSORCONFIG", + "MODE", + "INLINE", + "DISTRIBUTED", + "EXECUTIONTYPE", + "STANDARD", + "ITEMPROCESSOR", + "ITERATOR", + "ITEMSELECTOR", + "MAXCONCURRENCY", + "RESOURCE", + "INPUTPATH", + "OUTPUTPATH", + "ITEMSPATH", + "RESULTPATH", + "RESULT", + "PARAMETERS", + "RESULTSELECTOR", + "ITEMREADER", + "READERCONFIG", + "INPUTTYPE", + "CSVHEADERLOCATION", + "CSVHEADERS", + "MAXITEMS", + "MAXITEMSPATH", + "NEXT", + "END", + "CAUSE", + "ERROR", + "RETRY", + "ERROREQUALS", + "INTERVALSECONDS", + "MAXATTEMPTS", + "BACKOFFRATE", + "CATCH", + "ERRORNAMEStatesALL", + "ERRORNAMEStatesHeartbeatTimeout", + "ERRORNAMEStatesTimeout", + "ERRORNAMEStatesTaskFailed", + "ERRORNAMEStatesPermissions", + "ERRORNAMEStatesResultPathMatchFailure", + "ERRORNAMEStatesParameterPathFailure", + "ERRORNAMEStatesBranchFailed", + "ERRORNAMEStatesNoChoiceMatched", + "ERRORNAMEStatesIntrinsicFailure", + "ERRORNAMEStatesExceedToleratedFailureThreshold", + "ERRORNAMEStatesItemReaderFailed", + "ERRORNAMEStatesResultWriterFailed", + "ERRORNAMEStatesRuntime", + "STRINGDOLLAR", + "STRINGPATHCONTEXTOBJ", + "STRINGPATH", + "STRING", + "INT", + "NUMBER", + "WS", + ] + + RULE_program_decl = 0 + RULE_top_layer_stmt = 1 + RULE_startat_decl = 2 + RULE_comment_decl = 3 + RULE_version_decl = 4 + RULE_state_stmt = 5 + RULE_states_decl = 6 + RULE_state_name = 7 + RULE_state_decl = 8 + RULE_state_decl_body = 9 + RULE_type_decl = 10 + RULE_next_decl = 11 + RULE_resource_decl = 12 + RULE_input_path_decl = 13 + RULE_result_decl = 14 + RULE_result_path_decl = 15 + RULE_output_path_decl = 16 + RULE_end_decl = 17 + RULE_default_decl = 18 + RULE_error_decl = 19 + RULE_cause_decl = 20 + RULE_seconds_decl = 21 + RULE_seconds_path_decl = 22 + RULE_timestamp_decl = 23 + RULE_timestamp_path_decl = 24 + RULE_items_path_decl = 25 + RULE_max_concurrency_decl = 26 + RULE_parameters_decl = 27 + RULE_timeout_seconds_decl = 28 + RULE_timeout_seconds_path_decl = 29 + RULE_heartbeat_seconds_decl = 30 + RULE_heartbeat_seconds_path_decl = 31 + RULE_payload_tmpl_decl = 32 + RULE_payload_binding = 33 + RULE_intrinsic_func = 34 + RULE_payload_arr_decl = 35 + RULE_payload_value_decl = 36 + RULE_payload_value_lit = 37 + RULE_result_selector_decl = 38 + RULE_state_type = 39 + RULE_choices_decl = 40 + RULE_choice_rule = 41 + RULE_comparison_variable_stmt = 42 + RULE_comparison_composite_stmt = 43 + RULE_comparison_composite = 44 + RULE_variable_decl = 45 + RULE_comparison_func = 46 + RULE_branches_decl = 47 + RULE_item_processor_decl = 48 + RULE_item_processor_item = 49 + RULE_processor_config_decl = 50 + RULE_processor_config_field = 51 + RULE_mode_decl = 52 + RULE_mode_type = 53 + RULE_execution_decl = 54 + RULE_execution_type = 55 + RULE_iterator_decl = 56 + RULE_iterator_decl_item = 57 + RULE_item_selector_decl = 58 + RULE_item_reader_decl = 59 + RULE_items_reader_field = 60 + RULE_reader_config_decl = 61 + RULE_reader_config_field = 62 + RULE_input_type_decl = 63 + RULE_csv_header_location_decl = 64 + RULE_csv_headers_decl = 65 + RULE_max_items_decl = 66 + RULE_max_items_path_decl = 67 + RULE_retry_decl = 68 + RULE_retrier_decl = 69 + RULE_retrier_stmt = 70 + RULE_error_equals_decl = 71 + RULE_interval_seconds_decl = 72 + RULE_max_attempts_decl = 73 + RULE_backoff_rate_decl = 74 + RULE_catch_decl = 75 + RULE_catcher_decl = 76 + RULE_catcher_stmt = 77 + RULE_comparison_op = 78 + RULE_choice_operator = 79 + RULE_states_error_name = 80 + RULE_error_name = 81 + RULE_json_obj_decl = 82 + RULE_json_binding = 83 + RULE_json_arr_decl = 84 + RULE_json_value_decl = 85 + RULE_keyword_or_string = 86 + + ruleNames = [ + "program_decl", + "top_layer_stmt", + "startat_decl", + "comment_decl", + "version_decl", + "state_stmt", + "states_decl", + "state_name", + "state_decl", + "state_decl_body", + "type_decl", + "next_decl", + "resource_decl", + "input_path_decl", + "result_decl", + "result_path_decl", + "output_path_decl", + "end_decl", + "default_decl", + "error_decl", + "cause_decl", + "seconds_decl", + "seconds_path_decl", + "timestamp_decl", + "timestamp_path_decl", + "items_path_decl", + "max_concurrency_decl", + "parameters_decl", + "timeout_seconds_decl", + "timeout_seconds_path_decl", + "heartbeat_seconds_decl", + "heartbeat_seconds_path_decl", + "payload_tmpl_decl", + "payload_binding", + "intrinsic_func", + "payload_arr_decl", + "payload_value_decl", + "payload_value_lit", + "result_selector_decl", + "state_type", + "choices_decl", + "choice_rule", + "comparison_variable_stmt", + "comparison_composite_stmt", + "comparison_composite", + "variable_decl", + "comparison_func", + "branches_decl", + "item_processor_decl", + "item_processor_item", + "processor_config_decl", + "processor_config_field", + "mode_decl", + "mode_type", + "execution_decl", + "execution_type", + "iterator_decl", + "iterator_decl_item", + "item_selector_decl", + "item_reader_decl", + "items_reader_field", + "reader_config_decl", + "reader_config_field", + "input_type_decl", + "csv_header_location_decl", + "csv_headers_decl", + "max_items_decl", + "max_items_path_decl", + "retry_decl", + "retrier_decl", + "retrier_stmt", + "error_equals_decl", + "interval_seconds_decl", + "max_attempts_decl", + "backoff_rate_decl", + "catch_decl", + "catcher_decl", + "catcher_stmt", + "comparison_op", + "choice_operator", + "states_error_name", + "error_name", + "json_obj_decl", + "json_binding", + "json_arr_decl", + "json_value_decl", + "keyword_or_string", + ] + + EOF = Token.EOF + COMMA = 1 + COLON = 2 + LBRACK = 3 + RBRACK = 4 + LBRACE = 5 + RBRACE = 6 + TRUE = 7 + FALSE = 8 + NULL = 9 + COMMENT = 10 + STATES = 11 + STARTAT = 12 + NEXTSTATE = 13 + VERSION = 14 + TYPE = 15 + TASK = 16 + CHOICE = 17 + FAIL = 18 + SUCCEED = 19 + PASS = 20 + WAIT = 21 + PARALLEL = 22 + MAP = 23 + CHOICES = 24 + VARIABLE = 25 + DEFAULT = 26 + BRANCHES = 27 + AND = 28 + BOOLEANEQUALS = 29 + BOOLEANQUALSPATH = 30 + ISBOOLEAN = 31 + ISNULL = 32 + ISNUMERIC = 33 + ISPRESENT = 34 + ISSTRING = 35 + ISTIMESTAMP = 36 + NOT = 37 + NUMERICEQUALS = 38 + NUMERICEQUALSPATH = 39 + NUMERICGREATERTHAN = 40 + NUMERICGREATERTHANPATH = 41 + NUMERICGREATERTHANEQUALS = 42 + NUMERICGREATERTHANEQUALSPATH = 43 + NUMERICLESSTHAN = 44 + NUMERICLESSTHANPATH = 45 + NUMERICLESSTHANEQUALS = 46 + NUMERICLESSTHANEQUALSPATH = 47 + OR = 48 + STRINGEQUALS = 49 + STRINGEQUALSPATH = 50 + STRINGGREATERTHAN = 51 + STRINGGREATERTHANPATH = 52 + STRINGGREATERTHANEQUALS = 53 + STRINGGREATERTHANEQUALSPATH = 54 + STRINGLESSTHAN = 55 + STRINGLESSTHANPATH = 56 + STRINGLESSTHANEQUALS = 57 + STRINGLESSTHANEQUALSPATH = 58 + STRINGMATCHES = 59 + TIMESTAMPEQUALS = 60 + TIMESTAMPEQUALSPATH = 61 + TIMESTAMPGREATERTHAN = 62 + TIMESTAMPGREATERTHANPATH = 63 + TIMESTAMPGREATERTHANEQUALS = 64 + TIMESTAMPGREATERTHANEQUALSPATH = 65 + TIMESTAMPLESSTHAN = 66 + TIMESTAMPLESSTHANPATH = 67 + TIMESTAMPLESSTHANEQUALS = 68 + TIMESTAMPLESSTHANEQUALSPATH = 69 + SECONDSPATH = 70 + SECONDS = 71 + TIMESTAMPPATH = 72 + TIMESTAMP = 73 + TIMEOUTSECONDS = 74 + TIMEOUTSECONDSPATH = 75 + HEARTBEATSECONDS = 76 + HEARTBEATSECONDSPATH = 77 + PROCESSORCONFIG = 78 + MODE = 79 + INLINE = 80 + DISTRIBUTED = 81 + EXECUTIONTYPE = 82 + STANDARD = 83 + ITEMPROCESSOR = 84 + ITERATOR = 85 + ITEMSELECTOR = 86 + MAXCONCURRENCY = 87 + RESOURCE = 88 + INPUTPATH = 89 + OUTPUTPATH = 90 + ITEMSPATH = 91 + RESULTPATH = 92 + RESULT = 93 + PARAMETERS = 94 + RESULTSELECTOR = 95 + ITEMREADER = 96 + READERCONFIG = 97 + INPUTTYPE = 98 + CSVHEADERLOCATION = 99 + CSVHEADERS = 100 + MAXITEMS = 101 + MAXITEMSPATH = 102 + NEXT = 103 + END = 104 + CAUSE = 105 + ERROR = 106 + RETRY = 107 + ERROREQUALS = 108 + INTERVALSECONDS = 109 + MAXATTEMPTS = 110 + BACKOFFRATE = 111 + CATCH = 112 + ERRORNAMEStatesALL = 113 + ERRORNAMEStatesHeartbeatTimeout = 114 + ERRORNAMEStatesTimeout = 115 + ERRORNAMEStatesTaskFailed = 116 + ERRORNAMEStatesPermissions = 117 + ERRORNAMEStatesResultPathMatchFailure = 118 + ERRORNAMEStatesParameterPathFailure = 119 + ERRORNAMEStatesBranchFailed = 120 + ERRORNAMEStatesNoChoiceMatched = 121 + ERRORNAMEStatesIntrinsicFailure = 122 + ERRORNAMEStatesExceedToleratedFailureThreshold = 123 + ERRORNAMEStatesItemReaderFailed = 124 + ERRORNAMEStatesResultWriterFailed = 125 + ERRORNAMEStatesRuntime = 126 + STRINGDOLLAR = 127 + STRINGPATHCONTEXTOBJ = 128 + STRINGPATH = 129 + STRING = 130 + INT = 131 + NUMBER = 132 + WS = 133 + + def __init__(self, input: TokenStream, output: TextIO = sys.stdout): + super().__init__(input, output) + self.checkVersion("4.13.1") + self._interp = ParserATNSimulator( + self, self.atn, self.decisionsToDFA, self.sharedContextCache + ) + self._predicates = None + + class Program_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def top_layer_stmt(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Top_layer_stmtContext) + else: + return self.getTypedRuleContext(ASLParser.Top_layer_stmtContext, i) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_program_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterProgram_decl"): + listener.enterProgram_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitProgram_decl"): + listener.exitProgram_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitProgram_decl"): + return visitor.visitProgram_decl(self) + else: + return visitor.visitChildren(self) + + def program_decl(self): + + localctx = ASLParser.Program_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 0, self.RULE_program_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 174 + self.match(ASLParser.LBRACE) + self.state = 175 + self.top_layer_stmt() + self.state = 180 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 176 + self.match(ASLParser.COMMA) + self.state = 177 + self.top_layer_stmt() + self.state = 182 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 183 + self.match(ASLParser.RBRACE) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Top_layer_stmtContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def comment_decl(self): + return self.getTypedRuleContext(ASLParser.Comment_declContext, 0) + + def version_decl(self): + return self.getTypedRuleContext(ASLParser.Version_declContext, 0) + + def startat_decl(self): + return self.getTypedRuleContext(ASLParser.Startat_declContext, 0) + + def states_decl(self): + return self.getTypedRuleContext(ASLParser.States_declContext, 0) + + def timeout_seconds_decl(self): + return self.getTypedRuleContext(ASLParser.Timeout_seconds_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_top_layer_stmt + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterTop_layer_stmt"): + listener.enterTop_layer_stmt(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitTop_layer_stmt"): + listener.exitTop_layer_stmt(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitTop_layer_stmt"): + return visitor.visitTop_layer_stmt(self) + else: + return visitor.visitChildren(self) + + def top_layer_stmt(self): + + localctx = ASLParser.Top_layer_stmtContext(self, self._ctx, self.state) + self.enterRule(localctx, 2, self.RULE_top_layer_stmt) + try: + self.state = 190 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [10]: + self.enterOuterAlt(localctx, 1) + self.state = 185 + self.comment_decl() + pass + elif token in [14]: + self.enterOuterAlt(localctx, 2) + self.state = 186 + self.version_decl() + pass + elif token in [12]: + self.enterOuterAlt(localctx, 3) + self.state = 187 + self.startat_decl() + pass + elif token in [11]: + self.enterOuterAlt(localctx, 4) + self.state = 188 + self.states_decl() + pass + elif token in [74]: + self.enterOuterAlt(localctx, 5) + self.state = 189 + self.timeout_seconds_decl() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Startat_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def STARTAT(self): + return self.getToken(ASLParser.STARTAT, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_startat_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterStartat_decl"): + listener.enterStartat_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitStartat_decl"): + listener.exitStartat_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitStartat_decl"): + return visitor.visitStartat_decl(self) + else: + return visitor.visitChildren(self) + + def startat_decl(self): + + localctx = ASLParser.Startat_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 4, self.RULE_startat_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 192 + self.match(ASLParser.STARTAT) + self.state = 193 + self.match(ASLParser.COLON) + self.state = 194 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Comment_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def COMMENT(self): + return self.getToken(ASLParser.COMMENT, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_comment_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterComment_decl"): + listener.enterComment_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitComment_decl"): + listener.exitComment_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitComment_decl"): + return visitor.visitComment_decl(self) + else: + return visitor.visitChildren(self) + + def comment_decl(self): + + localctx = ASLParser.Comment_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 6, self.RULE_comment_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 196 + self.match(ASLParser.COMMENT) + self.state = 197 + self.match(ASLParser.COLON) + self.state = 198 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Version_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def VERSION(self): + return self.getToken(ASLParser.VERSION, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_version_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterVersion_decl"): + listener.enterVersion_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitVersion_decl"): + listener.exitVersion_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitVersion_decl"): + return visitor.visitVersion_decl(self) + else: + return visitor.visitChildren(self) + + def version_decl(self): + + localctx = ASLParser.Version_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 8, self.RULE_version_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 200 + self.match(ASLParser.VERSION) + self.state = 201 + self.match(ASLParser.COLON) + self.state = 202 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class State_stmtContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def comment_decl(self): + return self.getTypedRuleContext(ASLParser.Comment_declContext, 0) + + def type_decl(self): + return self.getTypedRuleContext(ASLParser.Type_declContext, 0) + + def input_path_decl(self): + return self.getTypedRuleContext(ASLParser.Input_path_declContext, 0) + + def resource_decl(self): + return self.getTypedRuleContext(ASLParser.Resource_declContext, 0) + + def next_decl(self): + return self.getTypedRuleContext(ASLParser.Next_declContext, 0) + + def result_decl(self): + return self.getTypedRuleContext(ASLParser.Result_declContext, 0) + + def result_path_decl(self): + return self.getTypedRuleContext(ASLParser.Result_path_declContext, 0) + + def output_path_decl(self): + return self.getTypedRuleContext(ASLParser.Output_path_declContext, 0) + + def end_decl(self): + return self.getTypedRuleContext(ASLParser.End_declContext, 0) + + def default_decl(self): + return self.getTypedRuleContext(ASLParser.Default_declContext, 0) + + def choices_decl(self): + return self.getTypedRuleContext(ASLParser.Choices_declContext, 0) + + def error_decl(self): + return self.getTypedRuleContext(ASLParser.Error_declContext, 0) + + def cause_decl(self): + return self.getTypedRuleContext(ASLParser.Cause_declContext, 0) + + def seconds_decl(self): + return self.getTypedRuleContext(ASLParser.Seconds_declContext, 0) + + def seconds_path_decl(self): + return self.getTypedRuleContext(ASLParser.Seconds_path_declContext, 0) + + def timestamp_decl(self): + return self.getTypedRuleContext(ASLParser.Timestamp_declContext, 0) + + def timestamp_path_decl(self): + return self.getTypedRuleContext(ASLParser.Timestamp_path_declContext, 0) + + def items_path_decl(self): + return self.getTypedRuleContext(ASLParser.Items_path_declContext, 0) + + def item_processor_decl(self): + return self.getTypedRuleContext(ASLParser.Item_processor_declContext, 0) + + def iterator_decl(self): + return self.getTypedRuleContext(ASLParser.Iterator_declContext, 0) + + def item_selector_decl(self): + return self.getTypedRuleContext(ASLParser.Item_selector_declContext, 0) + + def item_reader_decl(self): + return self.getTypedRuleContext(ASLParser.Item_reader_declContext, 0) + + def max_concurrency_decl(self): + return self.getTypedRuleContext(ASLParser.Max_concurrency_declContext, 0) + + def timeout_seconds_decl(self): + return self.getTypedRuleContext(ASLParser.Timeout_seconds_declContext, 0) + + def timeout_seconds_path_decl(self): + return self.getTypedRuleContext( + ASLParser.Timeout_seconds_path_declContext, 0 + ) + + def heartbeat_seconds_decl(self): + return self.getTypedRuleContext(ASLParser.Heartbeat_seconds_declContext, 0) + + def heartbeat_seconds_path_decl(self): + return self.getTypedRuleContext( + ASLParser.Heartbeat_seconds_path_declContext, 0 + ) + + def branches_decl(self): + return self.getTypedRuleContext(ASLParser.Branches_declContext, 0) + + def parameters_decl(self): + return self.getTypedRuleContext(ASLParser.Parameters_declContext, 0) + + def retry_decl(self): + return self.getTypedRuleContext(ASLParser.Retry_declContext, 0) + + def catch_decl(self): + return self.getTypedRuleContext(ASLParser.Catch_declContext, 0) + + def result_selector_decl(self): + return self.getTypedRuleContext(ASLParser.Result_selector_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_state_stmt + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterState_stmt"): + listener.enterState_stmt(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitState_stmt"): + listener.exitState_stmt(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitState_stmt"): + return visitor.visitState_stmt(self) + else: + return visitor.visitChildren(self) + + def state_stmt(self): + + localctx = ASLParser.State_stmtContext(self, self._ctx, self.state) + self.enterRule(localctx, 10, self.RULE_state_stmt) + try: + self.state = 236 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [10]: + self.enterOuterAlt(localctx, 1) + self.state = 204 + self.comment_decl() + pass + elif token in [15]: + self.enterOuterAlt(localctx, 2) + self.state = 205 + self.type_decl() + pass + elif token in [89]: + self.enterOuterAlt(localctx, 3) + self.state = 206 + self.input_path_decl() + pass + elif token in [88]: + self.enterOuterAlt(localctx, 4) + self.state = 207 + self.resource_decl() + pass + elif token in [103]: + self.enterOuterAlt(localctx, 5) + self.state = 208 + self.next_decl() + pass + elif token in [93]: + self.enterOuterAlt(localctx, 6) + self.state = 209 + self.result_decl() + pass + elif token in [92]: + self.enterOuterAlt(localctx, 7) + self.state = 210 + self.result_path_decl() + pass + elif token in [90]: + self.enterOuterAlt(localctx, 8) + self.state = 211 + self.output_path_decl() + pass + elif token in [104]: + self.enterOuterAlt(localctx, 9) + self.state = 212 + self.end_decl() + pass + elif token in [26]: + self.enterOuterAlt(localctx, 10) + self.state = 213 + self.default_decl() + pass + elif token in [24]: + self.enterOuterAlt(localctx, 11) + self.state = 214 + self.choices_decl() + pass + elif token in [106]: + self.enterOuterAlt(localctx, 12) + self.state = 215 + self.error_decl() + pass + elif token in [105]: + self.enterOuterAlt(localctx, 13) + self.state = 216 + self.cause_decl() + pass + elif token in [71]: + self.enterOuterAlt(localctx, 14) + self.state = 217 + self.seconds_decl() + pass + elif token in [70]: + self.enterOuterAlt(localctx, 15) + self.state = 218 + self.seconds_path_decl() + pass + elif token in [73]: + self.enterOuterAlt(localctx, 16) + self.state = 219 + self.timestamp_decl() + pass + elif token in [72]: + self.enterOuterAlt(localctx, 17) + self.state = 220 + self.timestamp_path_decl() + pass + elif token in [91]: + self.enterOuterAlt(localctx, 18) + self.state = 221 + self.items_path_decl() + pass + elif token in [84]: + self.enterOuterAlt(localctx, 19) + self.state = 222 + self.item_processor_decl() + pass + elif token in [85]: + self.enterOuterAlt(localctx, 20) + self.state = 223 + self.iterator_decl() + pass + elif token in [86]: + self.enterOuterAlt(localctx, 21) + self.state = 224 + self.item_selector_decl() + pass + elif token in [96]: + self.enterOuterAlt(localctx, 22) + self.state = 225 + self.item_reader_decl() + pass + elif token in [87]: + self.enterOuterAlt(localctx, 23) + self.state = 226 + self.max_concurrency_decl() + pass + elif token in [74]: + self.enterOuterAlt(localctx, 24) + self.state = 227 + self.timeout_seconds_decl() + pass + elif token in [75]: + self.enterOuterAlt(localctx, 25) + self.state = 228 + self.timeout_seconds_path_decl() + pass + elif token in [76]: + self.enterOuterAlt(localctx, 26) + self.state = 229 + self.heartbeat_seconds_decl() + pass + elif token in [77]: + self.enterOuterAlt(localctx, 27) + self.state = 230 + self.heartbeat_seconds_path_decl() + pass + elif token in [27]: + self.enterOuterAlt(localctx, 28) + self.state = 231 + self.branches_decl() + pass + elif token in [94]: + self.enterOuterAlt(localctx, 29) + self.state = 232 + self.parameters_decl() + pass + elif token in [107]: + self.enterOuterAlt(localctx, 30) + self.state = 233 + self.retry_decl() + pass + elif token in [112]: + self.enterOuterAlt(localctx, 31) + self.state = 234 + self.catch_decl() + pass + elif token in [95]: + self.enterOuterAlt(localctx, 32) + self.state = 235 + self.result_selector_decl() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class States_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def STATES(self): + return self.getToken(ASLParser.STATES, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def state_decl(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.State_declContext) + else: + return self.getTypedRuleContext(ASLParser.State_declContext, i) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_states_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterStates_decl"): + listener.enterStates_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitStates_decl"): + listener.exitStates_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitStates_decl"): + return visitor.visitStates_decl(self) + else: + return visitor.visitChildren(self) + + def states_decl(self): + + localctx = ASLParser.States_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 12, self.RULE_states_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 238 + self.match(ASLParser.STATES) + self.state = 239 + self.match(ASLParser.COLON) + self.state = 240 + self.match(ASLParser.LBRACE) + self.state = 241 + self.state_decl() + self.state = 246 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 242 + self.match(ASLParser.COMMA) + self.state = 243 + self.state_decl() + self.state = 248 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 249 + self.match(ASLParser.RBRACE) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class State_nameContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_state_name + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterState_name"): + listener.enterState_name(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitState_name"): + listener.exitState_name(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitState_name"): + return visitor.visitState_name(self) + else: + return visitor.visitChildren(self) + + def state_name(self): + + localctx = ASLParser.State_nameContext(self, self._ctx, self.state) + self.enterRule(localctx, 14, self.RULE_state_name) + try: + self.enterOuterAlt(localctx, 1) + self.state = 251 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class State_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def state_name(self): + return self.getTypedRuleContext(ASLParser.State_nameContext, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def state_decl_body(self): + return self.getTypedRuleContext(ASLParser.State_decl_bodyContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_state_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterState_decl"): + listener.enterState_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitState_decl"): + listener.exitState_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitState_decl"): + return visitor.visitState_decl(self) + else: + return visitor.visitChildren(self) + + def state_decl(self): + + localctx = ASLParser.State_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 16, self.RULE_state_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 253 + self.state_name() + self.state = 254 + self.match(ASLParser.COLON) + self.state = 255 + self.state_decl_body() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class State_decl_bodyContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def state_stmt(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.State_stmtContext) + else: + return self.getTypedRuleContext(ASLParser.State_stmtContext, i) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_state_decl_body + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterState_decl_body"): + listener.enterState_decl_body(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitState_decl_body"): + listener.exitState_decl_body(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitState_decl_body"): + return visitor.visitState_decl_body(self) + else: + return visitor.visitChildren(self) + + def state_decl_body(self): + + localctx = ASLParser.State_decl_bodyContext(self, self._ctx, self.state) + self.enterRule(localctx, 18, self.RULE_state_decl_body) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 257 + self.match(ASLParser.LBRACE) + self.state = 258 + self.state_stmt() + self.state = 263 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 259 + self.match(ASLParser.COMMA) + self.state = 260 + self.state_stmt() + self.state = 265 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 266 + self.match(ASLParser.RBRACE) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Type_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def TYPE(self): + return self.getToken(ASLParser.TYPE, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def state_type(self): + return self.getTypedRuleContext(ASLParser.State_typeContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_type_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterType_decl"): + listener.enterType_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitType_decl"): + listener.exitType_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitType_decl"): + return visitor.visitType_decl(self) + else: + return visitor.visitChildren(self) + + def type_decl(self): + + localctx = ASLParser.Type_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 20, self.RULE_type_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 268 + self.match(ASLParser.TYPE) + self.state = 269 + self.match(ASLParser.COLON) + self.state = 270 + self.state_type() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Next_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def NEXT(self): + return self.getToken(ASLParser.NEXT, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_next_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterNext_decl"): + listener.enterNext_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitNext_decl"): + listener.exitNext_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitNext_decl"): + return visitor.visitNext_decl(self) + else: + return visitor.visitChildren(self) + + def next_decl(self): + + localctx = ASLParser.Next_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 22, self.RULE_next_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 272 + self.match(ASLParser.NEXT) + self.state = 273 + self.match(ASLParser.COLON) + self.state = 274 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Resource_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def RESOURCE(self): + return self.getToken(ASLParser.RESOURCE, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_resource_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterResource_decl"): + listener.enterResource_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitResource_decl"): + listener.exitResource_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitResource_decl"): + return visitor.visitResource_decl(self) + else: + return visitor.visitChildren(self) + + def resource_decl(self): + + localctx = ASLParser.Resource_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 24, self.RULE_resource_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 276 + self.match(ASLParser.RESOURCE) + self.state = 277 + self.match(ASLParser.COLON) + self.state = 278 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Input_path_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def INPUTPATH(self): + return self.getToken(ASLParser.INPUTPATH, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def NULL(self): + return self.getToken(ASLParser.NULL, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_input_path_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterInput_path_decl"): + listener.enterInput_path_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitInput_path_decl"): + listener.exitInput_path_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitInput_path_decl"): + return visitor.visitInput_path_decl(self) + else: + return visitor.visitChildren(self) + + def input_path_decl(self): + + localctx = ASLParser.Input_path_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 26, self.RULE_input_path_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 280 + self.match(ASLParser.INPUTPATH) + self.state = 281 + self.match(ASLParser.COLON) + self.state = 284 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [9]: + self.state = 282 + self.match(ASLParser.NULL) + pass + elif token in [ + 10, + 11, + 12, + 13, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + ]: + self.state = 283 + self.keyword_or_string() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Result_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def RESULT(self): + return self.getToken(ASLParser.RESULT, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def json_value_decl(self): + return self.getTypedRuleContext(ASLParser.Json_value_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_result_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterResult_decl"): + listener.enterResult_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitResult_decl"): + listener.exitResult_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitResult_decl"): + return visitor.visitResult_decl(self) + else: + return visitor.visitChildren(self) + + def result_decl(self): + + localctx = ASLParser.Result_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 28, self.RULE_result_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 286 + self.match(ASLParser.RESULT) + self.state = 287 + self.match(ASLParser.COLON) + self.state = 288 + self.json_value_decl() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Result_path_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def RESULTPATH(self): + return self.getToken(ASLParser.RESULTPATH, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def NULL(self): + return self.getToken(ASLParser.NULL, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_result_path_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterResult_path_decl"): + listener.enterResult_path_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitResult_path_decl"): + listener.exitResult_path_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitResult_path_decl"): + return visitor.visitResult_path_decl(self) + else: + return visitor.visitChildren(self) + + def result_path_decl(self): + + localctx = ASLParser.Result_path_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 30, self.RULE_result_path_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 290 + self.match(ASLParser.RESULTPATH) + self.state = 291 + self.match(ASLParser.COLON) + self.state = 294 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [9]: + self.state = 292 + self.match(ASLParser.NULL) + pass + elif token in [ + 10, + 11, + 12, + 13, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + ]: + self.state = 293 + self.keyword_or_string() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Output_path_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def OUTPUTPATH(self): + return self.getToken(ASLParser.OUTPUTPATH, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def NULL(self): + return self.getToken(ASLParser.NULL, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_output_path_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterOutput_path_decl"): + listener.enterOutput_path_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitOutput_path_decl"): + listener.exitOutput_path_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitOutput_path_decl"): + return visitor.visitOutput_path_decl(self) + else: + return visitor.visitChildren(self) + + def output_path_decl(self): + + localctx = ASLParser.Output_path_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 32, self.RULE_output_path_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 296 + self.match(ASLParser.OUTPUTPATH) + self.state = 297 + self.match(ASLParser.COLON) + self.state = 300 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [9]: + self.state = 298 + self.match(ASLParser.NULL) + pass + elif token in [ + 10, + 11, + 12, + 13, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + ]: + self.state = 299 + self.keyword_or_string() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class End_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def END(self): + return self.getToken(ASLParser.END, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def TRUE(self): + return self.getToken(ASLParser.TRUE, 0) + + def FALSE(self): + return self.getToken(ASLParser.FALSE, 0) + + def getRuleIndex(self): + return ASLParser.RULE_end_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterEnd_decl"): + listener.enterEnd_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitEnd_decl"): + listener.exitEnd_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitEnd_decl"): + return visitor.visitEnd_decl(self) + else: + return visitor.visitChildren(self) + + def end_decl(self): + + localctx = ASLParser.End_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 34, self.RULE_end_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 302 + self.match(ASLParser.END) + self.state = 303 + self.match(ASLParser.COLON) + self.state = 304 + _la = self._input.LA(1) + if not (_la == 7 or _la == 8): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Default_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def DEFAULT(self): + return self.getToken(ASLParser.DEFAULT, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_default_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterDefault_decl"): + listener.enterDefault_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitDefault_decl"): + listener.exitDefault_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitDefault_decl"): + return visitor.visitDefault_decl(self) + else: + return visitor.visitChildren(self) + + def default_decl(self): + + localctx = ASLParser.Default_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 36, self.RULE_default_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 306 + self.match(ASLParser.DEFAULT) + self.state = 307 + self.match(ASLParser.COLON) + self.state = 308 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Error_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def ERROR(self): + return self.getToken(ASLParser.ERROR, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_error_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterError_decl"): + listener.enterError_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitError_decl"): + listener.exitError_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitError_decl"): + return visitor.visitError_decl(self) + else: + return visitor.visitChildren(self) + + def error_decl(self): + + localctx = ASLParser.Error_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 38, self.RULE_error_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 310 + self.match(ASLParser.ERROR) + self.state = 311 + self.match(ASLParser.COLON) + self.state = 312 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Cause_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def CAUSE(self): + return self.getToken(ASLParser.CAUSE, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_cause_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterCause_decl"): + listener.enterCause_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitCause_decl"): + listener.exitCause_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitCause_decl"): + return visitor.visitCause_decl(self) + else: + return visitor.visitChildren(self) + + def cause_decl(self): + + localctx = ASLParser.Cause_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 40, self.RULE_cause_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 314 + self.match(ASLParser.CAUSE) + self.state = 315 + self.match(ASLParser.COLON) + self.state = 316 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Seconds_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def SECONDS(self): + return self.getToken(ASLParser.SECONDS, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def INT(self): + return self.getToken(ASLParser.INT, 0) + + def getRuleIndex(self): + return ASLParser.RULE_seconds_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterSeconds_decl"): + listener.enterSeconds_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitSeconds_decl"): + listener.exitSeconds_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitSeconds_decl"): + return visitor.visitSeconds_decl(self) + else: + return visitor.visitChildren(self) + + def seconds_decl(self): + + localctx = ASLParser.Seconds_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 42, self.RULE_seconds_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 318 + self.match(ASLParser.SECONDS) + self.state = 319 + self.match(ASLParser.COLON) + self.state = 320 + self.match(ASLParser.INT) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Seconds_path_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def SECONDSPATH(self): + return self.getToken(ASLParser.SECONDSPATH, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_seconds_path_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterSeconds_path_decl"): + listener.enterSeconds_path_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitSeconds_path_decl"): + listener.exitSeconds_path_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitSeconds_path_decl"): + return visitor.visitSeconds_path_decl(self) + else: + return visitor.visitChildren(self) + + def seconds_path_decl(self): + + localctx = ASLParser.Seconds_path_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 44, self.RULE_seconds_path_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 322 + self.match(ASLParser.SECONDSPATH) + self.state = 323 + self.match(ASLParser.COLON) + self.state = 324 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Timestamp_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def TIMESTAMP(self): + return self.getToken(ASLParser.TIMESTAMP, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_timestamp_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterTimestamp_decl"): + listener.enterTimestamp_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitTimestamp_decl"): + listener.exitTimestamp_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitTimestamp_decl"): + return visitor.visitTimestamp_decl(self) + else: + return visitor.visitChildren(self) + + def timestamp_decl(self): + + localctx = ASLParser.Timestamp_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 46, self.RULE_timestamp_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 326 + self.match(ASLParser.TIMESTAMP) + self.state = 327 + self.match(ASLParser.COLON) + self.state = 328 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Timestamp_path_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def TIMESTAMPPATH(self): + return self.getToken(ASLParser.TIMESTAMPPATH, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_timestamp_path_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterTimestamp_path_decl"): + listener.enterTimestamp_path_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitTimestamp_path_decl"): + listener.exitTimestamp_path_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitTimestamp_path_decl"): + return visitor.visitTimestamp_path_decl(self) + else: + return visitor.visitChildren(self) + + def timestamp_path_decl(self): + + localctx = ASLParser.Timestamp_path_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 48, self.RULE_timestamp_path_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 330 + self.match(ASLParser.TIMESTAMPPATH) + self.state = 331 + self.match(ASLParser.COLON) + self.state = 332 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Items_path_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def ITEMSPATH(self): + return self.getToken(ASLParser.ITEMSPATH, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_items_path_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterItems_path_decl"): + listener.enterItems_path_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitItems_path_decl"): + listener.exitItems_path_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitItems_path_decl"): + return visitor.visitItems_path_decl(self) + else: + return visitor.visitChildren(self) + + def items_path_decl(self): + + localctx = ASLParser.Items_path_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 50, self.RULE_items_path_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 334 + self.match(ASLParser.ITEMSPATH) + self.state = 335 + self.match(ASLParser.COLON) + self.state = 336 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Max_concurrency_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def MAXCONCURRENCY(self): + return self.getToken(ASLParser.MAXCONCURRENCY, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def INT(self): + return self.getToken(ASLParser.INT, 0) + + def getRuleIndex(self): + return ASLParser.RULE_max_concurrency_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterMax_concurrency_decl"): + listener.enterMax_concurrency_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitMax_concurrency_decl"): + listener.exitMax_concurrency_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitMax_concurrency_decl"): + return visitor.visitMax_concurrency_decl(self) + else: + return visitor.visitChildren(self) + + def max_concurrency_decl(self): + + localctx = ASLParser.Max_concurrency_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 52, self.RULE_max_concurrency_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 338 + self.match(ASLParser.MAXCONCURRENCY) + self.state = 339 + self.match(ASLParser.COLON) + self.state = 340 + self.match(ASLParser.INT) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Parameters_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def PARAMETERS(self): + return self.getToken(ASLParser.PARAMETERS, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def payload_tmpl_decl(self): + return self.getTypedRuleContext(ASLParser.Payload_tmpl_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_parameters_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterParameters_decl"): + listener.enterParameters_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitParameters_decl"): + listener.exitParameters_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitParameters_decl"): + return visitor.visitParameters_decl(self) + else: + return visitor.visitChildren(self) + + def parameters_decl(self): + + localctx = ASLParser.Parameters_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 54, self.RULE_parameters_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 342 + self.match(ASLParser.PARAMETERS) + self.state = 343 + self.match(ASLParser.COLON) + self.state = 344 + self.payload_tmpl_decl() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Timeout_seconds_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def TIMEOUTSECONDS(self): + return self.getToken(ASLParser.TIMEOUTSECONDS, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def INT(self): + return self.getToken(ASLParser.INT, 0) + + def getRuleIndex(self): + return ASLParser.RULE_timeout_seconds_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterTimeout_seconds_decl"): + listener.enterTimeout_seconds_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitTimeout_seconds_decl"): + listener.exitTimeout_seconds_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitTimeout_seconds_decl"): + return visitor.visitTimeout_seconds_decl(self) + else: + return visitor.visitChildren(self) + + def timeout_seconds_decl(self): + + localctx = ASLParser.Timeout_seconds_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 56, self.RULE_timeout_seconds_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 346 + self.match(ASLParser.TIMEOUTSECONDS) + self.state = 347 + self.match(ASLParser.COLON) + self.state = 348 + self.match(ASLParser.INT) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Timeout_seconds_path_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def TIMEOUTSECONDSPATH(self): + return self.getToken(ASLParser.TIMEOUTSECONDSPATH, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def STRINGPATH(self): + return self.getToken(ASLParser.STRINGPATH, 0) + + def getRuleIndex(self): + return ASLParser.RULE_timeout_seconds_path_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterTimeout_seconds_path_decl"): + listener.enterTimeout_seconds_path_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitTimeout_seconds_path_decl"): + listener.exitTimeout_seconds_path_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitTimeout_seconds_path_decl"): + return visitor.visitTimeout_seconds_path_decl(self) + else: + return visitor.visitChildren(self) + + def timeout_seconds_path_decl(self): + + localctx = ASLParser.Timeout_seconds_path_declContext( + self, self._ctx, self.state + ) + self.enterRule(localctx, 58, self.RULE_timeout_seconds_path_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 350 + self.match(ASLParser.TIMEOUTSECONDSPATH) + self.state = 351 + self.match(ASLParser.COLON) + self.state = 352 + self.match(ASLParser.STRINGPATH) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Heartbeat_seconds_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def HEARTBEATSECONDS(self): + return self.getToken(ASLParser.HEARTBEATSECONDS, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def INT(self): + return self.getToken(ASLParser.INT, 0) + + def getRuleIndex(self): + return ASLParser.RULE_heartbeat_seconds_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterHeartbeat_seconds_decl"): + listener.enterHeartbeat_seconds_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitHeartbeat_seconds_decl"): + listener.exitHeartbeat_seconds_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitHeartbeat_seconds_decl"): + return visitor.visitHeartbeat_seconds_decl(self) + else: + return visitor.visitChildren(self) + + def heartbeat_seconds_decl(self): + + localctx = ASLParser.Heartbeat_seconds_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 60, self.RULE_heartbeat_seconds_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 354 + self.match(ASLParser.HEARTBEATSECONDS) + self.state = 355 + self.match(ASLParser.COLON) + self.state = 356 + self.match(ASLParser.INT) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Heartbeat_seconds_path_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def HEARTBEATSECONDSPATH(self): + return self.getToken(ASLParser.HEARTBEATSECONDSPATH, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def STRINGPATH(self): + return self.getToken(ASLParser.STRINGPATH, 0) + + def getRuleIndex(self): + return ASLParser.RULE_heartbeat_seconds_path_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterHeartbeat_seconds_path_decl"): + listener.enterHeartbeat_seconds_path_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitHeartbeat_seconds_path_decl"): + listener.exitHeartbeat_seconds_path_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitHeartbeat_seconds_path_decl"): + return visitor.visitHeartbeat_seconds_path_decl(self) + else: + return visitor.visitChildren(self) + + def heartbeat_seconds_path_decl(self): + + localctx = ASLParser.Heartbeat_seconds_path_declContext( + self, self._ctx, self.state + ) + self.enterRule(localctx, 62, self.RULE_heartbeat_seconds_path_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 358 + self.match(ASLParser.HEARTBEATSECONDSPATH) + self.state = 359 + self.match(ASLParser.COLON) + self.state = 360 + self.match(ASLParser.STRINGPATH) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Payload_tmpl_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def payload_binding(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Payload_bindingContext) + else: + return self.getTypedRuleContext(ASLParser.Payload_bindingContext, i) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_payload_tmpl_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterPayload_tmpl_decl"): + listener.enterPayload_tmpl_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitPayload_tmpl_decl"): + listener.exitPayload_tmpl_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitPayload_tmpl_decl"): + return visitor.visitPayload_tmpl_decl(self) + else: + return visitor.visitChildren(self) + + def payload_tmpl_decl(self): + + localctx = ASLParser.Payload_tmpl_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 64, self.RULE_payload_tmpl_decl) + self._la = 0 # Token type + try: + self.state = 375 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 9, self._ctx) + if la_ == 1: + self.enterOuterAlt(localctx, 1) + self.state = 362 + self.match(ASLParser.LBRACE) + self.state = 363 + self.payload_binding() + self.state = 368 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 364 + self.match(ASLParser.COMMA) + self.state = 365 + self.payload_binding() + self.state = 370 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 371 + self.match(ASLParser.RBRACE) + pass + + elif la_ == 2: + self.enterOuterAlt(localctx, 2) + self.state = 373 + self.match(ASLParser.LBRACE) + self.state = 374 + self.match(ASLParser.RBRACE) + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Payload_bindingContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def getRuleIndex(self): + return ASLParser.RULE_payload_binding + + def copyFrom(self, ctx: ParserRuleContext): + super().copyFrom(ctx) + + class Payload_binding_pathContext(Payload_bindingContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLParser.Payload_bindingContext + super().__init__(parser) + self.copyFrom(ctx) + + def STRINGDOLLAR(self): + return self.getToken(ASLParser.STRINGDOLLAR, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def STRINGPATH(self): + return self.getToken(ASLParser.STRINGPATH, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterPayload_binding_path"): + listener.enterPayload_binding_path(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitPayload_binding_path"): + listener.exitPayload_binding_path(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitPayload_binding_path"): + return visitor.visitPayload_binding_path(self) + else: + return visitor.visitChildren(self) + + class Payload_binding_path_context_objContext(Payload_bindingContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLParser.Payload_bindingContext + super().__init__(parser) + self.copyFrom(ctx) + + def STRINGDOLLAR(self): + return self.getToken(ASLParser.STRINGDOLLAR, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def STRINGPATHCONTEXTOBJ(self): + return self.getToken(ASLParser.STRINGPATHCONTEXTOBJ, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterPayload_binding_path_context_obj"): + listener.enterPayload_binding_path_context_obj(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitPayload_binding_path_context_obj"): + listener.exitPayload_binding_path_context_obj(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitPayload_binding_path_context_obj"): + return visitor.visitPayload_binding_path_context_obj(self) + else: + return visitor.visitChildren(self) + + class Payload_binding_intrinsic_funcContext(Payload_bindingContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLParser.Payload_bindingContext + super().__init__(parser) + self.copyFrom(ctx) + + def STRINGDOLLAR(self): + return self.getToken(ASLParser.STRINGDOLLAR, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def intrinsic_func(self): + return self.getTypedRuleContext(ASLParser.Intrinsic_funcContext, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterPayload_binding_intrinsic_func"): + listener.enterPayload_binding_intrinsic_func(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitPayload_binding_intrinsic_func"): + listener.exitPayload_binding_intrinsic_func(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitPayload_binding_intrinsic_func"): + return visitor.visitPayload_binding_intrinsic_func(self) + else: + return visitor.visitChildren(self) + + class Payload_binding_valueContext(Payload_bindingContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLParser.Payload_bindingContext + super().__init__(parser) + self.copyFrom(ctx) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def payload_value_decl(self): + return self.getTypedRuleContext(ASLParser.Payload_value_declContext, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterPayload_binding_value"): + listener.enterPayload_binding_value(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitPayload_binding_value"): + listener.exitPayload_binding_value(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitPayload_binding_value"): + return visitor.visitPayload_binding_value(self) + else: + return visitor.visitChildren(self) + + def payload_binding(self): + + localctx = ASLParser.Payload_bindingContext(self, self._ctx, self.state) + self.enterRule(localctx, 66, self.RULE_payload_binding) + try: + self.state = 390 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 10, self._ctx) + if la_ == 1: + localctx = ASLParser.Payload_binding_pathContext(self, localctx) + self.enterOuterAlt(localctx, 1) + self.state = 377 + self.match(ASLParser.STRINGDOLLAR) + self.state = 378 + self.match(ASLParser.COLON) + self.state = 379 + self.match(ASLParser.STRINGPATH) + pass + + elif la_ == 2: + localctx = ASLParser.Payload_binding_path_context_objContext( + self, localctx + ) + self.enterOuterAlt(localctx, 2) + self.state = 380 + self.match(ASLParser.STRINGDOLLAR) + self.state = 381 + self.match(ASLParser.COLON) + self.state = 382 + self.match(ASLParser.STRINGPATHCONTEXTOBJ) + pass + + elif la_ == 3: + localctx = ASLParser.Payload_binding_intrinsic_funcContext( + self, localctx + ) + self.enterOuterAlt(localctx, 3) + self.state = 383 + self.match(ASLParser.STRINGDOLLAR) + self.state = 384 + self.match(ASLParser.COLON) + self.state = 385 + self.intrinsic_func() + pass + + elif la_ == 4: + localctx = ASLParser.Payload_binding_valueContext(self, localctx) + self.enterOuterAlt(localctx, 4) + self.state = 386 + self.keyword_or_string() + self.state = 387 + self.match(ASLParser.COLON) + self.state = 388 + self.payload_value_decl() + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Intrinsic_funcContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def STRING(self): + return self.getToken(ASLParser.STRING, 0) + + def getRuleIndex(self): + return ASLParser.RULE_intrinsic_func + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterIntrinsic_func"): + listener.enterIntrinsic_func(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitIntrinsic_func"): + listener.exitIntrinsic_func(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitIntrinsic_func"): + return visitor.visitIntrinsic_func(self) + else: + return visitor.visitChildren(self) + + def intrinsic_func(self): + + localctx = ASLParser.Intrinsic_funcContext(self, self._ctx, self.state) + self.enterRule(localctx, 68, self.RULE_intrinsic_func) + try: + self.enterOuterAlt(localctx, 1) + self.state = 392 + self.match(ASLParser.STRING) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Payload_arr_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def LBRACK(self): + return self.getToken(ASLParser.LBRACK, 0) + + def payload_value_decl(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Payload_value_declContext) + else: + return self.getTypedRuleContext(ASLParser.Payload_value_declContext, i) + + def RBRACK(self): + return self.getToken(ASLParser.RBRACK, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_payload_arr_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterPayload_arr_decl"): + listener.enterPayload_arr_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitPayload_arr_decl"): + listener.exitPayload_arr_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitPayload_arr_decl"): + return visitor.visitPayload_arr_decl(self) + else: + return visitor.visitChildren(self) + + def payload_arr_decl(self): + + localctx = ASLParser.Payload_arr_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 70, self.RULE_payload_arr_decl) + self._la = 0 # Token type + try: + self.state = 407 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 12, self._ctx) + if la_ == 1: + self.enterOuterAlt(localctx, 1) + self.state = 394 + self.match(ASLParser.LBRACK) + self.state = 395 + self.payload_value_decl() + self.state = 400 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 396 + self.match(ASLParser.COMMA) + self.state = 397 + self.payload_value_decl() + self.state = 402 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 403 + self.match(ASLParser.RBRACK) + pass + + elif la_ == 2: + self.enterOuterAlt(localctx, 2) + self.state = 405 + self.match(ASLParser.LBRACK) + self.state = 406 + self.match(ASLParser.RBRACK) + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Payload_value_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def payload_binding(self): + return self.getTypedRuleContext(ASLParser.Payload_bindingContext, 0) + + def payload_arr_decl(self): + return self.getTypedRuleContext(ASLParser.Payload_arr_declContext, 0) + + def payload_tmpl_decl(self): + return self.getTypedRuleContext(ASLParser.Payload_tmpl_declContext, 0) + + def payload_value_lit(self): + return self.getTypedRuleContext(ASLParser.Payload_value_litContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_payload_value_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterPayload_value_decl"): + listener.enterPayload_value_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitPayload_value_decl"): + listener.exitPayload_value_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitPayload_value_decl"): + return visitor.visitPayload_value_decl(self) + else: + return visitor.visitChildren(self) + + def payload_value_decl(self): + + localctx = ASLParser.Payload_value_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 72, self.RULE_payload_value_decl) + try: + self.state = 413 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 13, self._ctx) + if la_ == 1: + self.enterOuterAlt(localctx, 1) + self.state = 409 + self.payload_binding() + pass + + elif la_ == 2: + self.enterOuterAlt(localctx, 2) + self.state = 410 + self.payload_arr_decl() + pass + + elif la_ == 3: + self.enterOuterAlt(localctx, 3) + self.state = 411 + self.payload_tmpl_decl() + pass + + elif la_ == 4: + self.enterOuterAlt(localctx, 4) + self.state = 412 + self.payload_value_lit() + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Payload_value_litContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def getRuleIndex(self): + return ASLParser.RULE_payload_value_lit + + def copyFrom(self, ctx: ParserRuleContext): + super().copyFrom(ctx) + + class Payload_value_boolContext(Payload_value_litContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLParser.Payload_value_litContext + super().__init__(parser) + self.copyFrom(ctx) + + def TRUE(self): + return self.getToken(ASLParser.TRUE, 0) + + def FALSE(self): + return self.getToken(ASLParser.FALSE, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterPayload_value_bool"): + listener.enterPayload_value_bool(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitPayload_value_bool"): + listener.exitPayload_value_bool(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitPayload_value_bool"): + return visitor.visitPayload_value_bool(self) + else: + return visitor.visitChildren(self) + + class Payload_value_intContext(Payload_value_litContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLParser.Payload_value_litContext + super().__init__(parser) + self.copyFrom(ctx) + + def INT(self): + return self.getToken(ASLParser.INT, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterPayload_value_int"): + listener.enterPayload_value_int(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitPayload_value_int"): + listener.exitPayload_value_int(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitPayload_value_int"): + return visitor.visitPayload_value_int(self) + else: + return visitor.visitChildren(self) + + class Payload_value_strContext(Payload_value_litContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLParser.Payload_value_litContext + super().__init__(parser) + self.copyFrom(ctx) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterPayload_value_str"): + listener.enterPayload_value_str(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitPayload_value_str"): + listener.exitPayload_value_str(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitPayload_value_str"): + return visitor.visitPayload_value_str(self) + else: + return visitor.visitChildren(self) + + class Payload_value_floatContext(Payload_value_litContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLParser.Payload_value_litContext + super().__init__(parser) + self.copyFrom(ctx) + + def NUMBER(self): + return self.getToken(ASLParser.NUMBER, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterPayload_value_float"): + listener.enterPayload_value_float(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitPayload_value_float"): + listener.exitPayload_value_float(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitPayload_value_float"): + return visitor.visitPayload_value_float(self) + else: + return visitor.visitChildren(self) + + class Payload_value_nullContext(Payload_value_litContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLParser.Payload_value_litContext + super().__init__(parser) + self.copyFrom(ctx) + + def NULL(self): + return self.getToken(ASLParser.NULL, 0) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterPayload_value_null"): + listener.enterPayload_value_null(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitPayload_value_null"): + listener.exitPayload_value_null(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitPayload_value_null"): + return visitor.visitPayload_value_null(self) + else: + return visitor.visitChildren(self) + + def payload_value_lit(self): + + localctx = ASLParser.Payload_value_litContext(self, self._ctx, self.state) + self.enterRule(localctx, 74, self.RULE_payload_value_lit) + self._la = 0 # Token type + try: + self.state = 420 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [132]: + localctx = ASLParser.Payload_value_floatContext(self, localctx) + self.enterOuterAlt(localctx, 1) + self.state = 415 + self.match(ASLParser.NUMBER) + pass + elif token in [131]: + localctx = ASLParser.Payload_value_intContext(self, localctx) + self.enterOuterAlt(localctx, 2) + self.state = 416 + self.match(ASLParser.INT) + pass + elif token in [7, 8]: + localctx = ASLParser.Payload_value_boolContext(self, localctx) + self.enterOuterAlt(localctx, 3) + self.state = 417 + _la = self._input.LA(1) + if not (_la == 7 or _la == 8): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + pass + elif token in [9]: + localctx = ASLParser.Payload_value_nullContext(self, localctx) + self.enterOuterAlt(localctx, 4) + self.state = 418 + self.match(ASLParser.NULL) + pass + elif token in [ + 10, + 11, + 12, + 13, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + ]: + localctx = ASLParser.Payload_value_strContext(self, localctx) + self.enterOuterAlt(localctx, 5) + self.state = 419 + self.keyword_or_string() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Result_selector_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def RESULTSELECTOR(self): + return self.getToken(ASLParser.RESULTSELECTOR, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def payload_tmpl_decl(self): + return self.getTypedRuleContext(ASLParser.Payload_tmpl_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_result_selector_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterResult_selector_decl"): + listener.enterResult_selector_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitResult_selector_decl"): + listener.exitResult_selector_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitResult_selector_decl"): + return visitor.visitResult_selector_decl(self) + else: + return visitor.visitChildren(self) + + def result_selector_decl(self): + + localctx = ASLParser.Result_selector_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 76, self.RULE_result_selector_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 422 + self.match(ASLParser.RESULTSELECTOR) + self.state = 423 + self.match(ASLParser.COLON) + self.state = 424 + self.payload_tmpl_decl() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class State_typeContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def TASK(self): + return self.getToken(ASLParser.TASK, 0) + + def PASS(self): + return self.getToken(ASLParser.PASS, 0) + + def CHOICE(self): + return self.getToken(ASLParser.CHOICE, 0) + + def FAIL(self): + return self.getToken(ASLParser.FAIL, 0) + + def SUCCEED(self): + return self.getToken(ASLParser.SUCCEED, 0) + + def WAIT(self): + return self.getToken(ASLParser.WAIT, 0) + + def MAP(self): + return self.getToken(ASLParser.MAP, 0) + + def PARALLEL(self): + return self.getToken(ASLParser.PARALLEL, 0) + + def getRuleIndex(self): + return ASLParser.RULE_state_type + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterState_type"): + listener.enterState_type(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitState_type"): + listener.exitState_type(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitState_type"): + return visitor.visitState_type(self) + else: + return visitor.visitChildren(self) + + def state_type(self): + + localctx = ASLParser.State_typeContext(self, self._ctx, self.state) + self.enterRule(localctx, 78, self.RULE_state_type) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 426 + _la = self._input.LA(1) + if not ((((_la) & ~0x3F) == 0 and ((1 << _la) & 16711680) != 0)): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Choices_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def CHOICES(self): + return self.getToken(ASLParser.CHOICES, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def LBRACK(self): + return self.getToken(ASLParser.LBRACK, 0) + + def choice_rule(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Choice_ruleContext) + else: + return self.getTypedRuleContext(ASLParser.Choice_ruleContext, i) + + def RBRACK(self): + return self.getToken(ASLParser.RBRACK, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_choices_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterChoices_decl"): + listener.enterChoices_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitChoices_decl"): + listener.exitChoices_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitChoices_decl"): + return visitor.visitChoices_decl(self) + else: + return visitor.visitChildren(self) + + def choices_decl(self): + + localctx = ASLParser.Choices_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 80, self.RULE_choices_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 428 + self.match(ASLParser.CHOICES) + self.state = 429 + self.match(ASLParser.COLON) + self.state = 430 + self.match(ASLParser.LBRACK) + self.state = 431 + self.choice_rule() + self.state = 436 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 432 + self.match(ASLParser.COMMA) + self.state = 433 + self.choice_rule() + self.state = 438 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 439 + self.match(ASLParser.RBRACK) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Choice_ruleContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def getRuleIndex(self): + return ASLParser.RULE_choice_rule + + def copyFrom(self, ctx: ParserRuleContext): + super().copyFrom(ctx) + + class Choice_rule_comparison_variableContext(Choice_ruleContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLParser.Choice_ruleContext + super().__init__(parser) + self.copyFrom(ctx) + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def comparison_variable_stmt(self, i: int = None): + if i is None: + return self.getTypedRuleContexts( + ASLParser.Comparison_variable_stmtContext + ) + else: + return self.getTypedRuleContext( + ASLParser.Comparison_variable_stmtContext, i + ) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterChoice_rule_comparison_variable"): + listener.enterChoice_rule_comparison_variable(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitChoice_rule_comparison_variable"): + listener.exitChoice_rule_comparison_variable(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitChoice_rule_comparison_variable"): + return visitor.visitChoice_rule_comparison_variable(self) + else: + return visitor.visitChildren(self) + + class Choice_rule_comparison_compositeContext(Choice_ruleContext): + def __init__( + self, parser, ctx: ParserRuleContext + ): # actually a ASLParser.Choice_ruleContext + super().__init__(parser) + self.copyFrom(ctx) + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def comparison_composite_stmt(self, i: int = None): + if i is None: + return self.getTypedRuleContexts( + ASLParser.Comparison_composite_stmtContext + ) + else: + return self.getTypedRuleContext( + ASLParser.Comparison_composite_stmtContext, i + ) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterChoice_rule_comparison_composite"): + listener.enterChoice_rule_comparison_composite(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitChoice_rule_comparison_composite"): + listener.exitChoice_rule_comparison_composite(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitChoice_rule_comparison_composite"): + return visitor.visitChoice_rule_comparison_composite(self) + else: + return visitor.visitChildren(self) + + def choice_rule(self): + + localctx = ASLParser.Choice_ruleContext(self, self._ctx, self.state) + self.enterRule(localctx, 82, self.RULE_choice_rule) + self._la = 0 # Token type + try: + self.state = 462 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 18, self._ctx) + if la_ == 1: + localctx = ASLParser.Choice_rule_comparison_variableContext( + self, localctx + ) + self.enterOuterAlt(localctx, 1) + self.state = 441 + self.match(ASLParser.LBRACE) + self.state = 442 + self.comparison_variable_stmt() + self.state = 445 + self._errHandler.sync(self) + _la = self._input.LA(1) + while True: + self.state = 443 + self.match(ASLParser.COMMA) + self.state = 444 + self.comparison_variable_stmt() + self.state = 447 + self._errHandler.sync(self) + _la = self._input.LA(1) + if not (_la == 1): + break + + self.state = 449 + self.match(ASLParser.RBRACE) + pass + + elif la_ == 2: + localctx = ASLParser.Choice_rule_comparison_compositeContext( + self, localctx + ) + self.enterOuterAlt(localctx, 2) + self.state = 451 + self.match(ASLParser.LBRACE) + self.state = 452 + self.comparison_composite_stmt() + self.state = 457 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 453 + self.match(ASLParser.COMMA) + self.state = 454 + self.comparison_composite_stmt() + self.state = 459 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 460 + self.match(ASLParser.RBRACE) + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Comparison_variable_stmtContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def variable_decl(self): + return self.getTypedRuleContext(ASLParser.Variable_declContext, 0) + + def comparison_func(self): + return self.getTypedRuleContext(ASLParser.Comparison_funcContext, 0) + + def next_decl(self): + return self.getTypedRuleContext(ASLParser.Next_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_comparison_variable_stmt + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterComparison_variable_stmt"): + listener.enterComparison_variable_stmt(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitComparison_variable_stmt"): + listener.exitComparison_variable_stmt(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitComparison_variable_stmt"): + return visitor.visitComparison_variable_stmt(self) + else: + return visitor.visitChildren(self) + + def comparison_variable_stmt(self): + + localctx = ASLParser.Comparison_variable_stmtContext( + self, self._ctx, self.state + ) + self.enterRule(localctx, 84, self.RULE_comparison_variable_stmt) + try: + self.state = 467 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [25]: + self.enterOuterAlt(localctx, 1) + self.state = 464 + self.variable_decl() + pass + elif token in [ + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + ]: + self.enterOuterAlt(localctx, 2) + self.state = 465 + self.comparison_func() + pass + elif token in [103]: + self.enterOuterAlt(localctx, 3) + self.state = 466 + self.next_decl() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Comparison_composite_stmtContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def comparison_composite(self): + return self.getTypedRuleContext(ASLParser.Comparison_compositeContext, 0) + + def next_decl(self): + return self.getTypedRuleContext(ASLParser.Next_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_comparison_composite_stmt + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterComparison_composite_stmt"): + listener.enterComparison_composite_stmt(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitComparison_composite_stmt"): + listener.exitComparison_composite_stmt(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitComparison_composite_stmt"): + return visitor.visitComparison_composite_stmt(self) + else: + return visitor.visitChildren(self) + + def comparison_composite_stmt(self): + + localctx = ASLParser.Comparison_composite_stmtContext( + self, self._ctx, self.state + ) + self.enterRule(localctx, 86, self.RULE_comparison_composite_stmt) + try: + self.state = 471 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [28, 37, 48]: + self.enterOuterAlt(localctx, 1) + self.state = 469 + self.comparison_composite() + pass + elif token in [103]: + self.enterOuterAlt(localctx, 2) + self.state = 470 + self.next_decl() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Comparison_compositeContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def choice_operator(self): + return self.getTypedRuleContext(ASLParser.Choice_operatorContext, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def choice_rule(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Choice_ruleContext) + else: + return self.getTypedRuleContext(ASLParser.Choice_ruleContext, i) + + def LBRACK(self): + return self.getToken(ASLParser.LBRACK, 0) + + def RBRACK(self): + return self.getToken(ASLParser.RBRACK, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_comparison_composite + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterComparison_composite"): + listener.enterComparison_composite(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitComparison_composite"): + listener.exitComparison_composite(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitComparison_composite"): + return visitor.visitComparison_composite(self) + else: + return visitor.visitChildren(self) + + def comparison_composite(self): + + localctx = ASLParser.Comparison_compositeContext(self, self._ctx, self.state) + self.enterRule(localctx, 88, self.RULE_comparison_composite) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 473 + self.choice_operator() + self.state = 474 + self.match(ASLParser.COLON) + self.state = 487 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [5]: + self.state = 475 + self.choice_rule() + pass + elif token in [3]: + self.state = 476 + self.match(ASLParser.LBRACK) + self.state = 477 + self.choice_rule() + self.state = 482 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 478 + self.match(ASLParser.COMMA) + self.state = 479 + self.choice_rule() + self.state = 484 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 485 + self.match(ASLParser.RBRACK) + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Variable_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def VARIABLE(self): + return self.getToken(ASLParser.VARIABLE, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_variable_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterVariable_decl"): + listener.enterVariable_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitVariable_decl"): + listener.exitVariable_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitVariable_decl"): + return visitor.visitVariable_decl(self) + else: + return visitor.visitChildren(self) + + def variable_decl(self): + + localctx = ASLParser.Variable_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 90, self.RULE_variable_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 489 + self.match(ASLParser.VARIABLE) + self.state = 490 + self.match(ASLParser.COLON) + self.state = 491 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Comparison_funcContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def comparison_op(self): + return self.getTypedRuleContext(ASLParser.Comparison_opContext, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def json_value_decl(self): + return self.getTypedRuleContext(ASLParser.Json_value_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_comparison_func + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterComparison_func"): + listener.enterComparison_func(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitComparison_func"): + listener.exitComparison_func(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitComparison_func"): + return visitor.visitComparison_func(self) + else: + return visitor.visitChildren(self) + + def comparison_func(self): + + localctx = ASLParser.Comparison_funcContext(self, self._ctx, self.state) + self.enterRule(localctx, 92, self.RULE_comparison_func) + try: + self.enterOuterAlt(localctx, 1) + self.state = 493 + self.comparison_op() + self.state = 494 + self.match(ASLParser.COLON) + self.state = 495 + self.json_value_decl() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Branches_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def BRANCHES(self): + return self.getToken(ASLParser.BRANCHES, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def LBRACK(self): + return self.getToken(ASLParser.LBRACK, 0) + + def program_decl(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Program_declContext) + else: + return self.getTypedRuleContext(ASLParser.Program_declContext, i) + + def RBRACK(self): + return self.getToken(ASLParser.RBRACK, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_branches_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterBranches_decl"): + listener.enterBranches_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitBranches_decl"): + listener.exitBranches_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitBranches_decl"): + return visitor.visitBranches_decl(self) + else: + return visitor.visitChildren(self) + + def branches_decl(self): + + localctx = ASLParser.Branches_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 94, self.RULE_branches_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 497 + self.match(ASLParser.BRANCHES) + self.state = 498 + self.match(ASLParser.COLON) + self.state = 499 + self.match(ASLParser.LBRACK) + self.state = 500 + self.program_decl() + self.state = 505 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 501 + self.match(ASLParser.COMMA) + self.state = 502 + self.program_decl() + self.state = 507 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 508 + self.match(ASLParser.RBRACK) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Item_processor_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def ITEMPROCESSOR(self): + return self.getToken(ASLParser.ITEMPROCESSOR, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def item_processor_item(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Item_processor_itemContext) + else: + return self.getTypedRuleContext(ASLParser.Item_processor_itemContext, i) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_item_processor_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterItem_processor_decl"): + listener.enterItem_processor_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitItem_processor_decl"): + listener.exitItem_processor_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitItem_processor_decl"): + return visitor.visitItem_processor_decl(self) + else: + return visitor.visitChildren(self) + + def item_processor_decl(self): + + localctx = ASLParser.Item_processor_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 96, self.RULE_item_processor_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 510 + self.match(ASLParser.ITEMPROCESSOR) + self.state = 511 + self.match(ASLParser.COLON) + self.state = 512 + self.match(ASLParser.LBRACE) + self.state = 513 + self.item_processor_item() + self.state = 518 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 514 + self.match(ASLParser.COMMA) + self.state = 515 + self.item_processor_item() + self.state = 520 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 521 + self.match(ASLParser.RBRACE) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Item_processor_itemContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def processor_config_decl(self): + return self.getTypedRuleContext(ASLParser.Processor_config_declContext, 0) + + def startat_decl(self): + return self.getTypedRuleContext(ASLParser.Startat_declContext, 0) + + def states_decl(self): + return self.getTypedRuleContext(ASLParser.States_declContext, 0) + + def comment_decl(self): + return self.getTypedRuleContext(ASLParser.Comment_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_item_processor_item + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterItem_processor_item"): + listener.enterItem_processor_item(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitItem_processor_item"): + listener.exitItem_processor_item(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitItem_processor_item"): + return visitor.visitItem_processor_item(self) + else: + return visitor.visitChildren(self) + + def item_processor_item(self): + + localctx = ASLParser.Item_processor_itemContext(self, self._ctx, self.state) + self.enterRule(localctx, 98, self.RULE_item_processor_item) + try: + self.state = 527 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [78]: + self.enterOuterAlt(localctx, 1) + self.state = 523 + self.processor_config_decl() + pass + elif token in [12]: + self.enterOuterAlt(localctx, 2) + self.state = 524 + self.startat_decl() + pass + elif token in [11]: + self.enterOuterAlt(localctx, 3) + self.state = 525 + self.states_decl() + pass + elif token in [10]: + self.enterOuterAlt(localctx, 4) + self.state = 526 + self.comment_decl() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Processor_config_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def PROCESSORCONFIG(self): + return self.getToken(ASLParser.PROCESSORCONFIG, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def processor_config_field(self, i: int = None): + if i is None: + return self.getTypedRuleContexts( + ASLParser.Processor_config_fieldContext + ) + else: + return self.getTypedRuleContext( + ASLParser.Processor_config_fieldContext, i + ) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_processor_config_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterProcessor_config_decl"): + listener.enterProcessor_config_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitProcessor_config_decl"): + listener.exitProcessor_config_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitProcessor_config_decl"): + return visitor.visitProcessor_config_decl(self) + else: + return visitor.visitChildren(self) + + def processor_config_decl(self): + + localctx = ASLParser.Processor_config_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 100, self.RULE_processor_config_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 529 + self.match(ASLParser.PROCESSORCONFIG) + self.state = 530 + self.match(ASLParser.COLON) + self.state = 531 + self.match(ASLParser.LBRACE) + self.state = 532 + self.processor_config_field() + self.state = 537 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 533 + self.match(ASLParser.COMMA) + self.state = 534 + self.processor_config_field() + self.state = 539 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 540 + self.match(ASLParser.RBRACE) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Processor_config_fieldContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def mode_decl(self): + return self.getTypedRuleContext(ASLParser.Mode_declContext, 0) + + def execution_decl(self): + return self.getTypedRuleContext(ASLParser.Execution_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_processor_config_field + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterProcessor_config_field"): + listener.enterProcessor_config_field(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitProcessor_config_field"): + listener.exitProcessor_config_field(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitProcessor_config_field"): + return visitor.visitProcessor_config_field(self) + else: + return visitor.visitChildren(self) + + def processor_config_field(self): + + localctx = ASLParser.Processor_config_fieldContext(self, self._ctx, self.state) + self.enterRule(localctx, 102, self.RULE_processor_config_field) + try: + self.state = 544 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [79]: + self.enterOuterAlt(localctx, 1) + self.state = 542 + self.mode_decl() + pass + elif token in [82]: + self.enterOuterAlt(localctx, 2) + self.state = 543 + self.execution_decl() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Mode_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def MODE(self): + return self.getToken(ASLParser.MODE, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def mode_type(self): + return self.getTypedRuleContext(ASLParser.Mode_typeContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_mode_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterMode_decl"): + listener.enterMode_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitMode_decl"): + listener.exitMode_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitMode_decl"): + return visitor.visitMode_decl(self) + else: + return visitor.visitChildren(self) + + def mode_decl(self): + + localctx = ASLParser.Mode_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 104, self.RULE_mode_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 546 + self.match(ASLParser.MODE) + self.state = 547 + self.match(ASLParser.COLON) + self.state = 548 + self.mode_type() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Mode_typeContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def INLINE(self): + return self.getToken(ASLParser.INLINE, 0) + + def DISTRIBUTED(self): + return self.getToken(ASLParser.DISTRIBUTED, 0) + + def getRuleIndex(self): + return ASLParser.RULE_mode_type + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterMode_type"): + listener.enterMode_type(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitMode_type"): + listener.exitMode_type(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitMode_type"): + return visitor.visitMode_type(self) + else: + return visitor.visitChildren(self) + + def mode_type(self): + + localctx = ASLParser.Mode_typeContext(self, self._ctx, self.state) + self.enterRule(localctx, 106, self.RULE_mode_type) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 550 + _la = self._input.LA(1) + if not (_la == 80 or _la == 81): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Execution_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def EXECUTIONTYPE(self): + return self.getToken(ASLParser.EXECUTIONTYPE, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def execution_type(self): + return self.getTypedRuleContext(ASLParser.Execution_typeContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_execution_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterExecution_decl"): + listener.enterExecution_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitExecution_decl"): + listener.exitExecution_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitExecution_decl"): + return visitor.visitExecution_decl(self) + else: + return visitor.visitChildren(self) + + def execution_decl(self): + + localctx = ASLParser.Execution_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 108, self.RULE_execution_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 552 + self.match(ASLParser.EXECUTIONTYPE) + self.state = 553 + self.match(ASLParser.COLON) + self.state = 554 + self.execution_type() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Execution_typeContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def STANDARD(self): + return self.getToken(ASLParser.STANDARD, 0) + + def getRuleIndex(self): + return ASLParser.RULE_execution_type + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterExecution_type"): + listener.enterExecution_type(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitExecution_type"): + listener.exitExecution_type(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitExecution_type"): + return visitor.visitExecution_type(self) + else: + return visitor.visitChildren(self) + + def execution_type(self): + + localctx = ASLParser.Execution_typeContext(self, self._ctx, self.state) + self.enterRule(localctx, 110, self.RULE_execution_type) + try: + self.enterOuterAlt(localctx, 1) + self.state = 556 + self.match(ASLParser.STANDARD) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Iterator_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def ITERATOR(self): + return self.getToken(ASLParser.ITERATOR, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def iterator_decl_item(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Iterator_decl_itemContext) + else: + return self.getTypedRuleContext(ASLParser.Iterator_decl_itemContext, i) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_iterator_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterIterator_decl"): + listener.enterIterator_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitIterator_decl"): + listener.exitIterator_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitIterator_decl"): + return visitor.visitIterator_decl(self) + else: + return visitor.visitChildren(self) + + def iterator_decl(self): + + localctx = ASLParser.Iterator_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 112, self.RULE_iterator_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 558 + self.match(ASLParser.ITERATOR) + self.state = 559 + self.match(ASLParser.COLON) + self.state = 560 + self.match(ASLParser.LBRACE) + self.state = 561 + self.iterator_decl_item() + self.state = 566 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 562 + self.match(ASLParser.COMMA) + self.state = 563 + self.iterator_decl_item() + self.state = 568 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 569 + self.match(ASLParser.RBRACE) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Iterator_decl_itemContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def startat_decl(self): + return self.getTypedRuleContext(ASLParser.Startat_declContext, 0) + + def states_decl(self): + return self.getTypedRuleContext(ASLParser.States_declContext, 0) + + def comment_decl(self): + return self.getTypedRuleContext(ASLParser.Comment_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_iterator_decl_item + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterIterator_decl_item"): + listener.enterIterator_decl_item(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitIterator_decl_item"): + listener.exitIterator_decl_item(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitIterator_decl_item"): + return visitor.visitIterator_decl_item(self) + else: + return visitor.visitChildren(self) + + def iterator_decl_item(self): + + localctx = ASLParser.Iterator_decl_itemContext(self, self._ctx, self.state) + self.enterRule(localctx, 114, self.RULE_iterator_decl_item) + try: + self.state = 574 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [12]: + self.enterOuterAlt(localctx, 1) + self.state = 571 + self.startat_decl() + pass + elif token in [11]: + self.enterOuterAlt(localctx, 2) + self.state = 572 + self.states_decl() + pass + elif token in [10]: + self.enterOuterAlt(localctx, 3) + self.state = 573 + self.comment_decl() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Item_selector_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def ITEMSELECTOR(self): + return self.getToken(ASLParser.ITEMSELECTOR, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def payload_tmpl_decl(self): + return self.getTypedRuleContext(ASLParser.Payload_tmpl_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_item_selector_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterItem_selector_decl"): + listener.enterItem_selector_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitItem_selector_decl"): + listener.exitItem_selector_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitItem_selector_decl"): + return visitor.visitItem_selector_decl(self) + else: + return visitor.visitChildren(self) + + def item_selector_decl(self): + + localctx = ASLParser.Item_selector_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 116, self.RULE_item_selector_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 576 + self.match(ASLParser.ITEMSELECTOR) + self.state = 577 + self.match(ASLParser.COLON) + self.state = 578 + self.payload_tmpl_decl() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Item_reader_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def ITEMREADER(self): + return self.getToken(ASLParser.ITEMREADER, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def items_reader_field(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Items_reader_fieldContext) + else: + return self.getTypedRuleContext(ASLParser.Items_reader_fieldContext, i) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_item_reader_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterItem_reader_decl"): + listener.enterItem_reader_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitItem_reader_decl"): + listener.exitItem_reader_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitItem_reader_decl"): + return visitor.visitItem_reader_decl(self) + else: + return visitor.visitChildren(self) + + def item_reader_decl(self): + + localctx = ASLParser.Item_reader_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 118, self.RULE_item_reader_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 580 + self.match(ASLParser.ITEMREADER) + self.state = 581 + self.match(ASLParser.COLON) + self.state = 582 + self.match(ASLParser.LBRACE) + self.state = 583 + self.items_reader_field() + self.state = 588 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 584 + self.match(ASLParser.COMMA) + self.state = 585 + self.items_reader_field() + self.state = 590 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 591 + self.match(ASLParser.RBRACE) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Items_reader_fieldContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def resource_decl(self): + return self.getTypedRuleContext(ASLParser.Resource_declContext, 0) + + def parameters_decl(self): + return self.getTypedRuleContext(ASLParser.Parameters_declContext, 0) + + def reader_config_decl(self): + return self.getTypedRuleContext(ASLParser.Reader_config_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_items_reader_field + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterItems_reader_field"): + listener.enterItems_reader_field(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitItems_reader_field"): + listener.exitItems_reader_field(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitItems_reader_field"): + return visitor.visitItems_reader_field(self) + else: + return visitor.visitChildren(self) + + def items_reader_field(self): + + localctx = ASLParser.Items_reader_fieldContext(self, self._ctx, self.state) + self.enterRule(localctx, 120, self.RULE_items_reader_field) + try: + self.state = 596 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [88]: + self.enterOuterAlt(localctx, 1) + self.state = 593 + self.resource_decl() + pass + elif token in [94]: + self.enterOuterAlt(localctx, 2) + self.state = 594 + self.parameters_decl() + pass + elif token in [97]: + self.enterOuterAlt(localctx, 3) + self.state = 595 + self.reader_config_decl() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Reader_config_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def READERCONFIG(self): + return self.getToken(ASLParser.READERCONFIG, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def reader_config_field(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Reader_config_fieldContext) + else: + return self.getTypedRuleContext(ASLParser.Reader_config_fieldContext, i) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_reader_config_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterReader_config_decl"): + listener.enterReader_config_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitReader_config_decl"): + listener.exitReader_config_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitReader_config_decl"): + return visitor.visitReader_config_decl(self) + else: + return visitor.visitChildren(self) + + def reader_config_decl(self): + + localctx = ASLParser.Reader_config_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 122, self.RULE_reader_config_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 598 + self.match(ASLParser.READERCONFIG) + self.state = 599 + self.match(ASLParser.COLON) + self.state = 600 + self.match(ASLParser.LBRACE) + self.state = 601 + self.reader_config_field() + self.state = 606 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 602 + self.match(ASLParser.COMMA) + self.state = 603 + self.reader_config_field() + self.state = 608 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 609 + self.match(ASLParser.RBRACE) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Reader_config_fieldContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def input_type_decl(self): + return self.getTypedRuleContext(ASLParser.Input_type_declContext, 0) + + def csv_header_location_decl(self): + return self.getTypedRuleContext( + ASLParser.Csv_header_location_declContext, 0 + ) + + def csv_headers_decl(self): + return self.getTypedRuleContext(ASLParser.Csv_headers_declContext, 0) + + def max_items_decl(self): + return self.getTypedRuleContext(ASLParser.Max_items_declContext, 0) + + def max_items_path_decl(self): + return self.getTypedRuleContext(ASLParser.Max_items_path_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_reader_config_field + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterReader_config_field"): + listener.enterReader_config_field(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitReader_config_field"): + listener.exitReader_config_field(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitReader_config_field"): + return visitor.visitReader_config_field(self) + else: + return visitor.visitChildren(self) + + def reader_config_field(self): + + localctx = ASLParser.Reader_config_fieldContext(self, self._ctx, self.state) + self.enterRule(localctx, 124, self.RULE_reader_config_field) + try: + self.state = 616 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [98]: + self.enterOuterAlt(localctx, 1) + self.state = 611 + self.input_type_decl() + pass + elif token in [99]: + self.enterOuterAlt(localctx, 2) + self.state = 612 + self.csv_header_location_decl() + pass + elif token in [100]: + self.enterOuterAlt(localctx, 3) + self.state = 613 + self.csv_headers_decl() + pass + elif token in [101]: + self.enterOuterAlt(localctx, 4) + self.state = 614 + self.max_items_decl() + pass + elif token in [102]: + self.enterOuterAlt(localctx, 5) + self.state = 615 + self.max_items_path_decl() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Input_type_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def INPUTTYPE(self): + return self.getToken(ASLParser.INPUTTYPE, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_input_type_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterInput_type_decl"): + listener.enterInput_type_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitInput_type_decl"): + listener.exitInput_type_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitInput_type_decl"): + return visitor.visitInput_type_decl(self) + else: + return visitor.visitChildren(self) + + def input_type_decl(self): + + localctx = ASLParser.Input_type_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 126, self.RULE_input_type_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 618 + self.match(ASLParser.INPUTTYPE) + self.state = 619 + self.match(ASLParser.COLON) + self.state = 620 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Csv_header_location_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def CSVHEADERLOCATION(self): + return self.getToken(ASLParser.CSVHEADERLOCATION, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_csv_header_location_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterCsv_header_location_decl"): + listener.enterCsv_header_location_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitCsv_header_location_decl"): + listener.exitCsv_header_location_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitCsv_header_location_decl"): + return visitor.visitCsv_header_location_decl(self) + else: + return visitor.visitChildren(self) + + def csv_header_location_decl(self): + + localctx = ASLParser.Csv_header_location_declContext( + self, self._ctx, self.state + ) + self.enterRule(localctx, 128, self.RULE_csv_header_location_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 622 + self.match(ASLParser.CSVHEADERLOCATION) + self.state = 623 + self.match(ASLParser.COLON) + self.state = 624 + self.keyword_or_string() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Csv_headers_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def CSVHEADERS(self): + return self.getToken(ASLParser.CSVHEADERS, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def LBRACK(self): + return self.getToken(ASLParser.LBRACK, 0) + + def keyword_or_string(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Keyword_or_stringContext) + else: + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, i) + + def RBRACK(self): + return self.getToken(ASLParser.RBRACK, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_csv_headers_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterCsv_headers_decl"): + listener.enterCsv_headers_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitCsv_headers_decl"): + listener.exitCsv_headers_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitCsv_headers_decl"): + return visitor.visitCsv_headers_decl(self) + else: + return visitor.visitChildren(self) + + def csv_headers_decl(self): + + localctx = ASLParser.Csv_headers_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 130, self.RULE_csv_headers_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 626 + self.match(ASLParser.CSVHEADERS) + self.state = 627 + self.match(ASLParser.COLON) + self.state = 628 + self.match(ASLParser.LBRACK) + self.state = 629 + self.keyword_or_string() + self.state = 634 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 630 + self.match(ASLParser.COMMA) + self.state = 631 + self.keyword_or_string() + self.state = 636 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 637 + self.match(ASLParser.RBRACK) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Max_items_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def MAXITEMS(self): + return self.getToken(ASLParser.MAXITEMS, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def INT(self): + return self.getToken(ASLParser.INT, 0) + + def getRuleIndex(self): + return ASLParser.RULE_max_items_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterMax_items_decl"): + listener.enterMax_items_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitMax_items_decl"): + listener.exitMax_items_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitMax_items_decl"): + return visitor.visitMax_items_decl(self) + else: + return visitor.visitChildren(self) + + def max_items_decl(self): + + localctx = ASLParser.Max_items_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 132, self.RULE_max_items_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 639 + self.match(ASLParser.MAXITEMS) + self.state = 640 + self.match(ASLParser.COLON) + self.state = 641 + self.match(ASLParser.INT) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Max_items_path_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def MAXITEMSPATH(self): + return self.getToken(ASLParser.MAXITEMSPATH, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def STRINGPATH(self): + return self.getToken(ASLParser.STRINGPATH, 0) + + def getRuleIndex(self): + return ASLParser.RULE_max_items_path_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterMax_items_path_decl"): + listener.enterMax_items_path_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitMax_items_path_decl"): + listener.exitMax_items_path_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitMax_items_path_decl"): + return visitor.visitMax_items_path_decl(self) + else: + return visitor.visitChildren(self) + + def max_items_path_decl(self): + + localctx = ASLParser.Max_items_path_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 134, self.RULE_max_items_path_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 643 + self.match(ASLParser.MAXITEMSPATH) + self.state = 644 + self.match(ASLParser.COLON) + self.state = 645 + self.match(ASLParser.STRINGPATH) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Retry_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def RETRY(self): + return self.getToken(ASLParser.RETRY, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def LBRACK(self): + return self.getToken(ASLParser.LBRACK, 0) + + def RBRACK(self): + return self.getToken(ASLParser.RBRACK, 0) + + def retrier_decl(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Retrier_declContext) + else: + return self.getTypedRuleContext(ASLParser.Retrier_declContext, i) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_retry_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterRetry_decl"): + listener.enterRetry_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitRetry_decl"): + listener.exitRetry_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitRetry_decl"): + return visitor.visitRetry_decl(self) + else: + return visitor.visitChildren(self) + + def retry_decl(self): + + localctx = ASLParser.Retry_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 136, self.RULE_retry_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 647 + self.match(ASLParser.RETRY) + self.state = 648 + self.match(ASLParser.COLON) + self.state = 649 + self.match(ASLParser.LBRACK) + self.state = 658 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la == 5: + self.state = 650 + self.retrier_decl() + self.state = 655 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 651 + self.match(ASLParser.COMMA) + self.state = 652 + self.retrier_decl() + self.state = 657 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 660 + self.match(ASLParser.RBRACK) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Retrier_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def retrier_stmt(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Retrier_stmtContext) + else: + return self.getTypedRuleContext(ASLParser.Retrier_stmtContext, i) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_retrier_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterRetrier_decl"): + listener.enterRetrier_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitRetrier_decl"): + listener.exitRetrier_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitRetrier_decl"): + return visitor.visitRetrier_decl(self) + else: + return visitor.visitChildren(self) + + def retrier_decl(self): + + localctx = ASLParser.Retrier_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 138, self.RULE_retrier_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 662 + self.match(ASLParser.LBRACE) + self.state = 663 + self.retrier_stmt() + self.state = 668 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 664 + self.match(ASLParser.COMMA) + self.state = 665 + self.retrier_stmt() + self.state = 670 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 671 + self.match(ASLParser.RBRACE) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Retrier_stmtContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def error_equals_decl(self): + return self.getTypedRuleContext(ASLParser.Error_equals_declContext, 0) + + def interval_seconds_decl(self): + return self.getTypedRuleContext(ASLParser.Interval_seconds_declContext, 0) + + def max_attempts_decl(self): + return self.getTypedRuleContext(ASLParser.Max_attempts_declContext, 0) + + def backoff_rate_decl(self): + return self.getTypedRuleContext(ASLParser.Backoff_rate_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_retrier_stmt + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterRetrier_stmt"): + listener.enterRetrier_stmt(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitRetrier_stmt"): + listener.exitRetrier_stmt(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitRetrier_stmt"): + return visitor.visitRetrier_stmt(self) + else: + return visitor.visitChildren(self) + + def retrier_stmt(self): + + localctx = ASLParser.Retrier_stmtContext(self, self._ctx, self.state) + self.enterRule(localctx, 140, self.RULE_retrier_stmt) + try: + self.state = 677 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [108]: + self.enterOuterAlt(localctx, 1) + self.state = 673 + self.error_equals_decl() + pass + elif token in [109]: + self.enterOuterAlt(localctx, 2) + self.state = 674 + self.interval_seconds_decl() + pass + elif token in [110]: + self.enterOuterAlt(localctx, 3) + self.state = 675 + self.max_attempts_decl() + pass + elif token in [111]: + self.enterOuterAlt(localctx, 4) + self.state = 676 + self.backoff_rate_decl() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Error_equals_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def ERROREQUALS(self): + return self.getToken(ASLParser.ERROREQUALS, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def LBRACK(self): + return self.getToken(ASLParser.LBRACK, 0) + + def error_name(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Error_nameContext) + else: + return self.getTypedRuleContext(ASLParser.Error_nameContext, i) + + def RBRACK(self): + return self.getToken(ASLParser.RBRACK, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_error_equals_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterError_equals_decl"): + listener.enterError_equals_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitError_equals_decl"): + listener.exitError_equals_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitError_equals_decl"): + return visitor.visitError_equals_decl(self) + else: + return visitor.visitChildren(self) + + def error_equals_decl(self): + + localctx = ASLParser.Error_equals_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 142, self.RULE_error_equals_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 679 + self.match(ASLParser.ERROREQUALS) + self.state = 680 + self.match(ASLParser.COLON) + self.state = 681 + self.match(ASLParser.LBRACK) + self.state = 682 + self.error_name() + self.state = 687 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 683 + self.match(ASLParser.COMMA) + self.state = 684 + self.error_name() + self.state = 689 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 690 + self.match(ASLParser.RBRACK) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Interval_seconds_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def INTERVALSECONDS(self): + return self.getToken(ASLParser.INTERVALSECONDS, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def INT(self): + return self.getToken(ASLParser.INT, 0) + + def getRuleIndex(self): + return ASLParser.RULE_interval_seconds_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterInterval_seconds_decl"): + listener.enterInterval_seconds_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitInterval_seconds_decl"): + listener.exitInterval_seconds_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitInterval_seconds_decl"): + return visitor.visitInterval_seconds_decl(self) + else: + return visitor.visitChildren(self) + + def interval_seconds_decl(self): + + localctx = ASLParser.Interval_seconds_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 144, self.RULE_interval_seconds_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 692 + self.match(ASLParser.INTERVALSECONDS) + self.state = 693 + self.match(ASLParser.COLON) + self.state = 694 + self.match(ASLParser.INT) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Max_attempts_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def MAXATTEMPTS(self): + return self.getToken(ASLParser.MAXATTEMPTS, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def INT(self): + return self.getToken(ASLParser.INT, 0) + + def getRuleIndex(self): + return ASLParser.RULE_max_attempts_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterMax_attempts_decl"): + listener.enterMax_attempts_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitMax_attempts_decl"): + listener.exitMax_attempts_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitMax_attempts_decl"): + return visitor.visitMax_attempts_decl(self) + else: + return visitor.visitChildren(self) + + def max_attempts_decl(self): + + localctx = ASLParser.Max_attempts_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 146, self.RULE_max_attempts_decl) + try: + self.enterOuterAlt(localctx, 1) + self.state = 696 + self.match(ASLParser.MAXATTEMPTS) + self.state = 697 + self.match(ASLParser.COLON) + self.state = 698 + self.match(ASLParser.INT) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Backoff_rate_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def BACKOFFRATE(self): + return self.getToken(ASLParser.BACKOFFRATE, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def INT(self): + return self.getToken(ASLParser.INT, 0) + + def NUMBER(self): + return self.getToken(ASLParser.NUMBER, 0) + + def getRuleIndex(self): + return ASLParser.RULE_backoff_rate_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterBackoff_rate_decl"): + listener.enterBackoff_rate_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitBackoff_rate_decl"): + listener.exitBackoff_rate_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitBackoff_rate_decl"): + return visitor.visitBackoff_rate_decl(self) + else: + return visitor.visitChildren(self) + + def backoff_rate_decl(self): + + localctx = ASLParser.Backoff_rate_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 148, self.RULE_backoff_rate_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 700 + self.match(ASLParser.BACKOFFRATE) + self.state = 701 + self.match(ASLParser.COLON) + self.state = 702 + _la = self._input.LA(1) + if not (_la == 131 or _la == 132): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Catch_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def CATCH(self): + return self.getToken(ASLParser.CATCH, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def LBRACK(self): + return self.getToken(ASLParser.LBRACK, 0) + + def RBRACK(self): + return self.getToken(ASLParser.RBRACK, 0) + + def catcher_decl(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Catcher_declContext) + else: + return self.getTypedRuleContext(ASLParser.Catcher_declContext, i) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_catch_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterCatch_decl"): + listener.enterCatch_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitCatch_decl"): + listener.exitCatch_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitCatch_decl"): + return visitor.visitCatch_decl(self) + else: + return visitor.visitChildren(self) + + def catch_decl(self): + + localctx = ASLParser.Catch_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 150, self.RULE_catch_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 704 + self.match(ASLParser.CATCH) + self.state = 705 + self.match(ASLParser.COLON) + self.state = 706 + self.match(ASLParser.LBRACK) + self.state = 715 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la == 5: + self.state = 707 + self.catcher_decl() + self.state = 712 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 708 + self.match(ASLParser.COMMA) + self.state = 709 + self.catcher_decl() + self.state = 714 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 717 + self.match(ASLParser.RBRACK) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Catcher_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def catcher_stmt(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Catcher_stmtContext) + else: + return self.getTypedRuleContext(ASLParser.Catcher_stmtContext, i) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_catcher_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterCatcher_decl"): + listener.enterCatcher_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitCatcher_decl"): + listener.exitCatcher_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitCatcher_decl"): + return visitor.visitCatcher_decl(self) + else: + return visitor.visitChildren(self) + + def catcher_decl(self): + + localctx = ASLParser.Catcher_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 152, self.RULE_catcher_decl) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 719 + self.match(ASLParser.LBRACE) + self.state = 720 + self.catcher_stmt() + self.state = 725 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 721 + self.match(ASLParser.COMMA) + self.state = 722 + self.catcher_stmt() + self.state = 727 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 728 + self.match(ASLParser.RBRACE) + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Catcher_stmtContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def error_equals_decl(self): + return self.getTypedRuleContext(ASLParser.Error_equals_declContext, 0) + + def result_path_decl(self): + return self.getTypedRuleContext(ASLParser.Result_path_declContext, 0) + + def next_decl(self): + return self.getTypedRuleContext(ASLParser.Next_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_catcher_stmt + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterCatcher_stmt"): + listener.enterCatcher_stmt(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitCatcher_stmt"): + listener.exitCatcher_stmt(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitCatcher_stmt"): + return visitor.visitCatcher_stmt(self) + else: + return visitor.visitChildren(self) + + def catcher_stmt(self): + + localctx = ASLParser.Catcher_stmtContext(self, self._ctx, self.state) + self.enterRule(localctx, 154, self.RULE_catcher_stmt) + try: + self.state = 733 + self._errHandler.sync(self) + token = self._input.LA(1) + if token in [108]: + self.enterOuterAlt(localctx, 1) + self.state = 730 + self.error_equals_decl() + pass + elif token in [92]: + self.enterOuterAlt(localctx, 2) + self.state = 731 + self.result_path_decl() + pass + elif token in [103]: + self.enterOuterAlt(localctx, 3) + self.state = 732 + self.next_decl() + pass + else: + raise NoViableAltException(self) + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Comparison_opContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def BOOLEANEQUALS(self): + return self.getToken(ASLParser.BOOLEANEQUALS, 0) + + def BOOLEANQUALSPATH(self): + return self.getToken(ASLParser.BOOLEANQUALSPATH, 0) + + def ISBOOLEAN(self): + return self.getToken(ASLParser.ISBOOLEAN, 0) + + def ISNULL(self): + return self.getToken(ASLParser.ISNULL, 0) + + def ISNUMERIC(self): + return self.getToken(ASLParser.ISNUMERIC, 0) + + def ISPRESENT(self): + return self.getToken(ASLParser.ISPRESENT, 0) + + def ISSTRING(self): + return self.getToken(ASLParser.ISSTRING, 0) + + def ISTIMESTAMP(self): + return self.getToken(ASLParser.ISTIMESTAMP, 0) + + def NUMERICEQUALS(self): + return self.getToken(ASLParser.NUMERICEQUALS, 0) + + def NUMERICEQUALSPATH(self): + return self.getToken(ASLParser.NUMERICEQUALSPATH, 0) + + def NUMERICGREATERTHAN(self): + return self.getToken(ASLParser.NUMERICGREATERTHAN, 0) + + def NUMERICGREATERTHANPATH(self): + return self.getToken(ASLParser.NUMERICGREATERTHANPATH, 0) + + def NUMERICGREATERTHANEQUALS(self): + return self.getToken(ASLParser.NUMERICGREATERTHANEQUALS, 0) + + def NUMERICGREATERTHANEQUALSPATH(self): + return self.getToken(ASLParser.NUMERICGREATERTHANEQUALSPATH, 0) + + def NUMERICLESSTHAN(self): + return self.getToken(ASLParser.NUMERICLESSTHAN, 0) + + def NUMERICLESSTHANPATH(self): + return self.getToken(ASLParser.NUMERICLESSTHANPATH, 0) + + def NUMERICLESSTHANEQUALS(self): + return self.getToken(ASLParser.NUMERICLESSTHANEQUALS, 0) + + def NUMERICLESSTHANEQUALSPATH(self): + return self.getToken(ASLParser.NUMERICLESSTHANEQUALSPATH, 0) + + def STRINGEQUALS(self): + return self.getToken(ASLParser.STRINGEQUALS, 0) + + def STRINGEQUALSPATH(self): + return self.getToken(ASLParser.STRINGEQUALSPATH, 0) + + def STRINGGREATERTHAN(self): + return self.getToken(ASLParser.STRINGGREATERTHAN, 0) + + def STRINGGREATERTHANPATH(self): + return self.getToken(ASLParser.STRINGGREATERTHANPATH, 0) + + def STRINGGREATERTHANEQUALS(self): + return self.getToken(ASLParser.STRINGGREATERTHANEQUALS, 0) + + def STRINGGREATERTHANEQUALSPATH(self): + return self.getToken(ASLParser.STRINGGREATERTHANEQUALSPATH, 0) + + def STRINGLESSTHAN(self): + return self.getToken(ASLParser.STRINGLESSTHAN, 0) + + def STRINGLESSTHANPATH(self): + return self.getToken(ASLParser.STRINGLESSTHANPATH, 0) + + def STRINGLESSTHANEQUALS(self): + return self.getToken(ASLParser.STRINGLESSTHANEQUALS, 0) + + def STRINGLESSTHANEQUALSPATH(self): + return self.getToken(ASLParser.STRINGLESSTHANEQUALSPATH, 0) + + def STRINGMATCHES(self): + return self.getToken(ASLParser.STRINGMATCHES, 0) + + def TIMESTAMPEQUALS(self): + return self.getToken(ASLParser.TIMESTAMPEQUALS, 0) + + def TIMESTAMPEQUALSPATH(self): + return self.getToken(ASLParser.TIMESTAMPEQUALSPATH, 0) + + def TIMESTAMPGREATERTHAN(self): + return self.getToken(ASLParser.TIMESTAMPGREATERTHAN, 0) + + def TIMESTAMPGREATERTHANPATH(self): + return self.getToken(ASLParser.TIMESTAMPGREATERTHANPATH, 0) + + def TIMESTAMPGREATERTHANEQUALS(self): + return self.getToken(ASLParser.TIMESTAMPGREATERTHANEQUALS, 0) + + def TIMESTAMPGREATERTHANEQUALSPATH(self): + return self.getToken(ASLParser.TIMESTAMPGREATERTHANEQUALSPATH, 0) + + def TIMESTAMPLESSTHAN(self): + return self.getToken(ASLParser.TIMESTAMPLESSTHAN, 0) + + def TIMESTAMPLESSTHANPATH(self): + return self.getToken(ASLParser.TIMESTAMPLESSTHANPATH, 0) + + def TIMESTAMPLESSTHANEQUALS(self): + return self.getToken(ASLParser.TIMESTAMPLESSTHANEQUALS, 0) + + def TIMESTAMPLESSTHANEQUALSPATH(self): + return self.getToken(ASLParser.TIMESTAMPLESSTHANEQUALSPATH, 0) + + def getRuleIndex(self): + return ASLParser.RULE_comparison_op + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterComparison_op"): + listener.enterComparison_op(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitComparison_op"): + listener.exitComparison_op(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitComparison_op"): + return visitor.visitComparison_op(self) + else: + return visitor.visitChildren(self) + + def comparison_op(self): + + localctx = ASLParser.Comparison_opContext(self, self._ctx, self.state) + self.enterRule(localctx, 156, self.RULE_comparison_op) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 735 + _la = self._input.LA(1) + if not ( + ( + (((_la - 29)) & ~0x3F) == 0 + and ((1 << (_la - 29)) & 2199022731007) != 0 + ) + ): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Choice_operatorContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def NOT(self): + return self.getToken(ASLParser.NOT, 0) + + def AND(self): + return self.getToken(ASLParser.AND, 0) + + def OR(self): + return self.getToken(ASLParser.OR, 0) + + def getRuleIndex(self): + return ASLParser.RULE_choice_operator + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterChoice_operator"): + listener.enterChoice_operator(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitChoice_operator"): + listener.exitChoice_operator(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitChoice_operator"): + return visitor.visitChoice_operator(self) + else: + return visitor.visitChildren(self) + + def choice_operator(self): + + localctx = ASLParser.Choice_operatorContext(self, self._ctx, self.state) + self.enterRule(localctx, 158, self.RULE_choice_operator) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 737 + _la = self._input.LA(1) + if not ((((_la) & ~0x3F) == 0 and ((1 << _la) & 281612684099584) != 0)): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class States_error_nameContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def ERRORNAMEStatesALL(self): + return self.getToken(ASLParser.ERRORNAMEStatesALL, 0) + + def ERRORNAMEStatesHeartbeatTimeout(self): + return self.getToken(ASLParser.ERRORNAMEStatesHeartbeatTimeout, 0) + + def ERRORNAMEStatesTimeout(self): + return self.getToken(ASLParser.ERRORNAMEStatesTimeout, 0) + + def ERRORNAMEStatesTaskFailed(self): + return self.getToken(ASLParser.ERRORNAMEStatesTaskFailed, 0) + + def ERRORNAMEStatesPermissions(self): + return self.getToken(ASLParser.ERRORNAMEStatesPermissions, 0) + + def ERRORNAMEStatesResultPathMatchFailure(self): + return self.getToken(ASLParser.ERRORNAMEStatesResultPathMatchFailure, 0) + + def ERRORNAMEStatesParameterPathFailure(self): + return self.getToken(ASLParser.ERRORNAMEStatesParameterPathFailure, 0) + + def ERRORNAMEStatesBranchFailed(self): + return self.getToken(ASLParser.ERRORNAMEStatesBranchFailed, 0) + + def ERRORNAMEStatesNoChoiceMatched(self): + return self.getToken(ASLParser.ERRORNAMEStatesNoChoiceMatched, 0) + + def ERRORNAMEStatesIntrinsicFailure(self): + return self.getToken(ASLParser.ERRORNAMEStatesIntrinsicFailure, 0) + + def ERRORNAMEStatesExceedToleratedFailureThreshold(self): + return self.getToken( + ASLParser.ERRORNAMEStatesExceedToleratedFailureThreshold, 0 + ) + + def ERRORNAMEStatesItemReaderFailed(self): + return self.getToken(ASLParser.ERRORNAMEStatesItemReaderFailed, 0) + + def ERRORNAMEStatesResultWriterFailed(self): + return self.getToken(ASLParser.ERRORNAMEStatesResultWriterFailed, 0) + + def ERRORNAMEStatesRuntime(self): + return self.getToken(ASLParser.ERRORNAMEStatesRuntime, 0) + + def getRuleIndex(self): + return ASLParser.RULE_states_error_name + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterStates_error_name"): + listener.enterStates_error_name(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitStates_error_name"): + listener.exitStates_error_name(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitStates_error_name"): + return visitor.visitStates_error_name(self) + else: + return visitor.visitChildren(self) + + def states_error_name(self): + + localctx = ASLParser.States_error_nameContext(self, self._ctx, self.state) + self.enterRule(localctx, 160, self.RULE_states_error_name) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 739 + _la = self._input.LA(1) + if not ( + ((((_la - 113)) & ~0x3F) == 0 and ((1 << (_la - 113)) & 16383) != 0) + ): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Error_nameContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def states_error_name(self): + return self.getTypedRuleContext(ASLParser.States_error_nameContext, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_error_name + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterError_name"): + listener.enterError_name(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitError_name"): + listener.exitError_name(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitError_name"): + return visitor.visitError_name(self) + else: + return visitor.visitChildren(self) + + def error_name(self): + + localctx = ASLParser.Error_nameContext(self, self._ctx, self.state) + self.enterRule(localctx, 162, self.RULE_error_name) + try: + self.state = 743 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 44, self._ctx) + if la_ == 1: + self.enterOuterAlt(localctx, 1) + self.state = 741 + self.states_error_name() + pass + + elif la_ == 2: + self.enterOuterAlt(localctx, 2) + self.state = 742 + self.keyword_or_string() + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Json_obj_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def LBRACE(self): + return self.getToken(ASLParser.LBRACE, 0) + + def json_binding(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Json_bindingContext) + else: + return self.getTypedRuleContext(ASLParser.Json_bindingContext, i) + + def RBRACE(self): + return self.getToken(ASLParser.RBRACE, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_json_obj_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_obj_decl"): + listener.enterJson_obj_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_obj_decl"): + listener.exitJson_obj_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_obj_decl"): + return visitor.visitJson_obj_decl(self) + else: + return visitor.visitChildren(self) + + def json_obj_decl(self): + + localctx = ASLParser.Json_obj_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 164, self.RULE_json_obj_decl) + self._la = 0 # Token type + try: + self.state = 758 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 46, self._ctx) + if la_ == 1: + self.enterOuterAlt(localctx, 1) + self.state = 745 + self.match(ASLParser.LBRACE) + self.state = 746 + self.json_binding() + self.state = 751 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 747 + self.match(ASLParser.COMMA) + self.state = 748 + self.json_binding() + self.state = 753 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 754 + self.match(ASLParser.RBRACE) + pass + + elif la_ == 2: + self.enterOuterAlt(localctx, 2) + self.state = 756 + self.match(ASLParser.LBRACE) + self.state = 757 + self.match(ASLParser.RBRACE) + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Json_bindingContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def COLON(self): + return self.getToken(ASLParser.COLON, 0) + + def json_value_decl(self): + return self.getTypedRuleContext(ASLParser.Json_value_declContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_json_binding + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_binding"): + listener.enterJson_binding(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_binding"): + listener.exitJson_binding(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_binding"): + return visitor.visitJson_binding(self) + else: + return visitor.visitChildren(self) + + def json_binding(self): + + localctx = ASLParser.Json_bindingContext(self, self._ctx, self.state) + self.enterRule(localctx, 166, self.RULE_json_binding) + try: + self.enterOuterAlt(localctx, 1) + self.state = 760 + self.keyword_or_string() + self.state = 761 + self.match(ASLParser.COLON) + self.state = 762 + self.json_value_decl() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Json_arr_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def LBRACK(self): + return self.getToken(ASLParser.LBRACK, 0) + + def json_value_decl(self, i: int = None): + if i is None: + return self.getTypedRuleContexts(ASLParser.Json_value_declContext) + else: + return self.getTypedRuleContext(ASLParser.Json_value_declContext, i) + + def RBRACK(self): + return self.getToken(ASLParser.RBRACK, 0) + + def COMMA(self, i: int = None): + if i is None: + return self.getTokens(ASLParser.COMMA) + else: + return self.getToken(ASLParser.COMMA, i) + + def getRuleIndex(self): + return ASLParser.RULE_json_arr_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_arr_decl"): + listener.enterJson_arr_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_arr_decl"): + listener.exitJson_arr_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_arr_decl"): + return visitor.visitJson_arr_decl(self) + else: + return visitor.visitChildren(self) + + def json_arr_decl(self): + + localctx = ASLParser.Json_arr_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 168, self.RULE_json_arr_decl) + self._la = 0 # Token type + try: + self.state = 777 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 48, self._ctx) + if la_ == 1: + self.enterOuterAlt(localctx, 1) + self.state = 764 + self.match(ASLParser.LBRACK) + self.state = 765 + self.json_value_decl() + self.state = 770 + self._errHandler.sync(self) + _la = self._input.LA(1) + while _la == 1: + self.state = 766 + self.match(ASLParser.COMMA) + self.state = 767 + self.json_value_decl() + self.state = 772 + self._errHandler.sync(self) + _la = self._input.LA(1) + + self.state = 773 + self.match(ASLParser.RBRACK) + pass + + elif la_ == 2: + self.enterOuterAlt(localctx, 2) + self.state = 775 + self.match(ASLParser.LBRACK) + self.state = 776 + self.match(ASLParser.RBRACK) + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Json_value_declContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def NUMBER(self): + return self.getToken(ASLParser.NUMBER, 0) + + def INT(self): + return self.getToken(ASLParser.INT, 0) + + def TRUE(self): + return self.getToken(ASLParser.TRUE, 0) + + def FALSE(self): + return self.getToken(ASLParser.FALSE, 0) + + def NULL(self): + return self.getToken(ASLParser.NULL, 0) + + def json_binding(self): + return self.getTypedRuleContext(ASLParser.Json_bindingContext, 0) + + def json_arr_decl(self): + return self.getTypedRuleContext(ASLParser.Json_arr_declContext, 0) + + def json_obj_decl(self): + return self.getTypedRuleContext(ASLParser.Json_obj_declContext, 0) + + def keyword_or_string(self): + return self.getTypedRuleContext(ASLParser.Keyword_or_stringContext, 0) + + def getRuleIndex(self): + return ASLParser.RULE_json_value_decl + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterJson_value_decl"): + listener.enterJson_value_decl(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitJson_value_decl"): + listener.exitJson_value_decl(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitJson_value_decl"): + return visitor.visitJson_value_decl(self) + else: + return visitor.visitChildren(self) + + def json_value_decl(self): + + localctx = ASLParser.Json_value_declContext(self, self._ctx, self.state) + self.enterRule(localctx, 170, self.RULE_json_value_decl) + try: + self.state = 788 + self._errHandler.sync(self) + la_ = self._interp.adaptivePredict(self._input, 49, self._ctx) + if la_ == 1: + self.enterOuterAlt(localctx, 1) + self.state = 779 + self.match(ASLParser.NUMBER) + pass + + elif la_ == 2: + self.enterOuterAlt(localctx, 2) + self.state = 780 + self.match(ASLParser.INT) + pass + + elif la_ == 3: + self.enterOuterAlt(localctx, 3) + self.state = 781 + self.match(ASLParser.TRUE) + pass + + elif la_ == 4: + self.enterOuterAlt(localctx, 4) + self.state = 782 + self.match(ASLParser.FALSE) + pass + + elif la_ == 5: + self.enterOuterAlt(localctx, 5) + self.state = 783 + self.match(ASLParser.NULL) + pass + + elif la_ == 6: + self.enterOuterAlt(localctx, 6) + self.state = 784 + self.json_binding() + pass + + elif la_ == 7: + self.enterOuterAlt(localctx, 7) + self.state = 785 + self.json_arr_decl() + pass + + elif la_ == 8: + self.enterOuterAlt(localctx, 8) + self.state = 786 + self.json_obj_decl() + pass + + elif la_ == 9: + self.enterOuterAlt(localctx, 9) + self.state = 787 + self.keyword_or_string() + pass + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class Keyword_or_stringContext(ParserRuleContext): + __slots__ = "parser" + + def __init__( + self, parser, parent: ParserRuleContext = None, invokingState: int = -1 + ): + super().__init__(parent, invokingState) + self.parser = parser + + def STRINGDOLLAR(self): + return self.getToken(ASLParser.STRINGDOLLAR, 0) + + def STRINGPATHCONTEXTOBJ(self): + return self.getToken(ASLParser.STRINGPATHCONTEXTOBJ, 0) + + def STRINGPATH(self): + return self.getToken(ASLParser.STRINGPATH, 0) + + def STRING(self): + return self.getToken(ASLParser.STRING, 0) + + def COMMENT(self): + return self.getToken(ASLParser.COMMENT, 0) + + def STATES(self): + return self.getToken(ASLParser.STATES, 0) + + def STARTAT(self): + return self.getToken(ASLParser.STARTAT, 0) + + def NEXTSTATE(self): + return self.getToken(ASLParser.NEXTSTATE, 0) + + def TYPE(self): + return self.getToken(ASLParser.TYPE, 0) + + def TASK(self): + return self.getToken(ASLParser.TASK, 0) + + def CHOICE(self): + return self.getToken(ASLParser.CHOICE, 0) + + def FAIL(self): + return self.getToken(ASLParser.FAIL, 0) + + def SUCCEED(self): + return self.getToken(ASLParser.SUCCEED, 0) + + def PASS(self): + return self.getToken(ASLParser.PASS, 0) + + def WAIT(self): + return self.getToken(ASLParser.WAIT, 0) + + def PARALLEL(self): + return self.getToken(ASLParser.PARALLEL, 0) + + def MAP(self): + return self.getToken(ASLParser.MAP, 0) + + def CHOICES(self): + return self.getToken(ASLParser.CHOICES, 0) + + def VARIABLE(self): + return self.getToken(ASLParser.VARIABLE, 0) + + def DEFAULT(self): + return self.getToken(ASLParser.DEFAULT, 0) + + def BRANCHES(self): + return self.getToken(ASLParser.BRANCHES, 0) + + def AND(self): + return self.getToken(ASLParser.AND, 0) + + def BOOLEANEQUALS(self): + return self.getToken(ASLParser.BOOLEANEQUALS, 0) + + def BOOLEANQUALSPATH(self): + return self.getToken(ASLParser.BOOLEANQUALSPATH, 0) + + def ISBOOLEAN(self): + return self.getToken(ASLParser.ISBOOLEAN, 0) + + def ISNULL(self): + return self.getToken(ASLParser.ISNULL, 0) + + def ISNUMERIC(self): + return self.getToken(ASLParser.ISNUMERIC, 0) + + def ISPRESENT(self): + return self.getToken(ASLParser.ISPRESENT, 0) + + def ISSTRING(self): + return self.getToken(ASLParser.ISSTRING, 0) + + def ISTIMESTAMP(self): + return self.getToken(ASLParser.ISTIMESTAMP, 0) + + def NOT(self): + return self.getToken(ASLParser.NOT, 0) + + def NUMERICEQUALS(self): + return self.getToken(ASLParser.NUMERICEQUALS, 0) + + def NUMERICEQUALSPATH(self): + return self.getToken(ASLParser.NUMERICEQUALSPATH, 0) + + def NUMERICGREATERTHAN(self): + return self.getToken(ASLParser.NUMERICGREATERTHAN, 0) + + def NUMERICGREATERTHANPATH(self): + return self.getToken(ASLParser.NUMERICGREATERTHANPATH, 0) + + def NUMERICGREATERTHANEQUALS(self): + return self.getToken(ASLParser.NUMERICGREATERTHANEQUALS, 0) + + def NUMERICGREATERTHANEQUALSPATH(self): + return self.getToken(ASLParser.NUMERICGREATERTHANEQUALSPATH, 0) + + def NUMERICLESSTHAN(self): + return self.getToken(ASLParser.NUMERICLESSTHAN, 0) + + def NUMERICLESSTHANPATH(self): + return self.getToken(ASLParser.NUMERICLESSTHANPATH, 0) + + def NUMERICLESSTHANEQUALS(self): + return self.getToken(ASLParser.NUMERICLESSTHANEQUALS, 0) + + def NUMERICLESSTHANEQUALSPATH(self): + return self.getToken(ASLParser.NUMERICLESSTHANEQUALSPATH, 0) + + def OR(self): + return self.getToken(ASLParser.OR, 0) + + def STRINGEQUALS(self): + return self.getToken(ASLParser.STRINGEQUALS, 0) + + def STRINGEQUALSPATH(self): + return self.getToken(ASLParser.STRINGEQUALSPATH, 0) + + def STRINGGREATERTHAN(self): + return self.getToken(ASLParser.STRINGGREATERTHAN, 0) + + def STRINGGREATERTHANPATH(self): + return self.getToken(ASLParser.STRINGGREATERTHANPATH, 0) + + def STRINGGREATERTHANEQUALS(self): + return self.getToken(ASLParser.STRINGGREATERTHANEQUALS, 0) + + def STRINGGREATERTHANEQUALSPATH(self): + return self.getToken(ASLParser.STRINGGREATERTHANEQUALSPATH, 0) + + def STRINGLESSTHAN(self): + return self.getToken(ASLParser.STRINGLESSTHAN, 0) + + def STRINGLESSTHANPATH(self): + return self.getToken(ASLParser.STRINGLESSTHANPATH, 0) + + def STRINGLESSTHANEQUALS(self): + return self.getToken(ASLParser.STRINGLESSTHANEQUALS, 0) + + def STRINGLESSTHANEQUALSPATH(self): + return self.getToken(ASLParser.STRINGLESSTHANEQUALSPATH, 0) + + def STRINGMATCHES(self): + return self.getToken(ASLParser.STRINGMATCHES, 0) + + def TIMESTAMPEQUALS(self): + return self.getToken(ASLParser.TIMESTAMPEQUALS, 0) + + def TIMESTAMPEQUALSPATH(self): + return self.getToken(ASLParser.TIMESTAMPEQUALSPATH, 0) + + def TIMESTAMPGREATERTHAN(self): + return self.getToken(ASLParser.TIMESTAMPGREATERTHAN, 0) + + def TIMESTAMPGREATERTHANPATH(self): + return self.getToken(ASLParser.TIMESTAMPGREATERTHANPATH, 0) + + def TIMESTAMPGREATERTHANEQUALS(self): + return self.getToken(ASLParser.TIMESTAMPGREATERTHANEQUALS, 0) + + def TIMESTAMPGREATERTHANEQUALSPATH(self): + return self.getToken(ASLParser.TIMESTAMPGREATERTHANEQUALSPATH, 0) + + def TIMESTAMPLESSTHAN(self): + return self.getToken(ASLParser.TIMESTAMPLESSTHAN, 0) + + def TIMESTAMPLESSTHANPATH(self): + return self.getToken(ASLParser.TIMESTAMPLESSTHANPATH, 0) + + def TIMESTAMPLESSTHANEQUALS(self): + return self.getToken(ASLParser.TIMESTAMPLESSTHANEQUALS, 0) + + def TIMESTAMPLESSTHANEQUALSPATH(self): + return self.getToken(ASLParser.TIMESTAMPLESSTHANEQUALSPATH, 0) + + def SECONDSPATH(self): + return self.getToken(ASLParser.SECONDSPATH, 0) + + def SECONDS(self): + return self.getToken(ASLParser.SECONDS, 0) + + def TIMESTAMPPATH(self): + return self.getToken(ASLParser.TIMESTAMPPATH, 0) + + def TIMESTAMP(self): + return self.getToken(ASLParser.TIMESTAMP, 0) + + def TIMEOUTSECONDS(self): + return self.getToken(ASLParser.TIMEOUTSECONDS, 0) + + def TIMEOUTSECONDSPATH(self): + return self.getToken(ASLParser.TIMEOUTSECONDSPATH, 0) + + def HEARTBEATSECONDS(self): + return self.getToken(ASLParser.HEARTBEATSECONDS, 0) + + def HEARTBEATSECONDSPATH(self): + return self.getToken(ASLParser.HEARTBEATSECONDSPATH, 0) + + def PROCESSORCONFIG(self): + return self.getToken(ASLParser.PROCESSORCONFIG, 0) + + def MODE(self): + return self.getToken(ASLParser.MODE, 0) + + def INLINE(self): + return self.getToken(ASLParser.INLINE, 0) + + def DISTRIBUTED(self): + return self.getToken(ASLParser.DISTRIBUTED, 0) + + def EXECUTIONTYPE(self): + return self.getToken(ASLParser.EXECUTIONTYPE, 0) + + def STANDARD(self): + return self.getToken(ASLParser.STANDARD, 0) + + def ITEMPROCESSOR(self): + return self.getToken(ASLParser.ITEMPROCESSOR, 0) + + def ITERATOR(self): + return self.getToken(ASLParser.ITERATOR, 0) + + def ITEMSELECTOR(self): + return self.getToken(ASLParser.ITEMSELECTOR, 0) + + def MAXCONCURRENCY(self): + return self.getToken(ASLParser.MAXCONCURRENCY, 0) + + def RESOURCE(self): + return self.getToken(ASLParser.RESOURCE, 0) + + def INPUTPATH(self): + return self.getToken(ASLParser.INPUTPATH, 0) + + def OUTPUTPATH(self): + return self.getToken(ASLParser.OUTPUTPATH, 0) + + def ITEMSPATH(self): + return self.getToken(ASLParser.ITEMSPATH, 0) + + def RESULTPATH(self): + return self.getToken(ASLParser.RESULTPATH, 0) + + def RESULT(self): + return self.getToken(ASLParser.RESULT, 0) + + def PARAMETERS(self): + return self.getToken(ASLParser.PARAMETERS, 0) + + def RESULTSELECTOR(self): + return self.getToken(ASLParser.RESULTSELECTOR, 0) + + def ITEMREADER(self): + return self.getToken(ASLParser.ITEMREADER, 0) + + def READERCONFIG(self): + return self.getToken(ASLParser.READERCONFIG, 0) + + def INPUTTYPE(self): + return self.getToken(ASLParser.INPUTTYPE, 0) + + def CSVHEADERLOCATION(self): + return self.getToken(ASLParser.CSVHEADERLOCATION, 0) + + def CSVHEADERS(self): + return self.getToken(ASLParser.CSVHEADERS, 0) + + def MAXITEMS(self): + return self.getToken(ASLParser.MAXITEMS, 0) + + def MAXITEMSPATH(self): + return self.getToken(ASLParser.MAXITEMSPATH, 0) + + def NEXT(self): + return self.getToken(ASLParser.NEXT, 0) + + def END(self): + return self.getToken(ASLParser.END, 0) + + def CAUSE(self): + return self.getToken(ASLParser.CAUSE, 0) + + def ERROR(self): + return self.getToken(ASLParser.ERROR, 0) + + def RETRY(self): + return self.getToken(ASLParser.RETRY, 0) + + def ERROREQUALS(self): + return self.getToken(ASLParser.ERROREQUALS, 0) + + def INTERVALSECONDS(self): + return self.getToken(ASLParser.INTERVALSECONDS, 0) + + def MAXATTEMPTS(self): + return self.getToken(ASLParser.MAXATTEMPTS, 0) + + def BACKOFFRATE(self): + return self.getToken(ASLParser.BACKOFFRATE, 0) + + def CATCH(self): + return self.getToken(ASLParser.CATCH, 0) + + def ERRORNAMEStatesALL(self): + return self.getToken(ASLParser.ERRORNAMEStatesALL, 0) + + def ERRORNAMEStatesHeartbeatTimeout(self): + return self.getToken(ASLParser.ERRORNAMEStatesHeartbeatTimeout, 0) + + def ERRORNAMEStatesTimeout(self): + return self.getToken(ASLParser.ERRORNAMEStatesTimeout, 0) + + def ERRORNAMEStatesTaskFailed(self): + return self.getToken(ASLParser.ERRORNAMEStatesTaskFailed, 0) + + def ERRORNAMEStatesPermissions(self): + return self.getToken(ASLParser.ERRORNAMEStatesPermissions, 0) + + def ERRORNAMEStatesResultPathMatchFailure(self): + return self.getToken(ASLParser.ERRORNAMEStatesResultPathMatchFailure, 0) + + def ERRORNAMEStatesParameterPathFailure(self): + return self.getToken(ASLParser.ERRORNAMEStatesParameterPathFailure, 0) + + def ERRORNAMEStatesBranchFailed(self): + return self.getToken(ASLParser.ERRORNAMEStatesBranchFailed, 0) + + def ERRORNAMEStatesNoChoiceMatched(self): + return self.getToken(ASLParser.ERRORNAMEStatesNoChoiceMatched, 0) + + def ERRORNAMEStatesIntrinsicFailure(self): + return self.getToken(ASLParser.ERRORNAMEStatesIntrinsicFailure, 0) + + def ERRORNAMEStatesExceedToleratedFailureThreshold(self): + return self.getToken( + ASLParser.ERRORNAMEStatesExceedToleratedFailureThreshold, 0 + ) + + def ERRORNAMEStatesItemReaderFailed(self): + return self.getToken(ASLParser.ERRORNAMEStatesItemReaderFailed, 0) + + def ERRORNAMEStatesResultWriterFailed(self): + return self.getToken(ASLParser.ERRORNAMEStatesResultWriterFailed, 0) + + def ERRORNAMEStatesRuntime(self): + return self.getToken(ASLParser.ERRORNAMEStatesRuntime, 0) + + def getRuleIndex(self): + return ASLParser.RULE_keyword_or_string + + def enterRule(self, listener: ParseTreeListener): + if hasattr(listener, "enterKeyword_or_string"): + listener.enterKeyword_or_string(self) + + def exitRule(self, listener: ParseTreeListener): + if hasattr(listener, "exitKeyword_or_string"): + listener.exitKeyword_or_string(self) + + def accept(self, visitor: ParseTreeVisitor): + if hasattr(visitor, "visitKeyword_or_string"): + return visitor.visitKeyword_or_string(self) + else: + return visitor.visitChildren(self) + + def keyword_or_string(self): + + localctx = ASLParser.Keyword_or_stringContext(self, self._ctx, self.state) + self.enterRule(localctx, 172, self.RULE_keyword_or_string) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 790 + _la = self._input.LA(1) + if not ( + ((((_la - 10)) & ~0x3F) == 0 and ((1 << (_la - 10)) & -17) != 0) + or ( + (((_la - 74)) & ~0x3F) == 0 + and ((1 << (_la - 74)) & 144115188075855871) != 0 + ) + ): + self._errHandler.recoverInline(self) + else: + self._errHandler.reportMatch(self) + self.consume() + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLParser.tokens b/moto/stepfunctions/parser/asl/antlr/runtime/ASLParser.tokens new file mode 100644 index 000000000..7f35b74e8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLParser.tokens @@ -0,0 +1,259 @@ +COMMA=1 +COLON=2 +LBRACK=3 +RBRACK=4 +LBRACE=5 +RBRACE=6 +TRUE=7 +FALSE=8 +NULL=9 +COMMENT=10 +STATES=11 +STARTAT=12 +NEXTSTATE=13 +VERSION=14 +TYPE=15 +TASK=16 +CHOICE=17 +FAIL=18 +SUCCEED=19 +PASS=20 +WAIT=21 +PARALLEL=22 +MAP=23 +CHOICES=24 +VARIABLE=25 +DEFAULT=26 +BRANCHES=27 +AND=28 +BOOLEANEQUALS=29 +BOOLEANQUALSPATH=30 +ISBOOLEAN=31 +ISNULL=32 +ISNUMERIC=33 +ISPRESENT=34 +ISSTRING=35 +ISTIMESTAMP=36 +NOT=37 +NUMERICEQUALS=38 +NUMERICEQUALSPATH=39 +NUMERICGREATERTHAN=40 +NUMERICGREATERTHANPATH=41 +NUMERICGREATERTHANEQUALS=42 +NUMERICGREATERTHANEQUALSPATH=43 +NUMERICLESSTHAN=44 +NUMERICLESSTHANPATH=45 +NUMERICLESSTHANEQUALS=46 +NUMERICLESSTHANEQUALSPATH=47 +OR=48 +STRINGEQUALS=49 +STRINGEQUALSPATH=50 +STRINGGREATERTHAN=51 +STRINGGREATERTHANPATH=52 +STRINGGREATERTHANEQUALS=53 +STRINGGREATERTHANEQUALSPATH=54 +STRINGLESSTHAN=55 +STRINGLESSTHANPATH=56 +STRINGLESSTHANEQUALS=57 +STRINGLESSTHANEQUALSPATH=58 +STRINGMATCHES=59 +TIMESTAMPEQUALS=60 +TIMESTAMPEQUALSPATH=61 +TIMESTAMPGREATERTHAN=62 +TIMESTAMPGREATERTHANPATH=63 +TIMESTAMPGREATERTHANEQUALS=64 +TIMESTAMPGREATERTHANEQUALSPATH=65 +TIMESTAMPLESSTHAN=66 +TIMESTAMPLESSTHANPATH=67 +TIMESTAMPLESSTHANEQUALS=68 +TIMESTAMPLESSTHANEQUALSPATH=69 +SECONDSPATH=70 +SECONDS=71 +TIMESTAMPPATH=72 +TIMESTAMP=73 +TIMEOUTSECONDS=74 +TIMEOUTSECONDSPATH=75 +HEARTBEATSECONDS=76 +HEARTBEATSECONDSPATH=77 +PROCESSORCONFIG=78 +MODE=79 +INLINE=80 +DISTRIBUTED=81 +EXECUTIONTYPE=82 +STANDARD=83 +ITEMPROCESSOR=84 +ITERATOR=85 +ITEMSELECTOR=86 +MAXCONCURRENCY=87 +RESOURCE=88 +INPUTPATH=89 +OUTPUTPATH=90 +ITEMSPATH=91 +RESULTPATH=92 +RESULT=93 +PARAMETERS=94 +RESULTSELECTOR=95 +ITEMREADER=96 +READERCONFIG=97 +INPUTTYPE=98 +CSVHEADERLOCATION=99 +CSVHEADERS=100 +MAXITEMS=101 +MAXITEMSPATH=102 +NEXT=103 +END=104 +CAUSE=105 +ERROR=106 +RETRY=107 +ERROREQUALS=108 +INTERVALSECONDS=109 +MAXATTEMPTS=110 +BACKOFFRATE=111 +CATCH=112 +ERRORNAMEStatesALL=113 +ERRORNAMEStatesHeartbeatTimeout=114 +ERRORNAMEStatesTimeout=115 +ERRORNAMEStatesTaskFailed=116 +ERRORNAMEStatesPermissions=117 +ERRORNAMEStatesResultPathMatchFailure=118 +ERRORNAMEStatesParameterPathFailure=119 +ERRORNAMEStatesBranchFailed=120 +ERRORNAMEStatesNoChoiceMatched=121 +ERRORNAMEStatesIntrinsicFailure=122 +ERRORNAMEStatesExceedToleratedFailureThreshold=123 +ERRORNAMEStatesItemReaderFailed=124 +ERRORNAMEStatesResultWriterFailed=125 +ERRORNAMEStatesRuntime=126 +STRINGDOLLAR=127 +STRINGPATHCONTEXTOBJ=128 +STRINGPATH=129 +STRING=130 +INT=131 +NUMBER=132 +WS=133 +','=1 +':'=2 +'['=3 +']'=4 +'{'=5 +'}'=6 +'true'=7 +'false'=8 +'null'=9 +'"Comment"'=10 +'"States"'=11 +'"StartAt"'=12 +'"NextState"'=13 +'"Version"'=14 +'"Type"'=15 +'"Task"'=16 +'"Choice"'=17 +'"Fail"'=18 +'"Succeed"'=19 +'"Pass"'=20 +'"Wait"'=21 +'"Parallel"'=22 +'"Map"'=23 +'"Choices"'=24 +'"Variable"'=25 +'"Default"'=26 +'"Branches"'=27 +'"And"'=28 +'"BooleanEquals"'=29 +'"BooleanEqualsPath"'=30 +'"IsBoolean"'=31 +'"IsNull"'=32 +'"IsNumeric"'=33 +'"IsPresent"'=34 +'"IsString"'=35 +'"IsTimestamp"'=36 +'"Not"'=37 +'"NumericEquals"'=38 +'"NumericEqualsPath"'=39 +'"NumericGreaterThan"'=40 +'"NumericGreaterThanPath"'=41 +'"NumericGreaterThanEquals"'=42 +'"NumericGreaterThanEqualsPath"'=43 +'"NumericLessThan"'=44 +'"NumericLessThanPath"'=45 +'"NumericLessThanEquals"'=46 +'"NumericLessThanEqualsPath"'=47 +'"Or"'=48 +'"StringEquals"'=49 +'"StringEqualsPath"'=50 +'"StringGreaterThan"'=51 +'"StringGreaterThanPath"'=52 +'"StringGreaterThanEquals"'=53 +'"StringGreaterThanEqualsPath"'=54 +'"StringLessThan"'=55 +'"StringLessThanPath"'=56 +'"StringLessThanEquals"'=57 +'"StringLessThanEqualsPath"'=58 +'"StringMatches"'=59 +'"TimestampEquals"'=60 +'"TimestampEqualsPath"'=61 +'"TimestampGreaterThan"'=62 +'"TimestampGreaterThanPath"'=63 +'"TimestampGreaterThanEquals"'=64 +'"TimestampGreaterThanEqualsPath"'=65 +'"TimestampLessThan"'=66 +'"TimestampLessThanPath"'=67 +'"TimestampLessThanEquals"'=68 +'"TimestampLessThanEqualsPath"'=69 +'"SecondsPath"'=70 +'"Seconds"'=71 +'"TimestampPath"'=72 +'"Timestamp"'=73 +'"TimeoutSeconds"'=74 +'"TimeoutSecondsPath"'=75 +'"HeartbeatSeconds"'=76 +'"HeartbeatSecondsPath"'=77 +'"ProcessorConfig"'=78 +'"Mode"'=79 +'"INLINE"'=80 +'"DISTRIBUTED"'=81 +'"ExecutionType"'=82 +'"STANDARD"'=83 +'"ItemProcessor"'=84 +'"Iterator"'=85 +'"ItemSelector"'=86 +'"MaxConcurrency"'=87 +'"Resource"'=88 +'"InputPath"'=89 +'"OutputPath"'=90 +'"ItemsPath"'=91 +'"ResultPath"'=92 +'"Result"'=93 +'"Parameters"'=94 +'"ResultSelector"'=95 +'"ItemReader"'=96 +'"ReaderConfig"'=97 +'"InputType"'=98 +'"CSVHeaderLocation"'=99 +'"CSVHeaders"'=100 +'"MaxItems"'=101 +'"MaxItemsPath"'=102 +'"Next"'=103 +'"End"'=104 +'"Cause"'=105 +'"Error"'=106 +'"Retry"'=107 +'"ErrorEquals"'=108 +'"IntervalSeconds"'=109 +'"MaxAttempts"'=110 +'"BackoffRate"'=111 +'"Catch"'=112 +'"States.ALL"'=113 +'"States.HeartbeatTimeout"'=114 +'"States.Timeout"'=115 +'"States.TaskFailed"'=116 +'"States.Permissions"'=117 +'"States.ResultPathMatchFailure"'=118 +'"States.ParameterPathFailure"'=119 +'"States.BranchFailed"'=120 +'"States.NoChoiceMatched"'=121 +'"States.IntrinsicFailure"'=122 +'"States.ExceedToleratedFailureThreshold"'=123 +'"States.ItemReaderFailed"'=124 +'"States.ResultWriterFailed"'=125 +'"States.Runtime"'=126 diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLParserListener.py b/moto/stepfunctions/parser/asl/antlr/runtime/ASLParserListener.py new file mode 100644 index 000000000..0236c85fb --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLParserListener.py @@ -0,0 +1,809 @@ +# Generated from /Users/mep/LocalStack/localstack/localstack/services/stepfunctions/asl/antlr/ASLParser.g4 by ANTLR 4.13.1 +from antlr4 import ParseTreeListener + +if "." in __name__: + from .ASLParser import ASLParser +else: + from ASLParser import ASLParser + +# This class defines a complete listener for a parse tree produced by ASLParser. +class ASLParserListener(ParseTreeListener): + + # Enter a parse tree produced by ASLParser#program_decl. + def enterProgram_decl(self, ctx: ASLParser.Program_declContext): + pass + + # Exit a parse tree produced by ASLParser#program_decl. + def exitProgram_decl(self, ctx: ASLParser.Program_declContext): + pass + + # Enter a parse tree produced by ASLParser#top_layer_stmt. + def enterTop_layer_stmt(self, ctx: ASLParser.Top_layer_stmtContext): + pass + + # Exit a parse tree produced by ASLParser#top_layer_stmt. + def exitTop_layer_stmt(self, ctx: ASLParser.Top_layer_stmtContext): + pass + + # Enter a parse tree produced by ASLParser#startat_decl. + def enterStartat_decl(self, ctx: ASLParser.Startat_declContext): + pass + + # Exit a parse tree produced by ASLParser#startat_decl. + def exitStartat_decl(self, ctx: ASLParser.Startat_declContext): + pass + + # Enter a parse tree produced by ASLParser#comment_decl. + def enterComment_decl(self, ctx: ASLParser.Comment_declContext): + pass + + # Exit a parse tree produced by ASLParser#comment_decl. + def exitComment_decl(self, ctx: ASLParser.Comment_declContext): + pass + + # Enter a parse tree produced by ASLParser#version_decl. + def enterVersion_decl(self, ctx: ASLParser.Version_declContext): + pass + + # Exit a parse tree produced by ASLParser#version_decl. + def exitVersion_decl(self, ctx: ASLParser.Version_declContext): + pass + + # Enter a parse tree produced by ASLParser#state_stmt. + def enterState_stmt(self, ctx: ASLParser.State_stmtContext): + pass + + # Exit a parse tree produced by ASLParser#state_stmt. + def exitState_stmt(self, ctx: ASLParser.State_stmtContext): + pass + + # Enter a parse tree produced by ASLParser#states_decl. + def enterStates_decl(self, ctx: ASLParser.States_declContext): + pass + + # Exit a parse tree produced by ASLParser#states_decl. + def exitStates_decl(self, ctx: ASLParser.States_declContext): + pass + + # Enter a parse tree produced by ASLParser#state_name. + def enterState_name(self, ctx: ASLParser.State_nameContext): + pass + + # Exit a parse tree produced by ASLParser#state_name. + def exitState_name(self, ctx: ASLParser.State_nameContext): + pass + + # Enter a parse tree produced by ASLParser#state_decl. + def enterState_decl(self, ctx: ASLParser.State_declContext): + pass + + # Exit a parse tree produced by ASLParser#state_decl. + def exitState_decl(self, ctx: ASLParser.State_declContext): + pass + + # Enter a parse tree produced by ASLParser#state_decl_body. + def enterState_decl_body(self, ctx: ASLParser.State_decl_bodyContext): + pass + + # Exit a parse tree produced by ASLParser#state_decl_body. + def exitState_decl_body(self, ctx: ASLParser.State_decl_bodyContext): + pass + + # Enter a parse tree produced by ASLParser#type_decl. + def enterType_decl(self, ctx: ASLParser.Type_declContext): + pass + + # Exit a parse tree produced by ASLParser#type_decl. + def exitType_decl(self, ctx: ASLParser.Type_declContext): + pass + + # Enter a parse tree produced by ASLParser#next_decl. + def enterNext_decl(self, ctx: ASLParser.Next_declContext): + pass + + # Exit a parse tree produced by ASLParser#next_decl. + def exitNext_decl(self, ctx: ASLParser.Next_declContext): + pass + + # Enter a parse tree produced by ASLParser#resource_decl. + def enterResource_decl(self, ctx: ASLParser.Resource_declContext): + pass + + # Exit a parse tree produced by ASLParser#resource_decl. + def exitResource_decl(self, ctx: ASLParser.Resource_declContext): + pass + + # Enter a parse tree produced by ASLParser#input_path_decl. + def enterInput_path_decl(self, ctx: ASLParser.Input_path_declContext): + pass + + # Exit a parse tree produced by ASLParser#input_path_decl. + def exitInput_path_decl(self, ctx: ASLParser.Input_path_declContext): + pass + + # Enter a parse tree produced by ASLParser#result_decl. + def enterResult_decl(self, ctx: ASLParser.Result_declContext): + pass + + # Exit a parse tree produced by ASLParser#result_decl. + def exitResult_decl(self, ctx: ASLParser.Result_declContext): + pass + + # Enter a parse tree produced by ASLParser#result_path_decl. + def enterResult_path_decl(self, ctx: ASLParser.Result_path_declContext): + pass + + # Exit a parse tree produced by ASLParser#result_path_decl. + def exitResult_path_decl(self, ctx: ASLParser.Result_path_declContext): + pass + + # Enter a parse tree produced by ASLParser#output_path_decl. + def enterOutput_path_decl(self, ctx: ASLParser.Output_path_declContext): + pass + + # Exit a parse tree produced by ASLParser#output_path_decl. + def exitOutput_path_decl(self, ctx: ASLParser.Output_path_declContext): + pass + + # Enter a parse tree produced by ASLParser#end_decl. + def enterEnd_decl(self, ctx: ASLParser.End_declContext): + pass + + # Exit a parse tree produced by ASLParser#end_decl. + def exitEnd_decl(self, ctx: ASLParser.End_declContext): + pass + + # Enter a parse tree produced by ASLParser#default_decl. + def enterDefault_decl(self, ctx: ASLParser.Default_declContext): + pass + + # Exit a parse tree produced by ASLParser#default_decl. + def exitDefault_decl(self, ctx: ASLParser.Default_declContext): + pass + + # Enter a parse tree produced by ASLParser#error_decl. + def enterError_decl(self, ctx: ASLParser.Error_declContext): + pass + + # Exit a parse tree produced by ASLParser#error_decl. + def exitError_decl(self, ctx: ASLParser.Error_declContext): + pass + + # Enter a parse tree produced by ASLParser#cause_decl. + def enterCause_decl(self, ctx: ASLParser.Cause_declContext): + pass + + # Exit a parse tree produced by ASLParser#cause_decl. + def exitCause_decl(self, ctx: ASLParser.Cause_declContext): + pass + + # Enter a parse tree produced by ASLParser#seconds_decl. + def enterSeconds_decl(self, ctx: ASLParser.Seconds_declContext): + pass + + # Exit a parse tree produced by ASLParser#seconds_decl. + def exitSeconds_decl(self, ctx: ASLParser.Seconds_declContext): + pass + + # Enter a parse tree produced by ASLParser#seconds_path_decl. + def enterSeconds_path_decl(self, ctx: ASLParser.Seconds_path_declContext): + pass + + # Exit a parse tree produced by ASLParser#seconds_path_decl. + def exitSeconds_path_decl(self, ctx: ASLParser.Seconds_path_declContext): + pass + + # Enter a parse tree produced by ASLParser#timestamp_decl. + def enterTimestamp_decl(self, ctx: ASLParser.Timestamp_declContext): + pass + + # Exit a parse tree produced by ASLParser#timestamp_decl. + def exitTimestamp_decl(self, ctx: ASLParser.Timestamp_declContext): + pass + + # Enter a parse tree produced by ASLParser#timestamp_path_decl. + def enterTimestamp_path_decl(self, ctx: ASLParser.Timestamp_path_declContext): + pass + + # Exit a parse tree produced by ASLParser#timestamp_path_decl. + def exitTimestamp_path_decl(self, ctx: ASLParser.Timestamp_path_declContext): + pass + + # Enter a parse tree produced by ASLParser#items_path_decl. + def enterItems_path_decl(self, ctx: ASLParser.Items_path_declContext): + pass + + # Exit a parse tree produced by ASLParser#items_path_decl. + def exitItems_path_decl(self, ctx: ASLParser.Items_path_declContext): + pass + + # Enter a parse tree produced by ASLParser#max_concurrency_decl. + def enterMax_concurrency_decl(self, ctx: ASLParser.Max_concurrency_declContext): + pass + + # Exit a parse tree produced by ASLParser#max_concurrency_decl. + def exitMax_concurrency_decl(self, ctx: ASLParser.Max_concurrency_declContext): + pass + + # Enter a parse tree produced by ASLParser#parameters_decl. + def enterParameters_decl(self, ctx: ASLParser.Parameters_declContext): + pass + + # Exit a parse tree produced by ASLParser#parameters_decl. + def exitParameters_decl(self, ctx: ASLParser.Parameters_declContext): + pass + + # Enter a parse tree produced by ASLParser#timeout_seconds_decl. + def enterTimeout_seconds_decl(self, ctx: ASLParser.Timeout_seconds_declContext): + pass + + # Exit a parse tree produced by ASLParser#timeout_seconds_decl. + def exitTimeout_seconds_decl(self, ctx: ASLParser.Timeout_seconds_declContext): + pass + + # Enter a parse tree produced by ASLParser#timeout_seconds_path_decl. + def enterTimeout_seconds_path_decl( + self, ctx: ASLParser.Timeout_seconds_path_declContext + ): + pass + + # Exit a parse tree produced by ASLParser#timeout_seconds_path_decl. + def exitTimeout_seconds_path_decl( + self, ctx: ASLParser.Timeout_seconds_path_declContext + ): + pass + + # Enter a parse tree produced by ASLParser#heartbeat_seconds_decl. + def enterHeartbeat_seconds_decl(self, ctx: ASLParser.Heartbeat_seconds_declContext): + pass + + # Exit a parse tree produced by ASLParser#heartbeat_seconds_decl. + def exitHeartbeat_seconds_decl(self, ctx: ASLParser.Heartbeat_seconds_declContext): + pass + + # Enter a parse tree produced by ASLParser#heartbeat_seconds_path_decl. + def enterHeartbeat_seconds_path_decl( + self, ctx: ASLParser.Heartbeat_seconds_path_declContext + ): + pass + + # Exit a parse tree produced by ASLParser#heartbeat_seconds_path_decl. + def exitHeartbeat_seconds_path_decl( + self, ctx: ASLParser.Heartbeat_seconds_path_declContext + ): + pass + + # Enter a parse tree produced by ASLParser#payload_tmpl_decl. + def enterPayload_tmpl_decl(self, ctx: ASLParser.Payload_tmpl_declContext): + pass + + # Exit a parse tree produced by ASLParser#payload_tmpl_decl. + def exitPayload_tmpl_decl(self, ctx: ASLParser.Payload_tmpl_declContext): + pass + + # Enter a parse tree produced by ASLParser#payload_binding_path. + def enterPayload_binding_path(self, ctx: ASLParser.Payload_binding_pathContext): + pass + + # Exit a parse tree produced by ASLParser#payload_binding_path. + def exitPayload_binding_path(self, ctx: ASLParser.Payload_binding_pathContext): + pass + + # Enter a parse tree produced by ASLParser#payload_binding_path_context_obj. + def enterPayload_binding_path_context_obj( + self, ctx: ASLParser.Payload_binding_path_context_objContext + ): + pass + + # Exit a parse tree produced by ASLParser#payload_binding_path_context_obj. + def exitPayload_binding_path_context_obj( + self, ctx: ASLParser.Payload_binding_path_context_objContext + ): + pass + + # Enter a parse tree produced by ASLParser#payload_binding_intrinsic_func. + def enterPayload_binding_intrinsic_func( + self, ctx: ASLParser.Payload_binding_intrinsic_funcContext + ): + pass + + # Exit a parse tree produced by ASLParser#payload_binding_intrinsic_func. + def exitPayload_binding_intrinsic_func( + self, ctx: ASLParser.Payload_binding_intrinsic_funcContext + ): + pass + + # Enter a parse tree produced by ASLParser#payload_binding_value. + def enterPayload_binding_value(self, ctx: ASLParser.Payload_binding_valueContext): + pass + + # Exit a parse tree produced by ASLParser#payload_binding_value. + def exitPayload_binding_value(self, ctx: ASLParser.Payload_binding_valueContext): + pass + + # Enter a parse tree produced by ASLParser#intrinsic_func. + def enterIntrinsic_func(self, ctx: ASLParser.Intrinsic_funcContext): + pass + + # Exit a parse tree produced by ASLParser#intrinsic_func. + def exitIntrinsic_func(self, ctx: ASLParser.Intrinsic_funcContext): + pass + + # Enter a parse tree produced by ASLParser#payload_arr_decl. + def enterPayload_arr_decl(self, ctx: ASLParser.Payload_arr_declContext): + pass + + # Exit a parse tree produced by ASLParser#payload_arr_decl. + def exitPayload_arr_decl(self, ctx: ASLParser.Payload_arr_declContext): + pass + + # Enter a parse tree produced by ASLParser#payload_value_decl. + def enterPayload_value_decl(self, ctx: ASLParser.Payload_value_declContext): + pass + + # Exit a parse tree produced by ASLParser#payload_value_decl. + def exitPayload_value_decl(self, ctx: ASLParser.Payload_value_declContext): + pass + + # Enter a parse tree produced by ASLParser#payload_value_float. + def enterPayload_value_float(self, ctx: ASLParser.Payload_value_floatContext): + pass + + # Exit a parse tree produced by ASLParser#payload_value_float. + def exitPayload_value_float(self, ctx: ASLParser.Payload_value_floatContext): + pass + + # Enter a parse tree produced by ASLParser#payload_value_int. + def enterPayload_value_int(self, ctx: ASLParser.Payload_value_intContext): + pass + + # Exit a parse tree produced by ASLParser#payload_value_int. + def exitPayload_value_int(self, ctx: ASLParser.Payload_value_intContext): + pass + + # Enter a parse tree produced by ASLParser#payload_value_bool. + def enterPayload_value_bool(self, ctx: ASLParser.Payload_value_boolContext): + pass + + # Exit a parse tree produced by ASLParser#payload_value_bool. + def exitPayload_value_bool(self, ctx: ASLParser.Payload_value_boolContext): + pass + + # Enter a parse tree produced by ASLParser#payload_value_null. + def enterPayload_value_null(self, ctx: ASLParser.Payload_value_nullContext): + pass + + # Exit a parse tree produced by ASLParser#payload_value_null. + def exitPayload_value_null(self, ctx: ASLParser.Payload_value_nullContext): + pass + + # Enter a parse tree produced by ASLParser#payload_value_str. + def enterPayload_value_str(self, ctx: ASLParser.Payload_value_strContext): + pass + + # Exit a parse tree produced by ASLParser#payload_value_str. + def exitPayload_value_str(self, ctx: ASLParser.Payload_value_strContext): + pass + + # Enter a parse tree produced by ASLParser#result_selector_decl. + def enterResult_selector_decl(self, ctx: ASLParser.Result_selector_declContext): + pass + + # Exit a parse tree produced by ASLParser#result_selector_decl. + def exitResult_selector_decl(self, ctx: ASLParser.Result_selector_declContext): + pass + + # Enter a parse tree produced by ASLParser#state_type. + def enterState_type(self, ctx: ASLParser.State_typeContext): + pass + + # Exit a parse tree produced by ASLParser#state_type. + def exitState_type(self, ctx: ASLParser.State_typeContext): + pass + + # Enter a parse tree produced by ASLParser#choices_decl. + def enterChoices_decl(self, ctx: ASLParser.Choices_declContext): + pass + + # Exit a parse tree produced by ASLParser#choices_decl. + def exitChoices_decl(self, ctx: ASLParser.Choices_declContext): + pass + + # Enter a parse tree produced by ASLParser#choice_rule_comparison_variable. + def enterChoice_rule_comparison_variable( + self, ctx: ASLParser.Choice_rule_comparison_variableContext + ): + pass + + # Exit a parse tree produced by ASLParser#choice_rule_comparison_variable. + def exitChoice_rule_comparison_variable( + self, ctx: ASLParser.Choice_rule_comparison_variableContext + ): + pass + + # Enter a parse tree produced by ASLParser#choice_rule_comparison_composite. + def enterChoice_rule_comparison_composite( + self, ctx: ASLParser.Choice_rule_comparison_compositeContext + ): + pass + + # Exit a parse tree produced by ASLParser#choice_rule_comparison_composite. + def exitChoice_rule_comparison_composite( + self, ctx: ASLParser.Choice_rule_comparison_compositeContext + ): + pass + + # Enter a parse tree produced by ASLParser#comparison_variable_stmt. + def enterComparison_variable_stmt( + self, ctx: ASLParser.Comparison_variable_stmtContext + ): + pass + + # Exit a parse tree produced by ASLParser#comparison_variable_stmt. + def exitComparison_variable_stmt( + self, ctx: ASLParser.Comparison_variable_stmtContext + ): + pass + + # Enter a parse tree produced by ASLParser#comparison_composite_stmt. + def enterComparison_composite_stmt( + self, ctx: ASLParser.Comparison_composite_stmtContext + ): + pass + + # Exit a parse tree produced by ASLParser#comparison_composite_stmt. + def exitComparison_composite_stmt( + self, ctx: ASLParser.Comparison_composite_stmtContext + ): + pass + + # Enter a parse tree produced by ASLParser#comparison_composite. + def enterComparison_composite(self, ctx: ASLParser.Comparison_compositeContext): + pass + + # Exit a parse tree produced by ASLParser#comparison_composite. + def exitComparison_composite(self, ctx: ASLParser.Comparison_compositeContext): + pass + + # Enter a parse tree produced by ASLParser#variable_decl. + def enterVariable_decl(self, ctx: ASLParser.Variable_declContext): + pass + + # Exit a parse tree produced by ASLParser#variable_decl. + def exitVariable_decl(self, ctx: ASLParser.Variable_declContext): + pass + + # Enter a parse tree produced by ASLParser#comparison_func. + def enterComparison_func(self, ctx: ASLParser.Comparison_funcContext): + pass + + # Exit a parse tree produced by ASLParser#comparison_func. + def exitComparison_func(self, ctx: ASLParser.Comparison_funcContext): + pass + + # Enter a parse tree produced by ASLParser#branches_decl. + def enterBranches_decl(self, ctx: ASLParser.Branches_declContext): + pass + + # Exit a parse tree produced by ASLParser#branches_decl. + def exitBranches_decl(self, ctx: ASLParser.Branches_declContext): + pass + + # Enter a parse tree produced by ASLParser#item_processor_decl. + def enterItem_processor_decl(self, ctx: ASLParser.Item_processor_declContext): + pass + + # Exit a parse tree produced by ASLParser#item_processor_decl. + def exitItem_processor_decl(self, ctx: ASLParser.Item_processor_declContext): + pass + + # Enter a parse tree produced by ASLParser#item_processor_item. + def enterItem_processor_item(self, ctx: ASLParser.Item_processor_itemContext): + pass + + # Exit a parse tree produced by ASLParser#item_processor_item. + def exitItem_processor_item(self, ctx: ASLParser.Item_processor_itemContext): + pass + + # Enter a parse tree produced by ASLParser#processor_config_decl. + def enterProcessor_config_decl(self, ctx: ASLParser.Processor_config_declContext): + pass + + # Exit a parse tree produced by ASLParser#processor_config_decl. + def exitProcessor_config_decl(self, ctx: ASLParser.Processor_config_declContext): + pass + + # Enter a parse tree produced by ASLParser#processor_config_field. + def enterProcessor_config_field(self, ctx: ASLParser.Processor_config_fieldContext): + pass + + # Exit a parse tree produced by ASLParser#processor_config_field. + def exitProcessor_config_field(self, ctx: ASLParser.Processor_config_fieldContext): + pass + + # Enter a parse tree produced by ASLParser#mode_decl. + def enterMode_decl(self, ctx: ASLParser.Mode_declContext): + pass + + # Exit a parse tree produced by ASLParser#mode_decl. + def exitMode_decl(self, ctx: ASLParser.Mode_declContext): + pass + + # Enter a parse tree produced by ASLParser#mode_type. + def enterMode_type(self, ctx: ASLParser.Mode_typeContext): + pass + + # Exit a parse tree produced by ASLParser#mode_type. + def exitMode_type(self, ctx: ASLParser.Mode_typeContext): + pass + + # Enter a parse tree produced by ASLParser#execution_decl. + def enterExecution_decl(self, ctx: ASLParser.Execution_declContext): + pass + + # Exit a parse tree produced by ASLParser#execution_decl. + def exitExecution_decl(self, ctx: ASLParser.Execution_declContext): + pass + + # Enter a parse tree produced by ASLParser#execution_type. + def enterExecution_type(self, ctx: ASLParser.Execution_typeContext): + pass + + # Exit a parse tree produced by ASLParser#execution_type. + def exitExecution_type(self, ctx: ASLParser.Execution_typeContext): + pass + + # Enter a parse tree produced by ASLParser#iterator_decl. + def enterIterator_decl(self, ctx: ASLParser.Iterator_declContext): + pass + + # Exit a parse tree produced by ASLParser#iterator_decl. + def exitIterator_decl(self, ctx: ASLParser.Iterator_declContext): + pass + + # Enter a parse tree produced by ASLParser#iterator_decl_item. + def enterIterator_decl_item(self, ctx: ASLParser.Iterator_decl_itemContext): + pass + + # Exit a parse tree produced by ASLParser#iterator_decl_item. + def exitIterator_decl_item(self, ctx: ASLParser.Iterator_decl_itemContext): + pass + + # Enter a parse tree produced by ASLParser#item_selector_decl. + def enterItem_selector_decl(self, ctx: ASLParser.Item_selector_declContext): + pass + + # Exit a parse tree produced by ASLParser#item_selector_decl. + def exitItem_selector_decl(self, ctx: ASLParser.Item_selector_declContext): + pass + + # Enter a parse tree produced by ASLParser#item_reader_decl. + def enterItem_reader_decl(self, ctx: ASLParser.Item_reader_declContext): + pass + + # Exit a parse tree produced by ASLParser#item_reader_decl. + def exitItem_reader_decl(self, ctx: ASLParser.Item_reader_declContext): + pass + + # Enter a parse tree produced by ASLParser#items_reader_field. + def enterItems_reader_field(self, ctx: ASLParser.Items_reader_fieldContext): + pass + + # Exit a parse tree produced by ASLParser#items_reader_field. + def exitItems_reader_field(self, ctx: ASLParser.Items_reader_fieldContext): + pass + + # Enter a parse tree produced by ASLParser#reader_config_decl. + def enterReader_config_decl(self, ctx: ASLParser.Reader_config_declContext): + pass + + # Exit a parse tree produced by ASLParser#reader_config_decl. + def exitReader_config_decl(self, ctx: ASLParser.Reader_config_declContext): + pass + + # Enter a parse tree produced by ASLParser#reader_config_field. + def enterReader_config_field(self, ctx: ASLParser.Reader_config_fieldContext): + pass + + # Exit a parse tree produced by ASLParser#reader_config_field. + def exitReader_config_field(self, ctx: ASLParser.Reader_config_fieldContext): + pass + + # Enter a parse tree produced by ASLParser#input_type_decl. + def enterInput_type_decl(self, ctx: ASLParser.Input_type_declContext): + pass + + # Exit a parse tree produced by ASLParser#input_type_decl. + def exitInput_type_decl(self, ctx: ASLParser.Input_type_declContext): + pass + + # Enter a parse tree produced by ASLParser#csv_header_location_decl. + def enterCsv_header_location_decl( + self, ctx: ASLParser.Csv_header_location_declContext + ): + pass + + # Exit a parse tree produced by ASLParser#csv_header_location_decl. + def exitCsv_header_location_decl( + self, ctx: ASLParser.Csv_header_location_declContext + ): + pass + + # Enter a parse tree produced by ASLParser#csv_headers_decl. + def enterCsv_headers_decl(self, ctx: ASLParser.Csv_headers_declContext): + pass + + # Exit a parse tree produced by ASLParser#csv_headers_decl. + def exitCsv_headers_decl(self, ctx: ASLParser.Csv_headers_declContext): + pass + + # Enter a parse tree produced by ASLParser#max_items_decl. + def enterMax_items_decl(self, ctx: ASLParser.Max_items_declContext): + pass + + # Exit a parse tree produced by ASLParser#max_items_decl. + def exitMax_items_decl(self, ctx: ASLParser.Max_items_declContext): + pass + + # Enter a parse tree produced by ASLParser#max_items_path_decl. + def enterMax_items_path_decl(self, ctx: ASLParser.Max_items_path_declContext): + pass + + # Exit a parse tree produced by ASLParser#max_items_path_decl. + def exitMax_items_path_decl(self, ctx: ASLParser.Max_items_path_declContext): + pass + + # Enter a parse tree produced by ASLParser#retry_decl. + def enterRetry_decl(self, ctx: ASLParser.Retry_declContext): + pass + + # Exit a parse tree produced by ASLParser#retry_decl. + def exitRetry_decl(self, ctx: ASLParser.Retry_declContext): + pass + + # Enter a parse tree produced by ASLParser#retrier_decl. + def enterRetrier_decl(self, ctx: ASLParser.Retrier_declContext): + pass + + # Exit a parse tree produced by ASLParser#retrier_decl. + def exitRetrier_decl(self, ctx: ASLParser.Retrier_declContext): + pass + + # Enter a parse tree produced by ASLParser#retrier_stmt. + def enterRetrier_stmt(self, ctx: ASLParser.Retrier_stmtContext): + pass + + # Exit a parse tree produced by ASLParser#retrier_stmt. + def exitRetrier_stmt(self, ctx: ASLParser.Retrier_stmtContext): + pass + + # Enter a parse tree produced by ASLParser#error_equals_decl. + def enterError_equals_decl(self, ctx: ASLParser.Error_equals_declContext): + pass + + # Exit a parse tree produced by ASLParser#error_equals_decl. + def exitError_equals_decl(self, ctx: ASLParser.Error_equals_declContext): + pass + + # Enter a parse tree produced by ASLParser#interval_seconds_decl. + def enterInterval_seconds_decl(self, ctx: ASLParser.Interval_seconds_declContext): + pass + + # Exit a parse tree produced by ASLParser#interval_seconds_decl. + def exitInterval_seconds_decl(self, ctx: ASLParser.Interval_seconds_declContext): + pass + + # Enter a parse tree produced by ASLParser#max_attempts_decl. + def enterMax_attempts_decl(self, ctx: ASLParser.Max_attempts_declContext): + pass + + # Exit a parse tree produced by ASLParser#max_attempts_decl. + def exitMax_attempts_decl(self, ctx: ASLParser.Max_attempts_declContext): + pass + + # Enter a parse tree produced by ASLParser#backoff_rate_decl. + def enterBackoff_rate_decl(self, ctx: ASLParser.Backoff_rate_declContext): + pass + + # Exit a parse tree produced by ASLParser#backoff_rate_decl. + def exitBackoff_rate_decl(self, ctx: ASLParser.Backoff_rate_declContext): + pass + + # Enter a parse tree produced by ASLParser#catch_decl. + def enterCatch_decl(self, ctx: ASLParser.Catch_declContext): + pass + + # Exit a parse tree produced by ASLParser#catch_decl. + def exitCatch_decl(self, ctx: ASLParser.Catch_declContext): + pass + + # Enter a parse tree produced by ASLParser#catcher_decl. + def enterCatcher_decl(self, ctx: ASLParser.Catcher_declContext): + pass + + # Exit a parse tree produced by ASLParser#catcher_decl. + def exitCatcher_decl(self, ctx: ASLParser.Catcher_declContext): + pass + + # Enter a parse tree produced by ASLParser#catcher_stmt. + def enterCatcher_stmt(self, ctx: ASLParser.Catcher_stmtContext): + pass + + # Exit a parse tree produced by ASLParser#catcher_stmt. + def exitCatcher_stmt(self, ctx: ASLParser.Catcher_stmtContext): + pass + + # Enter a parse tree produced by ASLParser#comparison_op. + def enterComparison_op(self, ctx: ASLParser.Comparison_opContext): + pass + + # Exit a parse tree produced by ASLParser#comparison_op. + def exitComparison_op(self, ctx: ASLParser.Comparison_opContext): + pass + + # Enter a parse tree produced by ASLParser#choice_operator. + def enterChoice_operator(self, ctx: ASLParser.Choice_operatorContext): + pass + + # Exit a parse tree produced by ASLParser#choice_operator. + def exitChoice_operator(self, ctx: ASLParser.Choice_operatorContext): + pass + + # Enter a parse tree produced by ASLParser#states_error_name. + def enterStates_error_name(self, ctx: ASLParser.States_error_nameContext): + pass + + # Exit a parse tree produced by ASLParser#states_error_name. + def exitStates_error_name(self, ctx: ASLParser.States_error_nameContext): + pass + + # Enter a parse tree produced by ASLParser#error_name. + def enterError_name(self, ctx: ASLParser.Error_nameContext): + pass + + # Exit a parse tree produced by ASLParser#error_name. + def exitError_name(self, ctx: ASLParser.Error_nameContext): + pass + + # Enter a parse tree produced by ASLParser#json_obj_decl. + def enterJson_obj_decl(self, ctx: ASLParser.Json_obj_declContext): + pass + + # Exit a parse tree produced by ASLParser#json_obj_decl. + def exitJson_obj_decl(self, ctx: ASLParser.Json_obj_declContext): + pass + + # Enter a parse tree produced by ASLParser#json_binding. + def enterJson_binding(self, ctx: ASLParser.Json_bindingContext): + pass + + # Exit a parse tree produced by ASLParser#json_binding. + def exitJson_binding(self, ctx: ASLParser.Json_bindingContext): + pass + + # Enter a parse tree produced by ASLParser#json_arr_decl. + def enterJson_arr_decl(self, ctx: ASLParser.Json_arr_declContext): + pass + + # Exit a parse tree produced by ASLParser#json_arr_decl. + def exitJson_arr_decl(self, ctx: ASLParser.Json_arr_declContext): + pass + + # Enter a parse tree produced by ASLParser#json_value_decl. + def enterJson_value_decl(self, ctx: ASLParser.Json_value_declContext): + pass + + # Exit a parse tree produced by ASLParser#json_value_decl. + def exitJson_value_decl(self, ctx: ASLParser.Json_value_declContext): + pass + + # Enter a parse tree produced by ASLParser#keyword_or_string. + def enterKeyword_or_string(self, ctx: ASLParser.Keyword_or_stringContext): + pass + + # Exit a parse tree produced by ASLParser#keyword_or_string. + def exitKeyword_or_string(self, ctx: ASLParser.Keyword_or_stringContext): + pass + + +del ASLParser diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/ASLParserVisitor.py b/moto/stepfunctions/parser/asl/antlr/runtime/ASLParserVisitor.py new file mode 100644 index 000000000..6b2c059b7 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlr/runtime/ASLParserVisitor.py @@ -0,0 +1,413 @@ +# Generated from /Users/mep/LocalStack/localstack/localstack/services/stepfunctions/asl/antlr/ASLParser.g4 by ANTLR 4.13.1 +from antlr4 import ParseTreeVisitor + +if "." in __name__: + from .ASLParser import ASLParser +else: + from ASLParser import ASLParser + +# This class defines a complete generic visitor for a parse tree produced by ASLParser. + + +class ASLParserVisitor(ParseTreeVisitor): + + # Visit a parse tree produced by ASLParser#program_decl. + def visitProgram_decl(self, ctx: ASLParser.Program_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#top_layer_stmt. + def visitTop_layer_stmt(self, ctx: ASLParser.Top_layer_stmtContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#startat_decl. + def visitStartat_decl(self, ctx: ASLParser.Startat_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#comment_decl. + def visitComment_decl(self, ctx: ASLParser.Comment_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#version_decl. + def visitVersion_decl(self, ctx: ASLParser.Version_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#state_stmt. + def visitState_stmt(self, ctx: ASLParser.State_stmtContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#states_decl. + def visitStates_decl(self, ctx: ASLParser.States_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#state_name. + def visitState_name(self, ctx: ASLParser.State_nameContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#state_decl. + def visitState_decl(self, ctx: ASLParser.State_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#state_decl_body. + def visitState_decl_body(self, ctx: ASLParser.State_decl_bodyContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#type_decl. + def visitType_decl(self, ctx: ASLParser.Type_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#next_decl. + def visitNext_decl(self, ctx: ASLParser.Next_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#resource_decl. + def visitResource_decl(self, ctx: ASLParser.Resource_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#input_path_decl. + def visitInput_path_decl(self, ctx: ASLParser.Input_path_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#result_decl. + def visitResult_decl(self, ctx: ASLParser.Result_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#result_path_decl. + def visitResult_path_decl(self, ctx: ASLParser.Result_path_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#output_path_decl. + def visitOutput_path_decl(self, ctx: ASLParser.Output_path_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#end_decl. + def visitEnd_decl(self, ctx: ASLParser.End_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#default_decl. + def visitDefault_decl(self, ctx: ASLParser.Default_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#error_decl. + def visitError_decl(self, ctx: ASLParser.Error_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#cause_decl. + def visitCause_decl(self, ctx: ASLParser.Cause_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#seconds_decl. + def visitSeconds_decl(self, ctx: ASLParser.Seconds_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#seconds_path_decl. + def visitSeconds_path_decl(self, ctx: ASLParser.Seconds_path_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#timestamp_decl. + def visitTimestamp_decl(self, ctx: ASLParser.Timestamp_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#timestamp_path_decl. + def visitTimestamp_path_decl(self, ctx: ASLParser.Timestamp_path_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#items_path_decl. + def visitItems_path_decl(self, ctx: ASLParser.Items_path_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#max_concurrency_decl. + def visitMax_concurrency_decl(self, ctx: ASLParser.Max_concurrency_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#parameters_decl. + def visitParameters_decl(self, ctx: ASLParser.Parameters_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#timeout_seconds_decl. + def visitTimeout_seconds_decl(self, ctx: ASLParser.Timeout_seconds_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#timeout_seconds_path_decl. + def visitTimeout_seconds_path_decl( + self, ctx: ASLParser.Timeout_seconds_path_declContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#heartbeat_seconds_decl. + def visitHeartbeat_seconds_decl(self, ctx: ASLParser.Heartbeat_seconds_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#heartbeat_seconds_path_decl. + def visitHeartbeat_seconds_path_decl( + self, ctx: ASLParser.Heartbeat_seconds_path_declContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#payload_tmpl_decl. + def visitPayload_tmpl_decl(self, ctx: ASLParser.Payload_tmpl_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#payload_binding_path. + def visitPayload_binding_path(self, ctx: ASLParser.Payload_binding_pathContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#payload_binding_path_context_obj. + def visitPayload_binding_path_context_obj( + self, ctx: ASLParser.Payload_binding_path_context_objContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#payload_binding_intrinsic_func. + def visitPayload_binding_intrinsic_func( + self, ctx: ASLParser.Payload_binding_intrinsic_funcContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#payload_binding_value. + def visitPayload_binding_value(self, ctx: ASLParser.Payload_binding_valueContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#intrinsic_func. + def visitIntrinsic_func(self, ctx: ASLParser.Intrinsic_funcContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#payload_arr_decl. + def visitPayload_arr_decl(self, ctx: ASLParser.Payload_arr_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#payload_value_decl. + def visitPayload_value_decl(self, ctx: ASLParser.Payload_value_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#payload_value_float. + def visitPayload_value_float(self, ctx: ASLParser.Payload_value_floatContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#payload_value_int. + def visitPayload_value_int(self, ctx: ASLParser.Payload_value_intContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#payload_value_bool. + def visitPayload_value_bool(self, ctx: ASLParser.Payload_value_boolContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#payload_value_null. + def visitPayload_value_null(self, ctx: ASLParser.Payload_value_nullContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#payload_value_str. + def visitPayload_value_str(self, ctx: ASLParser.Payload_value_strContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#result_selector_decl. + def visitResult_selector_decl(self, ctx: ASLParser.Result_selector_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#state_type. + def visitState_type(self, ctx: ASLParser.State_typeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#choices_decl. + def visitChoices_decl(self, ctx: ASLParser.Choices_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#choice_rule_comparison_variable. + def visitChoice_rule_comparison_variable( + self, ctx: ASLParser.Choice_rule_comparison_variableContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#choice_rule_comparison_composite. + def visitChoice_rule_comparison_composite( + self, ctx: ASLParser.Choice_rule_comparison_compositeContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#comparison_variable_stmt. + def visitComparison_variable_stmt( + self, ctx: ASLParser.Comparison_variable_stmtContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#comparison_composite_stmt. + def visitComparison_composite_stmt( + self, ctx: ASLParser.Comparison_composite_stmtContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#comparison_composite. + def visitComparison_composite(self, ctx: ASLParser.Comparison_compositeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#variable_decl. + def visitVariable_decl(self, ctx: ASLParser.Variable_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#comparison_func. + def visitComparison_func(self, ctx: ASLParser.Comparison_funcContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#branches_decl. + def visitBranches_decl(self, ctx: ASLParser.Branches_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#item_processor_decl. + def visitItem_processor_decl(self, ctx: ASLParser.Item_processor_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#item_processor_item. + def visitItem_processor_item(self, ctx: ASLParser.Item_processor_itemContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#processor_config_decl. + def visitProcessor_config_decl(self, ctx: ASLParser.Processor_config_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#processor_config_field. + def visitProcessor_config_field(self, ctx: ASLParser.Processor_config_fieldContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#mode_decl. + def visitMode_decl(self, ctx: ASLParser.Mode_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#mode_type. + def visitMode_type(self, ctx: ASLParser.Mode_typeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#execution_decl. + def visitExecution_decl(self, ctx: ASLParser.Execution_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#execution_type. + def visitExecution_type(self, ctx: ASLParser.Execution_typeContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#iterator_decl. + def visitIterator_decl(self, ctx: ASLParser.Iterator_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#iterator_decl_item. + def visitIterator_decl_item(self, ctx: ASLParser.Iterator_decl_itemContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#item_selector_decl. + def visitItem_selector_decl(self, ctx: ASLParser.Item_selector_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#item_reader_decl. + def visitItem_reader_decl(self, ctx: ASLParser.Item_reader_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#items_reader_field. + def visitItems_reader_field(self, ctx: ASLParser.Items_reader_fieldContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#reader_config_decl. + def visitReader_config_decl(self, ctx: ASLParser.Reader_config_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#reader_config_field. + def visitReader_config_field(self, ctx: ASLParser.Reader_config_fieldContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#input_type_decl. + def visitInput_type_decl(self, ctx: ASLParser.Input_type_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#csv_header_location_decl. + def visitCsv_header_location_decl( + self, ctx: ASLParser.Csv_header_location_declContext + ): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#csv_headers_decl. + def visitCsv_headers_decl(self, ctx: ASLParser.Csv_headers_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#max_items_decl. + def visitMax_items_decl(self, ctx: ASLParser.Max_items_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#max_items_path_decl. + def visitMax_items_path_decl(self, ctx: ASLParser.Max_items_path_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#retry_decl. + def visitRetry_decl(self, ctx: ASLParser.Retry_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#retrier_decl. + def visitRetrier_decl(self, ctx: ASLParser.Retrier_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#retrier_stmt. + def visitRetrier_stmt(self, ctx: ASLParser.Retrier_stmtContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#error_equals_decl. + def visitError_equals_decl(self, ctx: ASLParser.Error_equals_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#interval_seconds_decl. + def visitInterval_seconds_decl(self, ctx: ASLParser.Interval_seconds_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#max_attempts_decl. + def visitMax_attempts_decl(self, ctx: ASLParser.Max_attempts_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#backoff_rate_decl. + def visitBackoff_rate_decl(self, ctx: ASLParser.Backoff_rate_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#catch_decl. + def visitCatch_decl(self, ctx: ASLParser.Catch_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#catcher_decl. + def visitCatcher_decl(self, ctx: ASLParser.Catcher_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#catcher_stmt. + def visitCatcher_stmt(self, ctx: ASLParser.Catcher_stmtContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#comparison_op. + def visitComparison_op(self, ctx: ASLParser.Comparison_opContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#choice_operator. + def visitChoice_operator(self, ctx: ASLParser.Choice_operatorContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#states_error_name. + def visitStates_error_name(self, ctx: ASLParser.States_error_nameContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#error_name. + def visitError_name(self, ctx: ASLParser.Error_nameContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#json_obj_decl. + def visitJson_obj_decl(self, ctx: ASLParser.Json_obj_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#json_binding. + def visitJson_binding(self, ctx: ASLParser.Json_bindingContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#json_arr_decl. + def visitJson_arr_decl(self, ctx: ASLParser.Json_arr_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#json_value_decl. + def visitJson_value_decl(self, ctx: ASLParser.Json_value_declContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by ASLParser#keyword_or_string. + def visitKeyword_or_string(self, ctx: ASLParser.Keyword_or_stringContext): + return self.visitChildren(ctx) + + +del ASLParser diff --git a/moto/stepfunctions/parser/asl/antlr/runtime/__init__.py b/moto/stepfunctions/parser/asl/antlr/runtime/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/antlt4utils/__init__.py b/moto/stepfunctions/parser/asl/antlt4utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/antlt4utils/antlr4utils.py b/moto/stepfunctions/parser/asl/antlt4utils/antlr4utils.py new file mode 100644 index 000000000..a6311c104 --- /dev/null +++ b/moto/stepfunctions/parser/asl/antlt4utils/antlr4utils.py @@ -0,0 +1,27 @@ +from typing import Optional + +from antlr4 import ParserRuleContext +from antlr4.tree.Tree import ParseTree, TerminalNodeImpl + + +class Antlr4Utils: + @staticmethod + def is_production( + pt: ParseTree, rule_index: Optional[int] = None + ) -> Optional[ParserRuleContext]: + if isinstance(pt, ParserRuleContext): + prc = pt.getRuleContext() # noqa + if rule_index is not None: + return prc if prc.getRuleIndex() == rule_index else None + return prc + return None + + @staticmethod + def is_terminal( + pt: ParseTree, token_type: Optional[int] = None + ) -> Optional[TerminalNodeImpl]: + if isinstance(pt, TerminalNodeImpl): + if token_type is not None: + return pt if pt.getSymbol().type == token_type else None + return pt + return None diff --git a/moto/stepfunctions/parser/asl/component/__init__.py b/moto/stepfunctions/parser/asl/component/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/__init__.py b/moto/stepfunctions/parser/asl/component/common/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/catch/__init__.py b/moto/stepfunctions/parser/asl/component/common/catch/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/catch/catch_decl.py b/moto/stepfunctions/parser/asl/component/common/catch/catch_decl.py new file mode 100644 index 000000000..390deb634 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/catch/catch_decl.py @@ -0,0 +1,30 @@ +from typing import Final, List + +from moto.stepfunctions.parser.asl.component.common.catch.catch_outcome import ( + CatchOutcome, +) +from moto.stepfunctions.parser.asl.component.common.catch.catcher_decl import ( + CatcherDecl, +) +from moto.stepfunctions.parser.asl.component.common.catch.catcher_outcome import ( + CatcherOutcome, + CatcherOutcomeCaught, +) +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class CatchDecl(EvalComponent): + def __init__(self, catchers: List[CatcherDecl]): + self.catchers: Final[List[CatcherDecl]] = catchers + + def _eval_body(self, env: Environment) -> None: + for catcher in self.catchers: + catcher.eval(env) + catcher_outcome: CatcherOutcome = env.stack.pop() + + if isinstance(catcher_outcome, CatcherOutcomeCaught): + env.stack.append(CatchOutcome.Caught) + return + + env.stack.append(CatchOutcome.NotCaught) diff --git a/moto/stepfunctions/parser/asl/component/common/catch/catch_outcome.py b/moto/stepfunctions/parser/asl/component/common/catch/catch_outcome.py new file mode 100644 index 000000000..e31a946c6 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/catch/catch_outcome.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class CatchOutcome(Enum): + Caught = 0 + NotCaught = 1 diff --git a/moto/stepfunctions/parser/asl/component/common/catch/catcher_decl.py b/moto/stepfunctions/parser/asl/component/common/catch/catcher_decl.py new file mode 100644 index 000000000..1b06f1c9d --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/catch/catcher_decl.py @@ -0,0 +1,96 @@ +from __future__ import annotations + +from typing import Final + +from moto.stepfunctions.parser.asl.component.common.catch.catcher_outcome import ( + CatcherOutcomeCaught, + CatcherOutcomeNotCaught, +) +from moto.stepfunctions.parser.asl.component.common.catch.catcher_props import ( + CatcherProps, +) +from moto.stepfunctions.parser.asl.component.common.error_name.error_equals_decl import ( + ErrorEqualsDecl, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.common.flow.next import Next +from moto.stepfunctions.parser.asl.component.common.path.result_path import ResultPath +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class CatcherDecl(EvalComponent): + _DEFAULT_RESULT_PATH: Final[ResultPath] = ResultPath(result_path_src="$") + + def __init__( + self, + error_equals: ErrorEqualsDecl, + next_decl: Next, + result_path: ResultPath = _DEFAULT_RESULT_PATH, + ): + self.error_equals: Final[ErrorEqualsDecl] = error_equals + self.result_path: Final[ResultPath] = ( + result_path or CatcherDecl._DEFAULT_RESULT_PATH + ) + self.next_decl: Final[Next] = next_decl + + @classmethod + def from_catcher_props(cls, props: CatcherProps) -> CatcherDecl: + return cls( + error_equals=props.get( + typ=ErrorEqualsDecl, + raise_on_missing=ValueError( + f"Missing ErrorEquals declaration for Catcher declaration, in props '{props}'." + ), + ), + next_decl=props.get( + typ=Next, + raise_on_missing=ValueError( + f"Missing Next declaration for Catcher declaration, in props '{props}'." + ), + ), + result_path=props.get(typ=ResultPath), + ) + + @staticmethod + def _extract_error_cause(failure_event: FailureEvent) -> dict: + # TODO: consider formalising all EventDetails to ensure FailureEvent can always reach the state below. + # As per AWS's Api specification, all failure event carry one + # details field, with at least fields 'cause and 'error' + specs_event_details = list(failure_event.event_details.values()) + if ( + len(specs_event_details) != 1 + and "error" in specs_event_details + and "cause" in specs_event_details + ): + raise RuntimeError( + f"Internal Error: invalid event details declaration in FailureEvent: '{failure_event}'." + ) + spec_event_details: dict = list(failure_event.event_details.values())[0] + error = spec_event_details["error"] + cause = spec_event_details.get("cause") or "" + # Stepfunctions renames these fields to capital in this scenario. + return { + "Error": error, + "Cause": cause, + } + + def _eval_body(self, env: Environment) -> None: + failure_event: FailureEvent = env.stack.pop() + + env.stack.append(failure_event.error_name) + self.error_equals.eval(env) + + equals: bool = env.stack.pop() + if equals: + error_cause: dict = self._extract_error_cause(failure_event) + env.stack.append(error_cause) + + self.result_path.eval(env) + env.next_state_name = self.next_decl.name + env.stack.append(CatcherOutcomeCaught()) + else: + env.stack.append(failure_event) + env.stack.append(CatcherOutcomeNotCaught()) diff --git a/moto/stepfunctions/parser/asl/component/common/catch/catcher_outcome.py b/moto/stepfunctions/parser/asl/component/common/catch/catcher_outcome.py new file mode 100644 index 000000000..d37768355 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/catch/catcher_outcome.py @@ -0,0 +1,13 @@ +import abc + + +class CatcherOutcome(abc.ABC): + ... + + +class CatcherOutcomeCaught(CatcherOutcome): + pass + + +class CatcherOutcomeNotCaught(CatcherOutcome): + pass diff --git a/moto/stepfunctions/parser/asl/component/common/catch/catcher_props.py b/moto/stepfunctions/parser/asl/component/common/catch/catcher_props.py new file mode 100644 index 000000000..e8709a148 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/catch/catcher_props.py @@ -0,0 +1,5 @@ +from moto.stepfunctions.parser.asl.parse.typed_props import TypedProps + + +class CatcherProps(TypedProps): + pass diff --git a/moto/stepfunctions/parser/asl/component/common/cause_decl.py b/moto/stepfunctions/parser/asl/component/common/cause_decl.py new file mode 100644 index 000000000..59ab43451 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/cause_decl.py @@ -0,0 +1,8 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class CauseDecl(Component): + def __init__(self, cause: str): + self.cause: Final[str] = cause diff --git a/moto/stepfunctions/parser/asl/component/common/comment.py b/moto/stepfunctions/parser/asl/component/common/comment.py new file mode 100644 index 000000000..2edc515b4 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/comment.py @@ -0,0 +1,8 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class Comment(Component): + def __init__(self, comment: str): + self.comment: Final[str] = comment diff --git a/moto/stepfunctions/parser/asl/component/common/error_decl.py b/moto/stepfunctions/parser/asl/component/common/error_decl.py new file mode 100644 index 000000000..752d32bbf --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/error_decl.py @@ -0,0 +1,8 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class ErrorDecl(Component): + def __init__(self, error: str): + self.error: Final[str] = error diff --git a/moto/stepfunctions/parser/asl/component/common/error_name/__init__.py b/moto/stepfunctions/parser/asl/component/common/error_name/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/error_name/custom_error_name.py b/moto/stepfunctions/parser/asl/component/common/error_name/custom_error_name.py new file mode 100644 index 000000000..bb30b8f7e --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/error_name/custom_error_name.py @@ -0,0 +1,20 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.common.error_name.error_name import ( + ErrorName, +) + + +class CustomErrorName(ErrorName): + """ + States MAY report errors with other names, which MUST NOT begin with the prefix "States.". + """ + + _ILLEGAL_PREFIX: Final[str] = "States." + + def __init__(self, error_name: str): + if error_name.startswith(CustomErrorName._ILLEGAL_PREFIX): + raise ValueError( + f"Custom Error Names MUST NOT begin with the prefix 'States.', got '{error_name}'." + ) + super().__init__(error_name=error_name) diff --git a/moto/stepfunctions/parser/asl/component/common/error_name/error_equals_decl.py b/moto/stepfunctions/parser/asl/component/common/error_name/error_equals_decl.py new file mode 100644 index 000000000..b8fb636d3 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/error_name/error_equals_decl.py @@ -0,0 +1,62 @@ +from typing import Final, List + +from moto.stepfunctions.parser.asl.component.common.error_name.error_name import ( + ErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name import ( + StatesErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ErrorEqualsDecl(EvalComponent): + """ + ErrorEquals value MUST be a non-empty array of Strings, which match Error Names. + Each Retrier MUST contain a field named "ErrorEquals" whose value MUST be a non-empty array of Strings, + which match Error Names. + """ + + _STATE_ALL_ERROR: Final[StatesErrorName] = StatesErrorName( + typ=StatesErrorNameType.StatesALL + ) + _STATE_TASK_ERROR: Final[StatesErrorName] = StatesErrorName( + typ=StatesErrorNameType.StatesTaskFailed + ) + + def __init__(self, error_names: List[ErrorName]): + # The reserved name "States.ALL" in a Retrier’s "ErrorEquals" field is a wildcard + # and matches any Error Name. Such a value MUST appear alone in the "ErrorEquals" + # array and MUST appear in the last Retrier in the "Retry" array. + if ErrorEqualsDecl._STATE_ALL_ERROR in error_names and len(error_names) > 1: + raise ValueError( + f"States.ALL must appear alone in the ErrorEquals array, got '{error_names}'." + ) + + # TODO: how to handle duplicate ErrorName? + self.error_names: List[ErrorName] = error_names + + def _eval_body(self, env: Environment) -> None: + """ + When a state reports an error, the interpreter scans through the Retriers and, + when the Error Name appears in the value of a Retrier’s "ErrorEquals" field, implements the retry policy + described in that Retrier. + This pops the error from the stack, and appends the bool of this check. + """ + + # Try to reduce error response to ErrorName or pass exception upstream. + error_name: ErrorName = env.stack.pop() + + if ErrorEqualsDecl._STATE_ALL_ERROR in self.error_names: + res = True + elif ErrorEqualsDecl._STATE_TASK_ERROR in self.error_names and not isinstance( + error_name, StatesErrorName + ): # TODO: consider binding a 'context' variable to error_names to more formally detect their evaluation type. + res = True + else: + res = error_name in self.error_names + + env.stack.append(res) diff --git a/moto/stepfunctions/parser/asl/component/common/error_name/error_name.py b/moto/stepfunctions/parser/asl/component/common/error_name/error_name.py new file mode 100644 index 000000000..852039ed8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/error_name/error_name.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +import abc +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class ErrorName(Component, abc.ABC): + def __init__(self, error_name: str): + self.error_name: Final[str] = error_name + + def matches(self, error_name: str) -> bool: + return self.error_name == error_name + + def __eq__(self, other): + if isinstance(other, ErrorName): + return self.matches(other.error_name) + return False diff --git a/moto/stepfunctions/parser/asl/component/common/error_name/failure_event.py b/moto/stepfunctions/parser/asl/component/common/error_name/failure_event.py new file mode 100644 index 000000000..20f81bcb9 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/error_name/failure_event.py @@ -0,0 +1,58 @@ +from typing import Final, Optional, Tuple + +from moto.stepfunctions.parser.api import ExecutionFailedEventDetails, HistoryEventType +from moto.stepfunctions.parser.asl.component.common.error_name.error_name import ( + ErrorName, +) +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails + + +class FailureEvent: + error_name: Final[Optional[ErrorName]] + event_type: Final[HistoryEventType] + event_details: Final[Optional[EventDetails]] + + def __init__( + self, + error_name: Optional[ErrorName], + event_type: HistoryEventType, + event_details: Optional[EventDetails] = None, + ): + self.error_name = error_name + self.event_type = event_type + self.event_details = event_details + + +class FailureEventException(Exception): + failure_event: Final[FailureEvent] + + def __init__(self, failure_event: FailureEvent): + self.failure_event = failure_event + + def extract_error_cause_pair(self) -> Optional[Tuple[Optional[str], Optional[str]]]: + if self.failure_event.event_details is None: + return None + + failure_event_spec = list(self.failure_event.event_details.values())[0] + + error = None + cause = None + if "error" in failure_event_spec: + error = failure_event_spec["error"] + if "cause" in failure_event_spec: + cause = failure_event_spec["cause"] + return error, cause + + def get_execution_failed_event_details( + self, + ) -> Optional[ExecutionFailedEventDetails]: + maybe_error_cause_pair = self.extract_error_cause_pair() + if maybe_error_cause_pair is None: + return None + execution_failed_event_details = ExecutionFailedEventDetails() + error, cause = maybe_error_cause_pair + if error: + execution_failed_event_details["error"] = error + if cause: + execution_failed_event_details["cause"] = cause + return execution_failed_event_details diff --git a/moto/stepfunctions/parser/asl/component/common/error_name/states_error_name.py b/moto/stepfunctions/parser/asl/component/common/error_name/states_error_name.py new file mode 100644 index 000000000..e613a79bc --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/error_name/states_error_name.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +from typing import Final + +from moto.stepfunctions.parser.asl.component.common.error_name.error_name import ( + ErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) + + +class StatesErrorName(ErrorName): + def __init__(self, typ: StatesErrorNameType): + super().__init__(error_name=typ.to_name()) + self.typ: Final[StatesErrorNameType] = typ + + @classmethod + def from_name(cls, error_name: str) -> StatesErrorName: + error_name_type: StatesErrorNameType = StatesErrorNameType.from_name(error_name) + return cls(typ=error_name_type) diff --git a/moto/stepfunctions/parser/asl/component/common/error_name/states_error_name_type.py b/moto/stepfunctions/parser/asl/component/common/error_name/states_error_name_type.py new file mode 100644 index 000000000..29c50f4fa --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/error_name/states_error_name_type.py @@ -0,0 +1,52 @@ +from __future__ import annotations + +from enum import Enum +from typing import Dict, Final + +from moto.stepfunctions.parser.asl.antlr.runtime.ASLLexer import ASLLexer + + +class StatesErrorNameType(Enum): + StatesALL = ASLLexer.ERRORNAMEStatesALL + StatesHeartbeatTimeout = ASLLexer.ERRORNAMEStatesHeartbeatTimeout + StatesTimeout = ASLLexer.ERRORNAMEStatesTimeout + StatesTaskFailed = ASLLexer.ERRORNAMEStatesTaskFailed + StatesPermissions = ASLLexer.ERRORNAMEStatesPermissions + StatesResultPathMatchFailure = ASLLexer.ERRORNAMEStatesResultPathMatchFailure + StatesParameterPathFailure = ASLLexer.ERRORNAMEStatesParameterPathFailure + StatesBranchFailed = ASLLexer.ERRORNAMEStatesBranchFailed + StatesNoChoiceMatched = ASLLexer.ERRORNAMEStatesNoChoiceMatched + StatesIntrinsicFailure = ASLLexer.ERRORNAMEStatesIntrinsicFailure + StatesExceedToleratedFailureThreshold = ( + ASLLexer.ERRORNAMEStatesExceedToleratedFailureThreshold + ) + StatesItemReaderFailed = ASLLexer.ERRORNAMEStatesItemReaderFailed + StatesResultWriterFailed = ASLLexer.ERRORNAMEStatesResultWriterFailed + StatesRuntime = ASLLexer.ERRORNAMEStatesRuntime + + def to_name(self) -> str: + return _error_name(self) + + @classmethod + def from_name(cls, name: str) -> StatesErrorNameType: + error_name = _REVERSE_NAME_LOOKUP.get(name, None) + if error_name is None: + raise ValueError(f"Unknown ErrorName type, got: '{name}'.") + return cls(error_name.value) + + +def _error_name(error_name: StatesErrorNameType) -> str: + return ASLLexer.literalNames[error_name.value][2:-2] + + +def _reverse_error_name_lookup() -> Dict[str, StatesErrorNameType]: + lookup: Dict[str, StatesErrorNameType] = dict() + for error_name in StatesErrorNameType: + error_text: str = _error_name(error_name) + lookup[error_text] = error_name + return lookup + + +_REVERSE_NAME_LOOKUP: Final[ + Dict[str, StatesErrorNameType] +] = _reverse_error_name_lookup() diff --git a/moto/stepfunctions/parser/asl/component/common/flow/__init__.py b/moto/stepfunctions/parser/asl/component/common/flow/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/flow/end.py b/moto/stepfunctions/parser/asl/component/common/flow/end.py new file mode 100644 index 000000000..5ace29a19 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/flow/end.py @@ -0,0 +1,9 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class End(Component): + def __init__(self, is_end: bool): + # Designates this state as a terminal state (ends the execution) if set to true. + self.is_end: Final[bool] = is_end diff --git a/moto/stepfunctions/parser/asl/component/common/flow/next.py b/moto/stepfunctions/parser/asl/component/common/flow/next.py new file mode 100644 index 000000000..8a53bc73e --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/flow/next.py @@ -0,0 +1,11 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class Next(Component): + name: Final[str] + + def __init__(self, name: str): + # The name of the next state that is run when the current state finishes. + self.name = name diff --git a/moto/stepfunctions/parser/asl/component/common/flow/start_at.py b/moto/stepfunctions/parser/asl/component/common/flow/start_at.py new file mode 100644 index 000000000..94fa0f1fc --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/flow/start_at.py @@ -0,0 +1,8 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class StartAt(Component): + def __init__(self, start_at_name: str): + self.start_at_name: Final[str] = start_at_name diff --git a/moto/stepfunctions/parser/asl/component/common/parameters.py b/moto/stepfunctions/parser/asl/component/common/parameters.py new file mode 100644 index 000000000..a6c0a7e06 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/parameters.py @@ -0,0 +1,15 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadtmpl.payload_tmpl import ( + PayloadTmpl, +) +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class Parameters(EvalComponent): + def __init__(self, payload_tmpl: PayloadTmpl): + self.payload_tmpl: Final[PayloadTmpl] = payload_tmpl + + def _eval_body(self, env: Environment) -> None: + self.payload_tmpl.eval(env=env) diff --git a/moto/stepfunctions/parser/asl/component/common/path/__init__.py b/moto/stepfunctions/parser/asl/component/common/path/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/path/input_path.py b/moto/stepfunctions/parser/asl/component/common/path/input_path.py new file mode 100644 index 000000000..5b03cb129 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/path/input_path.py @@ -0,0 +1,24 @@ +import copy +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class InputPath(EvalComponent): + DEFAULT_PATH: Final[str] = "$" + + input_path_src: Final[Optional[str]] + + def __init__(self, input_path_src: Optional[str]): + self.input_path_src = input_path_src + + def _eval_body(self, env: Environment) -> None: + if self.input_path_src is None: + value = dict() + elif self.input_path_src == InputPath.DEFAULT_PATH: + value = env.inp + else: + value = JSONPathUtils.extract_json(self.input_path_src, env.inp) + env.stack.append(copy.deepcopy(value)) diff --git a/moto/stepfunctions/parser/asl/component/common/path/items_path.py b/moto/stepfunctions/parser/asl/component/common/path/items_path.py new file mode 100644 index 000000000..ff439218b --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/path/items_path.py @@ -0,0 +1,19 @@ +import copy +from typing import Final + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class ItemsPath(EvalComponent): + DEFAULT_PATH: Final[str] = "$" + + def __init__(self, items_path_src: str = DEFAULT_PATH): + self.items_path_src: Final[str] = items_path_src + + def _eval_body(self, env: Environment) -> None: + if self.items_path_src != ItemsPath.DEFAULT_PATH: + value = copy.deepcopy(env.stack[-1]) + value = JSONPathUtils.extract_json(self.items_path_src, value) + env.stack.append(value) diff --git a/moto/stepfunctions/parser/asl/component/common/path/output_path.py b/moto/stepfunctions/parser/asl/component/common/path/output_path.py new file mode 100644 index 000000000..002c653ce --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/path/output_path.py @@ -0,0 +1,22 @@ +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class OutputPath(EvalComponent): + DEFAULT_PATH: Final[str] = "$" + + output_path: Final[Optional[str]] + + def __init__(self, output_path: Optional[str]): + self.output_path = output_path + + def _eval_body(self, env: Environment) -> None: + if self.output_path is None: + env.inp = dict() + else: + current_output = env.stack.pop() + state_output = JSONPathUtils.extract_json(self.output_path, current_output) + env.inp = state_output diff --git a/moto/stepfunctions/parser/asl/component/common/path/result_path.py b/moto/stepfunctions/parser/asl/component/common/path/result_path.py new file mode 100644 index 000000000..87b97a559 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/path/result_path.py @@ -0,0 +1,33 @@ +import copy +from typing import Final, Optional + +from jsonpath_ng import parse + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ResultPath(EvalComponent): + DEFAULT_PATH: Final[str] = "$" + + result_path_src: Final[Optional[str]] + + def __init__(self, result_path_src: Optional[str]): + self.result_path_src = result_path_src + + def _eval_body(self, env: Environment) -> None: + state_input = copy.deepcopy(env.inp) + + # Discard task output if there is one, and set the output ot be the state's input. + if self.result_path_src is None: + env.stack.clear() + env.stack.append(state_input) + return + + # Transform the output with the input. + current_output = env.stack.pop() + result_expr = parse(self.result_path_src) + state_output = result_expr.update_or_create( + state_input, copy.deepcopy(current_output) + ) + env.stack.append(state_output) diff --git a/moto/stepfunctions/parser/asl/component/common/payload/__init__.py b/moto/stepfunctions/parser/asl/component/common/payload/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/__init__.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payload_value.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payload_value.py new file mode 100644 index 000000000..a784f507a --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payload_value.py @@ -0,0 +1,7 @@ +import abc + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent + + +class PayloadValue(EvalComponent, abc.ABC): + ... diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadarr/__init__.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadarr/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadarr/payload_arr.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadarr/payload_arr.py new file mode 100644 index 000000000..0e830f265 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadarr/payload_arr.py @@ -0,0 +1,18 @@ +from typing import Final, List + +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payload_value import ( + PayloadValue, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class PayloadArr(PayloadValue): + def __init__(self, payload_values: List[PayloadValue]): + self.payload_values: Final[List[PayloadValue]] = payload_values + + def _eval_body(self, env: Environment) -> None: + arr = list() + for payload_value in self.payload_values: + payload_value.eval(env) + arr.append(env.stack.pop()) + env.stack.append(arr) diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/__init__.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding.py new file mode 100644 index 000000000..ac80eb192 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding.py @@ -0,0 +1,22 @@ +import abc +from typing import Any, Final + +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payload_value import ( + PayloadValue, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class PayloadBinding(PayloadValue, abc.ABC): + def __init__(self, field: str): + self.field: Final[str] = field + + @abc.abstractmethod + def _eval_val(self, env: Environment) -> Any: + ... + + def _eval_body(self, env: Environment) -> None: + cnt: dict = env.stack.pop() + val = self._eval_val(env=env) + cnt[self.field] = val + env.stack.append(cnt) diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding_intrinsic_func.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding_intrinsic_func.py new file mode 100644 index 000000000..3b2ddab2b --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding_intrinsic_func.py @@ -0,0 +1,27 @@ +from typing import Any, Final + +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadbinding.payload_binding import ( + PayloadBinding, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.function import Function +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.parse.intrinsic.intrinsic_parser import ( + IntrinsicParser, +) + + +class PayloadBindingIntrinsicFunc(PayloadBinding): + def __init__(self, field: str, intrinsic_func: str): + super().__init__(field=field) + self.src: Final[str] = intrinsic_func + self.function: Final[Function] = IntrinsicParser.parse(self.src) + + @classmethod + def from_raw(cls, string_dollar: str, intrinsic_func: str): + field: str = string_dollar[:-2] + return cls(field=field, intrinsic_func=intrinsic_func) + + def _eval_val(self, env: Environment) -> Any: + self.function.eval(env=env) + val = env.stack.pop() + return val diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding_path.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding_path.py new file mode 100644 index 000000000..37fa477df --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding_path.py @@ -0,0 +1,49 @@ +from typing import Any, Final + +from moto.stepfunctions.parser.api import HistoryEventType, TaskFailedEventDetails +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name import ( + StatesErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadbinding.payload_binding import ( + PayloadBinding, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class PayloadBindingPath(PayloadBinding): + def __init__(self, field: str, path: str): + super().__init__(field=field) + self.path: Final[str] = path + + @classmethod + def from_raw(cls, string_dollar: str, string_path: str): + field: str = string_dollar[:-2] + return cls(field=field, path=string_path) + + def _eval_val(self, env: Environment) -> Any: + inp = env.stack[-1] + try: + value = JSONPathUtils.extract_json(self.path, inp) + except RuntimeError: + failure_event = FailureEvent( + error_name=StatesErrorName(typ=StatesErrorNameType.StatesRuntime), + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + error=StatesErrorNameType.StatesRuntime.to_name(), + cause=f"The JSONPath {self.path} specified for the field {self.field}.$ could not be found in the input {to_json_str(inp)}", + ) + ), + ) + raise FailureEventException(failure_event=failure_event) + return value diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding_path_context_obj.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding_path_context_obj.py new file mode 100644 index 000000000..c54a11351 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding_path_context_obj.py @@ -0,0 +1,30 @@ +from typing import Any, Final + +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadbinding.payload_binding import ( + PayloadBinding, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class PayloadBindingPathContextObj(PayloadBinding): + def __init__(self, field: str, path_context_obj: str): + super().__init__(field=field) + self.path_context_obj: Final[str] = path_context_obj + + @classmethod + def from_raw(cls, string_dollar: str, string_path_context_obj: str): + field: str = string_dollar[:-2] + path_context_obj: str = string_path_context_obj[1:] + return cls(field=field, path_context_obj=path_context_obj) + + def _eval_val(self, env: Environment) -> Any: + if self.path_context_obj.endswith("Task.Token"): + task_token = env.context_object_manager.update_task_token() + env.callback_pool_manager.add(task_token) + value = task_token + else: + value = JSONPathUtils.extract_json( + self.path_context_obj, env.context_object_manager.context_object + ) + return value diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding_value.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding_value.py new file mode 100644 index 000000000..1f3fd31e9 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadbinding/payload_binding_value.py @@ -0,0 +1,20 @@ +from typing import Any, Final + +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payload_value import ( + PayloadValue, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadbinding.payload_binding import ( + PayloadBinding, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class PayloadBindingValue(PayloadBinding): + def __init__(self, field: str, value: PayloadValue): + super().__init__(field=field) + self.value: Final[PayloadValue] = value + + def _eval_val(self, env: Environment) -> Any: + self.value.eval(env) + val: Any = env.stack.pop() + return val diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadtmpl/__init__.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadtmpl/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadtmpl/payload_tmpl.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadtmpl/payload_tmpl.py new file mode 100644 index 000000000..6bb32eaac --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadtmpl/payload_tmpl.py @@ -0,0 +1,19 @@ +from typing import Final, List + +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payload_value import ( + PayloadValue, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadbinding.payload_binding import ( + PayloadBinding, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class PayloadTmpl(PayloadValue): + def __init__(self, payload_bindings: List[PayloadBinding]): + self.payload_bindings: Final[List[PayloadBinding]] = payload_bindings + + def _eval_body(self, env: Environment) -> None: + env.stack.append(dict()) + for payload_binding in self.payload_bindings: + payload_binding.eval(env) diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/__init__.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_bool.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_bool.py new file mode 100644 index 000000000..b447b6eaa --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_bool.py @@ -0,0 +1,10 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadvaluelit.payload_value_lit import ( + PayloadValueLit, +) + + +class PayloadValueBool(PayloadValueLit): + def __init__(self, val: bool): + self.val: Final[bool] = val diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_float.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_float.py new file mode 100644 index 000000000..e743cd066 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_float.py @@ -0,0 +1,10 @@ +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadvaluelit.payload_value_lit import ( + PayloadValueLit, +) + + +class PayloadValueFloat(PayloadValueLit): + val: float + + def __init__(self, val: float): + super().__init__(val=val) diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_int.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_int.py new file mode 100644 index 000000000..e30182ab8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_int.py @@ -0,0 +1,10 @@ +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadvaluelit.payload_value_lit import ( + PayloadValueLit, +) + + +class PayloadValueInt(PayloadValueLit): + val: int + + def __init__(self, val: int): + super().__init__(val=val) diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_lit.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_lit.py new file mode 100644 index 000000000..2f8831ea7 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_lit.py @@ -0,0 +1,17 @@ +import abc +from typing import Any + +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payload_value import ( + PayloadValue, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class PayloadValueLit(PayloadValue, abc.ABC): + val: Any + + def __init__(self, val: Any): + self.val: Any = val + + def _eval_body(self, env: Environment) -> None: + env.stack.append(self.val) diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_null.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_null.py new file mode 100644 index 000000000..b0f14e81e --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_null.py @@ -0,0 +1,10 @@ +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadvaluelit.payload_value_lit import ( + PayloadValueLit, +) + + +class PayloadValueNull(PayloadValueLit): + val: None + + def __init__(self): + super().__init__(val=None) diff --git a/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_str.py b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_str.py new file mode 100644 index 000000000..7ac631c03 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/payload/payloadvalue/payloadvaluelit/payload_value_str.py @@ -0,0 +1,10 @@ +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadvaluelit.payload_value_lit import ( + PayloadValueLit, +) + + +class PayloadValueStr(PayloadValueLit): + val: str + + def __init__(self, val: str): + super().__init__(val=val) diff --git a/moto/stepfunctions/parser/asl/component/common/result_selector.py b/moto/stepfunctions/parser/asl/component/common/result_selector.py new file mode 100644 index 000000000..f741eeb37 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/result_selector.py @@ -0,0 +1,13 @@ +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadtmpl.payload_tmpl import ( + PayloadTmpl, +) +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ResultSelector(EvalComponent): + def __init__(self, payload_tmpl: PayloadTmpl): + self.payload_tmpl: PayloadTmpl = payload_tmpl + + def _eval_body(self, env: Environment) -> None: + self.payload_tmpl.eval(env=env) diff --git a/moto/stepfunctions/parser/asl/component/common/retry/__init__.py b/moto/stepfunctions/parser/asl/component/common/retry/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/retry/backoff_rate_decl.py b/moto/stepfunctions/parser/asl/component/common/retry/backoff_rate_decl.py new file mode 100644 index 000000000..1fea05462 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/retry/backoff_rate_decl.py @@ -0,0 +1,20 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class BackoffRateDecl(Component): + """ + "BackoffRate": a number which is the multiplier that increases the retry interval on each + attempt (default: 2.0). The value of BackoffRate MUST be greater than or equal to 1.0. + """ + + DEFAULT_RATE: Final[float] = 2.0 + MIN_RATE: Final[float] = 1.0 + + def __init__(self, rate: float = DEFAULT_RATE): + if rate < self.MIN_RATE: + raise ValueError( + f"The value of BackoffRate MUST be greater than or equal to 1.0, got '{rate}'." + ) + self.rate: Final[float] = rate diff --git a/moto/stepfunctions/parser/asl/component/common/retry/interval_seconds_decl.py b/moto/stepfunctions/parser/asl/component/common/retry/interval_seconds_decl.py new file mode 100644 index 000000000..5996817c8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/retry/interval_seconds_decl.py @@ -0,0 +1,19 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class IntervalSecondsDecl(Component): + """ + IntervalSeconds: its value MUST be a positive integer, representing the number of seconds before the + first retry attempt (default value: 1); + """ + + DEFAULT_SECONDS: Final[int] = 1 + + def __init__(self, seconds: int = DEFAULT_SECONDS): + if seconds < 0: + raise ValueError( + f"IntervalSeconds value must be a positive integer, found '{seconds}'." + ) + self.seconds: Final[int] = seconds diff --git a/moto/stepfunctions/parser/asl/component/common/retry/max_attempts_decl.py b/moto/stepfunctions/parser/asl/component/common/retry/max_attempts_decl.py new file mode 100644 index 000000000..f0422ce65 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/retry/max_attempts_decl.py @@ -0,0 +1,19 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class MaxAttemptsDecl(Component): + """ + "MaxAttempts": value MUST be a non-negative integer, representing the maximum number + of retry attempts (default: 3) + """ + + DEFAULT_ATTEMPTS: Final[int] = 3 + + def __init__(self, attempts: int = DEFAULT_ATTEMPTS): + if attempts < 0: + raise ValueError( + f"MaxAttempts value MUST be a non-negative integer, got '{attempts}'." + ) + self.attempts: Final[int] = attempts diff --git a/moto/stepfunctions/parser/asl/component/common/retry/retrier_decl.py b/moto/stepfunctions/parser/asl/component/common/retry/retrier_decl.py new file mode 100644 index 000000000..b996c9f32 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/retry/retrier_decl.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +import time +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.common.error_name.error_equals_decl import ( + ErrorEqualsDecl, +) +from moto.stepfunctions.parser.asl.component.common.retry.backoff_rate_decl import ( + BackoffRateDecl, +) +from moto.stepfunctions.parser.asl.component.common.retry.interval_seconds_decl import ( + IntervalSecondsDecl, +) +from moto.stepfunctions.parser.asl.component.common.retry.max_attempts_decl import ( + MaxAttemptsDecl, +) +from moto.stepfunctions.parser.asl.component.common.retry.retrier_outcome import ( + RetrierOutcome, +) +from moto.stepfunctions.parser.asl.component.common.retry.retrier_props import ( + RetrierProps, +) +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class RetrierDecl(EvalComponent): + def __init__( + self, + error_equals: ErrorEqualsDecl, + interval_seconds: Optional[IntervalSecondsDecl] = None, + max_attempts: Optional[MaxAttemptsDecl] = None, + backoff_rate: Optional[BackoffRateDecl] = None, + ): + self.error_equals: Final[ErrorEqualsDecl] = error_equals + self.interval_seconds: Final[IntervalSecondsDecl] = ( + interval_seconds or IntervalSecondsDecl() + ) + self.max_attempts: Final[MaxAttemptsDecl] = max_attempts or MaxAttemptsDecl() + self.backoff_rate: Final[BackoffRateDecl] = backoff_rate or BackoffRateDecl() + + self._attempts_counter: int = 0 + self._next_interval_seconds: float = self.interval_seconds.seconds + + @classmethod + def from_retrier_props(cls, props: RetrierProps) -> RetrierDecl: + return cls( + error_equals=props.get( + typ=ErrorEqualsDecl, + raise_on_missing=ValueError( + f"Missing ErrorEquals declaration for Retrier declaration, in props '{props}'." + ), + ), + interval_seconds=props.get(IntervalSecondsDecl), + max_attempts=props.get(MaxAttemptsDecl), + backoff_rate=props.get(BackoffRateDecl), + ) + + def _eval_body(self, env: Environment) -> None: + # When a state reports an error, the interpreter scans through the Retriers and, when the Error Name appears + # in the value of a Retrier’s "ErrorEquals" field, implements the retry policy described in that Retrier. + + self.error_equals.eval(env) + res: bool = env.stack.pop() + + # This Retrier does not match + if not res: + env.stack.append(RetrierOutcome.Skipped) + return + + # This is a matching Retrier, but was exhausted. + self._attempts_counter += 1 + if self._attempts_counter > self.max_attempts.attempts: + env.stack.append(RetrierOutcome.Failed) + return + + # Execute the Retrier logic. + # TODO: continue after interrupts? + time.sleep(self._next_interval_seconds) + + self._next_interval_seconds = ( + self._attempts_counter + * self.interval_seconds.seconds + * self.backoff_rate.rate + ) + + env.stack.append(RetrierOutcome.Executed) diff --git a/moto/stepfunctions/parser/asl/component/common/retry/retrier_outcome.py b/moto/stepfunctions/parser/asl/component/common/retry/retrier_outcome.py new file mode 100644 index 000000000..d2237bdd8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/retry/retrier_outcome.py @@ -0,0 +1,7 @@ +import enum + + +class RetrierOutcome(enum.Enum): + Executed = 0 + Failed = 1 + Skipped = 2 diff --git a/moto/stepfunctions/parser/asl/component/common/retry/retrier_props.py b/moto/stepfunctions/parser/asl/component/common/retry/retrier_props.py new file mode 100644 index 000000000..3f60094a5 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/retry/retrier_props.py @@ -0,0 +1,5 @@ +from moto.stepfunctions.parser.asl.parse.typed_props import TypedProps + + +class RetrierProps(TypedProps): + pass diff --git a/moto/stepfunctions/parser/asl/component/common/retry/retry_decl.py b/moto/stepfunctions/parser/asl/component/common/retry/retry_decl.py new file mode 100644 index 000000000..50ed38d54 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/retry/retry_decl.py @@ -0,0 +1,40 @@ +from typing import Final, List + +from moto.stepfunctions.parser.asl.component.common.error_name.error_name import ( + ErrorName, +) +from moto.stepfunctions.parser.asl.component.common.retry.retrier_decl import ( + RetrierDecl, +) +from moto.stepfunctions.parser.asl.component.common.retry.retrier_outcome import ( + RetrierOutcome, +) +from moto.stepfunctions.parser.asl.component.common.retry.retry_outcome import ( + RetryOutcome, +) +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class RetryDecl(EvalComponent): + def __init__(self, retriers: List[RetrierDecl]): + self.retriers: Final[List[RetrierDecl]] = retriers + + def _eval_body(self, env: Environment) -> None: + error_name: ErrorName = env.stack.pop() + + for retrier in self.retriers: + env.stack.append(error_name) + retrier.eval(env) + outcome: RetrierOutcome = env.stack.pop() + + if outcome == RetrierOutcome.Skipped: + continue + elif outcome == RetrierOutcome.Executed: + env.stack.append(RetryOutcome.CanRetry) + return + elif outcome == RetrierOutcome.Failed: + env.stack.append(RetryOutcome.CannotRetry) + return + + env.stack.append(RetryOutcome.NoRetrier) diff --git a/moto/stepfunctions/parser/asl/component/common/retry/retry_outcome.py b/moto/stepfunctions/parser/asl/component/common/retry/retry_outcome.py new file mode 100644 index 000000000..7e12c3f1e --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/retry/retry_outcome.py @@ -0,0 +1,7 @@ +from enum import Enum + + +class RetryOutcome(Enum): + CanRetry = 0 + CannotRetry = 1 + NoRetrier = 2 diff --git a/moto/stepfunctions/parser/asl/component/common/timeouts/__init__.py b/moto/stepfunctions/parser/asl/component/common/timeouts/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/common/timeouts/heartbeat.py b/moto/stepfunctions/parser/asl/component/common/timeouts/heartbeat.py new file mode 100644 index 000000000..60591c9ba --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/timeouts/heartbeat.py @@ -0,0 +1,46 @@ +import abc +from typing import Final + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class Heartbeat(EvalComponent, abc.ABC): + @abc.abstractmethod + def _eval_seconds(self, env: Environment) -> int: + ... + + def _eval_body(self, env: Environment) -> None: + seconds = self._eval_seconds(env=env) + env.stack.append(seconds) + + +class HeartbeatSeconds(Heartbeat): + def __init__(self, heartbeat_seconds: int): + if not isinstance(heartbeat_seconds, int) and heartbeat_seconds <= 0: + raise ValueError( + f"Expected non-negative integer for HeartbeatSeconds, got '{heartbeat_seconds}' instead." + ) + self.heartbeat_seconds: Final[int] = heartbeat_seconds + + def _eval_seconds(self, env: Environment) -> int: + return self.heartbeat_seconds + + +class HeartbeatSecondsPath(Heartbeat): + def __init__(self, path: str): + self.path: Final[str] = path + + @classmethod + def from_raw(cls, path: str): + return cls(path=path) + + def _eval_seconds(self, env: Environment) -> int: + inp = env.stack[-1] + seconds = JSONPathUtils.extract_json(self.path, inp) + if not isinstance(seconds, int) and seconds <= 0: + raise ValueError( + f"Expected non-negative integer for HeartbeatSecondsPath, got '{seconds}' instead." + ) + return seconds diff --git a/moto/stepfunctions/parser/asl/component/common/timeouts/timeout.py b/moto/stepfunctions/parser/asl/component/common/timeouts/timeout.py new file mode 100644 index 000000000..60f1e5880 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/timeouts/timeout.py @@ -0,0 +1,65 @@ +import abc +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class Timeout(EvalComponent, abc.ABC): + @abc.abstractmethod + def is_default_value(self) -> bool: + ... + + @abc.abstractmethod + def _eval_seconds(self, env: Environment) -> int: + ... + + def _eval_body(self, env: Environment) -> None: + seconds = self._eval_seconds(env=env) + env.stack.append(seconds) + + +class TimeoutSeconds(Timeout): + DEFAULT_TIMEOUT_SECONDS: Final[int] = 99999999 + + def __init__(self, timeout_seconds: int, is_default: Optional[bool] = None): + if not isinstance(timeout_seconds, int) and timeout_seconds <= 0: + raise ValueError( + f"Expected non-negative integer for TimeoutSeconds, got '{timeout_seconds}' instead." + ) + self.timeout_seconds: Final[int] = timeout_seconds + self.is_default: Optional[bool] = is_default + + def is_default_value(self) -> bool: + if self.is_default is not None: + return self.is_default + return self.timeout_seconds == self.DEFAULT_TIMEOUT_SECONDS + + def _eval_seconds(self, env: Environment) -> int: + return self.timeout_seconds + + +class TimeoutSecondsPath(Timeout): + def __init__(self, path: str): + self.path: Final[str] = path + + @classmethod + def from_raw(cls, path: str): + return cls(path=path) + + def is_default_value(self) -> bool: + return False + + def _eval_seconds(self, env: Environment) -> int: + inp = env.stack[-1] + seconds = JSONPathUtils.extract_json(self.path, inp) + if not isinstance(seconds, int) and seconds <= 0: + raise ValueError( + f"Expected non-negative integer for TimeoutSecondsPath, got '{seconds}' instead." + ) + return seconds + + +class EvalTimeoutError(TimeoutError): + pass diff --git a/moto/stepfunctions/parser/asl/component/common/version.py b/moto/stepfunctions/parser/asl/component/common/version.py new file mode 100644 index 000000000..0ab0b3fa1 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/common/version.py @@ -0,0 +1,17 @@ +from typing import Final, Set + +from moto.stepfunctions.parser.asl.component.component import Component + + +class Version(Component): + _SUPPORTED_VERSIONS: Final[Set[str]] = {"1.0"} + + version: Final[str] + + def __init__(self, version: str): + if version not in self._SUPPORTED_VERSIONS: + raise ValueError( + f"Version value '{version}' is not accepted. Supported Versions: {list(self._SUPPORTED_VERSIONS)}" + ) + + self.version = version diff --git a/moto/stepfunctions/parser/asl/component/component.py b/moto/stepfunctions/parser/asl/component/component.py new file mode 100644 index 000000000..029db9d43 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/component.py @@ -0,0 +1,9 @@ +import abc + + +class Component(abc.ABC): + def __str__(self): + return f"({self.__class__.__name__}| {vars(self)}" + + def __repr__(self): + return str(self) diff --git a/moto/stepfunctions/parser/asl/component/eval_component.py b/moto/stepfunctions/parser/asl/component/eval_component.py new file mode 100644 index 000000000..163f7e772 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/eval_component.py @@ -0,0 +1,70 @@ +import abc +import logging + +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.component import Component +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str + +LOG = logging.getLogger(__name__) + + +class EvalComponent(Component, abc.ABC): + def _log_evaluation_step(self, subject: str = "Generic") -> None: + LOG.debug( + f"[ASL] [{subject.lower()[:4]}] [{self.__class__.__name__}]: '{repr(self)}'" + ) + + def _log_failure_event_exception( + self, failure_event_exception: FailureEventException + ) -> None: + error_log_parts = ["Exception=FailureEventException"] + + error_name = failure_event_exception.failure_event.error_name + if error_name: + error_log_parts.append(f"Error={error_name.error_name}") + + event_details = failure_event_exception.failure_event.event_details + if event_details: + error_log_parts.append(f"Details={to_json_str(event_details)}") + + error_log = ", ".join(error_log_parts) + component_repr = repr(self) + LOG.error(f"{error_log} at '{component_repr}'") + + def _log_exception(self, exception: Exception) -> None: + exception_name = exception.__class__.__name__ + + error_log_parts = [f"Exception={exception_name}"] + + exception_body = list(exception.args) + if exception_body: + error_log_parts.append(f"Details={exception_body}") + else: + error_log_parts.append("Details=None-Available") + + error_log = ", ".join(error_log_parts) + component_repr = repr(self) + LOG.error(f"{error_log} at '{component_repr}'") + + def eval(self, env: Environment) -> None: + if env.is_running(): + self._log_evaluation_step("Computing") + try: + self._eval_body(env) + except FailureEventException as failure_event_exception: + self._log_failure_event_exception( + failure_event_exception=failure_event_exception + ) + raise failure_event_exception + except Exception as exception: + self._log_exception(exception=exception) + raise exception + else: + self._log_evaluation_step("Pruning") + + @abc.abstractmethod + def _eval_body(self, env: Environment) -> None: + raise NotImplementedError() diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/argument/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/argument/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument.py b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument.py new file mode 100644 index 000000000..8c01c0b72 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument.py @@ -0,0 +1,15 @@ +import abc +from typing import Any, Optional + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class FunctionArgument(EvalComponent, abc.ABC): + _value: Optional[Any] + + def __init__(self, value: Any = None): + self._value = value + + def _eval_body(self, env: Environment) -> None: + env.stack.append(self._value) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_bool.py b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_bool.py new file mode 100644 index 000000000..6f86059cd --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_bool.py @@ -0,0 +1,10 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument import ( + FunctionArgument, +) + + +class FunctionArgumentBool(FunctionArgument): + _value: bool + + def __init__(self, boolean: bool): + super().__init__(value=boolean) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_context_path.py b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_context_path.py new file mode 100644 index 000000000..052b6d974 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_context_path.py @@ -0,0 +1,19 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument import ( + FunctionArgument, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class FunctionArgumentContextPath(FunctionArgument): + _value: str + + def __init__(self, json_path: str): + super().__init__() + self._json_path: str = json_path + + def _eval_body(self, env: Environment) -> None: + self._value = JSONPathUtils.extract_json( + self._json_path, env.context_object_manager.context_object + ) + super()._eval_body(env=env) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_float.py b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_float.py new file mode 100644 index 000000000..c73cb84d7 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_float.py @@ -0,0 +1,10 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument import ( + FunctionArgument, +) + + +class FunctionArgumentFloat(FunctionArgument): + _value: float + + def __init__(self, number: float): + super().__init__(value=number) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_function.py b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_function.py new file mode 100644 index 000000000..80e767f52 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_function.py @@ -0,0 +1,18 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument import ( + FunctionArgument, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.function import Function +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class FunctionArgumentFunction(FunctionArgument): + def __init__(self, function: Function): + super().__init__() + self.function: Final[Function] = function + + def _eval_body(self, env: Environment) -> None: + self.function.eval(env=env) + self._value = env.stack.pop() + super()._eval_body(env=env) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_int.py b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_int.py new file mode 100644 index 000000000..6f7a857de --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_int.py @@ -0,0 +1,10 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument import ( + FunctionArgument, +) + + +class FunctionArgumentInt(FunctionArgument): + _value: int + + def __init__(self, integer: int): + super().__init__(value=integer) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_json_path.py b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_json_path.py new file mode 100644 index 000000000..f9ec948e7 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_json_path.py @@ -0,0 +1,18 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument import ( + FunctionArgument, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class FunctionArgumentJsonPath(FunctionArgument): + _value: str + + def __init__(self, json_path: str): + super().__init__() + self._json_path: str = json_path + + def _eval_body(self, env: Environment) -> None: + inp = env.stack[-1] + self._value = JSONPathUtils.extract_json(self._json_path, inp) + super()._eval_body(env=env) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_list.py b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_list.py new file mode 100644 index 000000000..cbff4665f --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_list.py @@ -0,0 +1,20 @@ +from typing import Final, List + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument import ( + FunctionArgument, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class FunctionArgumentList(EvalComponent): + def __init__(self, arg_list: List[FunctionArgument]): + self.arg_list: Final[List[FunctionArgument]] = arg_list + self.size: Final[int] = len(arg_list) + + def _eval_body(self, env: Environment) -> None: + values = list() + for arg in self.arg_list: + arg.eval(env=env) + values.append(env.stack.pop()) + env.stack.append(values) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_string.py b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_string.py new file mode 100644 index 000000000..c9af522f0 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/argument/function_argument_string.py @@ -0,0 +1,10 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument import ( + FunctionArgument, +) + + +class FunctionArgumentString(FunctionArgument): + _value: str + + def __init__(self, string: str): + super().__init__(value=string) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/component.py b/moto/stepfunctions/parser/asl/component/intrinsic/component.py new file mode 100644 index 000000000..98b1e50e4 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/component.py @@ -0,0 +1,11 @@ +import abc + + +class Component(abc.ABC): + # TODO. + def __str__(self): + return str(self.__dict__) + + # TODO. + def __repr__(self): + return self.__str__() diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/function.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/function.py new file mode 100644 index 000000000..ce5882a7e --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/function.py @@ -0,0 +1,18 @@ +import abc +from typing import Final + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.function_name import ( + FunctionName, +) + + +class Function(EvalComponent, abc.ABC): + name: FunctionName + + def __init__(self, name: FunctionName, arg_list: FunctionArgumentList): + self.name = name + self.arg_list: Final[FunctionArgumentList] = arg_list diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array.py new file mode 100644 index 000000000..a94071d32 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array.py @@ -0,0 +1,28 @@ +from typing import Any, List + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class Array(StatesFunction): + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName(function_type=StatesFunctionNameType.Array), + arg_list=arg_list, + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + values: List[Any] = env.stack.pop() + env.stack.append(values) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_contains.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_contains.py new file mode 100644 index 000000000..3fb1805f1 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_contains.py @@ -0,0 +1,54 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ArrayContains(StatesFunction): + # Determines if a specific value is present in an array. + # + # For example: + # With input + # { + # "inputArray": [1,2,3,4,5,6,7,8,9], + # "lookingFor": 5 + # } + # + # The call: + # States.ArrayContains($.inputArray, $.lookingFor) + # + # Returns: + # true + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.ArrayContains + ), + arg_list=arg_list, + ) + if arg_list.size != 2: + raise ValueError( + f"Expected 2 arguments for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + array = args[0] + value = args[1] + if not isinstance(array, list): + raise TypeError( + f"Expected an array type as first argument, but got {array}." + ) + contains = value in array + env.stack.append(contains) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_get_item.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_get_item.py new file mode 100644 index 000000000..8999ec25b --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_get_item.py @@ -0,0 +1,56 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ArrayGetItem(StatesFunction): + # Returns a specified index's value. + # + # For example: + # With input + # { + # "inputArray": [1,2,3,4,5,6,7,8,9], + # "index": 5 + # } + # + # The call + # States.ArrayGetItem($.inputArray, $.index) + # + # Returns + # 6 + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.ArrayGetItem + ), + arg_list=arg_list, + ) + if arg_list.size != 2: + raise ValueError( + f"Expected 2 arguments for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + index = args.pop() + if not isinstance(index, int): + raise TypeError(f"Expected an integer index value, but got '{index}'.") + + array = args.pop() + if not isinstance(array, list): + raise TypeError(f"Expected an array type, but got '{array}'.") + + item = array[index] + env.stack.append(item) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_length.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_length.py new file mode 100644 index 000000000..87b8dcb1c --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_length.py @@ -0,0 +1,51 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ArrayLength(StatesFunction): + # Returns the length of the array. + # + # For example: + # With input + # { + # "inputArray": [1,2,3,4,5,6,7,8,9] + # } + # + # The call + # States.ArrayLength($.inputArray) + # + # Returns + # 9 + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.ArrayLength + ), + arg_list=arg_list, + ) + if arg_list.size != 1: + raise ValueError( + f"Expected 1 argument for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + array = args.pop() + if not isinstance(array, list): + raise TypeError(f"Expected an array type, but got '{array}'.") + + length = len(array) + env.stack.append(length) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_partition.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_partition.py new file mode 100644 index 000000000..b09bfdd0c --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_partition.py @@ -0,0 +1,72 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ArrayPartition(StatesFunction): + # Partitions the input array. + # + # For example: + # With input + # { + # "inputArray": [1, 2, 3, 4, 5, 6, 7, 8, 9] + # } + # + # The call + # States.ArrayPartition($.inputArray,4) + # + # Returns + # [ [1,2,3,4], [5,6,7,8], [9]] + + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.ArrayPartition + ), + arg_list=arg_list, + ) + if arg_list.size != 2: + raise ValueError( + f"Expected 2 arguments for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + chunk_size = args.pop() + if not isinstance(chunk_size, (int, float)): + raise TypeError( + f"Expected an integer value as chunk_size, but got {chunk_size}." + ) + chunk_size = round(chunk_size) + if chunk_size < 0: + raise ValueError( + f"Expected a non-zero, positive integer as chuck_size, but got {chunk_size}." + ) + + array = args.pop() + if not isinstance(array, list): + raise TypeError( + f"Expected an array type as first argument, but got {array}." + ) + + chunks = self._to_chunks(array=array, chunk_size=chunk_size) + env.stack.append(chunks) + + @staticmethod + def _to_chunks(array: list, chunk_size: int): + chunks = list() + for i in range(0, len(array), chunk_size): + chunks.append(array[i : i + chunk_size]) + return chunks diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_range.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_range.py new file mode 100644 index 000000000..c82d0b788 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_range.py @@ -0,0 +1,62 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ArrayRange(StatesFunction): + # Creates a new array containing a specific range of elements. + # + # For example: + # The call + # States.ArrayRange(1, 9, 2) + # + # Returns + # [1,3,5,7,9] + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.ArrayRange + ), + arg_list=arg_list, + ) + if arg_list.size != 3: + raise ValueError( + f"Expected 3 arguments for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + range_vals = env.stack.pop() + + for range_val in range_vals: + if not isinstance(range_val, (int, float)): + raise TypeError( + f"Expected 3 integer arguments for function type '{type(self)}', but got: '{range_vals}'." + ) + first = round(range_vals[0]) + last = round(range_vals[1]) + step = round(range_vals[2]) + + if step <= 0: + raise ValueError( + f"Expected step argument to be non negative, but got: '{step}'." + ) + + array = list(range(first, last + 1, step)) + + if len(array) > 1000: + raise ValueError( + f"Arrays cannot contain more than 1000 items, size: {len(array)}." + ) + + env.stack.append(array) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_unique.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_unique.py new file mode 100644 index 000000000..40ff5f51f --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/array/array_unique.py @@ -0,0 +1,56 @@ +from collections import OrderedDict + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ArrayUnique(StatesFunction): + # Removes duplicate values from an array and returns an array containing only unique elements + # + # For example: + # With input + # { + # "inputArray": [1,2,3,3,3,3,3,3,4] + # } + # + # The call + # States.ArrayUnique($.inputArray) + # + # Returns + # [1,2,3,4] + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.ArrayUnique + ), + arg_list=arg_list, + ) + if arg_list.size != 1: + raise ValueError( + f"Expected 1 argument for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + array = args.pop() + if not isinstance(array, list): + raise TypeError(f"Expected an array type, but got '{array}'.") + + # Remove duplicates through an ordered set, in this + # case we consider they key set of an ordered dict. + items_odict = OrderedDict.fromkeys(array).keys() + unique_array = list(items_odict) + env.stack.append(unique_array) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/encoding_decoding/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/encoding_decoding/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/encoding_decoding/base_64_decode.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/encoding_decoding/base_64_decode.py new file mode 100644 index 000000000..d5da229cd --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/encoding_decoding/base_64_decode.py @@ -0,0 +1,62 @@ +import base64 +from typing import Final + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class Base64Decode(StatesFunction): + # Encodes data based on MIME Base64 encoding scheme. + # + # For example: + # With input + # { + # "input": "Data to encode" + # } + # + # The call + # "base64.$": "States.Base64Encode($.input)" + # + # Returns + # {"base64": "RGF0YSB0byBlbmNvZGU="} + + MAX_INPUT_CHAR_LEN: Final[int] = 10_000 + + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.Base64Decode + ), + arg_list=arg_list, + ) + if arg_list.size != 1: + raise ValueError( + f"Expected 1 argument for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + base64_string: str = args.pop() + if len(base64_string) > self.MAX_INPUT_CHAR_LEN: + raise ValueError( + f"Maximum input string for function type '{type(self)}' " + f"is '{self.MAX_INPUT_CHAR_LEN}', but got '{len(base64_string)}'." + ) + + base64_string_bytes = base64_string.encode("ascii") + string_bytes = base64.b64decode(base64_string_bytes) + string = string_bytes.decode("ascii") + env.stack.append(string) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/encoding_decoding/base_64_encode.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/encoding_decoding/base_64_encode.py new file mode 100644 index 000000000..6ad426c65 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/encoding_decoding/base_64_encode.py @@ -0,0 +1,62 @@ +import base64 +from typing import Final + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class Base64Encode(StatesFunction): + # Decodes data based on MIME Base64 encoding scheme. + # + # For example: + # With input + # { + # "base64": "RGF0YSB0byBlbmNvZGU=" + # } + # + # The call + # "data.$": "States.Base64Decode($.base64)" + # + # Returns + # {"data": "Decoded data"} + + MAX_INPUT_CHAR_LEN: Final[int] = 10_000 + + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.Base64Encode + ), + arg_list=arg_list, + ) + if arg_list.size != 1: + raise ValueError( + f"Expected 1 argument for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + string: str = args.pop() + if len(string) > self.MAX_INPUT_CHAR_LEN: + raise ValueError( + f"Maximum input string for function type '{type(self)}' " + f"is '{self.MAX_INPUT_CHAR_LEN}', but got '{len(string)}'." + ) + + string_bytes = string.encode("ascii") + string_base64_bytes = base64.b64encode(string_bytes) + base64_string = string_base64_bytes.decode("ascii") + env.stack.append(base64_string) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/factory.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/factory.py new file mode 100644 index 000000000..3c948afaf --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/factory.py @@ -0,0 +1,107 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.array import ( + array, + array_contains, + array_get_item, + array_length, + array_partition, + array_range, + array_unique, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.encoding_decoding import ( + base_64_decode, + base_64_encode, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.generic import ( + string_format, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.hash_calculations import ( + hash_func, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.json_manipulation import ( + json_merge, + json_to_string, + string_to_json, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.math_operations import ( + math_add, + math_random, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.string_operations import ( + string_split, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.unique_id_generation import ( + uuid, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) + + +# TODO: could use reflection on StatesFunctionNameType values. +class StatesFunctionFactory: + @staticmethod + def from_name( + func_name: StatesFunctionName, arg_list: FunctionArgumentList + ) -> StatesFunction: + if func_name.function_type == StatesFunctionNameType.Array: + return array.Array(arg_list=arg_list) + if func_name.function_type == StatesFunctionNameType.ArrayPartition: + return array_partition.ArrayPartition(arg_list=arg_list) + if func_name.function_type == StatesFunctionNameType.ArrayContains: + return array_contains.ArrayContains(arg_list=arg_list) + if func_name.function_type == StatesFunctionNameType.ArrayRange: + return array_range.ArrayRange(arg_list=arg_list) + if func_name.function_type == StatesFunctionNameType.ArrayGetItem: + return array_get_item.ArrayGetItem(arg_list=arg_list) + if func_name.function_type == StatesFunctionNameType.ArrayLength: + return array_length.ArrayLength(arg_list=arg_list) + if func_name.function_type == StatesFunctionNameType.ArrayUnique: + return array_unique.ArrayUnique(arg_list=arg_list) + + # JSON Manipulation + if func_name.function_type == StatesFunctionNameType.JsonToString: + return json_to_string.JsonToString(arg_list=arg_list) + if func_name.function_type == StatesFunctionNameType.StringToJson: + return string_to_json.StringToJson(arg_list=arg_list) + if func_name.function_type == StatesFunctionNameType.JsonMerge: + return json_merge.JsonMerge(arg_list=arg_list) + + # Unique Id Generation. + if func_name.function_type == StatesFunctionNameType.UUID: + return uuid.UUID(arg_list=arg_list) + + # String Operations. + if func_name.function_type == StatesFunctionNameType.StringSplit: + return string_split.StringSplit(arg_list=arg_list) + + # Hash Calculations. + if func_name.function_type == StatesFunctionNameType.Hash: + return hash_func.HashFunc(arg_list=arg_list) + + # Encoding and Decoding. + if func_name.function_type == StatesFunctionNameType.Base64Encode: + return base_64_encode.Base64Encode(arg_list=arg_list) + if func_name.function_type == StatesFunctionNameType.Base64Decode: + return base_64_decode.Base64Decode(arg_list=arg_list) + + # Math Operations. + if func_name.function_type == StatesFunctionNameType.MathRandom: + return math_random.MathRandom(arg_list=arg_list) + if func_name.function_type == StatesFunctionNameType.MathAdd: + return math_add.MathAdd(arg_list=arg_list) + + # Generic. + if func_name.function_type == StatesFunctionNameType.Format: + return string_format.StringFormat(arg_list=arg_list) + + # Unsupported. + raise NotImplementedError(func_name.function_type) # noqa diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/generic/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/generic/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/generic/string_format.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/generic/string_format.py new file mode 100644 index 000000000..ab9381476 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/generic/string_format.py @@ -0,0 +1,95 @@ +import json +from typing import Any, Final, List + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_string import ( + FunctionArgumentString, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class StringFormat(StatesFunction): + # It constructs a string from both literal and interpolated values. This function takes one or more arguments. + # The value of the first argument must be a string, and may include zero or more instances of the character + # sequence {}. The interpreter returns the string defined in the first argument with each {} replaced by the value + # of the positionally-corresponding argument in the Intrinsic invocation. + # + # For example: + # With input + # { + # "name": "Arnav", + # "template": "Hello, my name is {}." + # } + # + # Calls + # States.Format('Hello, my name is {}.', $.name) + # States.Format($.template, $.name) + # + # Return + # Hello, my name is Arnav. + _DELIMITER: Final[str] = "{}" + + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName(function_type=StatesFunctionNameType.Format), + arg_list=arg_list, + ) + if arg_list.size == 0: + raise ValueError( + f"Expected at least 1 argument for function type '{type(self)}', but got: '{arg_list}'." + ) + if not isinstance(arg_list.arg_list[0], FunctionArgumentString): + raise ValueError( + f"Expected the first argument for function type '{type(self)}' to be a string, but got: '{arg_list.arg_list[0]}'." + ) + + def _eval_body(self, env: Environment) -> None: + # TODO: investigate behaviour for incorrect number of arguments in string format. + self.arg_list.eval(env=env) + args = env.stack.pop() + + string_format: str = args[0] + values: List[Any] = args[1:] + + values_str_repr = map(self._to_str_repr, values) + string_result = string_format.format(*values_str_repr) + + env.stack.append(string_result) + + @staticmethod + def _to_str_repr(value: Any) -> str: + # Converts a value or object to a string representation compatible with sfn. + # For example: + # Input object + # { + # "Arg1": 1, + # "Arg2": [] + # } + # Is mapped to the string + # {Arg1=1, Arg2=[]} + + if isinstance(value, str): + return value + elif isinstance(value, list): + value_parts: List[str] = list(map(StringFormat._to_str_repr, value)) + return f"[{', '.join(value_parts)}]" + elif isinstance(value, dict): + dict_items = list() + for d_key, d_value in value.items(): + d_value_lit = StringFormat._to_str_repr(d_value) + dict_items.append(f"{d_key}={d_value_lit}") + return f"{{{', '.join(dict_items)}}}" + else: + # Return json representation of terminal value. + return json.dumps(value) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/hash_calculations/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/hash_calculations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/hash_calculations/hash_algorithm.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/hash_calculations/hash_algorithm.py new file mode 100644 index 000000000..efb4239e1 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/hash_calculations/hash_algorithm.py @@ -0,0 +1,9 @@ +import enum + + +class HashAlgorithm(enum.Enum): + MD5 = "MD5" + SHA_1 = "SHA-1" + SHA_256 = "SHA-256" + SHA_384 = "SHA-384" + SHA_512 = "SHA-512" diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/hash_calculations/hash_func.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/hash_calculations/hash_func.py new file mode 100644 index 000000000..0e40dafa8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/hash_calculations/hash_func.py @@ -0,0 +1,75 @@ +import hashlib +from typing import Final + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.hash_calculations.hash_algorithm import ( + HashAlgorithm, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class HashFunc(StatesFunction): + MAX_INPUT_CHAR_LEN: Final[int] = 10_000 + + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName(function_type=StatesFunctionNameType.Hash), + arg_list=arg_list, + ) + if arg_list.size != 2: + raise ValueError( + f"Expected 2 arguments for function type '{type(self)}', but got: '{arg_list}'." + ) + + @staticmethod + def _hash_inp_with_alg(inp: str, alg: HashAlgorithm) -> str: + inp_enc = inp.encode() + hash_inp = None + if alg == HashAlgorithm.MD5: + hash_inp = hashlib.md5(inp_enc) + if alg == HashAlgorithm.SHA_1: + hash_inp = hashlib.sha1(inp_enc) + elif alg == HashAlgorithm.SHA_256: + hash_inp = hashlib.sha256(inp_enc) + elif alg == HashAlgorithm.SHA_384: + hash_inp = hashlib.sha384(inp_enc) + elif alg == HashAlgorithm.SHA_512: + hash_inp = hashlib.sha512(inp_enc) + hash_value: str = hash_inp.hexdigest() + return hash_value + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + algorithm = args.pop() + try: + hash_algorithm = HashAlgorithm(algorithm) + except Exception: + raise ValueError(f"Unknown hash function '{algorithm}'.") + + input_data = args.pop() + if not isinstance(input_data, str): + raise TypeError( + f"Expected string type as input data for function type '{type(self)}', but got: '{input_data}'." + ) + + if len(input_data) > self.MAX_INPUT_CHAR_LEN: + raise ValueError( + f"Maximum character input length for for function type '{type(self)}' " + f"is '{self.MAX_INPUT_CHAR_LEN}', but got '{len(input_data)}'." + ) + + res = self._hash_inp_with_alg(input_data, hash_algorithm) + env.stack.append(res) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/json_manipulation/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/json_manipulation/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/json_manipulation/json_merge.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/json_manipulation/json_merge.py new file mode 100644 index 000000000..5156df429 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/json_manipulation/json_merge.py @@ -0,0 +1,93 @@ +import copy +from typing import Any + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class JsonMerge(StatesFunction): + # Merges two JSON objects into a single object + # + # For example: + # With input + # { + # "json1": { "a": {"a1": 1, "a2": 2}, "b": 2, }, + # "json2": { "a": {"a3": 1, "a4": 2}, "c": 3 } + # } + # + # Call + # "output.$": "States.JsonMerge($.json1, $.json2, false)" + # + # Returns + # { + # "output": { + # "a": {"a3": 1, "a4": 2}, + # "b": 2, + # "c": 3 + # } + # } + + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.JsonMerge + ), + arg_list=arg_list, + ) + if arg_list.size != 3: + raise ValueError( + f"Expected 3 arguments for function type '{type(self)}', but got: '{arg_list}'." + ) + + @staticmethod + def _validate_is_deep_merge_argument(is_deep_merge: Any) -> None: + if not isinstance(is_deep_merge, bool): + raise TypeError( + f"Expected boolean value for deep merge mode, but got: '{is_deep_merge}'." + ) + if is_deep_merge: + # This is AWS's limitation, not LocalStack's. + raise NotImplementedError( + "Currently, Step Functions only supports the shallow merging mode; " + "therefore, you must specify the boolean value as false." + ) + + @staticmethod + def _validate_merge_argument(argument: Any, num: int) -> None: + if not isinstance(argument, dict): + raise TypeError( + f"Expected a JSON object the argument {num}, but got: '{argument}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + is_deep_merge = args.pop() + self._validate_is_deep_merge_argument(is_deep_merge) + + snd = args.pop() + self._validate_merge_argument(snd, 2) + + fst = args.pop() + self._validate_merge_argument(snd, 2) + + # Currently, Step Functions only supports the shallow merging mode; therefore, you must specify the boolean + # value as false. In the shallow mode, if the same key exists in both JSON objects, the latter object's key + # overrides the same key in the first object. Additionally, objects nested within a JSON object aren't merged + # when you use shallow merging. + merged = copy.deepcopy(fst) + merged.update(snd) + + env.stack.append(merged) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/json_manipulation/json_to_string.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/json_manipulation/json_to_string.py new file mode 100644 index 000000000..118d6aae5 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/json_manipulation/json_to_string.py @@ -0,0 +1,36 @@ +import json + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class JsonToString(StatesFunction): + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.JsonToString + ), + arg_list=arg_list, + ) + if arg_list.size != 1: + raise ValueError( + f"Expected 1 argument for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + json_obj: json = args.pop() + json_string: str = json.dumps(json_obj, separators=(",", ":")) + env.stack.append(json_string) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/json_manipulation/string_to_json.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/json_manipulation/string_to_json.py new file mode 100644 index 000000000..373af461f --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/json_manipulation/string_to_json.py @@ -0,0 +1,41 @@ +import json + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class StringToJson(StatesFunction): + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.StringToJson + ), + arg_list=arg_list, + ) + if arg_list.size != 1: + raise ValueError( + f"Expected 1 argument for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + string_json: str = args.pop() + + if string_json is not None and string_json.strip(): + json_obj: json = json.loads(string_json) + else: + json_obj: json = None + env.stack.append(json_obj) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/math_operations/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/math_operations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/math_operations/math_add.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/math_operations/math_add.py new file mode 100644 index 000000000..58a365f56 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/math_operations/math_add.py @@ -0,0 +1,80 @@ +import decimal +from typing import Any + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +def _round_like_java(f: float) -> int: + # this behaves a bit weird for boundary values + # AWS stepfunctions is implemented in Java, so we need to adjust the rounding accordingly + # python by default rounds half to even + if f >= 0: + decimal.getcontext().rounding = decimal.ROUND_HALF_UP + else: + decimal.getcontext().rounding = decimal.ROUND_HALF_DOWN + d = decimal.Decimal(f) + return round(d, 0) + + +class MathAdd(StatesFunction): + # Returns the sum of two numbers. + # + # For example: + # With input + # { + # "value1": 111, + # "step": -1 + # } + # + # Call + # "value1.$": "States.MathAdd($.value1, $.step)" + # + # Returns + # {"value1": 110 } + + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.MathAdd + ), + arg_list=arg_list, + ) + if arg_list.size != 2: + raise ValueError( + f"Expected 2 arguments for function type '{type(self)}', but got: '{arg_list}'." + ) + + @staticmethod + def _validate_integer_value(value: Any) -> int: + if not isinstance(value, (int, float)): + raise TypeError(f"Expected integer value, but got: '{value}'.") + # If you specify a non-integer value for one or both the arguments, + # Step Functions will round it off to the nearest integer. + + if isinstance(value, float): + result = _round_like_java(value) + return int(result) + + return value + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + a = self._validate_integer_value(args[0]) + b = self._validate_integer_value(args[1]) + + res = a + b + env.stack.append(res) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/math_operations/math_random.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/math_operations/math_random.py new file mode 100644 index 000000000..5107e635e --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/math_operations/math_random.py @@ -0,0 +1,71 @@ +import random +from typing import Any + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class MathRandom(StatesFunction): + # Returns a random number between the specified start and end number. + # + # For example: + # With input + # { + # "start": 1, + # "end": 999 + # } + # + # Call + # "random.$": "States.MathRandom($.start, $.end)" + # + # Returns + # {"random": 456 } + + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.MathRandom + ), + arg_list=arg_list, + ) + if arg_list.size < 2 or arg_list.size > 3: + raise ValueError( + f"Expected 2-3 arguments for function type '{type(self)}', but got: '{arg_list}'." + ) + + @staticmethod + def _validate_integer_value(value: Any, argument_name: str) -> int: + if not isinstance(value, (int, float)): + raise TypeError( + f"Expected integer value for {argument_name}, but got: '{value}'." + ) + # If you specify a non-integer value for the start number or end number argument, + # Step Functions will round it off to the nearest integer. + return int(value) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + seed = None + if self.arg_list.size == 3: + seed = args.pop() + self._validate_integer_value(seed, "seed") + + end = self._validate_integer_value(args.pop(), "end") + start = self._validate_integer_value(args.pop(), "start") + + rand_gen = random.Random(seed) + rand_int = rand_gen.randint(start, end) + env.stack.append(rand_int) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function.py new file mode 100644 index 000000000..96a0592e8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function.py @@ -0,0 +1,14 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.function import Function +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) + + +class StatesFunction(Function): + name: StatesFunctionName + + def __init__(self, states_name: StatesFunctionName, arg_list: FunctionArgumentList): + super().__init__(name=states_name, arg_list=arg_list) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_array.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_array.py new file mode 100644 index 000000000..cc60a0cbb --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_array.py @@ -0,0 +1,31 @@ +from typing import Any, List + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class StatesFunctionArray(StatesFunction): + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName(function_type=StatesFunctionNameType.Array), + arg_list=arg_list, + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + values: List[Any] = list() + for _ in range(self.arg_list.size): + values.append(env.stack.pop()) + values.reverse() + env.stack.append(values) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_format.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_format.py new file mode 100644 index 000000000..a1e1ebf5d --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_format.py @@ -0,0 +1,54 @@ +from typing import Any, Final, List + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_string import ( + FunctionArgumentString, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class StatesFunctionFormat(StatesFunction): + _DELIMITER: Final[str] = "{}" + + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName(function_type=StatesFunctionNameType.Format), + arg_list=arg_list, + ) + if arg_list.size > 0: + raise ValueError( + f"Expected at least 1 argument for function type '{type(self)}', but got: '{arg_list}'." + ) + if not isinstance(arg_list.arg_list[0], FunctionArgumentString): + raise ValueError( + f"Expected the first argument for function type '{type(self)}' to be a string, but got: '{arg_list.arg_list[0]}'." + ) + + def _eval_body(self, env: Environment) -> None: + # TODO: investigate behaviour for incorrect number of arguments in string format. + self.arg_list.eval(env=env) + + values: List[Any] = list() + for _ in range(self.arg_list.size): + values.append(env.stack.pop()) + string_format: str = values.pop() + values.reverse() + + string_format_parts: List[str] = string_format.split(self._DELIMITER) + string_result: str = "" + for part in string_format_parts: + string_result += part + string_result += values.pop() + + env.stack.append(string_result) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_json_to_string.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_json_to_string.py new file mode 100644 index 000000000..b528c7818 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_json_to_string.py @@ -0,0 +1,35 @@ +import json + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class StatesFunctionJsonToString(StatesFunction): + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.JsonToString + ), + arg_list=arg_list, + ) + if arg_list.size != 1: + raise ValueError( + f"Expected 1 argument for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + json_obj: json = env.stack.pop() + json_string: str = json.dumps(json_obj) + env.stack.append(json_string) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_string_to_json.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_string_to_json.py new file mode 100644 index 000000000..fb967db67 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_string_to_json.py @@ -0,0 +1,35 @@ +import json + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class StatesFunctionStringToJson(StatesFunction): + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.StringToJson + ), + arg_list=arg_list, + ) + if arg_list.size != 1: + raise ValueError( + f"Expected 1 argument for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + string_json: str = env.stack.pop() + json_obj: json = json.loads(string_json) + env.stack.append(json_obj) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_uuid.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_uuid.py new file mode 100644 index 000000000..87b6f2bc0 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/states_function_uuid.py @@ -0,0 +1,29 @@ +from moto.moto_api._internal import mock_random +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class StatesFunctionUUID(StatesFunction): + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName(function_type=StatesFunctionNameType.UUID), + arg_list=arg_list, + ) + if len(arg_list.arg_list) != 0: + raise ValueError( + f"Expected no arguments for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + env.stack.append(str(mock_random.uuid4())) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/string_operations/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/string_operations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/string_operations/string_split.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/string_operations/string_split.py new file mode 100644 index 000000000..1ef6b02c1 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/string_operations/string_split.py @@ -0,0 +1,74 @@ +import re + +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class StringSplit(StatesFunction): + # Splits a string into an array of values. + # + # For example: + # With input + # { + # "inputString": "This.is+a,test=string", + # "splitter": ".+,=" + # } + # + # The call + # { + # "myStringArray.$": "States.StringSplit($.inputString, $.splitter)" + # } + # + # Returns + # {"myStringArray": [ + # "This", + # "is", + # "a", + # "test", + # "string" + # ]} + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName( + function_type=StatesFunctionNameType.StringSplit + ), + arg_list=arg_list, + ) + if arg_list.size != 2: + raise ValueError( + f"Expected 2 arguments for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + self.arg_list.eval(env=env) + args = env.stack.pop() + + del_chars = args.pop() + if not isinstance(del_chars, str): + raise ValueError( + f"Expected string value as delimiting characters, but got '{del_chars}'." + ) + + string = args.pop() + if not isinstance(del_chars, str): + raise ValueError(f"Expected string value, but got '{del_chars}'.") + + patterns = [] + for c in del_chars: + patterns.append(f"\\{c}") + pattern = "|".join(patterns) + + parts = re.split(pattern, string) + parts_clean = list(filter(bool, parts)) + env.stack.append(parts_clean) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/unique_id_generation/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/unique_id_generation/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/unique_id_generation/uuid.py b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/unique_id_generation/uuid.py new file mode 100644 index 000000000..1c3dc93db --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/function/statesfunction/unique_id_generation/uuid.py @@ -0,0 +1,29 @@ +from moto.moto_api._internal import mock_random +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class UUID(StatesFunction): + def __init__(self, arg_list: FunctionArgumentList): + super().__init__( + states_name=StatesFunctionName(function_type=StatesFunctionNameType.UUID), + arg_list=arg_list, + ) + if len(arg_list.arg_list) != 0: + raise ValueError( + f"Expected no arguments for function type '{type(self)}', but got: '{arg_list}'." + ) + + def _eval_body(self, env: Environment) -> None: + env.stack.append(str(mock_random.uuid4())) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/functionname/__init__.py b/moto/stepfunctions/parser/asl/component/intrinsic/functionname/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/functionname/custom_function_name.py b/moto/stepfunctions/parser/asl/component/intrinsic/functionname/custom_function_name.py new file mode 100644 index 000000000..48f738f89 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/functionname/custom_function_name.py @@ -0,0 +1,8 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.function_name import ( + FunctionName, +) + + +class CustomFunctionName(FunctionName): + def __init__(self, name: str): + super().__init__(name=name) diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/functionname/function_name.py b/moto/stepfunctions/parser/asl/component/intrinsic/functionname/function_name.py new file mode 100644 index 000000000..75823b5a2 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/functionname/function_name.py @@ -0,0 +1,10 @@ +import abc + +from moto.stepfunctions.parser.asl.component.component import Component + + +class FunctionName(Component, abc.ABC): + name: str + + def __init__(self, name: str): + self.name = name diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/functionname/state_function_name_types.py b/moto/stepfunctions/parser/asl/component/intrinsic/functionname/state_function_name_types.py new file mode 100644 index 000000000..a6e4e3b71 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/functionname/state_function_name_types.py @@ -0,0 +1,29 @@ +from enum import Enum + +from moto.stepfunctions.parser.asl.antlr.runtime.ASLIntrinsicLexer import ( + ASLIntrinsicLexer, +) + + +class StatesFunctionNameType(Enum): + Format = ASLIntrinsicLexer.Format + StringToJson = ASLIntrinsicLexer.StringToJson + JsonToString = ASLIntrinsicLexer.JsonToString + Array = ASLIntrinsicLexer.Array + ArrayPartition = ASLIntrinsicLexer.ArrayPartition + ArrayContains = ASLIntrinsicLexer.ArrayContains + ArrayRange = ASLIntrinsicLexer.ArrayRange + ArrayGetItem = ASLIntrinsicLexer.ArrayGetItem + ArrayLength = ASLIntrinsicLexer.ArrayLength + ArrayUnique = ASLIntrinsicLexer.ArrayUnique + Base64Encode = ASLIntrinsicLexer.Base64Encode + Base64Decode = ASLIntrinsicLexer.Base64Decode + Hash = ASLIntrinsicLexer.Hash + JsonMerge = ASLIntrinsicLexer.JsonMerge + MathRandom = ASLIntrinsicLexer.MathRandom + MathAdd = ASLIntrinsicLexer.MathAdd + StringSplit = ASLIntrinsicLexer.StringSplit + UUID = ASLIntrinsicLexer.UUID + + def name(self) -> str: # noqa # pylint: disable=function-redefined + return ASLIntrinsicLexer.literalNames[self.value][1:-1] diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/functionname/states_function_name.py b/moto/stepfunctions/parser/asl/component/intrinsic/functionname/states_function_name.py new file mode 100644 index 000000000..739507b6a --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/functionname/states_function_name.py @@ -0,0 +1,12 @@ +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.function_name import ( + FunctionName, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) + + +class StatesFunctionName(FunctionName): + def __init__(self, function_type: StatesFunctionNameType): + super().__init__(name=function_type.name()) + self.function_type: StatesFunctionNameType = function_type diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/member.py b/moto/stepfunctions/parser/asl/component/intrinsic/member.py new file mode 100644 index 000000000..05174b958 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/member.py @@ -0,0 +1,17 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.intrinsic.component import Component + + +class Member(Component): + ... + + +class IdentifiedMember(Member): + def __init__(self, identifier: str): + self.identifier: Final[str] = identifier + + +class DollarMember(IdentifiedMember): + def __init__(self): + super(DollarMember, self).__init__(identifier="$") diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/member_access.py b/moto/stepfunctions/parser/asl/component/intrinsic/member_access.py new file mode 100644 index 000000000..ab0efecd1 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/member_access.py @@ -0,0 +1,9 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.intrinsic.member import Member + + +class MemberAccess(Member): + def __init__(self, subject: Member, target: Member): + self.subject: Final[Member] = subject + self.target: Final[Member] = target diff --git a/moto/stepfunctions/parser/asl/component/intrinsic/program.py b/moto/stepfunctions/parser/asl/component/intrinsic/program.py new file mode 100644 index 000000000..0c93c967c --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/intrinsic/program.py @@ -0,0 +1,8 @@ +from typing import Final, List + +from moto.stepfunctions.parser.asl.component.intrinsic.component import Component + + +class Program(Component): + def __init__(self): + self.statements: Final[List[Component]] = [] diff --git a/moto/stepfunctions/parser/asl/component/program/__init__.py b/moto/stepfunctions/parser/asl/component/program/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/program/program.py b/moto/stepfunctions/parser/asl/component/program/program.py new file mode 100644 index 000000000..9a59006ef --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/program/program.py @@ -0,0 +1,149 @@ +import logging +import threading +from typing import Final, Optional + +from moto.stepfunctions.parser.api import ( + ExecutionAbortedEventDetails, + ExecutionFailedEventDetails, + ExecutionSucceededEventDetails, + ExecutionTimedOutEventDetails, + HistoryEventExecutionDataDetails, + HistoryEventType, +) +from moto.stepfunctions.parser.asl.component.common.comment import Comment +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name import ( + StatesErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from moto.stepfunctions.parser.asl.component.common.flow.start_at import StartAt +from moto.stepfunctions.parser.asl.component.common.timeouts.timeout import ( + TimeoutSeconds, +) +from moto.stepfunctions.parser.asl.component.common.version import Version +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.component.state.state import CommonStateField +from moto.stepfunctions.parser.asl.component.states import States +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.eval.program_state import ( + ProgramEnded, + ProgramError, + ProgramState, + ProgramStopped, + ProgramTimedOut, +) +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str +from moto.stepfunctions.parser.utils import TMP_THREADS + +LOG = logging.getLogger(__name__) + + +class Program(EvalComponent): + start_at: Final[StartAt] + states: Final[States] + timeout_seconds: Final[Optional[TimeoutSeconds]] + comment: Final[Optional[Comment]] + version: Final[Optional[Version]] + + def __init__( + self, + start_at: StartAt, + states: States, + timeout_seconds: Optional[TimeoutSeconds], + comment: Optional[Comment] = None, + version: Optional[Version] = None, + ): + self.start_at = start_at + self.states = states + self.timeout_seconds = timeout_seconds + self.comment = comment + self.version = version + + def _get_state(self, state_name: str) -> CommonStateField: + state: Optional[CommonStateField] = self.states.states.get(state_name, None) + if state is None: + raise ValueError(f"No such state {state}.") + return state + + def eval(self, env: Environment) -> None: + timeout = self.timeout_seconds.timeout_seconds if self.timeout_seconds else None + env.next_state_name = self.start_at.start_at_name + worker_thread = threading.Thread(target=super().eval, args=(env,)) + TMP_THREADS.append(worker_thread) + worker_thread.start() + worker_thread.join(timeout=timeout) + is_timeout = worker_thread.is_alive() + if is_timeout: + env.set_timed_out() + + def _eval_body(self, env: Environment) -> None: + try: + while env.is_running(): + next_state: CommonStateField = self._get_state(env.next_state_name) + next_state.eval(env) + env.stack.clear() + except FailureEventException as ex: + env.set_error(error=ex.get_execution_failed_event_details()) + except Exception as ex: + cause = f"{type(ex).__name__}({str(ex)})" + LOG.error(f"Stepfunctions computation ended with exception '{cause}'.") + env.set_error( + ExecutionFailedEventDetails( + error=StatesErrorName( + typ=StatesErrorNameType.StatesRuntime + ).error_name, + cause=cause, + ) + ) + + # If the program is evaluating within a frames then these are not allowed to produce program termination states. + if env.is_frame(): + return + + program_state: ProgramState = env.program_state() + if isinstance(program_state, ProgramError): + exec_failed_event_details = program_state.error or dict() + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.ExecutionFailed, + event_detail=EventDetails( + executionFailedEventDetails=exec_failed_event_details + ), + ) + elif isinstance(program_state, ProgramStopped): + env.event_history_context.source_event_id = 0 + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.ExecutionAborted, + event_detail=EventDetails( + executionAbortedEventDetails=ExecutionAbortedEventDetails( + error=program_state.error, cause=program_state.cause + ) + ), + ) + elif isinstance(program_state, ProgramTimedOut): + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.ExecutionTimedOut, + event_detail=EventDetails( + executionTimedOutEventDetails=ExecutionTimedOutEventDetails() + ), + ) + elif isinstance(program_state, ProgramEnded): + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.ExecutionSucceeded, + event_detail=EventDetails( + executionSucceededEventDetails=ExecutionSucceededEventDetails( + output=to_json_str(env.inp, separators=(",", ":")), + outputDetails=HistoryEventExecutionDataDetails( + truncated=False # Always False for api calls. + ), + ) + ), + ) diff --git a/moto/stepfunctions/parser/asl/component/state/__init__.py b/moto/stepfunctions/parser/asl/component/state/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state.py b/moto/stepfunctions/parser/asl/component/state/state.py new file mode 100644 index 000000000..2cc1e2128 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state.py @@ -0,0 +1,168 @@ +from __future__ import annotations + +import abc +import datetime +import logging +from abc import ABC +from typing import Final, Optional + +from moto.stepfunctions.parser.api import ( + HistoryEventExecutionDataDetails, + HistoryEventType, + StateEnteredEventDetails, + StateExitedEventDetails, +) +from moto.stepfunctions.parser.asl.component.common.comment import Comment +from moto.stepfunctions.parser.asl.component.common.flow.end import End +from moto.stepfunctions.parser.asl.component.common.flow.next import Next +from moto.stepfunctions.parser.asl.component.common.path.input_path import InputPath +from moto.stepfunctions.parser.asl.component.common.path.output_path import OutputPath +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.component.state.state_continue_with import ( + ContinueWith, + ContinueWithEnd, + ContinueWithNext, +) +from moto.stepfunctions.parser.asl.component.state.state_props import StateProps +from moto.stepfunctions.parser.asl.component.state.state_type import StateType +from moto.stepfunctions.parser.asl.eval.contextobject.contex_object import State +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.eval.program_state import ProgramRunning +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str + +LOG = logging.getLogger(__name__) + + +class CommonStateField(EvalComponent, ABC): + name: str + + # The state's type. + state_type: StateType + + # There can be any number of terminal states per state machine. Only one of Next or End can + # be used in a state. Some state types, such as Choice, don't support or use the End field. + continue_with: ContinueWith + + def __init__( + self, + state_entered_event_type: HistoryEventType, + state_exited_event_type: Optional[HistoryEventType], + ): + # Holds a human-readable description of the state. + self.comment: Optional[Comment] = None + + # A path that selects a portion of the state's input to be passed to the state's state_task for processing. + # If omitted, it has the value $ which designates the entire input. + self.input_path: InputPath = InputPath(InputPath.DEFAULT_PATH) + + # A path that selects a portion of the state's output to be passed to the next state. + # If omitted, it has the value $ which designates the entire output. + self.output_path: OutputPath = OutputPath(OutputPath.DEFAULT_PATH) + + self.state_entered_event_type: Final[ + HistoryEventType + ] = state_entered_event_type + self.state_exited_event_type: Final[ + Optional[HistoryEventType] + ] = state_exited_event_type + + def from_state_props(self, state_props: StateProps) -> None: + self.name = state_props.name + self.state_type = state_props.get(StateType) + self.continue_with = ( + ContinueWithEnd() + if state_props.get(End) + else ContinueWithNext(state_props.get(Next)) + ) + self.comment = state_props.get(Comment) + self.input_path = state_props.get(InputPath) or InputPath( + InputPath.DEFAULT_PATH + ) + self.output_path = state_props.get(OutputPath) or OutputPath( + OutputPath.DEFAULT_PATH + ) + + def _set_next(self, env: Environment) -> None: + if env.next_state_name != self.name: + # Next was already overriden. + return + + if isinstance(self.continue_with, ContinueWithNext): + env.next_state_name = self.continue_with.next_state.name + elif isinstance( + self.continue_with, ContinueWithEnd + ): # This includes ContinueWithSuccess + env.set_ended() + else: + LOG.error( + f"Could not handle ContinueWith type of '{type(self.continue_with)}'." + ) + + def _get_state_entered_event_details( + self, env: Environment + ) -> StateEnteredEventDetails: + return StateEnteredEventDetails( + name=self.name, + input=to_json_str(env.inp, separators=(",", ":")), + inputDetails=HistoryEventExecutionDataDetails( + truncated=False # Always False for api calls. + ), + ) + + def _get_state_exited_event_details( + self, env: Environment + ) -> StateExitedEventDetails: + return StateExitedEventDetails( + name=self.name, + output=to_json_str(env.inp, separators=(",", ":")), + outputDetails=HistoryEventExecutionDataDetails( + truncated=False # Always False for api calls. + ), + ) + + @abc.abstractmethod + def _eval_state(self, env: Environment) -> None: + ... + + def _eval_body(self, env: Environment) -> None: + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=self.state_entered_event_type, + event_detail=EventDetails( + stateEnteredEventDetails=self._get_state_entered_event_details(env=env) + ), + ) + + env.context_object_manager.context_object["State"] = State( + EnteredTime=datetime.datetime.now(tz=datetime.timezone.utc).isoformat(), + Name=self.name, + ) + + # Filter the input onto the stack. + if self.input_path: + self.input_path.eval(env) + + # Exec the state's logic. + self._eval_state(env) + # + if not isinstance(env.program_state(), ProgramRunning): + return + + # Filter the input onto the input. + if self.output_path: + self.output_path.eval(env) + + if self.state_exited_event_type is not None: + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=self.state_exited_event_type, + event_detail=EventDetails( + stateExitedEventDetails=self._get_state_exited_event_details( + env=env + ), + ), + ) + + # Set next state or halt (end). + self._set_next(env) diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_choice/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/choice_rule.py b/moto/stepfunctions/parser/asl/component/state/state_choice/choice_rule.py new file mode 100644 index 000000000..295802f13 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/choice_rule.py @@ -0,0 +1,20 @@ +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.common.flow.next import Next +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison import ( + Comparison, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ChoiceRule(EvalComponent): + comparison: Final[Optional[Comparison]] + next_stmt: Final[Optional[Next]] + + def __init__(self, comparison: Optional[Comparison], next_stmt: Optional[Next]): + self.comparison = comparison + self.next_stmt = next_stmt + + def _eval_body(self, env: Environment) -> None: + self.comparison.eval(env) diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/choices_decl.py b/moto/stepfunctions/parser/asl/component/state/state_choice/choices_decl.py new file mode 100644 index 000000000..dbd3d0e8f --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/choices_decl.py @@ -0,0 +1,11 @@ +from typing import Final, List + +from moto.stepfunctions.parser.asl.component.component import Component +from moto.stepfunctions.parser.asl.component.state.state_choice.choice_rule import ( + ChoiceRule, +) + + +class ChoicesDecl(Component): + def __init__(self, rules: List[ChoiceRule]): + self.rules: Final[List[ChoiceRule]] = rules diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison.py new file mode 100644 index 000000000..03fb7ca68 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison.py @@ -0,0 +1,7 @@ +from abc import ABC + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent + + +class Comparison(EvalComponent, ABC): + ... diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison_composite.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison_composite.py new file mode 100644 index 000000000..5328db52d --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison_composite.py @@ -0,0 +1,101 @@ +from __future__ import annotations + +import abc +from enum import Enum +from typing import Any, Final, List + +from moto.stepfunctions.parser.asl.antlr.runtime.ASLLexer import ASLLexer +from moto.stepfunctions.parser.asl.component.state.state_choice.choice_rule import ( + ChoiceRule, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison import ( + Comparison, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.parse.typed_props import TypedProps + + +class ComparisonCompositeProps(TypedProps): + def add(self, instance: Any) -> None: + inst_type = type(instance) + + if issubclass(inst_type, ComparisonComposite): + super()._add(ComparisonComposite, instance) + return + + super().add(instance) + + +class ComparisonComposite(Comparison, abc.ABC): + class ChoiceOp(Enum): + And = ASLLexer.AND + Or = ASLLexer.OR + Not = ASLLexer.NOT + + operator: Final[ComparisonComposite.ChoiceOp] + + def __init__(self, operator: ComparisonComposite.ChoiceOp): + self.operator = operator + + +class ComparisonCompositeSingle(ComparisonComposite, abc.ABC): + rule: Final[ChoiceRule] + + def __init__(self, operator: ComparisonComposite.ChoiceOp, rule: ChoiceRule): + super(ComparisonCompositeSingle, self).__init__(operator=operator) + self.rule = rule + + +class ComparisonCompositeMulti(ComparisonComposite, abc.ABC): + rules: Final[List[ChoiceRule]] + + def __init__(self, operator: ComparisonComposite.ChoiceOp, rules: List[ChoiceRule]): + super(ComparisonCompositeMulti, self).__init__(operator=operator) + self.rules = rules + + +class ComparisonCompositeNot(ComparisonCompositeSingle): + def __init__(self, rule: ChoiceRule): + super(ComparisonCompositeNot, self).__init__( + operator=ComparisonComposite.ChoiceOp.Not, rule=rule + ) + + def _eval_body(self, env: Environment) -> None: + self.rule.eval(env) + tmp: bool = env.stack.pop() + res = tmp is False + env.stack.append(res) + + +class ComparisonCompositeAnd(ComparisonCompositeMulti): + def __init__(self, rules: List[ChoiceRule]): + super(ComparisonCompositeAnd, self).__init__( + operator=ComparisonComposite.ChoiceOp.And, rules=rules + ) + + def _eval_body(self, env: Environment) -> None: + res = True + for rule in self.rules: + rule.eval(env) + rule_out = env.stack.pop() + if not rule_out: + res = False + break # TODO: Lazy evaluation? Can use all function instead? how's eval for that? + env.stack.append(res) + + +class ComparisonCompositeOr(ComparisonCompositeMulti): + def __init__(self, rules: List[ChoiceRule]): + super(ComparisonCompositeOr, self).__init__( + operator=ComparisonComposite.ChoiceOp.Or, rules=rules + ) + + def _eval_body(self, env: Environment) -> None: + res = False + for rule in self.rules: + rule.eval(env) + rule_out = env.stack.pop() + res = res or rule_out + if res: + break # TODO: Lazy evaluation? Can use all function instead? how's eval for that? + env.stack.append(res) diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison_func.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison_func.py new file mode 100644 index 000000000..c823cf6d3 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison_func.py @@ -0,0 +1,33 @@ +from __future__ import annotations + +import json +from typing import Final + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison_operator_type import ( + ComparisonOperatorType, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.factory import ( + OperatorFactory, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.operator import ( + Operator, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ComparisonFunc(EvalComponent): + def __init__(self, operator: ComparisonOperatorType, value: json): + self.operator_type: Final[ComparisonOperatorType] = operator + self.value: json = value + + def _eval_body(self, env: Environment) -> None: + value = self.value + operator: Operator = OperatorFactory.get(self.operator_type) + operator.eval(env=env, value=value) + + @staticmethod + def _string_equals(env: Environment, value: json) -> None: + val = env.stack.pop() + res = str(val) == value + env.stack.append(res) diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison_operator_type.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison_operator_type.py new file mode 100644 index 000000000..e20474624 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison_operator_type.py @@ -0,0 +1,45 @@ +from enum import Enum + +from moto.stepfunctions.parser.asl.antlr.runtime.ASLLexer import ASLLexer + + +class ComparisonOperatorType(Enum): + BooleanEquals = ASLLexer.BOOLEANEQUALS + BooleanEqualsPath = ASLLexer.BOOLEANQUALSPATH + IsBoolean = ASLLexer.ISBOOLEAN + IsNull = ASLLexer.ISNULL + IsNumeric = ASLLexer.ISNUMERIC + IsPresent = ASLLexer.ISPRESENT + IsString = ASLLexer.ISSTRING + IsTimestamp = ASLLexer.ISTIMESTAMP + NumericEquals = ASLLexer.NUMERICEQUALS + NumericEqualsPath = ASLLexer.NUMERICEQUALSPATH + NumericGreaterThan = ASLLexer.NUMERICGREATERTHAN + NumericGreaterThanPath = ASLLexer.NUMERICGREATERTHANPATH + NumericGreaterThanEquals = ASLLexer.NUMERICGREATERTHANEQUALS + NumericGreaterThanEqualsPath = ASLLexer.NUMERICGREATERTHANEQUALSPATH + NumericLessThan = ASLLexer.NUMERICLESSTHAN + NumericLessThanPath = ASLLexer.NUMERICLESSTHANPATH + NumericLessThanEquals = ASLLexer.NUMERICLESSTHANEQUALS + NumericLessThanEqualsPath = ASLLexer.NUMERICLESSTHANEQUALSPATH + StringEquals = ASLLexer.STRINGEQUALS + StringEqualsPath = ASLLexer.STRINGEQUALSPATH + StringGreaterThan = ASLLexer.STRINGGREATERTHAN + StringGreaterThanPath = ASLLexer.STRINGGREATERTHANPATH + StringGreaterThanEquals = ASLLexer.STRINGGREATERTHANEQUALS + StringGreaterThanEqualsPath = ASLLexer.STRINGGREATERTHANEQUALSPATH + StringLessThan = ASLLexer.STRINGLESSTHAN + StringLessThanPath = ASLLexer.STRINGLESSTHANPATH + StringLessThanEquals = ASLLexer.STRINGLESSTHANEQUALS + StringLessThanEqualsPath = ASLLexer.STRINGLESSTHANEQUALSPATH + StringMatches = ASLLexer.STRINGMATCHES + TimestampEquals = ASLLexer.TIMESTAMPEQUALS + TimestampEqualsPath = ASLLexer.TIMESTAMPEQUALSPATH + TimestampGreaterThan = ASLLexer.TIMESTAMPGREATERTHAN + TimestampGreaterThanPath = ASLLexer.TIMESTAMPGREATERTHANPATH + TimestampGreaterThanEquals = ASLLexer.TIMESTAMPGREATERTHANEQUALS + TimestampGreaterThanEqualsPath = ASLLexer.TIMESTAMPGREATERTHANEQUALSPATH + TimestampLessThan = ASLLexer.TIMESTAMPLESSTHAN + TimestampLessThanPath = ASLLexer.TIMESTAMPLESSTHANPATH + TimestampLessThanEquals = ASLLexer.TIMESTAMPLESSTHANEQUALS + TimestampLessThanEqualsPath = ASLLexer.TIMESTAMPLESSTHANEQUALSPATH diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison_variable.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison_variable.py new file mode 100644 index 000000000..842bcf949 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/comparison_variable.py @@ -0,0 +1,27 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison import ( + Comparison, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison_func import ( + ComparisonFunc, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.variable import ( + Variable, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ComparisonVariable(Comparison): + variable: Final[Variable] + comparison_function: Final[ComparisonFunc] + + def __init__(self, variable: Variable, func: ComparisonFunc): + self.variable = variable + self.comparison_function = func + + def _eval_body(self, env: Environment) -> None: + variable: Variable = self.variable + variable.eval(env) + comparison_function: ComparisonFunc = self.comparison_function + comparison_function.eval(env) diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/factory.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/factory.py new file mode 100644 index 000000000..2a0e0fc62 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/factory.py @@ -0,0 +1,20 @@ +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison_operator_type import ( + ComparisonOperatorType, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.implementations.boolean_equals import * # noqa +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.implementations.is_operator import * # noqa +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.implementations.numeric import * # noqa +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.implementations.string_operators import * # noqa +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.implementations.timestamp_operators import * # noqa +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.operator import ( + Operator, +) + + +class OperatorFactory: + @staticmethod + def get(typ: ComparisonOperatorType) -> Operator: + op = Operator.get((str(typ))) + if op is None: + raise NotImplementedError(f"{typ} is not supported.") + return op diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/boolean_equals.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/boolean_equals.py new file mode 100644 index 000000000..92f88c3ce --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/boolean_equals.py @@ -0,0 +1,46 @@ +from typing import Any + +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison_operator_type import ( + ComparisonOperatorType, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.operator import ( + Operator, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class BooleanEquals(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.BooleanEquals) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = False + if isinstance(variable, bool): + res = variable is value + env.stack.append(res) + + +class BooleanEqualsPath(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.BooleanEqualsPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + + inp = env.stack[-1] + comp_value: bool = JSONPathUtils.extract_json(value, inp) + if not isinstance(comp_value, bool): + raise TypeError( + f"Expected type bool, but got '{comp_value}' from path '{value}'." + ) + + res = False + if isinstance(variable, bool): + res = bool(variable) is comp_value + env.stack.append(res) diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/is_operator.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/is_operator.py new file mode 100644 index 000000000..e5ec4d7fc --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/is_operator.py @@ -0,0 +1,110 @@ +import datetime +import logging +from typing import Any, Final, Optional + +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison_operator_type import ( + ComparisonOperatorType, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.operator import ( + Operator, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.variable import ( + NoSuchVariable, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + +LOG = logging.getLogger(__name__) + + +class IsBoolean(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.IsBoolean) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = isinstance(variable, bool) is value + env.stack.append(res) + + +class IsNull(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.IsNull) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + is_null = variable is None and not isinstance(variable, NoSuchVariable) + res = is_null is value + env.stack.append(res) + + +class IsNumeric(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.IsNumeric) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = ( + isinstance(variable, (int, float)) and not isinstance(variable, bool) + ) is value + env.stack.append(res) + + +class IsPresent(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.IsPresent) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = isinstance(variable, NoSuchVariable) is not value + env.stack.append(res) + + +class IsString(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.IsString) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = isinstance(variable, str) is value + env.stack.append(res) + + +class IsTimestamp(Operator): + # Timestamps are strings which MUST conform to the RFC3339 profile of ISO 8601, with the further restrictions that + # an uppercase "T" character MUST be used to separate date and time, and an uppercase "Z" character MUST be + # present in the absence of a numeric time zone offset, for example "2016-03-14T01:59:00Z". + TIMESTAMP_FORMAT: Final[str] = "%Y-%m-%dT%H:%M:%SZ" + + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.IsTimestamp) + + @staticmethod + def string_to_timestamp(string: str) -> Optional[datetime.datetime]: + try: + return datetime.datetime.strptime(string, IsTimestamp.TIMESTAMP_FORMAT) + except Exception: + return None + + @staticmethod + def is_timestamp(inp: Any) -> bool: + return isinstance(inp, str) and IsTimestamp.string_to_timestamp(inp) is not None + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + LOG.warning( + f"State Choice's 'IsTimestamp' operator is not fully supported for input '{variable}' and target '{value}'." + ) + res = IsTimestamp.is_timestamp(variable) is value + env.stack.append(res) diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/numeric.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/numeric.py new file mode 100644 index 000000000..05d0420e9 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/numeric.py @@ -0,0 +1,179 @@ +from typing import Any + +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison_operator_type import ( + ComparisonOperatorType, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.operator import ( + Operator, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +def _is_numeric(variable: Any) -> bool: + return isinstance(variable, (int, float)) and not isinstance(variable, bool) + + +class NumericEquals(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.NumericEquals) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if _is_numeric(variable): + res = variable == comparison_value + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = NumericEquals._compare(variable, value) + env.stack.append(res) + + +class NumericEqualsPath(NumericEquals): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.NumericEqualsPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = NumericEquals._compare(variable, comp_value) + env.stack.append(res) + + +class NumericGreaterThan(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.NumericGreaterThan) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if _is_numeric(variable): + res = variable > comparison_value + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = NumericGreaterThan._compare(variable, value) + env.stack.append(res) + + +class NumericGreaterThanPath(NumericGreaterThan): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.NumericGreaterThanPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = NumericGreaterThanPath._compare(variable, comp_value) + env.stack.append(res) + + +class NumericGreaterThanEquals(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.NumericGreaterThanEquals) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if _is_numeric(variable): + res = variable >= comparison_value + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = NumericGreaterThanEquals._compare(variable, value) + env.stack.append(res) + + +class NumericGreaterThanEqualsPath(NumericGreaterThanEquals): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.NumericGreaterThanEqualsPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = NumericGreaterThanEqualsPath._compare(variable, comp_value) + env.stack.append(res) + + +class NumericLessThan(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.NumericLessThan) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if _is_numeric(variable): + res = variable < comparison_value + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = NumericLessThan._compare(variable, value) + env.stack.append(res) + + +class NumericLessThanPath(NumericLessThan): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.NumericLessThanPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = NumericLessThanPath._compare(variable, comp_value) + env.stack.append(res) + + +class NumericLessThanEquals(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.NumericLessThanEquals) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if _is_numeric(variable): + res = variable <= comparison_value + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = NumericLessThanEquals._compare(variable, value) + env.stack.append(res) + + +class NumericLessThanEqualsPath(NumericLessThanEquals): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.NumericLessThanEqualsPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = NumericLessThanEqualsPath._compare(variable, comp_value) + env.stack.append(res) diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/string_operators.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/string_operators.py new file mode 100644 index 000000000..a0b1d4e1f --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/string_operators.py @@ -0,0 +1,195 @@ +import fnmatch +from typing import Any + +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison_operator_type import ( + ComparisonOperatorType, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.operator import ( + Operator, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class StringEquals(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.StringEquals) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if isinstance(variable, str): + res = variable == comparison_value + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = StringEquals._compare(variable, value) + env.stack.append(res) + + +class StringEqualsPath(StringEquals): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.StringEqualsPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = StringEqualsPath._compare(variable, comp_value) + env.stack.append(res) + + +class StringGreaterThan(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.StringGreaterThan) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if isinstance(variable, str): + res = variable > comparison_value + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = StringGreaterThan._compare(variable, value) + env.stack.append(res) + + +class StringGreaterThanPath(StringGreaterThan): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.StringGreaterThanPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = StringGreaterThanPath._compare(variable, comp_value) + env.stack.append(res) + + +class StringGreaterThanEquals(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.StringGreaterThanEquals) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if isinstance(variable, str): + res = variable >= comparison_value + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = StringGreaterThanEquals._compare(variable, value) + env.stack.append(res) + + +class StringGreaterThanEqualsPath(StringGreaterThanEquals): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.StringGreaterThanEqualsPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = StringGreaterThanEqualsPath._compare(variable, comp_value) + env.stack.append(res) + + +class StringLessThan(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.StringLessThan) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if isinstance(variable, str): + res = variable < comparison_value + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = StringLessThan._compare(variable, value) + env.stack.append(res) + + +class StringLessThanPath(StringLessThan): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.StringLessThanPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = StringLessThanPath._compare(variable, comp_value) + env.stack.append(res) + + +class StringLessThanEquals(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.StringLessThanEquals) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if isinstance(variable, str): + res = variable <= comparison_value + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = StringLessThanEquals._compare(variable, value) + env.stack.append(res) + + +class StringLessThanEqualsPath(StringLessThanEquals): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.StringLessThanEqualsPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = StringLessThanEqualsPath._compare(variable, comp_value) + env.stack.append(res) + + +class StringMatches(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.StringMatches) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if isinstance(variable, str): + res = fnmatch.fnmatch(variable, comparison_value) + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = StringMatches._compare(variable, value) + env.stack.append(res) diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/timestamp_operators.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/timestamp_operators.py new file mode 100644 index 000000000..af3af1a76 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/implementations/timestamp_operators.py @@ -0,0 +1,193 @@ +from typing import Any + +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison_operator_type import ( + ComparisonOperatorType, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.implementations.is_operator import ( + IsTimestamp, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.operator.operator import ( + Operator, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class TimestampEquals(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.TimestampEquals) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if isinstance(variable, str): + a = IsTimestamp.string_to_timestamp(variable) + if a is not None: + b = IsTimestamp.string_to_timestamp(comparison_value) + res = a == b + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = TimestampEquals._compare(variable, value) + env.stack.append(res) + + +class TimestampEqualsPath(TimestampEquals): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.TimestampEqualsPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = TimestampEqualsPath._compare(variable, comp_value) + env.stack.append(res) + + +class TimestampGreaterThan(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.TimestampGreaterThan) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if isinstance(variable, str): + a = IsTimestamp.string_to_timestamp(variable) + if a is not None: + b = IsTimestamp.string_to_timestamp(comparison_value) + res = a > b + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = TimestampGreaterThan._compare(variable, value) + env.stack.append(res) + + +class TimestampGreaterThanPath(TimestampGreaterThan): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.TimestampGreaterThanPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = TimestampGreaterThanPath._compare(variable, comp_value) + env.stack.append(res) + + +class TimestampGreaterThanEquals(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.TimestampGreaterThanEquals) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if isinstance(variable, str): + a = IsTimestamp.string_to_timestamp(variable) + if a is not None: + b = IsTimestamp.string_to_timestamp(comparison_value) + res = a >= b + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = TimestampGreaterThanEquals._compare(variable, value) + env.stack.append(res) + + +class TimestampGreaterThanEqualsPath(TimestampGreaterThanEquals): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.TimestampGreaterThanEqualsPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = TimestampGreaterThanEqualsPath._compare(variable, comp_value) + env.stack.append(res) + + +class TimestampLessThan(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.TimestampLessThan) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if isinstance(variable, str): + a = IsTimestamp.string_to_timestamp(variable) + if a is not None: + b = IsTimestamp.string_to_timestamp(comparison_value) + res = a < b + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = TimestampLessThan._compare(variable, value) + env.stack.append(res) + + +class TimestampLessThanPath(TimestampLessThan): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.TimestampLessThanPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = TimestampLessThanPath._compare(variable, comp_value) + env.stack.append(res) + + +class TimestampLessThanEquals(Operator): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.TimestampLessThanEquals) + + @staticmethod + def _compare(variable: Any, comparison_value: Any) -> bool: + res = False + if isinstance(variable, str): + a = IsTimestamp.string_to_timestamp(variable) + if a is not None: + b = IsTimestamp.string_to_timestamp(comparison_value) + res = a <= b + return res + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + res = TimestampLessThanEquals._compare(variable, value) + env.stack.append(res) + + +class TimestampLessThanEqualsPath(TimestampLessThanEquals): + @staticmethod + def impl_name() -> str: + return str(ComparisonOperatorType.TimestampLessThanEqualsPath) + + @staticmethod + def eval(env: Environment, value: Any) -> None: + variable = env.stack.pop() + inp = env.stack[-1] + comp_value = JSONPathUtils.extract_json(value, inp) + res = TimestampLessThanEqualsPath._compare(variable, comp_value) + env.stack.append(res) diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/operator.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/operator.py new file mode 100644 index 000000000..b59d8ce0f --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/operator/operator.py @@ -0,0 +1,12 @@ +import abc +from typing import Any + +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.utils import SubtypesInstanceManager + + +class Operator(abc.ABC, SubtypesInstanceManager): + @staticmethod + @abc.abstractmethod + def eval(env: Environment, value: Any) -> None: + pass diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/variable.py b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/variable.py new file mode 100644 index 000000000..b600ebf58 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/comparison/variable.py @@ -0,0 +1,23 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class NoSuchVariable: + def __init__(self, path: str): + self.path: Final[str] = path + + +class Variable(EvalComponent): + def __init__(self, value: str): + self.value: Final[str] = value + + def _eval_body(self, env: Environment) -> None: + try: + inp = env.stack[-1] + value = JSONPathUtils.extract_json(self.value, inp) + except Exception as ex: + value = NoSuchVariable(f"{self.value}, {ex}") + env.stack.append(value) diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/default_decl.py b/moto/stepfunctions/parser/asl/component/state/state_choice/default_decl.py new file mode 100644 index 000000000..10ac9a4f3 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/default_decl.py @@ -0,0 +1,8 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class DefaultDecl(Component): + def __init__(self, state_name: str): + self.state_name: Final[str] = state_name diff --git a/moto/stepfunctions/parser/asl/component/state/state_choice/state_choice.py b/moto/stepfunctions/parser/asl/component/state/state_choice/state_choice.py new file mode 100644 index 000000000..4df4396c7 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_choice/state_choice.py @@ -0,0 +1,59 @@ +from typing import Optional + +from moto.stepfunctions.parser.api import HistoryEventType +from moto.stepfunctions.parser.asl.component.common.flow.end import End +from moto.stepfunctions.parser.asl.component.common.flow.next import Next +from moto.stepfunctions.parser.asl.component.state.state import CommonStateField +from moto.stepfunctions.parser.asl.component.state.state_choice.choices_decl import ( + ChoicesDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.default_decl import ( + DefaultDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_props import StateProps +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class StateChoice(CommonStateField): + choices_decl: ChoicesDecl + + def __init__(self): + super(StateChoice, self).__init__( + state_entered_event_type=HistoryEventType.ChoiceStateEntered, + state_exited_event_type=HistoryEventType.ChoiceStateExited, + ) + self.default_state: Optional[DefaultDecl] = None + self._next_state_name: Optional[str] = None + + def from_state_props(self, state_props: StateProps) -> None: + super(StateChoice, self).from_state_props(state_props) + self.choices_decl = state_props.get(ChoicesDecl) + self.default_state = state_props.get(DefaultDecl) + + if state_props.get(Next) or state_props.get(End): + raise ValueError( + "Choice states don't support the End field. " + "In addition, they use Next only inside their Choices field. " + f"With state '{self}'." + ) + + def _set_next(self, env: Environment) -> None: + if self._next_state_name is None: + raise RuntimeError(f"No Next option from state: '{self}'.") + env.next_state_name = self._next_state_name + + def _eval_state(self, env: Environment) -> None: + if self.default_state: + self._next_state_name = self.default_state.state_name + + # TODO: Lazy evaluation? + for rule in self.choices_decl.rules: + rule.eval(env) + res = env.stack.pop() + if res is True: + if not rule.next_stmt: + raise RuntimeError( + f"Missing Next definition for state_choice rule '{rule}' in choices '{self}'." + ) + self._next_state_name = rule.next_stmt.name + break diff --git a/moto/stepfunctions/parser/asl/component/state/state_continue_with.py b/moto/stepfunctions/parser/asl/component/state/state_continue_with.py new file mode 100644 index 000000000..1c7b1f891 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_continue_with.py @@ -0,0 +1,20 @@ +import abc + +from moto.stepfunctions.parser.asl.component.common.flow.next import Next + + +class ContinueWith(abc.ABC): + ... + + +class ContinueWithEnd(ContinueWith): + pass + + +class ContinueWithNext(ContinueWith): + def __init__(self, next_state: Next): + self.next_state: Next = next_state + + +class ContinueWithSuccess(ContinueWithEnd): + pass diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_execution/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/execute_state.py b/moto/stepfunctions/parser/asl/component/state/state_execution/execute_state.py new file mode 100644 index 000000000..b5ab7f845 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/execute_state.py @@ -0,0 +1,258 @@ +import abc +import copy +import logging +import threading +from threading import Thread +from typing import Any, List, Optional + +from moto.stepfunctions.parser.api import HistoryEventType, TaskFailedEventDetails +from moto.stepfunctions.parser.asl.component.common.catch.catch_decl import CatchDecl +from moto.stepfunctions.parser.asl.component.common.catch.catch_outcome import ( + CatchOutcome, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name import ( + StatesErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from moto.stepfunctions.parser.asl.component.common.path.result_path import ResultPath +from moto.stepfunctions.parser.asl.component.common.result_selector import ( + ResultSelector, +) +from moto.stepfunctions.parser.asl.component.common.retry.retry_decl import RetryDecl +from moto.stepfunctions.parser.asl.component.common.retry.retry_outcome import ( + RetryOutcome, +) +from moto.stepfunctions.parser.asl.component.common.timeouts.heartbeat import ( + Heartbeat, + HeartbeatSeconds, +) +from moto.stepfunctions.parser.asl.component.common.timeouts.timeout import ( + EvalTimeoutError, + Timeout, + TimeoutSeconds, +) +from moto.stepfunctions.parser.asl.component.state.state import CommonStateField +from moto.stepfunctions.parser.asl.component.state.state_props import StateProps +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails + +LOG = logging.getLogger(__name__) + + +class ExecutionState(CommonStateField, abc.ABC): + def __init__( + self, + state_entered_event_type: HistoryEventType, + state_exited_event_type: Optional[HistoryEventType], + ): + super().__init__( + state_entered_event_type=state_entered_event_type, + state_exited_event_type=state_exited_event_type, + ) + # ResultPath (Optional) + # Specifies where (in the input) to place the results of executing the state_task that's specified in Resource. + # The input is then filtered as specified by the OutputPath field (if present) before being used as the + # state's output. + self.result_path: Optional[ResultPath] = None + + # ResultSelector (Optional) + # Pass a collection of key value pairs, where the values are static or selected from the result. + self.result_selector: Optional[ResultSelector] = None + + # Retry (Optional) + # An array of objects, called Retriers, that define a retry policy if the state encounters runtime errors. + self.retry: Optional[RetryDecl] = None + + # Catch (Optional) + # An array of objects, called Catchers, that define a fallback state. This state is executed if the state + # encounters runtime errors and its retry policy is exhausted or isn't defined. + self.catch: Optional[CatchDecl] = None + + # TimeoutSeconds (Optional) + # If the state_task runs longer than the specified seconds, this state fails with a States.Timeout error name. + # Must be a positive, non-zero integer. If not provided, the default value is 99999999. The count begins after + # the state_task has been started, for example, when ActivityStarted or LambdaFunctionStarted are logged in the + # Execution event history. + # TimeoutSecondsPath (Optional) + # If you want to provide a timeout value dynamically from the state input using a reference path, use + # TimeoutSecondsPath. When resolved, the reference path must select fields whose values are positive integers. + # A Task state cannot include both TimeoutSeconds and TimeoutSecondsPath + # TimeoutSeconds and TimeoutSecondsPath fields are encoded by the timeout type. + self.timeout: Timeout = TimeoutSeconds( + timeout_seconds=TimeoutSeconds.DEFAULT_TIMEOUT_SECONDS + ) + + # HeartbeatSeconds (Optional) + # If more time than the specified seconds elapses between heartbeats from the task, this state fails with a + # States.Timeout error name. Must be a positive, non-zero integer less than the number of seconds specified in + # the TimeoutSeconds field. If not provided, the default value is 99999999. For Activities, the count begins + # when GetActivityTask receives a token and ActivityStarted is logged in the Execution event history. + # HeartbeatSecondsPath (Optional) + # If you want to provide a heartbeat value dynamically from the state input using a reference path, use + # HeartbeatSecondsPath. When resolved, the reference path must select fields whose values are positive integers. + # A Task state cannot include both HeartbeatSeconds and HeartbeatSecondsPath + # HeartbeatSeconds and HeartbeatSecondsPath fields are encoded by the Heartbeat type. + self.heartbeat: Optional[Heartbeat] = None + + def from_state_props(self, state_props: StateProps) -> None: + super().from_state_props(state_props=state_props) + self.result_path = state_props.get(ResultPath) or ResultPath( + result_path_src=ResultPath.DEFAULT_PATH + ) + self.result_selector = state_props.get(ResultSelector) + self.retry = state_props.get(RetryDecl) + self.catch = state_props.get(CatchDecl) + + # If provided, the "HeartbeatSeconds" interval MUST be smaller than the "TimeoutSeconds" value. + # If not provided, the default value of "TimeoutSeconds" is 60. + timeout = state_props.get(Timeout) + heartbeat = state_props.get(Heartbeat) + if isinstance(timeout, TimeoutSeconds) and isinstance( + heartbeat, HeartbeatSeconds + ): + if timeout.timeout_seconds <= heartbeat.heartbeat_seconds: + raise RuntimeError( + f"'HeartbeatSeconds' interval MUST be smaller than the 'TimeoutSeconds' value, " + f"got '{timeout.timeout_seconds}' and '{heartbeat.heartbeat_seconds}' respectively." + ) + if heartbeat is not None and timeout is None: + timeout = TimeoutSeconds(timeout_seconds=60, is_default=True) + + if timeout is not None: + self.timeout = timeout + if heartbeat is not None: + self.heartbeat = heartbeat + + def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: + if isinstance(ex, FailureEventException): + return ex.failure_event + LOG.warning( + "State Task encountered an unhandled exception that lead to a State.Runtime error." + ) + return FailureEvent( + error_name=StatesErrorName(typ=StatesErrorNameType.StatesRuntime), + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + error=StatesErrorNameType.StatesRuntime.to_name(), + cause=str(ex), + ) + ), + ) + + @abc.abstractmethod + def _eval_execution(self, env: Environment) -> None: + ... + + def _handle_retry( + self, env: Environment, failure_event: FailureEvent + ) -> RetryOutcome: + env.stack.append(failure_event.error_name) + self.retry.eval(env) + res: RetryOutcome = env.stack.pop() + if res == RetryOutcome.CanRetry: + retry_count = env.context_object_manager.context_object["State"][ + "RetryCount" + ] + env.context_object_manager.context_object["State"]["RetryCount"] = ( + retry_count + 1 + ) + return res + + def _handle_catch( + self, env: Environment, failure_event: FailureEvent + ) -> CatchOutcome: + env.stack.append(failure_event) + self.catch.eval(env) + res: CatchOutcome = env.stack.pop() + return res + + def _handle_uncaught(self, env: Environment, failure_event: FailureEvent) -> None: + self._terminate_with_event(env=env, failure_event=failure_event) + + @staticmethod + def _terminate_with_event(env: Environment, failure_event: FailureEvent) -> None: + raise FailureEventException(failure_event=failure_event) + + def _evaluate_with_timeout(self, env: Environment) -> None: + self.timeout.eval(env=env) + timeout_seconds: int = env.stack.pop() + + frame: Environment = env.open_frame() + frame.inp = copy.deepcopy(env.inp) + frame.stack = copy.deepcopy(env.stack) + execution_outputs: List[Any] = list() + execution_exceptions: List[Optional[Exception]] = [None] + terminated_event = threading.Event() + + def _exec_and_notify(): + try: + self._eval_execution(frame) + execution_outputs.extend(frame.stack) + except Exception as ex: + execution_exceptions.append(ex) + terminated_event.set() + + thread = Thread(target=_exec_and_notify) + thread.start() + finished_on_time: bool = terminated_event.wait(timeout_seconds) + frame.set_ended() + env.close_frame(frame) + + execution_exception = execution_exceptions.pop() + if execution_exception: + raise execution_exception + + if not finished_on_time: + raise EvalTimeoutError() + + execution_output = execution_outputs.pop() + env.stack.append(execution_output) + + if self.result_selector: + self.result_selector.eval(env=env) + + if self.result_path: + self.result_path.eval(env) + else: + res = env.stack.pop() + env.inp = res + + def _eval_state(self, env: Environment) -> None: + # Initialise the retry counter for execution states. + env.context_object_manager.context_object["State"]["RetryCount"] = 0 + + # Attempt to evaluate the state's logic through until it's successful, caught, or retries have run out. + while True: + try: + self._evaluate_with_timeout(env) + break + except Exception as ex: + failure_event: FailureEvent = self._from_error(env=env, ex=ex) + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=failure_event.event_type, + event_detail=failure_event.event_details, + ) + + if self.retry: + retry_outcome: RetryOutcome = self._handle_retry( + env=env, failure_event=failure_event + ) + if retry_outcome == RetryOutcome.CanRetry: + continue + + if self.catch: + catch_outcome: CatchOutcome = self._handle_catch( + env=env, failure_event=failure_event + ) + if catch_outcome == CatchOutcome.Caught: + break + + self._handle_uncaught(env=env, failure_event=failure_event) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/execution_type.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/execution_type.py new file mode 100644 index 000000000..1807c23a3 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/execution_type.py @@ -0,0 +1,7 @@ +from enum import Enum + +from moto.stepfunctions.parser.asl.antlr.runtime.ASLLexer import ASLLexer + + +class ExecutionType(Enum): + Standard = ASLLexer.STANDARD diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/item_reader_decl.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/item_reader_decl.py new file mode 100644 index 000000000..dc30b2b68 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/item_reader_decl.py @@ -0,0 +1,69 @@ +import copy +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.common.parameters import Parameters +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.reader_config_decl import ( + ReaderConfig, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.resource_eval.resource_eval import ( + ResourceEval, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.resource_eval.resource_eval_factory import ( + resource_eval_for, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.resource_eval.resource_output_transformer.resource_output_transformer import ( + ResourceOutputTransformer, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.resource_eval.resource_output_transformer.resource_output_transformer_factory import ( + resource_output_transformer_for, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + Resource, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ItemReader(EvalComponent): + resource_eval: Final[ResourceEval] + parameters: Final[Optional[Parameters]] + reader_config: Final[Optional[ReaderConfig]] + resource_output_transformer: Optional[ResourceOutputTransformer] + + def __init__( + self, + resource: Resource, + parameters: Optional[Parameters], + reader_config: Optional[ReaderConfig], + ): + self.resource_eval = resource_eval_for(resource=resource) + self.parameters = parameters + self.reader_config = reader_config + + self.resource_output_transformer = None + if self.reader_config: + self.resource_output_transformer = resource_output_transformer_for( + input_type=self.reader_config.input_type + ) + + @property + def resource(self): + return self.resource_eval.resource + + def __str__(self): + class_dict = copy.deepcopy(self.__dict__) + del class_dict["resource_eval"] + class_dict["resource"] = self.resource + return f"({self.__class__.__name__}| {class_dict})" + + def _eval_body(self, env: Environment) -> None: + if self.parameters: + self.parameters.eval(env=env) + else: + env.stack.append(dict()) + + self.resource_eval.eval_resource(env=env) + + if self.reader_config: + self.reader_config.eval(env=env) + self.resource_output_transformer.eval(env=env) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/csv_header_location.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/csv_header_location.py new file mode 100644 index 000000000..3bdb87ea6 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/csv_header_location.py @@ -0,0 +1,18 @@ +import enum +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class CSVHeaderLocationValue(enum.Enum): + FIRST_ROW = "FIRST_ROW" + GIVEN = "GIVEN" + + +class CSVHeaderLocation(Component): + csv_header_location_value: Final[CSVHeaderLocationValue] + + def __init__(self, csv_header_location_value: str): + self.csv_header_location_value = CSVHeaderLocationValue( + csv_header_location_value + ) # Pass error upstream. diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/csv_headers.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/csv_headers.py new file mode 100644 index 000000000..7f3397b32 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/csv_headers.py @@ -0,0 +1,10 @@ +from typing import Final, List + +from moto.stepfunctions.parser.asl.component.component import Component + + +class CSVHeaders(Component): + header_names: Final[List[str]] + + def __init__(self, header_names: List[str]): + self.header_names = header_names diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/input_type.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/input_type.py new file mode 100644 index 000000000..013642bf0 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/input_type.py @@ -0,0 +1,27 @@ +import enum +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class InputTypeValue(enum.Enum): + """ + Represents the supported InputType values for ItemReader configurations. + """ + + # TODO: add support for MANIFEST InputTypeValue. + CSV = "CSV" + JSON = "JSON" + + +class InputType(Component): + """ + "InputType" Specifies the type of Amazon S3 data source, such as CSV file, object, JSON file, or an + Amazon S3 inventory list. In Workflow Studio, you can select an input type from the Amazon S3 item + source dropdown list under the Item source field. + """ + + input_type_value: Final[InputTypeValue] + + def __init__(self, input_type: str): + self.input_type_value = InputTypeValue(input_type) # Pass error upstream. diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/max_items_decl.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/max_items_decl.py new file mode 100644 index 000000000..cf086c2f4 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/max_items_decl.py @@ -0,0 +1,55 @@ +import abc +from typing import Final + +from jsonpath_ng import parse + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class MaxItemsDecl(EvalComponent, abc.ABC): + @abc.abstractmethod + def _get_value(self, env: Environment) -> int: + ... + + def _eval_body(self, env: Environment) -> None: + max_items: int = self._get_value(env=env) + env.stack.append(max_items) + + +class MaxItems(MaxItemsDecl): + """ + "MaxItems": Limits the number of data items passed to the Map state. For example, suppose that you provide a + CSV file that contains 1000 rows and specify a limit of 100. Then, the interpreter passes only 100 rows to the + Map state. The Map state processes items in sequential order, starting after the header row. + Currently, you can specify a limit of up to 100,000,000 + """ + + MAX_VALUE: Final[int] = 100_000_000 + + max_items: Final[int] + + def __init__(self, max_items: int = MAX_VALUE): + if max_items < 0 or max_items > MaxItems.MAX_VALUE: + raise ValueError( + f"MaxItems value MUST be a non-negative integer " + f"non greater than '{MaxItems.MAX_VALUE}', got '{max_items}'." + ) + self.max_items = max_items + + def _get_value(self, env: Environment) -> int: + return self.max_items + + +class MaxItemsPath(MaxItemsDecl): + """ + "MaxItemsPath": computes a MaxItems value equal to the reference path it points to. + """ + + def __init__(self, path: str): + self.path: Final[str] = path + + def _get_value(self, env: Environment) -> int: + input_expr = parse(self.path) + max_items = input_expr.find(env.inp) + return max_items diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/reader_config_decl.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/reader_config_decl.py new file mode 100644 index 000000000..b3abb871e --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/reader_config/reader_config_decl.py @@ -0,0 +1,76 @@ +from typing import Final, List, Optional, TypedDict + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.csv_header_location import ( + CSVHeaderLocation, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.csv_headers import ( + CSVHeaders, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.input_type import ( + InputType, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.max_items_decl import ( + MaxItems, + MaxItemsDecl, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class InputTypeOutput(str): + CSV = "CSV" + JSON = "JSON" + + +class CSVHeaderLocationOutput(str): + FIRST_ROW = "FIRST_ROW" + GIVEN = "GIVEN" + + +CSVHeadersOutput = List[str] +MaxItemsValueOutput = int + + +class ReaderConfigOutput(TypedDict): + InputType: InputTypeOutput + CSVHeaderLocation: CSVHeaderLocationOutput + CSVHeaders: Optional[CSVHeadersOutput] + MaxItemsValue: MaxItemsValueOutput + + +class ReaderConfig(EvalComponent): + input_type: Final[InputType] + max_items: Final[MaxItemsDecl] + csv_header_location: Final[CSVHeaderLocation] + csv_headers: Optional[CSVHeaders] + + def __init__( + self, + input_type: InputType, + csv_header_location: CSVHeaderLocation, + csv_headers: Optional[CSVHeaders], + max_items: Optional[MaxItemsDecl], + ): + self.input_type = input_type + self.max_items = max_items or MaxItems() + self.csv_header_location = csv_header_location + self.csv_headers = csv_headers + # TODO: verify behaviours: + # - csv fields are declared with json input type + # - headers are declared with first_fow location set + + def _eval_body(self, env: Environment) -> None: + self.max_items.eval(env=env) + max_items_value: int = env.stack.pop() + + reader_config_output = ReaderConfigOutput( + InputType=InputTypeOutput(self.input_type.input_type_value), + MaxItemsValue=max_items_value, + ) + if self.csv_header_location: + reader_config_output[ + "CSVHeaderLocation" + ] = self.csv_header_location.csv_header_location_value.value + if self.csv_headers: + reader_config_output["CSVHeaders"] = self.csv_headers.header_names + env.stack.append(reader_config_output) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_eval.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_eval.py new file mode 100644 index 000000000..955a4ba9a --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_eval.py @@ -0,0 +1,17 @@ +import abc +from typing import Final + +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + ServiceResource, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ResourceEval(abc.ABC): + resource: Final[ServiceResource] + + def __init__(self, resource: ServiceResource): + self.resource = resource + + def eval_resource(self, env: Environment) -> None: + ... diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_eval_factory.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_eval_factory.py new file mode 100644 index 000000000..c6428917a --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_eval_factory.py @@ -0,0 +1,19 @@ +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.resource_eval.resource_eval import ( + ResourceEval, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.resource_eval.resource_eval_s3 import ( + ResourceEvalS3, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + Resource, + ServiceResource, +) + + +def resource_eval_for(resource: Resource) -> ResourceEval: + if isinstance(resource, ServiceResource): + if resource.service_name == "s3": + return ResourceEvalS3(resource=resource) + raise ValueError( + f"ItemReader's Resource fields must be states service resource, instead got '{resource.resource_arn}'." + ) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_eval_s3.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_eval_s3.py new file mode 100644 index 000000000..c98e3261d --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_eval_s3.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +from typing import Callable, Final + +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.resource_eval.resource_eval import ( + ResourceEval, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + ResourceRuntimePart, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.boto_client import boto_client_for +from moto.stepfunctions.parser.utils import camel_to_snake_case, to_str + + +class ResourceEvalS3(ResourceEval): + _HANDLER_REFLECTION_PREFIX: Final[str] = "_handle_" + _API_ACTION_HANDLER_TYPE = Callable[[Environment, ResourceRuntimePart], None] + + @staticmethod + def _get_s3_client(resource_runtime_part: ResourceRuntimePart): + return boto_client_for( + region=resource_runtime_part.region, + account=resource_runtime_part.account, + service="s3", + ) + + @staticmethod + def _handle_get_object( + env: Environment, resource_runtime_part: ResourceRuntimePart + ) -> None: + s3_client = ResourceEvalS3._get_s3_client( + resource_runtime_part=resource_runtime_part + ) + parameters = env.stack.pop() + response = s3_client.get_object(**parameters) + content = to_str(response["Body"].read()) + env.stack.append(content) + + @staticmethod + def _handle_list_objects_v2( + env: Environment, resource_runtime_part: ResourceRuntimePart + ) -> None: + s3_client = ResourceEvalS3._get_s3_client( + resource_runtime_part=resource_runtime_part + ) + parameters = env.stack.pop() + response = s3_client.list_objects_v2(**parameters) + contents = response["Contents"] + env.stack.append(contents) + + def _get_api_action_handler(self) -> ResourceEvalS3._API_ACTION_HANDLER_TYPE: + api_action = camel_to_snake_case(self.resource.api_action).strip() + handler_name = ResourceEvalS3._HANDLER_REFLECTION_PREFIX + api_action + resolver_handler = getattr(self, handler_name) + if resolver_handler is None: + raise ValueError(f"Unknown s3 action '{api_action}'.") + return resolver_handler + + def eval_resource(self, env: Environment) -> None: + self.resource.eval(env=env) + resource_runtime_part: ResourceRuntimePart = env.stack.pop() + resolver_handler = self._get_api_action_handler() + resolver_handler(env, resource_runtime_part) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer.py new file mode 100644 index 000000000..cc5225df9 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer.py @@ -0,0 +1,7 @@ +import abc + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent + + +class ResourceOutputTransformer(EvalComponent, abc.ABC): + ... diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer_csv.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer_csv.py new file mode 100644 index 000000000..69baeb10c --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer_csv.py @@ -0,0 +1,71 @@ +import csv +import io +from collections import OrderedDict + +from moto.stepfunctions.parser.api import HistoryEventType, MapRunFailedEventDetails +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name import ( + StatesErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.reader_config_decl import ( + CSVHeaderLocationOutput, + ReaderConfigOutput, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.resource_eval.resource_output_transformer.resource_output_transformer import ( + ResourceOutputTransformer, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails + + +class ResourceOutputTransformerCSV(ResourceOutputTransformer): + def _eval_body(self, env: Environment) -> None: + reader_config: ReaderConfigOutput = env.stack.pop() + resource_value: str = env.stack.pop() + + csv_file = io.StringIO(resource_value) + csv_reader = csv.reader(csv_file) + + location = reader_config["CSVHeaderLocation"] + if location == CSVHeaderLocationOutput.FIRST_ROW: + headers = next(csv_reader) + elif location == CSVHeaderLocationOutput.GIVEN: + headers = reader_config["CSVHeaders"] + else: + raise ValueError(f"Unknown CSVHeaderLocation value '{location}'.") + + if len(set(headers)) < len(headers): + error_name = StatesErrorName(typ=StatesErrorNameType.StatesItemReaderFailed) + failure_event = FailureEvent( + error_name=error_name, + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + mapRunFailedEventDetails=MapRunFailedEventDetails( + error=error_name.error_name, + cause="CSV headers cannot contain duplicates.", + ) + ), + ) + raise FailureEventException(failure_event=failure_event) + + transformed_outputs = list() + for row in csv_reader: + transformed_output = dict() + for i, header in enumerate(headers): + transformed_output[header] = row[i] if i < len(row) else "" + transformed_outputs.append( + OrderedDict( + sorted( + transformed_output.items(), + key=lambda item: (item[0].isalpha(), item[0]), + ) + ) + ) + + env.stack.append(transformed_outputs) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer_factory.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer_factory.py new file mode 100644 index 000000000..33d78bac1 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer_factory.py @@ -0,0 +1,22 @@ +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.input_type import ( + InputType, + InputTypeValue, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.resource_eval.resource_output_transformer.resource_output_transformer import ( + ResourceOutputTransformer, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.resource_eval.resource_output_transformer.resource_output_transformer_csv import ( + ResourceOutputTransformerCSV, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.resource_eval.resource_output_transformer.resource_output_transformer_json import ( + ResourceOutputTransformerJson, +) + + +def resource_output_transformer_for(input_type: InputType) -> ResourceOutputTransformer: + if input_type.input_type_value == InputTypeValue.CSV: + return ResourceOutputTransformerCSV() + elif input_type.input_type_value == InputTypeValue.JSON: + return ResourceOutputTransformerJson() + else: + raise ValueError(f"Unknown InputType value: '{input_type.input_type_value}'.") diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer_json.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer_json.py new file mode 100644 index 000000000..d164d31ce --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_reader/resource_eval/resource_output_transformer/resource_output_transformer_json.py @@ -0,0 +1,47 @@ +import json + +from moto.stepfunctions.parser.api import HistoryEventType, MapRunFailedEventDetails +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name import ( + StatesErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.reader_config_decl import ( + ReaderConfigOutput, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.resource_eval.resource_output_transformer.resource_output_transformer import ( + ResourceOutputTransformer, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails + + +class ResourceOutputTransformerJson(ResourceOutputTransformer): + def _eval_body(self, env: Environment) -> None: + _: ReaderConfigOutput = ( + env.stack.pop() + ) # Not used, but expected by workflow (hence should consume the stack). + resource_value: str = env.stack.pop() + + json_list = json.loads(resource_value) + + if not isinstance(json_list, list): + error_name = StatesErrorName(typ=StatesErrorNameType.StatesItemReaderFailed) + failure_event = FailureEvent( + error_name=error_name, + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + mapRunFailedEventDetails=MapRunFailedEventDetails( + error=error_name.error_name, + cause="Attempting to map over non-iterable node.", + ) + ), + ) + raise FailureEventException(failure_event=failure_event) + + env.stack.append(json_list) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_selector.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_selector.py new file mode 100644 index 000000000..4e6f76d41 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/item_selector.py @@ -0,0 +1,15 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadtmpl.payload_tmpl import ( + PayloadTmpl, +) +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ItemSelector(EvalComponent): + def __init__(self, payload_tmpl: PayloadTmpl): + self.payload_tmpl: Final[PayloadTmpl] = payload_tmpl + + def _eval_body(self, env: Environment) -> None: + self.payload_tmpl.eval(env=env) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/distributed_iteration_component.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/distributed_iteration_component.py new file mode 100644 index 000000000..5181b852b --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/distributed_iteration_component.py @@ -0,0 +1,193 @@ +from __future__ import annotations + +import abc +import json +import threading +from typing import Any, Final, List, Optional + +from moto.stepfunctions.parser.api import ( + HistoryEventType, + MapRunFailedEventDetails, + MapRunStartedEventDetails, + MapRunStatus, +) +from moto.stepfunctions.parser.asl.component.common.comment import Comment +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.common.flow.start_at import StartAt +from moto.stepfunctions.parser.asl.component.program.program import Program +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.item_reader_decl import ( + ItemReader, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.inline_iteration_component import ( + InlineIterationComponent, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.map_run_record import ( + MapRunRecord, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iteration_worker import ( + IterationWorker, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.job import ( + Job, + JobPool, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.max_concurrency import ( + MaxConcurrency, +) +from moto.stepfunctions.parser.asl.component.states import States +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.eval.event.event_history import EventHistory + + +class DistributedIterationComponentEvalInput: + state_name: Final[str] + max_concurrency: Final[int] + item_reader: Final[ItemReader] + + def __init__(self, state_name: str, max_concurrency: int, item_reader: ItemReader): + self.state_name = state_name + self.max_concurrency = max_concurrency + self.item_reader = item_reader + + +class DistributedIterationComponent(InlineIterationComponent, abc.ABC): + _eval_input: Optional[DistributedIterationComponentEvalInput] + _mutex: Final[threading.Lock] + _map_run_record: Optional[MapRunRecord] + _workers: List[IterationWorker] + + def __init__(self, start_at: StartAt, states: States, comment: Comment): + super().__init__(start_at=start_at, states=states, comment=comment) + self._mutex = threading.Lock() + self._map_run_record = None + self._workers = list() + + @abc.abstractmethod + def _create_worker(self, env: Environment) -> IterationWorker: + ... + + def _launch_worker(self, env: Environment) -> IterationWorker: + worker = super()._launch_worker(env=env) + self._workers.append(worker) + return worker + + def _set_active_workers(self, workers_number: int, env: Environment) -> None: + with self._mutex: + current_workers_number = len(self._workers) + workers_diff = workers_number - current_workers_number + if workers_diff > 0: + for _ in range(workers_diff): + self._launch_worker(env=env) + elif workers_diff < 0: + deletion_workers = list(self._workers)[workers_diff:] + for worker in deletion_workers: + worker.sig_stop() + self._workers.remove(worker) + + def _map_run(self, env: Environment) -> None: + input_items: List[json] = env.stack.pop() + + input_item_prog: Final[Program] = Program( + start_at=self._start_at, + states=self._states, + timeout_seconds=None, + comment=self._comment, + ) + self._job_pool = JobPool(job_program=input_item_prog, job_inputs=input_items) + + # TODO: add watch on map_run_record update event and adjust the number of running workers accordingly. + max_concurrency = self._map_run_record.max_concurrency + workers_number = ( + len(input_items) + if max_concurrency == MaxConcurrency.DEFAULT + else max_concurrency + ) + self._set_active_workers(workers_number=workers_number, env=env) + + self._job_pool.await_jobs() + + worker_exception: Optional[Exception] = self._job_pool.get_worker_exception() + if worker_exception is not None: + raise worker_exception + + closed_jobs: List[Job] = self._job_pool.get_closed_jobs() + outputs: List[Any] = [closed_job.job_output for closed_job in closed_jobs] + + env.stack.append(outputs) + + def _eval_body(self, env: Environment) -> None: + self._eval_input = env.stack.pop() + + self._map_run_record = MapRunRecord( + state_machine_arn=env.context_object_manager.context_object["StateMachine"][ + "Id" + ], + execution_arn=env.context_object_manager.context_object["Execution"]["Id"], + max_concurrency=self._eval_input.max_concurrency, + ) + env.map_run_record_pool_manager.add(self._map_run_record) + + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapRunStarted, + event_detail=EventDetails( + mapRunStartedEventDetails=MapRunStartedEventDetails( + mapRunArn=self._map_run_record.map_run_arn + ) + ), + ) + + execution_event_history = env.event_history + try: + self._eval_input.item_reader.eval(env=env) + # TODO: investigate if this is truly propagated also to eventual sub programs in map run states. + env.event_history = EventHistory() + self._map_run(env=env) + + except FailureEventException as failure_event_ex: + map_run_fail_event_detail = MapRunFailedEventDetails() + + maybe_error_cause_pair = failure_event_ex.extract_error_cause_pair() + if maybe_error_cause_pair: + error, cause = maybe_error_cause_pair + if error: + map_run_fail_event_detail["error"] = error + if cause: + map_run_fail_event_detail["cause"] = cause + + env.event_history = execution_event_history + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapRunFailed, + event_detail=EventDetails( + mapRunFailedEventDetails=map_run_fail_event_detail + ), + ) + self._map_run_record.set_stop(status=MapRunStatus.FAILED) + raise failure_event_ex + + except Exception as ex: + env.event_history = execution_event_history + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapRunFailed, + event_detail=EventDetails( + mapRunFailedEventDetails=MapRunFailedEventDetails() + ), + ) + self._map_run_record.set_stop(status=MapRunStatus.FAILED) + raise ex + finally: + env.event_history = execution_event_history + + # TODO: review workflow of program stops and maprunstops + # program_state = env.program_state() + # if isinstance(program_state, ProgramSucceeded) + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapRunSucceeded, + ) + self._map_run_record.set_stop(status=MapRunStatus.SUCCEEDED) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/inline_iteration_component.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/inline_iteration_component.py new file mode 100644 index 000000000..4791c89ab --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/inline_iteration_component.py @@ -0,0 +1,98 @@ +from __future__ import annotations + +import abc +import json +import threading +from typing import Any, Final, List, Optional + +from moto.stepfunctions.parser.asl.component.common.comment import Comment +from moto.stepfunctions.parser.asl.component.common.flow.start_at import StartAt +from moto.stepfunctions.parser.asl.component.program.program import Program +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iteration_component import ( + IterationComponent, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iteration_worker import ( + IterationWorker, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.job import ( + Job, + JobPool, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.max_concurrency import ( + MaxConcurrency, +) +from moto.stepfunctions.parser.asl.component.states import States +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.utils import TMP_THREADS + + +class InlineIterationComponentEvalInput: + state_name: Final[str] + max_concurrency: Final[int] + input_items: Final[List[json]] + + def __init__(self, state_name: str, max_concurrency: int, input_items: List[json]): + self.state_name = state_name + self.max_concurrency = max_concurrency + self.input_items = input_items + + +class InlineIterationComponent(IterationComponent, abc.ABC): + _eval_input: Optional[InlineIterationComponentEvalInput] + _job_pool: Optional[JobPool] + + def __init__( + self, + start_at: StartAt, + states: States, + comment: Optional[Comment], + ): + super().__init__(start_at=start_at, states=states, comment=comment) + self._eval_input = None + self._job_pool = None + + @abc.abstractmethod + def _create_worker(self, env: Environment) -> IterationWorker: + ... + + def _launch_worker(self, env: Environment) -> IterationWorker: + worker = self._create_worker(env=env) + worker_thread = threading.Thread(target=worker.eval) + TMP_THREADS.append(worker_thread) + worker_thread.start() + return worker + + def _eval_body(self, env: Environment) -> None: + self._eval_input = env.stack.pop() + + max_concurrency: int = self._eval_input.max_concurrency + input_items: List[json] = self._eval_input.input_items + + input_item_prog: Final[Program] = Program( + start_at=self._start_at, + states=self._states, + timeout_seconds=None, + comment=self._comment, + ) + self._job_pool = JobPool( + job_program=input_item_prog, job_inputs=self._eval_input.input_items + ) + + number_of_workers = ( + len(input_items) + if max_concurrency == MaxConcurrency.DEFAULT + else max_concurrency + ) + for _ in range(number_of_workers): + self._launch_worker(env=env) + + self._job_pool.await_jobs() + + worker_exception: Optional[Exception] = self._job_pool.get_worker_exception() + if worker_exception is not None: + raise worker_exception + + closed_jobs: List[Job] = self._job_pool.get_closed_jobs() + outputs: List[Any] = [closed_job.job_output for closed_job in closed_jobs] + + env.stack.append(outputs) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/distributed_item_processor.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/distributed_item_processor.py new file mode 100644 index 000000000..79c0e2cb2 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/distributed_item_processor.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.common.comment import Comment +from moto.stepfunctions.parser.asl.component.common.flow.start_at import StartAt +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.item_reader_decl import ( + ItemReader, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_selector import ( + ItemSelector, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.distributed_iteration_component import ( + DistributedIterationComponent, + DistributedIterationComponentEvalInput, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.distributed_item_processor_worker import ( + DistributedItemProcessorWorker, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.processor_config import ( + ProcessorConfig, +) +from moto.stepfunctions.parser.asl.component.states import States +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.parse.typed_props import TypedProps + + +class DistributedItemProcessorEvalInput(DistributedIterationComponentEvalInput): + item_selector: Final[Optional[ItemSelector]] + + def __init__( + self, + state_name: str, + max_concurrency: int, + item_reader: ItemReader, + item_selector: Optional[ItemSelector], + ): + super().__init__( + state_name=state_name, + max_concurrency=max_concurrency, + item_reader=item_reader, + ) + self.item_selector = item_selector + + +class DistributedItemProcessor(DistributedIterationComponent): + _processor_config: Final[ProcessorConfig] + _eval_input: Optional[DistributedItemProcessorEvalInput] + + def __init__( + self, + start_at: StartAt, + states: States, + comment: Optional[Comment], + processor_config: ProcessorConfig, + ): + super().__init__(start_at=start_at, states=states, comment=comment) + self._processor_config = processor_config + + @classmethod + def from_props(cls, props: TypedProps) -> DistributedItemProcessor: + item_processor = cls( + start_at=props.get( + typ=StartAt, + raise_on_missing=ValueError( + f"Missing StartAt declaration in props '{props}'." + ), + ), + states=props.get( + typ=States, + raise_on_missing=ValueError( + f"Missing States declaration in props '{props}'." + ), + ), + comment=props.get(Comment), + processor_config=props.get(ProcessorConfig), + ) + return item_processor + + def _create_worker(self, env: Environment) -> DistributedItemProcessorWorker: + return DistributedItemProcessorWorker( + work_name=self._eval_input.state_name, + job_pool=self._job_pool, + env=env, + item_reader=self._eval_input.item_reader, + item_selector=self._eval_input.item_selector, + map_run_record=self._map_run_record, + ) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/distributed_item_processor_worker.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/distributed_item_processor_worker.py new file mode 100644 index 000000000..2869634a8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/distributed_item_processor_worker.py @@ -0,0 +1,139 @@ +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.common.timeouts.timeout import ( + EvalTimeoutError, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.item_reader_decl import ( + ItemReader, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_selector import ( + ItemSelector, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.inline_item_processor_worker import ( + InlineItemProcessorWorker, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.map_run_record import ( + MapRunRecord, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.job import ( + Job, + JobPool, +) +from moto.stepfunctions.parser.asl.eval.contextobject.contex_object import Item, Map +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.program_state import ( + ProgramError, + ProgramState, + ProgramStopped, +) + + +class DistributedItemProcessorWorker(InlineItemProcessorWorker): + _item_reader: Final[ItemReader] + _map_run_record: MapRunRecord + + def __init__( + self, + work_name: str, + job_pool: JobPool, + env: Environment, + item_reader: ItemReader, + item_selector: Optional[ItemSelector], + map_run_record: MapRunRecord, + ): + super().__init__( + work_name=work_name, job_pool=job_pool, env=env, item_selector=item_selector + ) + self._item_reader = item_reader + self._map_run_record = map_run_record + + def _eval_job(self, env: Environment, job: Job) -> None: + self._map_run_record.item_counter.total.count() + self._map_run_record.item_counter.running.count() + + self._map_run_record.execution_counter.total.count() + self._map_run_record.execution_counter.running.count() + + job_output = None + try: + env.context_object_manager.context_object["Map"] = Map( + Item=Item(Index=job.job_index, Value=job.job_input) + ) + + env.inp = job.job_input + env.stack.append(env.inp) + self._eval_input(env_frame=env) + + job.job_program.eval(env) + + # TODO: verify behaviour with all of these scenarios. + end_program_state: ProgramState = env.program_state() + if isinstance(end_program_state, ProgramError): + self._map_run_record.execution_counter.failed.count() + self._map_run_record.item_counter.failed.count() + job_output = None + elif isinstance(end_program_state, ProgramStopped): + self._map_run_record.execution_counter.aborted.count() + self._map_run_record.item_counter.aborted.count() + else: + self._map_run_record.item_counter.succeeded.count() + self._map_run_record.item_counter.results_written.count() + + self._map_run_record.execution_counter.succeeded.count() + self._map_run_record.execution_counter.results_written.count() + self._map_run_record.execution_counter.running.offset(-1) + + job_output = env.inp + + except EvalTimeoutError: + self._map_run_record.item_counter.timed_out.count() + + except FailureEventException: + self._map_run_record.item_counter.failed.count() + + except Exception: + self._map_run_record.item_counter.failed.count() + + finally: + self._map_run_record.item_counter.running.offset(-1) + job.job_output = job_output + + def _eval_pool(self, job: Optional[Job], worker_frame: Environment) -> None: + # Note: the frame has to be closed before the job, to ensure the owner environment is correctly updated + # before the evaluation continues; map states await for job termination not workers termination. + if job is None: + self._env.delete_frame(worker_frame) + return + + # Evaluate the job. + job_frame = worker_frame.open_frame() + self._eval_job(env=job_frame, job=job) + worker_frame.delete_frame(job_frame) + + # Evaluation terminates here due to exception in job. + if isinstance(job.job_output, Exception): + self._env.delete_frame(worker_frame) + self._job_pool.close_job(job) + return + + # Worker was stopped. + if self.stopped(): + self._env.delete_frame(worker_frame) + self._job_pool.close_job(job) + return + + next_job: Job = self._job_pool.next_job() + # Iteration will terminate after this job. + if next_job is None: + self._env.delete_frame(worker_frame) + self._job_pool.close_job(job) + return + + self._job_pool.close_job(job) + self._eval_pool(job=next_job, worker_frame=worker_frame) + + def eval(self) -> None: + self._eval_pool(job=self._job_pool.next_job(), worker_frame=self._env) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/inline_item_processor.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/inline_item_processor.py new file mode 100644 index 000000000..809aaa968 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/inline_item_processor.py @@ -0,0 +1,81 @@ +from __future__ import annotations + +import json +import logging +from typing import Final, List, Optional + +from moto.stepfunctions.parser.asl.component.common.comment import Comment +from moto.stepfunctions.parser.asl.component.common.flow.start_at import StartAt +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_selector import ( + ItemSelector, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.inline_iteration_component import ( + InlineIterationComponent, + InlineIterationComponentEvalInput, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.inline_item_processor_worker import ( + InlineItemProcessorWorker, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.processor_config import ( + ProcessorConfig, +) +from moto.stepfunctions.parser.asl.component.states import States +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.parse.typed_props import TypedProps + +LOG = logging.getLogger(__name__) + + +class InlineItemProcessorEvalInput(InlineIterationComponentEvalInput): + item_selector: Final[Optional[ItemSelector]] + + def __init__( + self, + state_name: str, + max_concurrency: int, + input_items: List[json], + item_selector: Optional[ItemSelector], + ): + super().__init__( + state_name=state_name, + max_concurrency=max_concurrency, + input_items=input_items, + ) + self.item_selector = item_selector + + +class InlineItemProcessor(InlineIterationComponent): + _processor_config: Final[ProcessorConfig] + _eval_input: Optional[InlineItemProcessorEvalInput] + + def __init__( + self, + start_at: StartAt, + states: States, + comment: Optional[Comment], + processor_config: ProcessorConfig, + ): + super().__init__(start_at=start_at, states=states, comment=comment) + self._processor_config = processor_config + + @classmethod + def from_props(cls, props: TypedProps) -> InlineItemProcessor: + if not props.get(States): + raise ValueError(f"Missing States declaration in props '{props}'.") + if not props.get(StartAt): + raise ValueError(f"Missing StartAt declaration in props '{props}'.") + item_processor = cls( + start_at=props.get(StartAt), + states=props.get(States), + comment=props.get(Comment), + processor_config=props.get(ProcessorConfig), + ) + return item_processor + + def _create_worker(self, env: Environment) -> InlineItemProcessorWorker: + return InlineItemProcessorWorker( + work_name=self._eval_input.state_name, + job_pool=self._job_pool, + env=env, + item_selector=self._eval_input.item_selector, + ) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/inline_item_processor_worker.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/inline_item_processor_worker.py new file mode 100644 index 000000000..5efa7c1b4 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/inline_item_processor_worker.py @@ -0,0 +1,39 @@ +import copy +import logging +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_selector import ( + ItemSelector, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iteration_worker import ( + IterationWorker, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.job import ( + JobPool, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + +LOG = logging.getLogger(__name__) + + +class InlineItemProcessorWorker(IterationWorker): + _item_selector: Final[Optional[ItemSelector]] + + def __init__( + self, + work_name: str, + job_pool: JobPool, + env: Environment, + item_selector: Optional[ItemSelector], + ): + super().__init__(work_name=work_name, job_pool=job_pool, env=env) + self._item_selector = item_selector + + def _eval_input(self, env_frame: Environment) -> None: + if self._item_selector: + map_state_input = self._env.stack[-1] + env_frame.inp = copy.deepcopy(map_state_input) + env_frame.stack.append(env_frame.inp) + self._item_selector.eval(env_frame) + env_frame.inp = env_frame.stack.pop() + env_frame.stack.append(env_frame.inp) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/item_processor_decl.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/item_processor_decl.py new file mode 100644 index 000000000..5d194fd8c --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/item_processor_decl.py @@ -0,0 +1,25 @@ +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.common.comment import Comment +from moto.stepfunctions.parser.asl.component.common.flow.start_at import StartAt +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.processor_config import ( + ProcessorConfig, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iteration_declaration import ( + IterationDecl, +) +from moto.stepfunctions.parser.asl.component.states import States + + +class ItemProcessorDecl(IterationDecl): + processor_config: Final[ProcessorConfig] + + def __init__( + self, + comment: Optional[Comment], + start_at: StartAt, + states: States, + processor_config: Optional[ProcessorConfig], + ): + super().__init__(start_at=start_at, comment=comment, states=states) + self.processor_config = processor_config or ProcessorConfig() diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/item_processor_factory.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/item_processor_factory.py new file mode 100644 index 000000000..9b3c15f8e --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/item_processor_factory.py @@ -0,0 +1,38 @@ +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.distributed_item_processor import ( + DistributedItemProcessor, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.inline_item_processor import ( + InlineItemProcessor, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.item_processor_decl import ( + ItemProcessorDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iteration_component import ( + IterationComponent, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.mode import ( + Mode, +) + + +def from_item_processor_decl( + item_processor_decl: ItemProcessorDecl, +) -> IterationComponent: + if item_processor_decl.processor_config.mode == Mode.Inline: + return InlineItemProcessor( + start_at=item_processor_decl.start_at, + states=item_processor_decl.states, + comment=item_processor_decl.comment, + processor_config=item_processor_decl.processor_config, + ) + elif item_processor_decl.processor_config.mode == Mode.Distributed: + return DistributedItemProcessor( + start_at=item_processor_decl.start_at, + states=item_processor_decl.states, + comment=item_processor_decl.comment, + processor_config=item_processor_decl.processor_config, + ) + else: + raise ValueError( + f"Unknown Mode value '{item_processor_decl.processor_config.mode}'." + ) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/map_run_record.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/map_run_record.py new file mode 100644 index 000000000..3f271d8d5 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/map_run_record.py @@ -0,0 +1,192 @@ +import abc +import datetime +import threading +from collections import OrderedDict +from typing import Any, Dict, Final, List, Optional, Tuple + +from moto.moto_api._internal import mock_random +from moto.stepfunctions.parser.api import ( + MapRunExecutionCounts, + MapRunItemCounts, + MapRunStatus, + Timestamp, +) + + +class Counter: + _mutex: Final[threading.Lock] + _count: int + + def __init__(self): + self._mutex = threading.Lock() + self._count = 0 + + def offset(self, offset: int) -> None: + with self._mutex: + self._count = self._count + offset + + def count(self, increment: int = 1) -> None: + with self._mutex: + self._count += increment + + def get(self) -> int: + return self._count + + +class ProgressCounter(abc.ABC): + aborted: Final[Counter] + failed: Final[Counter] + pending: Final[Counter] + results_written: Final[Counter] + running: Final[Counter] + succeeded: Final[Counter] + timed_out: Final[Counter] + total: Final[Counter] + + def __init__(self): + self.aborted = Counter() + self.failed = Counter() + self.pending = Counter() + self.results_written = Counter() + self.running = Counter() + self.succeeded = Counter() + self.timed_out = Counter() + self.total = Counter() + + +class ExecutionCounter(ProgressCounter): + def describe(self) -> MapRunExecutionCounts: + return MapRunExecutionCounts( + aborted=self.aborted.get(), + failed=self.failed.get(), + pending=self.pending.get(), + resultsWritten=self.results_written.get(), + running=self.running.get(), + succeeded=self.succeeded.get(), + timedOut=self.timed_out.get(), + total=self.total.get(), + ) + + +class ItemCounter(ProgressCounter): + def describe(self) -> MapRunItemCounts: + return MapRunItemCounts( + aborted=self.aborted.get(), + failed=self.failed.get(), + pending=self.pending.get(), + resultsWritten=self.results_written.get(), + running=self.running.get(), + succeeded=self.succeeded.get(), + timedOut=self.timed_out.get(), + total=self.total.get(), + ) + + +class MapRunRecord: + update_event: Final[threading.Event] + # This is the original state machine arn plut the map run arn postfix. + map_state_machine_arn: str + execution_arn: str + map_run_arn: str + max_concurrency: int + execution_counter: Final[ExecutionCounter] + item_counter: Final[ItemCounter] + start_date: Timestamp + status: MapRunStatus + stop_date: Optional[Timestamp] + # TODO: add support for failure toleration fields. + tolerated_failure_count: int + tolerated_failure_percentage: float + + def __init__( + self, state_machine_arn: str, execution_arn: str, max_concurrency: int + ): + self.update_event = threading.Event() + ( + map_state_machine_arn, + map_run_arn, + ) = self._generate_map_run_arns(state_machine_arn=state_machine_arn) + self.map_run_arn = map_run_arn + self.map_state_machine_arn = map_state_machine_arn + self.execution_arn = execution_arn + self.max_concurrency = max_concurrency + self.execution_counter = ExecutionCounter() + self.item_counter = ItemCounter() + self.start_date = datetime.datetime.now(tz=datetime.timezone.utc) + self.status = MapRunStatus.RUNNING + self.stop_date = None + self.tolerated_failure_count = 0 + self.tolerated_failure_percentage = 0.0 + + @staticmethod + def _generate_map_run_arns(state_machine_arn: str) -> Tuple[str, str]: + # Generate a new MapRunArn given the StateMachineArn, such that: + # inp: arn:aws:states::111111111111:stateMachine: + # MRA: arn:aws:states::111111111111:mapRun:/: + # SMA: arn:aws:states::111111111111:mapRun:/ + map_run_arn = state_machine_arn.replace(":stateMachine:", ":mapRun:") + part_1 = str(mock_random.uuid4()) + map_run_arn = f"{map_run_arn}/{part_1}:{str(mock_random.uuid4())}" + return f"{state_machine_arn}/{part_1}", map_run_arn + + def set_stop(self, status: MapRunStatus): + self.status = status + self.stop_date = datetime.datetime.now(tz=datetime.timezone.utc) + + def describe(self) -> Dict[str, Any]: + resp = dict( + mapRunArn=self.map_run_arn, + executionArn=self.execution_arn, + status=self.status, + startDate=self.start_date.isoformat(), + maxConcurrency=self.max_concurrency, + toleratedFailurePercentage=self.tolerated_failure_percentage, + toleratedFailureCount=self.tolerated_failure_count, + itemCounts=self.item_counter.describe(), + executionCounts=self.execution_counter.describe(), + ) + stop_date = self.stop_date + if stop_date is not None: + resp["stopDate"] = self.stop_date.isoformat() + return resp + + def to_json(self) -> Dict[str, Any]: + resp = dict( + executionArn=self.execution_arn, + mapRunArn=self.map_run_arn, + stateMachineArn=self.map_state_machine_arn, + startDate=self.start_date.isoformat(), + ) + if self.stop_date: + resp["stopDate"] = self.stop_date.isoformat() + return resp + + def update( + self, + max_concurrency: Optional[int], + tolerated_failure_count: Optional[int], + tolerated_failure_percentage: Optional[float], + ) -> None: + if max_concurrency is not None: + self.max_concurrency = max_concurrency + if tolerated_failure_count is not None: + self.tolerated_failure_count = tolerated_failure_count + if tolerated_failure_percentage is not None: + self.tolerated_failure_percentage = tolerated_failure_percentage + self.update_event.set() + + +class MapRunRecordPoolManager: + _pool: Dict[str, MapRunRecord] + + def __init__(self): + self._pool = OrderedDict() + + def add(self, map_run_record: MapRunRecord) -> None: + self._pool[map_run_record.map_run_arn] = map_run_record + + def get(self, map_run_arn: str) -> Optional[MapRunRecord]: + return self._pool.get(map_run_arn) + + def get_all(self) -> List[MapRunRecord]: + return list(self._pool.values()) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/processor_config.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/processor_config.py new file mode 100644 index 000000000..329602959 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/itemprocessor/processor_config.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.execution_type import ( + ExecutionType, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.mode import ( + Mode, +) + + +class ProcessorConfig(Component): + DEFAULT_MODE: Final[Mode] = Mode.Inline + DEFAULT_EXECUTION_TYPE: Final[ExecutionType] = ExecutionType.Standard + + mode: Final[Mode] + execution_type: Final[ExecutionType] + + def __init__( + self, + mode: Mode = DEFAULT_MODE, + execution_type: ExecutionType = DEFAULT_EXECUTION_TYPE, + ): + super().__init__() + self.mode = mode + self.execution_type = execution_type diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iteration_component.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iteration_component.py new file mode 100644 index 000000000..330130523 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iteration_component.py @@ -0,0 +1,25 @@ +from __future__ import annotations + +import abc +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.common.comment import Comment +from moto.stepfunctions.parser.asl.component.common.flow.start_at import StartAt +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.component.states import States + + +class IterationComponent(EvalComponent, abc.ABC): + _start_at: Final[StartAt] + _states: Final[States] + _comment: Final[Optional[Comment]] + + def __init__( + self, + start_at: StartAt, + states: States, + comment: Optional[Comment], + ): + self._start_at = start_at + self._states = states + self._comment = comment diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iteration_declaration.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iteration_declaration.py new file mode 100644 index 000000000..13add3576 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iteration_declaration.py @@ -0,0 +1,22 @@ +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.common.comment import Comment +from moto.stepfunctions.parser.asl.component.common.flow.start_at import StartAt +from moto.stepfunctions.parser.asl.component.component import Component +from moto.stepfunctions.parser.asl.component.states import States + + +class IterationDecl(Component): + comment: Final[Optional[Comment]] + start_at: Final[StartAt] + states: Final[States] + + def __init__( + self, + comment: Optional[Comment], + start_at: StartAt, + states: States, + ): + self.start_at = start_at + self.comment = comment + self.states = states diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iteration_worker.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iteration_worker.py new file mode 100644 index 000000000..ff5619be5 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iteration_worker.py @@ -0,0 +1,218 @@ +import abc +import logging +from typing import Final, Optional + +from moto.stepfunctions.parser.api import HistoryEventType, MapIterationEventDetails +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.job import ( + Job, + JobPool, +) +from moto.stepfunctions.parser.asl.eval.contextobject.contex_object import Item, Map +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.eval.program_state import ( + ProgramError, + ProgramState, + ProgramStopped, +) + +LOG = logging.getLogger(__name__) + + +class IterationWorker(abc.ABC): + _work_name: Final[str] + _job_pool: Final[JobPool] + _env: Final[Environment] + _stop_signal_received: bool + + def __init__( + self, + work_name: str, + job_pool: JobPool, + env: Environment, + ): + self._work_name = work_name + self._job_pool = job_pool + self._env = env + self._stop_signal_received = False + + def sig_stop(self): + self._stop_signal_received = True + + def stopped(self): + return self._stop_signal_received + + @abc.abstractmethod + def _eval_input(self, env_frame: Environment) -> None: + ... + + def _eval_job(self, env: Environment, job: Job) -> None: + map_iteration_event_details = MapIterationEventDetails( + name=self._work_name, index=job.job_index + ) + + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapIterationStarted, + event_detail=EventDetails( + mapIterationStartedEventDetails=map_iteration_event_details + ), + ) + + job_output = RuntimeError( + f"Unexpected Runtime Error in ItemProcessor worker for input '{job.job_index}'." + ) + try: + env.context_object_manager.context_object["Map"] = Map( + Item=Item(Index=job.job_index, Value=job.job_input) + ) + + env.inp = job.job_input + self._eval_input(env_frame=env) + + job.job_program.eval(env) + + # Program evaluation suppressed runtime exceptions into an execution exception in the program state. + # Hence, here the routine extract this error triggering FailureEventExceptions, to allow the error at this + # depth to be logged appropriately and propagate to parent states. + + # In case of internal error that lead to failure, then raise execution Exception + # and hence leading to a MapIterationFailed event. + end_program_state: ProgramState = env.program_state() + if isinstance(end_program_state, ProgramError): + error_name = end_program_state.error.get("error") + if error_name is not None: + error_name = CustomErrorName(error_name=error_name) + raise FailureEventException( + failure_event=FailureEvent( + error_name=error_name, + event_type=HistoryEventType.MapIterationFailed, + event_details=EventDetails( + executionFailedEventDetails=end_program_state.error + ), + ) + ) + # If instead the program (parent state machine) was halted, then raise an execution Exception. + elif isinstance(end_program_state, ProgramStopped): + raise FailureEventException( + failure_event=FailureEvent( + error_name=CustomErrorName( + error_name=HistoryEventType.MapIterationAborted + ), + event_type=HistoryEventType.MapIterationAborted, + event_details=EventDetails( + executionFailedEventDetails=end_program_state.error + ), + ) + ) + + # Otherwise, execution succeeded and the output of this operation is available. + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapIterationSucceeded, + event_detail=EventDetails( + mapIterationSucceededEventDetails=map_iteration_event_details + ), + update_source_event_id=False, + ) + # Extract the output otherwise. + job_output = env.inp + + except FailureEventException as failure_event_ex: + # Extract the output to be this exception: this will trigger a failure workflow in the jobs pool. + job_output = failure_event_ex + + # At this depth, the next event is either a MapIterationFailed (for any reasons) or a MapIterationAborted + # if explicitly indicated. + if ( + failure_event_ex.failure_event.event_type + == HistoryEventType.MapIterationAborted + ): + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapIterationAborted, + event_detail=EventDetails( + mapIterationAbortedEventDetails=map_iteration_event_details + ), + update_source_event_id=False, + ) + else: + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapIterationFailed, + event_detail=EventDetails( + mapIterationFailedEventDetails=map_iteration_event_details + ), + update_source_event_id=False, + ) + + except Exception as ex: + # Error case. + LOG.warning( + f"Unhandled termination error in item processor worker for job '{job.job_index}'." + ) + + # Pass the exception upstream leading to evaluation halt. + job_output = ex + + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapIterationFailed, + event_detail=EventDetails( + mapIterationFailedEventDetails=map_iteration_event_details + ), + update_source_event_id=False, + ) + + finally: + job.job_output = job_output + + def _eval_pool(self, job: Optional[Job], worker_frame: Environment) -> None: + # Note: the frame has to be closed before the job, to ensure the owner environment is correctly updated + # before the evaluation continues; map states await for job termination not workers termination. + if job is None: + self._env.close_frame(worker_frame) + return + + # Evaluate the job. + job_frame = worker_frame.open_frame() + self._eval_job(env=job_frame, job=job) + worker_frame.close_frame(job_frame) + + # Evaluation terminates here due to exception in job. + if isinstance(job.job_output, Exception): + self._env.close_frame(worker_frame) + self._job_pool.close_job(job) + return + + # Worker was stopped. + if self.stopped(): + self._env.close_frame(worker_frame) + self._job_pool.close_job(job) + return + + next_job: Job = self._job_pool.next_job() + # Iteration will terminate after this job. + if next_job is None: + # Non-faulty terminal iteration update events are used as source of the following states. + worker_frame.event_history_context.source_event_id = ( + job_frame.event_history_context.last_published_event_id + ) + self._env.close_frame(worker_frame) + self._job_pool.close_job(job) + return + + self._job_pool.close_job(job) + self._eval_pool(job=next_job, worker_frame=worker_frame) + + def eval(self) -> None: + self._eval_pool( + job=self._job_pool.next_job(), worker_frame=self._env.open_frame() + ) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iterator/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iterator/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iterator/iterator.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iterator/iterator.py new file mode 100644 index 000000000..2f7b0aa1f --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iterator/iterator.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +import json +import logging +from typing import Final, List, Optional + +from moto.stepfunctions.parser.asl.component.common.parameters import Parameters +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_selector import ( + ItemSelector, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.inline_iteration_component import ( + InlineIterationComponent, + InlineIterationComponentEvalInput, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iterator.iterator_decl import ( + IteratorDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iterator.iterator_worker import ( + IteratorWorker, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + +LOG = logging.getLogger(__name__) + + +class IteratorEvalInput(InlineIterationComponentEvalInput): + parameters: Final[Optional[ItemSelector]] + + def __init__( + self, + state_name: str, + max_concurrency: int, + input_items: List[json], + parameters: Optional[Parameters], + ): + super().__init__( + state_name=state_name, + max_concurrency=max_concurrency, + input_items=input_items, + ) + self.parameters = parameters + + +class Iterator(InlineIterationComponent): + _eval_input: Optional[IteratorEvalInput] + + def _create_worker(self, env: Environment) -> IteratorWorker: + return IteratorWorker( + work_name=self._eval_input.state_name, + job_pool=self._job_pool, + env=env, + parameters=self._eval_input.parameters, + ) + + @classmethod + def from_declaration(cls, iterator_decl: IteratorDecl): + return cls( + start_at=iterator_decl.start_at, + states=iterator_decl.states, + comment=iterator_decl.comment, + ) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iterator/iterator_decl.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iterator/iterator_decl.py new file mode 100644 index 000000000..fa29ca56e --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iterator/iterator_decl.py @@ -0,0 +1,7 @@ +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iteration_declaration import ( + IterationDecl, +) + + +class IteratorDecl(IterationDecl): + pass diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iterator/iterator_worker.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iterator/iterator_worker.py new file mode 100644 index 000000000..ebe0276b4 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/iterator/iterator_worker.py @@ -0,0 +1,37 @@ +import copy +import logging +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.common.parameters import Parameters +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iteration_worker import ( + IterationWorker, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.job import ( + JobPool, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + +LOG = logging.getLogger(__name__) + + +class IteratorWorker(IterationWorker): + _parameters: Final[Optional[Parameters]] + + def __init__( + self, + work_name: str, + job_pool: JobPool, + env: Environment, + parameters: Optional[Parameters], + ): + super().__init__(work_name=work_name, job_pool=job_pool, env=env) + self._parameters = parameters + + def _eval_input(self, env_frame: Environment) -> None: + if self._parameters: + map_state_input = self._env.stack[-1] + env_frame.inp = copy.deepcopy(map_state_input) + env_frame.stack.append(env_frame.inp) + self._parameters.eval(env_frame) + env_frame.inp = env_frame.stack.pop() + env_frame.stack.append(env_frame.inp) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/job.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/job.py new file mode 100644 index 000000000..391a75afe --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/iteration/job.py @@ -0,0 +1,100 @@ +import copy +import logging +import threading +from typing import Any, Final, List, Optional, Set + +from moto.stepfunctions.parser.asl.component.program.program import Program +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str + +LOG = logging.getLogger(__name__) + + +class Job: + job_index: Final[int] + job_program: Final[Program] + job_input: Final[Optional[Any]] + job_output: Optional[Any] + + def __init__(self, job_index: int, job_program: Program, job_input: Optional[Any]): + self.job_index = job_index + self.job_program = job_program + self.job_input = job_input + self.job_output = None + + def __hash__(self): + return hash(self.job_index) + + +class JobPool: + _mutex: Final[threading.Lock] + _termination_event: Final[threading.Event] + _worker_exception: Optional[Exception] + + _jobs_number: Final[int] + _open_jobs: Final[List[Job]] + _closed_jobs: Final[Set[Job]] + + def __init__(self, job_program: Program, job_inputs: List[Any]): + self._mutex = threading.Lock() + self._termination_event = threading.Event() + self._worker_exception = None + + self._jobs_number = len(job_inputs) + self._open_jobs = [ + Job( + job_index=job_index, + job_program=copy.deepcopy(job_program), + job_input=job_input, + ) + for job_index, job_input in enumerate(job_inputs) + ] + self._open_jobs.reverse() + self._closed_jobs = set() + + def next_job(self) -> Optional[Any]: + with self._mutex: + if self._worker_exception is not None: + return None + try: + return self._open_jobs.pop() + except IndexError: + return None + + def _is_terminated(self) -> bool: + return ( + len(self._closed_jobs) == self._jobs_number + or self._worker_exception is not None + ) + + def _notify_on_termination(self): + if self._is_terminated(): + self._termination_event.set() + + def get_worker_exception(self) -> Optional[Exception]: + return self._worker_exception + + def close_job(self, job: Job): + with self._mutex: + if self._is_terminated(): + return + + if job in self._closed_jobs: + LOG.warning( + f"Duplicate execution of Job with index '{job.job_index}' and input '{to_json_str(job.job_input)}'" + ) + + if isinstance(job.job_output, Exception): + self._worker_exception = job.job_output + else: + self._closed_jobs.add(job) + + self._notify_on_termination() + + def get_closed_jobs(self) -> List[Job]: + with self._mutex: + closed_jobs = copy.deepcopy(self._closed_jobs) + return sorted(closed_jobs, key=lambda closed_job: closed_job.job_index) + + def await_jobs(self): + if not self._is_terminated(): + self._termination_event.wait() diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/max_concurrency.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/max_concurrency.py new file mode 100644 index 000000000..65a4053a8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/max_concurrency.py @@ -0,0 +1,10 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.component import Component + + +class MaxConcurrency(Component): + DEFAULT: Final[int] = 0 # No limit. + + def __init__(self, num: int = DEFAULT): + self.num: Final[int] = num diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/mode.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/mode.py new file mode 100644 index 000000000..adcf3033b --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/mode.py @@ -0,0 +1,8 @@ +from enum import Enum + +from moto.stepfunctions.parser.asl.antlr.runtime.ASLLexer import ASLLexer + + +class Mode(Enum): + Inline = ASLLexer.INLINE + Distributed = ASLLexer.DISTRIBUTED diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/state_map.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/state_map.py new file mode 100644 index 000000000..d9759b1e8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_map/state_map.py @@ -0,0 +1,204 @@ +from typing import Optional + +from moto.stepfunctions.parser.api import HistoryEventType, MapStateStartedEventDetails +from moto.stepfunctions.parser.asl.component.common.catch.catch_decl import CatchDecl +from moto.stepfunctions.parser.asl.component.common.catch.catch_outcome import ( + CatchOutcome, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.common.parameters import Parameters +from moto.stepfunctions.parser.asl.component.common.path.items_path import ItemsPath +from moto.stepfunctions.parser.asl.component.common.path.result_path import ResultPath +from moto.stepfunctions.parser.asl.component.common.result_selector import ( + ResultSelector, +) +from moto.stepfunctions.parser.asl.component.common.retry.retry_decl import RetryDecl +from moto.stepfunctions.parser.asl.component.common.retry.retry_outcome import ( + RetryOutcome, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.execute_state import ( + ExecutionState, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.item_reader_decl import ( + ItemReader, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_selector import ( + ItemSelector, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.distributed_item_processor import ( + DistributedItemProcessor, + DistributedItemProcessorEvalInput, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.inline_item_processor import ( + InlineItemProcessor, + InlineItemProcessorEvalInput, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.item_processor_decl import ( + ItemProcessorDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.item_processor_factory import ( + from_item_processor_decl, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iteration_component import ( + IterationComponent, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iterator.iterator import ( + Iterator, + IteratorEvalInput, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iterator.iterator_decl import ( + IteratorDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.max_concurrency import ( + MaxConcurrency, +) +from moto.stepfunctions.parser.asl.component.state.state_props import StateProps +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails + + +class StateMap(ExecutionState): + items_path: ItemsPath + iteration_component: IterationComponent + item_reader: Optional[ItemReader] + item_selector: Optional[ItemSelector] + parameters: Optional[Parameters] + max_concurrency: MaxConcurrency + result_path: Optional[ResultPath] + result_selector: ResultSelector + retry: Optional[RetryDecl] + catch: Optional[CatchDecl] + + def __init__(self): + super(StateMap, self).__init__( + state_entered_event_type=HistoryEventType.MapStateEntered, + state_exited_event_type=HistoryEventType.MapStateExited, + ) + + def from_state_props(self, state_props: StateProps) -> None: + super(StateMap, self).from_state_props(state_props) + self.items_path = state_props.get(ItemsPath) or ItemsPath() + self.item_reader = state_props.get(ItemReader) + self.item_selector = state_props.get(ItemSelector) + self.parameters = state_props.get(Parameters) + self.max_concurrency = state_props.get(MaxConcurrency) or MaxConcurrency() + self.result_path = state_props.get(ResultPath) or ResultPath( + result_path_src=ResultPath.DEFAULT_PATH + ) + self.result_selector = state_props.get(ResultSelector) + self.retry = state_props.get(RetryDecl) + self.catch = state_props.get(CatchDecl) + + # TODO: add check for itemreader used in distributed mode only. + + iterator_decl = state_props.get(typ=IteratorDecl) + item_processor_decl = state_props.get(typ=ItemProcessorDecl) + + if iterator_decl and item_processor_decl: + raise ValueError("Cannot define both Iterator and ItemProcessor.") + + iteration_decl = iterator_decl or item_processor_decl + if iteration_decl is None: + raise ValueError( + f"Missing ItemProcessor/Iterator definition in props '{state_props}'." + ) + + if isinstance(iteration_decl, IteratorDecl): + self.iteration_component = Iterator.from_declaration(iteration_decl) + elif isinstance(iteration_decl, ItemProcessorDecl): + self.iteration_component = from_item_processor_decl(iteration_decl) + else: + raise ValueError(f"Unknown value for IteratorDecl '{iteration_decl}'.") + + def _eval_execution(self, env: Environment) -> None: + self.items_path.eval(env) + if self.item_reader: + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapStateStarted, + event_detail=EventDetails( + mapStateStartedEventDetails=MapStateStartedEventDetails(length=0) + ), + ) + input_items = None + else: + input_items = env.stack.pop() + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapStateStarted, + event_detail=EventDetails( + mapStateStartedEventDetails=MapStateStartedEventDetails( + length=len(input_items) + ) + ), + ) + + if isinstance(self.iteration_component, Iterator): + eval_input = IteratorEvalInput( + state_name=self.name, + max_concurrency=self.max_concurrency.num, + input_items=input_items, + parameters=self.parameters, + ) + elif isinstance(self.iteration_component, InlineItemProcessor): + eval_input = InlineItemProcessorEvalInput( + state_name=self.name, + max_concurrency=self.max_concurrency.num, + input_items=input_items, + item_selector=self.item_selector, + ) + elif isinstance(self.iteration_component, DistributedItemProcessor): + eval_input = DistributedItemProcessorEvalInput( + state_name=self.name, + max_concurrency=self.max_concurrency.num, + item_reader=self.item_reader, + item_selector=self.item_selector, + ) + else: + raise RuntimeError( + f"Unknown iteration component of type '{type(self.iteration_component)}' '{self.iteration_component}'." + ) + + env.stack.append(eval_input) + self.iteration_component.eval(env) + + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapStateSucceeded, + update_source_event_id=False, + ) + + def _eval_state(self, env: Environment) -> None: + # Initialise the retry counter for execution states. + env.context_object_manager.context_object["State"]["RetryCount"] = 0 + + # Attempt to evaluate the state's logic through until it's successful, caught, or retries have run out. + while True: + try: + self._evaluate_with_timeout(env) + break + except Exception as ex: + failure_event: FailureEvent = self._from_error(env=env, ex=ex) + + if self.retry: + retry_outcome: RetryOutcome = self._handle_retry( + env=env, failure_event=failure_event + ) + if retry_outcome == RetryOutcome.CanRetry: + continue + + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.MapStateFailed, + ) + + if self.catch: + catch_outcome: CatchOutcome = self._handle_catch( + env=env, failure_event=failure_event + ) + if catch_outcome == CatchOutcome.Caught: + break + + self._handle_uncaught(env=env, failure_event=failure_event) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_parallel/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_parallel/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_parallel/branch_worker.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_parallel/branch_worker.py new file mode 100644 index 000000000..21925e224 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_parallel/branch_worker.py @@ -0,0 +1,60 @@ +import abc +import logging +import threading +from typing import Final, Optional + +from moto.stepfunctions.parser.api import Timestamp +from moto.stepfunctions.parser.asl.component.program.program import Program +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.utils import TMP_THREADS + +LOG = logging.getLogger(__name__) + + +class BranchWorker: + class BranchWorkerComm(abc.ABC): + @abc.abstractmethod + def on_terminated(self, env: Environment): + ... + + _branch_worker_comm: Final[BranchWorkerComm] + _program: Final[Program] + _worker_thread: Optional[threading.Thread] + env: Final[Environment] + + def __init__( + self, branch_worker_comm: BranchWorkerComm, program: Program, env: Environment + ): + self._branch_worker_comm = branch_worker_comm + self._program = program + self.env = env + self._worker_thread = None + + def _thread_routine(self) -> None: + LOG.info(f"[BranchWorker] [launched] [id: {self._worker_thread.native_id}]") + self._program.eval(self.env) + LOG.info(f"[BranchWorker] [terminated] [id: {self._worker_thread.native_id}]") + self._branch_worker_comm.on_terminated(env=self.env) + + def start(self): + if self._worker_thread is not None: + raise RuntimeError( + f"Attempted to rerun BranchWorker for program ${self._program}." + ) + + self._worker_thread = threading.Thread( + target=self._thread_routine, name=f"BranchWorker_${self._program}" + ) + TMP_THREADS.append(self._worker_thread) + self._worker_thread.start() + + def stop( + self, stop_date: Timestamp, cause: Optional[str], error: Optional[str] + ) -> None: + env = self.env + if env: + try: + env.set_stop(stop_date, cause, error) + except Exception: + # Ignore closing exceptions, this method attempts to release resources earlier. + pass diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_parallel/branches_decl.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_parallel/branches_decl.py new file mode 100644 index 000000000..a83457f96 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_parallel/branches_decl.py @@ -0,0 +1,114 @@ +import copy +import datetime +import threading +from typing import Final, List, Optional + +from moto.stepfunctions.parser.api import ExecutionFailedEventDetails, HistoryEventType +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.component.program.program import Program +from moto.stepfunctions.parser.asl.component.state.state_execution.state_parallel.branch_worker import ( + BranchWorker, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.eval.program_state import ProgramError, ProgramState + + +class BranchWorkerPool(BranchWorker.BranchWorkerComm): + _mutex: Final[threading.Lock] + _termination_event: Final[threading.Event] + _active_workers_num: int + + _terminated_with_error: Optional[ExecutionFailedEventDetails] + + def __init__(self, workers_num: int): + self._mutex = threading.Lock() + self._termination_event = threading.Event() + self._active_workers_num = workers_num + + self._terminated_with_error = None + + def on_terminated(self, env: Environment): + if self._termination_event.is_set(): + return + with self._mutex: + end_program_state: ProgramState = env.program_state() + if isinstance(end_program_state, ProgramError): + self._terminated_with_error = end_program_state.error or dict() + self._termination_event.set() + else: + self._active_workers_num -= 1 + if self._active_workers_num == 0: + self._termination_event.set() + + def wait(self): + self._termination_event.wait() + + def get_exit_event_details(self) -> Optional[ExecutionFailedEventDetails]: + return self._terminated_with_error + + +class BranchesDecl(EvalComponent): + def __init__(self, programs: List[Program]): + self.programs: Final[List[Program]] = programs + + def _eval_body(self, env: Environment) -> None: + # Input value for every state_parallel process. + input_val = env.stack.pop() + + branch_worker_pool = BranchWorkerPool(workers_num=len(self.programs)) + + branch_workers: List[BranchWorker] = list() + for program in self.programs: + # Environment frame for this sub process. + env_frame: Environment = env.open_frame() + env_frame.inp = copy.deepcopy(input_val) + + # Launch the worker. + worker = BranchWorker( + branch_worker_comm=branch_worker_pool, program=program, env=env_frame + ) + branch_workers.append(worker) + + worker.start() + + branch_worker_pool.wait() + + # Propagate exception if parallel task failed. + exit_event_details: Optional[ + ExecutionFailedEventDetails + ] = branch_worker_pool.get_exit_event_details() + if exit_event_details is not None: + for branch_worker in branch_workers: + branch_worker.stop( + stop_date=datetime.datetime.now(), cause=None, error=None + ) + env.close_frame(branch_worker.env) + + exit_error_name = exit_event_details.get("error") + raise FailureEventException( + failure_event=FailureEvent( + error_name=CustomErrorName(error_name=exit_error_name), + event_type=HistoryEventType.ExecutionFailed, + event_details=EventDetails( + executionFailedEventDetails=exit_event_details + ), + ) + ) + + # Collect the results and return. + result_list = list() + + for worker in branch_workers: + env_frame = worker.env + result_list.append(env_frame.inp) + env.close_frame(env_frame) + + env.stack.append(result_list) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_parallel/state_parallel.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_parallel/state_parallel.py new file mode 100644 index 000000000..1f51ea27b --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_parallel/state_parallel.py @@ -0,0 +1,93 @@ +import copy + +from moto.stepfunctions.parser.api import HistoryEventType +from moto.stepfunctions.parser.asl.component.common.catch.catch_outcome import ( + CatchOutcome, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.common.retry.retry_outcome import ( + RetryOutcome, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.execute_state import ( + ExecutionState, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_parallel.branches_decl import ( + BranchesDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_props import StateProps +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class StateParallel(ExecutionState): + # Branches (Required) + # An array of objects that specify state machines to execute in state_parallel. Each such state + # machine object must have fields named States and StartAt, whose meanings are exactly + # like those in the top level of a state machine. + branches: BranchesDecl + + def __init__(self): + super().__init__( + state_entered_event_type=HistoryEventType.ParallelStateEntered, + state_exited_event_type=HistoryEventType.ParallelStateExited, + ) + + def from_state_props(self, state_props: StateProps) -> None: + super(StateParallel, self).from_state_props(state_props) + self.branches = state_props.get( + typ=BranchesDecl, + raise_on_missing=ValueError( + f"Missing Branches definition in props '{state_props}'." + ), + ) + + def _eval_execution(self, env: Environment) -> None: + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.ParallelStateStarted, + ) + self.branches.eval(env) + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.ParallelStateSucceeded, + update_source_event_id=False, + ) + + def _eval_state(self, env: Environment) -> None: + # Initialise the retry counter for execution states. + env.context_object_manager.context_object["State"]["RetryCount"] = 0 + + # Cache the input, so it can be resubmitted in case of failure. + input_value = copy.deepcopy(env.stack.pop()) + + # Attempt to evaluate the state's logic through until it's successful, caught, or retries have run out. + while True: + try: + env.stack.append(input_value) + self._evaluate_with_timeout(env) + break + except FailureEventException as failure_event_ex: + failure_event: FailureEvent = failure_event_ex.failure_event + + if self.retry is not None: + retry_outcome: RetryOutcome = self._handle_retry( + env=env, failure_event=failure_event + ) + if retry_outcome == RetryOutcome.CanRetry: + continue + + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.ParallelStateFailed, + ) + + if self.catch is not None: + catch_outcome: CatchOutcome = self._handle_catch( + env=env, failure_event=failure_event + ) + if catch_outcome == CatchOutcome.Caught: + break + + self._handle_uncaught(env=env, failure_event=failure_event) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/lambda_eval_utils.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/lambda_eval_utils.py new file mode 100644 index 000000000..9c5fa56c8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/lambda_eval_utils.py @@ -0,0 +1,51 @@ +import json +from json import JSONDecodeError +from typing import Any, Final, Optional + +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.boto_client import boto_client_for +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str + + +class LambdaFunctionErrorException(Exception): + function_error: Final[Optional[str]] + payload: Final[str] + + def __init__(self, function_error: Optional[str], payload: str): + self.function_error = function_error + self.payload = payload + + +def exec_lambda_function( + env: Environment, parameters: dict, region: str, account: str +) -> None: + lambda_client = boto_client_for(region=region, account=account, service="lambda") + + invocation_resp = lambda_client.invoke(**parameters) + + func_error: Optional[str] = invocation_resp.get("FunctionError") + payload_json = json.load(invocation_resp["Payload"]) + if func_error: + payload_str = json.dumps(payload_json, separators=(",", ":")) + raise LambdaFunctionErrorException(func_error, payload_str) + + invocation_resp["Payload"] = payload_json + + env.stack.append(invocation_resp) + + +def to_payload_type(payload: Any) -> Optional[bytes]: + if isinstance(payload, bytes): + return payload + + if payload is None: + str_value = to_json_str(dict()) + elif isinstance(payload, str): + try: + json.loads(payload) + str_value = payload + except JSONDecodeError: + str_value = to_json_str(payload) + else: + str_value = to_json_str(payload) + return str_value.encode("utf-8") diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/resource.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/resource.py new file mode 100644 index 000000000..0009607d0 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/resource.py @@ -0,0 +1,167 @@ +from __future__ import annotations + +import abc +from itertools import takewhile +from typing import Final, Optional + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class ResourceCondition(str): + WaitForTaskToken = "waitForTaskToken" + Sync2 = "sync:2" + Sync = "sync" + + +class ResourceARN: + arn: str + partition: str + service: str + region: str + account: str + task_type: str + name: str + option: str + + def __init__( + self, + arn: str, + partition: str, + service: str, + region: str, + account: str, + task_type: str, + name: str, + option: Optional[str], + ): + self.arn = arn + self.partition = partition + self.service = service + self.region = region + self.account = account + self.task_type = task_type + self.name = name + self.option = option + + @staticmethod + def _consume_until(text: str, symbol: str) -> tuple[str, str]: + value = "".join(takewhile(lambda c: c != symbol, text)) + tail_idx = len(value) + 1 + return value, text[tail_idx:] + + @classmethod + def from_arn(cls, arn: str) -> ResourceARN: + _, arn_tail = ResourceARN._consume_until(arn, ":") + partition, arn_tail = ResourceARN._consume_until(arn_tail, ":") + service, arn_tail = ResourceARN._consume_until(arn_tail, ":") + region, arn_tail = ResourceARN._consume_until(arn_tail, ":") + account, arn_tail = ResourceARN._consume_until(arn_tail, ":") + task_type, arn_tail = ResourceARN._consume_until(arn_tail, ":") + name, arn_tail = ResourceARN._consume_until(arn_tail, ".") + option = arn_tail + return cls( + arn=arn, + partition=partition, + service=service, + region=region, + account=account, + task_type=task_type, + name=name, + option=option, + ) + + +class ResourceRuntimePart: + account: Final[str] + region: Final[str] + + def __init__(self, account: str, region: str): + self.region = region + self.account = account + + +class Resource(EvalComponent, abc.ABC): + _region: Final[str] + _account: Final[str] + resource_arn: Final[str] + partition: Final[str] + + def __init__(self, resource_arn: ResourceARN): + self._region = resource_arn.region + self._account = resource_arn.account + self.resource_arn = resource_arn.arn + self.partition = resource_arn.partition + + @staticmethod + def from_resource_arn(arn: str) -> Resource: + resource_arn = ResourceARN.from_arn(arn) + if (resource_arn.service, resource_arn.task_type) == ("lambda", "function"): + return LambdaResource(resource_arn=resource_arn) + if (resource_arn.service, resource_arn.task_type) == ("states", "activity"): + return ActivityResource(resource_arn=resource_arn) + if resource_arn.service == "states": + return ServiceResource(resource_arn=resource_arn) + + def _eval_runtime_part(self, env: Environment) -> ResourceRuntimePart: + region = self._region if self._region else env.aws_execution_details.region + account = self._account if self._account else env.aws_execution_details.account + return ResourceRuntimePart( + account=account, + region=region, + ) + + def _eval_body(self, env: Environment) -> None: + runtime_part = self._eval_runtime_part(env=env) + env.stack.append(runtime_part) + + +class ActivityResource(Resource): + name: Final[str] + + def __init__(self, resource_arn: ResourceARN): + super().__init__(resource_arn=resource_arn) + self.name = resource_arn.name + + +class LambdaResource(Resource): + function_name: Final[str] + + def __init__(self, resource_arn: ResourceARN): + super().__init__(resource_arn=resource_arn) + self.function_name = resource_arn.name + + +class ServiceResource(Resource): + service_name: Final[str] + api_name: Final[str] + api_action: Final[str] + condition: Final[Optional[str]] + + def __init__(self, resource_arn: ResourceARN): + super().__init__(resource_arn=resource_arn) + self.service_name = resource_arn.task_type + + name_parts = resource_arn.name.split(":") + if len(name_parts) == 1: + self.api_name = self.service_name + self.api_action = resource_arn.name + elif len(name_parts) > 1: + self.api_name = name_parts[0] + self.api_action = name_parts[1] + else: + raise RuntimeError( + f"Incorrect definition of ResourceArn.name: '{resource_arn.name}'." + ) + + self.condition = None + option = resource_arn.option + if option: + if option == ResourceCondition.WaitForTaskToken: + self.condition = ResourceCondition.WaitForTaskToken + elif option == "sync": + self.condition = ResourceCondition.Sync + elif option == "sync:2": + self.condition = ResourceCondition.Sync2 + else: + raise RuntimeError(f"Unsupported condition '{option}'.") diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service.py new file mode 100644 index 000000000..1d1179766 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service.py @@ -0,0 +1,238 @@ +from __future__ import annotations + +import abc +import copy +from typing import Any, Dict, Final, List, Optional, Tuple + +from botocore.model import StructureShape + +from moto.stepfunctions.parser.api import ( + HistoryEventExecutionDataDetails, + HistoryEventType, + TaskScheduledEventDetails, + TaskStartedEventDetails, + TaskSucceededEventDetails, + TaskTimedOutEventDetails, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name import ( + StatesErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + ResourceRuntimePart, + ServiceResource, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.state_task import ( + StateTask, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str +from moto.stepfunctions.parser.utils import camel_to_snake_case, snake_to_camel_case + + +class StateTaskService(StateTask, abc.ABC): + resource: ServiceResource + + _SERVICE_NAME_SFN_TO_BOTO_OVERRIDES: Final[Dict[str, str]] = { + "sfn": "stepfunctions", + "states": "stepfunctions", + } + + def _get_sfn_resource(self) -> str: + return self.resource.api_action + + def _get_sfn_resource_type(self) -> str: + return self.resource.service_name + + def _get_timed_out_failure_event(self) -> FailureEvent: + return FailureEvent( + error_name=StatesErrorName(typ=StatesErrorNameType.StatesTimeout), + event_type=HistoryEventType.TaskTimedOut, + event_details=EventDetails( + taskTimedOutEventDetails=TaskTimedOutEventDetails( + resourceType=self._get_sfn_resource_type(), + resource=self._get_sfn_resource(), + error=StatesErrorNameType.StatesTimeout.to_name(), + ) + ), + ) + + def _to_boto_args(self, parameters: dict, structure_shape: StructureShape) -> None: + shape_members = structure_shape.members + norm_member_binds: Dict[str, Tuple[str, Optional[StructureShape]]] = { + camel_to_snake_case(member_key): ( + member_key, + member_value if isinstance(member_value, StructureShape) else None, + ) + for member_key, member_value in shape_members.items() + } + parameters_bind_keys: List[str] = list(parameters.keys()) + for parameter_key in parameters_bind_keys: + norm_parameter_key = camel_to_snake_case(parameter_key) + norm_member_bind: Optional[ + Tuple[str, Optional[StructureShape]] + ] = norm_member_binds.get(norm_parameter_key) + if norm_member_bind is not None: + norm_member_bind_key, norm_member_bind_shape = norm_member_bind + parameter_value = parameters.pop(parameter_key) + if norm_member_bind_shape is not None: + self._to_boto_args(parameter_value, norm_member_bind_shape) + parameters[norm_member_bind_key] = parameter_value + + @staticmethod + def _to_sfn_cased(member_key: str) -> str: + # Normalise the string to snake case, e.g. "HelloWorld_hello__world" -> "hello_world_hello_world" + norm_member_key = camel_to_snake_case(member_key) + # Normalise the snake case to camel case, e.g. "hello_world_hello_world" -> "HelloWorldHelloWorld" + norm_member_key = snake_to_camel_case(norm_member_key) + return norm_member_key + + def _from_boto_response( + self, response: Any, structure_shape: StructureShape + ) -> None: + if not isinstance(response, dict): + return + + shape_members = structure_shape.members + response_bind_keys: List[str] = list(response.keys()) + for response_key in response_bind_keys: + norm_response_key = self._to_sfn_cased(response_key) + if response_key in shape_members: + shape_member = shape_members[response_key] + + response_value = response.pop(response_key) + if isinstance(shape_member, StructureShape): + self._from_boto_response(response_value, shape_member) + response[norm_response_key] = response_value + + def _get_boto_service_name(self, boto_service_name: Optional[str] = None) -> str: + api_name = boto_service_name or self.resource.api_name + return self._SERVICE_NAME_SFN_TO_BOTO_OVERRIDES.get(api_name, api_name) + + def _get_boto_service_action( + self, service_action_name: Optional[str] = None + ) -> str: + api_action = service_action_name or self.resource.api_action + return camel_to_snake_case(api_action) + + def _normalise_parameters( + self, + parameters: dict, + boto_service_name: Optional[str] = None, + service_action_name: Optional[str] = None, + ) -> None: + pass + + def _normalise_response( + self, + response: Any, + boto_service_name: Optional[str] = None, + service_action_name: Optional[str] = None, + ) -> None: + pass + + @abc.abstractmethod + def _eval_service_task( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ): + ... + + def _before_eval_execution( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + raw_parameters: dict, + ) -> None: + parameters_str = to_json_str(raw_parameters) + + scheduled_event_details = TaskScheduledEventDetails( + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + region=resource_runtime_part.region, + parameters=parameters_str, + ) + if not self.timeout.is_default_value(): + self.timeout.eval(env=env) + timeout_seconds = env.stack.pop() + scheduled_event_details["timeoutInSeconds"] = timeout_seconds + if self.heartbeat is not None: + self.heartbeat.eval(env=env) + heartbeat_seconds = env.stack.pop() + scheduled_event_details["heartbeatInSeconds"] = heartbeat_seconds + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.TaskScheduled, + event_detail=EventDetails( + taskScheduledEventDetails=scheduled_event_details + ), + ) + + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.TaskStarted, + event_detail=EventDetails( + taskStartedEventDetails=TaskStartedEventDetails( + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + ) + ), + ) + + def _after_eval_execution( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ) -> None: + output = env.stack[-1] + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.TaskSucceeded, + event_detail=EventDetails( + taskSucceededEventDetails=TaskSucceededEventDetails( + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + output=to_json_str(output), + outputDetails=HistoryEventExecutionDataDetails(truncated=False), + ) + ), + ) + + def _eval_execution(self, env: Environment) -> None: + self.resource.eval(env=env) + resource_runtime_part: ResourceRuntimePart = env.stack.pop() + + raw_parameters = self._eval_parameters(env=env) + + self._before_eval_execution( + env=env, + resource_runtime_part=resource_runtime_part, + raw_parameters=raw_parameters, + ) + + normalised_parameters = copy.deepcopy(raw_parameters) + self._normalise_parameters(normalised_parameters) + + self._eval_service_task( + env=env, + resource_runtime_part=resource_runtime_part, + normalised_parameters=normalised_parameters, + ) + + output_value = env.stack[-1] + self._normalise_response(output_value) + + self._after_eval_execution( + env=env, + resource_runtime_part=resource_runtime_part, + normalised_parameters=normalised_parameters, + ) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_api_gateway.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_api_gateway.py new file mode 100644 index 000000000..b5557b145 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_api_gateway.py @@ -0,0 +1,280 @@ +from __future__ import annotations + +import http +import json +import logging +from json import JSONDecodeError +from typing import Any, Dict, Final, Optional, Set, TypedDict, Union +from urllib.parse import urlencode, urljoin + +import requests +from requests import Response + +from moto.moto_api._internal import mock_random +from moto.stepfunctions.parser.api import HistoryEventType, TaskFailedEventDetails +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + ResourceRuntimePart, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_callback import ( + StateTaskServiceCallback, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails + +LOG = logging.getLogger(__name__) + +APPLICATION_JSON = "application/json" +HEADER_CONTENT_TYPE = "Content-Type" +PATH_USER_REQUEST = "_user_request_" + +ApiEndpoint = str +Headers = dict +Stage = str +Path = str +QueryParameters = dict +RequestBody = Union[dict, str] +ResponseBody = Union[dict, str] +StatusCode = int +StatusText = str +AllowNullValues = bool + + +class Method(str): + GET = "GET" + POST = "POST" + PUT = "PUT" + DELETE = "DELETE" + PATCH = "PATCH" + HEAD = "HEAD" + OPTIONS = "OPTIONS" + + +class AuthType(str): + NO_AUTH = "NO_AUTH" + IAM_ROLE = "IAM_ROLE" + RESOURCE_POLICY = "RESOURCE_POLICY" + + +class TaskParameters(TypedDict): + ApiEndpoint: ApiEndpoint + Method: Method + Headers: Optional[Headers] + Stage: Optional[Stage] + Path: Optional[Path] + QueryParameters: Optional[QueryParameters] + RequestBody: Optional[RequestBody] + AllowNullValues: Optional[AllowNullValues] + AuthType: Optional[AuthType] + + +class InvokeOutput(TypedDict): + Headers: Headers + ResponseBody: ResponseBody + StatusCode: StatusCode + StatusText: StatusText + + +class SupportedApiCalls(str): + invoke = "invoke" + + +class SfnGatewayException(Exception): + parameters: Final[TaskParameters] + response: Final[Response] + + def __init__(self, parameters: TaskParameters, response: Response): + self.parameters = parameters + self.response = response + + +class StateTaskServiceApiGateway(StateTaskServiceCallback): + _SUPPORTED_API_PARAM_BINDINGS: Final[Dict[str, Set[str]]] = { + SupportedApiCalls.invoke: {"ApiEndpoint", "Method"} + } + + _FORBIDDEN_HTTP_HEADERS_PREFIX: Final[Set[str]] = {"X-Forwarded", "X-Amz", "X-Amzn"} + _FORBIDDEN_HTTP_HEADERS: Final[Set[str]] = { + "Authorization", + "Connection", + "Content-md5", + "Expect", + "Host", + "Max-Forwards", + "Proxy-Authenticate", + "Server", + "TE", + "Transfer-Encoding", + "Trailer", + "Upgrade", + "Via", + "Www-Authenticate", + } + + def _get_supported_parameters(self) -> Optional[Set[str]]: + return self._SUPPORTED_API_PARAM_BINDINGS.get(self.resource.api_action.lower()) + + def _normalise_parameters( + self, + parameters: Dict[str, Any], + boto_service_name: Optional[str] = None, + service_action_name: Optional[str] = None, + ) -> None: + # ApiGateway does not support botocore request relay. + pass + + def _normalise_response( + self, + response: Any, + boto_service_name: Optional[str] = None, + service_action_name: Optional[str] = None, + ) -> None: + # ApiGateway does not support botocore request relay. + pass + + @staticmethod + def _query_parameters_of(parameters: TaskParameters) -> Optional[str]: + query_str = None + query_parameters = parameters.get("QueryParameters") + # TODO: add support for AllowNullValues. + if query_parameters is not None: + for key, value in list(query_parameters.items()): + if value: + query_parameters[key] = value[-1] + else: + query_parameters[key] = "" + query_str = f"?{urlencode(query_parameters)}" + return query_str + + @staticmethod + def _headers_of(parameters: TaskParameters) -> Optional[dict]: + headers = parameters.get("Headers", dict()) + if headers: + for key in headers.keys(): + # TODO: the following check takes place at parse time. + if key in StateTaskServiceApiGateway._FORBIDDEN_HTTP_HEADERS: + raise ValueError( + f"The 'Headers' field contains unsupported values: {key}" + ) + for ( + forbidden_prefix + ) in StateTaskServiceApiGateway._FORBIDDEN_HTTP_HEADERS_PREFIX: + if key.startswith(forbidden_prefix): + raise ValueError( + f"The 'Headers' field contains unsupported values: {key}" + ) + if "RequestBody" in parameters: + headers[HEADER_CONTENT_TYPE] = APPLICATION_JSON + headers["Accept"] = APPLICATION_JSON + return headers + + @staticmethod + def _invoke_url_of(parameters: TaskParameters) -> str: + given_api_endpoint = parameters["ApiEndpoint"] + api_endpoint = given_api_endpoint + + url_base = api_endpoint + "/" + # http://localhost:4566/restapis///_user_request_/(?)? + url_tail = "/".join( + [ + parameters.get("Stage", ""), + PATH_USER_REQUEST, + parameters.get("Path", ""), + StateTaskServiceApiGateway._query_parameters_of(parameters) or "", + ] + ) + invoke_url = urljoin(url_base, url_tail) + return invoke_url + + @staticmethod + def _invoke_output_of(response: Response) -> InvokeOutput: + status_code = response.status_code + status_text = http.HTTPStatus(status_code).phrase + + headers = dict(response.headers) + + try: + response_body = response.json() + except JSONDecodeError: + response_body = response.text + if response_body == json.dumps(dict()): + response_body = dict() + + headers.pop("server", None) + if "date" in headers: + headers["Date"] = [headers.pop("date")] + headers[HEADER_CONTENT_TYPE] = [APPLICATION_JSON] + headers["Content-Length"] = [headers["Content-Length"]] + # TODO: add support for the following generated fields. + headers["Connection"] = ["keep-alive"] + headers["x-amz-apigw-id"] = [str(mock_random.uuid4())] + headers["X-Amz-Cf-Id"] = [str(mock_random.uuid4())] + headers["X-Amz-Cf-Pop"] = [str(mock_random.uuid4())] + headers["x-amzn-RequestId"] = [str(mock_random.uuid4())] + headers["X-Amzn-Trace-Id"] = [str(mock_random.uuid4())] + headers["X-Cache"] = ["Miss from cloudfront"] + headers["Via"] = ["UNSUPPORTED"] + + return InvokeOutput( + Headers=headers, + ResponseBody=response_body, + StatusCode=status_code, + StatusText=status_text, + ) + + def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: + if isinstance(ex, SfnGatewayException): + error_name = f"ApiGateway.{ex.response.status_code}" + cause = ex.response.text + else: + ex_name = ex.__class__.__name__ + error_name = f"ApiGateway.{ex_name}" + cause = str(ex) + return FailureEvent( + error_name=CustomErrorName(error_name), + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + error=error_name, + cause=cause, # TODO: add support for cause decoration. + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + ) + ), + ) + + def _eval_service_task( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ): + task_parameters: TaskParameters = normalised_parameters + + method = task_parameters["Method"] + invoke_url = self._invoke_url_of(task_parameters) + headers = self._headers_of(task_parameters) + json_data = task_parameters.get("RequestBody") + + # RequestBody is only supported for PATCH, POST, and PUT + if json_data is not None and method not in { + Method.PATCH, + Method.POST, + Method.PUT, + }: + raise ValueError() # TODO + + response: Response = getattr(requests, method.lower())( + invoke_url, headers=headers, json=json_data + ) + + if response.status_code != 200: + raise SfnGatewayException(parameters=task_parameters, response=response) + + invoke_output = self._invoke_output_of(response) + env.stack.append(invoke_output) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_aws_sdk.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_aws_sdk.py new file mode 100644 index 000000000..80c6908b5 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_aws_sdk.py @@ -0,0 +1,101 @@ +from botocore.exceptions import ClientError + +from moto.stepfunctions.parser.api import HistoryEventType, TaskFailedEventDetails +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name import ( + StatesErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + ResourceRuntimePart, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_callback import ( + StateTaskServiceCallback, +) +from moto.stepfunctions.parser.asl.component.state.state_props import StateProps +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.utils.boto_client import boto_client_for + + +class StateTaskServiceAwsSdk(StateTaskServiceCallback): + _NORMALISED_SERVICE_NAMES = {"dynamodb": "DynamoDb"} + + def from_state_props(self, state_props: StateProps) -> None: + super().from_state_props(state_props=state_props) + + def _get_sfn_resource_type(self) -> str: + return f"{self.resource.service_name}:{self.resource.api_name}" + + @staticmethod + def _normalise_service_name(service_name: str) -> str: + service_name_lower = service_name.lower() + if service_name_lower in StateTaskServiceAwsSdk._NORMALISED_SERVICE_NAMES: + return StateTaskServiceAwsSdk._NORMALISED_SERVICE_NAMES[service_name_lower] + return service_name_lower + + @staticmethod + def _normalise_exception_name(norm_service_name: str, ex: Exception) -> str: + ex_name = ex.__class__.__name__ + norm_ex_name = f"{norm_service_name}.{norm_service_name if ex_name == 'ClientError' else ex_name}" + if not norm_ex_name.endswith("Exception"): + norm_ex_name += "Exception" + return norm_ex_name + + def _get_task_failure_event(self, error: str, cause: str) -> FailureEvent: + return FailureEvent( + error_name=StatesErrorName(typ=StatesErrorNameType.StatesTaskFailed), + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + error=error, + cause=cause, + ) + ), + ) + + def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: + if isinstance(ex, ClientError): + norm_service_name: str = self._normalise_service_name( + self.resource.api_name + ) + error: str = self._normalise_exception_name(norm_service_name, ex) + + error_message: str = ex.response["Error"]["Message"] + cause_details = [ + f"Service: {norm_service_name}", + f"Status Code: {ex.response['ResponseMetadata']['HTTPStatusCode']}", + f"Request ID: {ex.response['ResponseMetadata']['RequestId']}", + ] + if "HostId" in ex.response["ResponseMetadata"]: + cause_details.append( + f'Extended Request ID: {ex.response["ResponseMetadata"]["HostId"]}' + ) + + cause: str = f"{error_message} ({', '.join(cause_details)})" + failure_event = self._get_task_failure_event(error=error, cause=cause) + return failure_event + return super()._from_error(env=env, ex=ex) + + def _eval_service_task( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ): + service_name = self._get_boto_service_name() + api_action = self._get_boto_service_action() + api_client = boto_client_for( + region=resource_runtime_part.region, + account=resource_runtime_part.account, + service=service_name, + ) + response = getattr(api_client, api_action)(**normalised_parameters) or dict() + + env.stack.append(response) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_callback.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_callback.py new file mode 100644 index 000000000..3d87e913b --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_callback.py @@ -0,0 +1,188 @@ +import abc +import json + +from moto.stepfunctions.parser.api import ( + HistoryEventExecutionDataDetails, + HistoryEventType, + TaskFailedEventDetails, + TaskSubmittedEventDetails, +) +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + ResourceCondition, + ResourceRuntimePart, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service import ( + StateTaskService, +) +from moto.stepfunctions.parser.asl.eval.callback.callback import ( + CallbackOutcomeFailure, + CallbackOutcomeFailureError, + CallbackOutcomeSuccess, + CallbackTimeoutError, + HeartbeatEndpoint, + HeartbeatTimeoutError, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str + + +class StateTaskServiceCallback(StateTaskService, abc.ABC): + def _get_sfn_resource(self) -> str: + resource = super()._get_sfn_resource() + if self.resource.condition is not None: + resource += f".{self.resource.condition}" + return resource + + def _wait_for_task_token( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ) -> None: + # Discard the state evaluation output. + env.stack.pop() + + callback_id = env.context_object_manager.context_object["Task"]["Token"] + callback_endpoint = env.callback_pool_manager.get(callback_id) + + # With Timeouts-only definition: + if not self.heartbeat: + self.timeout.eval(env=env) + timeout_seconds = env.stack.pop() + # Although the timeout is handled already be the superclass (ExecutionState), + # the timeout value is specified here too, to allow this child process to terminate earlier even if + # discarded by the main process. + # Note: although this is the same timeout value, this can only decay strictly after the first timeout + # started as it is invoked strictly later. + outcome = callback_endpoint.wait(timeout=timeout_seconds) + else: + self.heartbeat.eval(env=env) + heartbeat_seconds = env.stack.pop() + heartbeat_endpoint: HeartbeatEndpoint = ( + callback_endpoint.setup_heartbeat_endpoint( + heartbeat_seconds=heartbeat_seconds + ) + ) + + outcome = None + while ( + env.is_running() and outcome is None + ): # Until subprocess hasn't timed out or result wasn't received. + received = heartbeat_endpoint.clear_and_wait() + if not received and env.is_running(): # Heartbeat timed out. + raise HeartbeatTimeoutError() + outcome = callback_endpoint.get_outcome() + + if outcome is None: + raise CallbackTimeoutError() + if isinstance(outcome, CallbackOutcomeSuccess): + outcome_output = json.loads(outcome.output) + env.stack.append(outcome_output) + elif isinstance(outcome, CallbackOutcomeFailure): + raise CallbackOutcomeFailureError(callback_outcome_failure=outcome) + else: + raise NotImplementedError( + f"Unsupported CallbackOutcome type '{type(outcome)}'." + ) + + def _sync( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ) -> None: + raise RuntimeError( + f"Unsupported .sync callback procedure in resource {self.resource.resource_arn}" + ) + + def _sync2( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ) -> None: + raise RuntimeError( + f"Unsupported .sync:2 callback procedure in resource {self.resource.resource_arn}" + ) + + def _is_condition(self): + return self.resource.condition is not None + + def _get_callback_outcome_failure_event( + self, ex: CallbackOutcomeFailureError + ) -> FailureEvent: + callback_outcome_failure: CallbackOutcomeFailure = ex.callback_outcome_failure + error: str = callback_outcome_failure.error + return FailureEvent( + error_name=CustomErrorName(error_name=callback_outcome_failure.error), + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + resourceType=self._get_sfn_resource_type(), + resource=self._get_sfn_resource(), + error=error, + cause=callback_outcome_failure.cause, + ) + ), + ) + + def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: + if isinstance(ex, CallbackOutcomeFailureError): + return self._get_callback_outcome_failure_event(ex=ex) + return super()._from_error(env=env, ex=ex) + + def _after_eval_execution( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ) -> None: + if self._is_condition(): + output = env.stack[-1] + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.TaskSubmitted, + event_detail=EventDetails( + taskSubmittedEventDetails=TaskSubmittedEventDetails( + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + output=to_json_str(output), + outputDetails=HistoryEventExecutionDataDetails(truncated=False), + ) + ), + ) + if self.resource.condition == ResourceCondition.WaitForTaskToken: + self._wait_for_task_token( + env=env, + resource_runtime_part=resource_runtime_part, + normalised_parameters=normalised_parameters, + ) + elif self.resource.condition == ResourceCondition.Sync: + self._sync( + env=env, + resource_runtime_part=resource_runtime_part, + normalised_parameters=normalised_parameters, + ) + elif self.resource.condition == ResourceCondition.Sync2: + self._sync2( + env=env, + resource_runtime_part=resource_runtime_part, + normalised_parameters=normalised_parameters, + ) + else: + raise NotImplementedError( + f"Unsupported callback type '{self.resource.condition}'." + ) + + super()._after_eval_execution( + env=env, + resource_runtime_part=resource_runtime_part, + normalised_parameters=normalised_parameters, + ) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_dynamodb.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_dynamodb.py new file mode 100644 index 000000000..3570ebc1a --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_dynamodb.py @@ -0,0 +1,141 @@ +from typing import Dict, Final, Optional, Set, Tuple + +from botocore.exceptions import ClientError + +from moto.stepfunctions.parser.api import HistoryEventType, TaskFailedEventDetails +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + ResourceRuntimePart, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service import ( + StateTaskService, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.utils.boto_client import boto_client_for + + +class StateTaskServiceDynamoDB(StateTaskService): + _ERROR_NAME_AWS: Final[str] = "DynamoDB.AmazonDynamoDBException" + + _SUPPORTED_API_PARAM_BINDINGS: Final[Dict[str, Set[str]]] = { + "getitem": { + "Key", + "TableName", + "AttributesToGet", + "ConsistentRead", + "ExpressionAttributeNames", + "ProjectionExpression", + "ReturnConsumedCapacity", + }, + "putitem": { + "Item", + "TableName", + "ConditionalOperator", + "ConditionExpression", + "Expected", + "ExpressionAttributeNames", + "ExpressionAttributeValues", + "ReturnConsumedCapacity", + "ReturnItemCollectionMetrics", + "ReturnValues", + }, + "deleteitem": { + "Key", + "TableName", + "ConditionalOperator", + "ConditionExpression", + "Expected", + "ExpressionAttributeNames", + "ExpressionAttributeValues", + "ReturnConsumedCapacity", + "ReturnItemCollectionMetrics", + "ReturnValues", + }, + "updateitem": { + "Key", + "TableName", + "AttributeUpdates", + "ConditionalOperator", + "ConditionExpression", + "Expected", + "ExpressionAttributeNames", + "ExpressionAttributeValues", + "ReturnConsumedCapacity", + "ReturnItemCollectionMetrics", + "ReturnValues", + "UpdateExpression", + }, + } + + def _get_supported_parameters(self) -> Optional[Set[str]]: + return self._SUPPORTED_API_PARAM_BINDINGS.get(self.resource.api_action.lower()) + + @staticmethod + def _error_cause_from_client_error(client_error: ClientError) -> Tuple[str, str]: + error_code: str = client_error.response["Error"]["Code"] + error_msg: str = client_error.response["Error"]["Message"] + response_details = "; ".join( + [ + "Service: AmazonDynamoDBv2", + f"Status Code: {client_error.response['ResponseMetadata']['HTTPStatusCode']}", + f"Error Code: {error_code}", + f"Request ID: {client_error.response['ResponseMetadata']['RequestId']}", + "Proxy: null", + ] + ) + error = f"DynamoDB.{error_code}" + cause = f"{error_msg} ({response_details})" + return error, cause + + def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: + if isinstance(ex, ClientError): + error, cause = self._error_cause_from_client_error(ex) + error_name = CustomErrorName(error) + return FailureEvent( + error_name=error_name, + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + error=error, + cause=cause, + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + ) + ), + ) + else: + return FailureEvent( + error_name=CustomErrorName(self._ERROR_NAME_AWS), + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + error=self._ERROR_NAME_AWS, + cause=str(ex), # TODO: update to report expected cause. + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + ) + ), + ) + + def _eval_service_task( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ): + service_name = self._get_boto_service_name() + api_action = self._get_boto_service_action() + dynamodb_client = boto_client_for( + region=resource_runtime_part.region, + account=resource_runtime_part.account, + service=service_name, + ) + response = getattr(dynamodb_client, api_action)(**normalised_parameters) + response.pop("ResponseMetadata", None) + env.stack.append(response) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_events.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_events.py new file mode 100644 index 000000000..48c48f174 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_events.py @@ -0,0 +1,112 @@ +import json +from typing import Dict, Final, Optional, Set + +from moto.stepfunctions.parser.api import HistoryEventType, TaskFailedEventDetails +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.error_name import ( + ErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + ResourceRuntimePart, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_callback import ( + StateTaskServiceCallback, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.utils.boto_client import boto_client_for +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str + + +class SfnFailedEntryCountException(RuntimeError): + cause: Final[Optional[dict]] + + def __init__(self, cause: Optional[dict]): + super().__init__(json.dumps(cause)) + self.cause = cause + + +class StateTaskServiceEvents(StateTaskServiceCallback): + _FAILED_ENTRY_ERROR_NAME: Final[ErrorName] = CustomErrorName( + error_name="EventBridge.FailedEntry" + ) + + _SUPPORTED_API_PARAM_BINDINGS: Final[Dict[str, Set[str]]] = { + "putevents": {"Entries"} + } + + def _get_supported_parameters(self) -> Optional[Set[str]]: + return self._SUPPORTED_API_PARAM_BINDINGS.get(self.resource.api_action.lower()) + + def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: + if isinstance(ex, SfnFailedEntryCountException): + return FailureEvent( + error_name=self._FAILED_ENTRY_ERROR_NAME, + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + error=self._FAILED_ENTRY_ERROR_NAME.error_name, + cause=ex.cause, + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + ) + ), + ) + return super()._from_error(env=env, ex=ex) + + @staticmethod + def _normalised_request_parameters(env: Environment, parameters: dict): + entries = parameters.get("Entries", []) + for entry in entries: + # Optimised integration for events automatically stringifies "Entries.Detail" if this is not a string, + # and only if these are json objects. + if "Detail" in entry: + detail = entry.get("Detail") + if isinstance(detail, dict): + entry["Detail"] = to_json_str( + detail + ) # Pass runtime error upstream. + + # The execution ARN and the state machine ARN are automatically appended to the Resources + # field of each PutEventsRequestEntry. + resources = entry.get("Resources", []) + resources.append( + env.context_object_manager.context_object["StateMachine"]["Id"] + ) + resources.append( + env.context_object_manager.context_object["Execution"]["Id"] + ) + entry["Resources"] = resources + + def _eval_service_task( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ): + self._normalised_request_parameters(env=env, parameters=normalised_parameters) + service_name = self._get_boto_service_name() + api_action = self._get_boto_service_action() + events_client = boto_client_for( + region=resource_runtime_part.region, + account=resource_runtime_part.account, + service=service_name, + ) + response = getattr(events_client, api_action)(**normalised_parameters) + response.pop("ResponseMetadata", None) + + # If the response from PutEvents contains a non-zero FailedEntryCount then the + # Task state fails with the error EventBridge.FailedEntry. + if self.resource.api_action == "putevents": + failed_entry_count = response.get("FailedEntryCount", 0) + if failed_entry_count > 0: + # TODO: pipe events' cause in the exception object. At them moment + # LS events does not update this field. + raise SfnFailedEntryCountException(cause={"Cause": "Unsupported"}) + + env.stack.append(response) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_factory.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_factory.py new file mode 100644 index 000000000..9b8cb0739 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_factory.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service import ( + StateTaskService, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_api_gateway import ( + StateTaskServiceApiGateway, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_aws_sdk import ( + StateTaskServiceAwsSdk, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_dynamodb import ( + StateTaskServiceDynamoDB, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_events import ( + StateTaskServiceEvents, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_lambda import ( + StateTaskServiceLambda, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_sfn import ( + StateTaskServiceSfn, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_sns import ( + StateTaskServiceSns, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_sqs import ( + StateTaskServiceSqs, +) + + +# TODO: improve on factory constructor (don't use SubtypeManager: cannot reuse state task instances). +def state_task_service_for(service_name: str) -> StateTaskService: + if service_name == "aws-sdk": + return StateTaskServiceAwsSdk() + if service_name == "lambda": + return StateTaskServiceLambda() + if service_name == "sqs": + return StateTaskServiceSqs() + if service_name == "states": + return StateTaskServiceSfn() + if service_name == "dynamodb": + return StateTaskServiceDynamoDB() + if service_name == "apigateway": + return StateTaskServiceApiGateway() + if service_name == "sns": + return StateTaskServiceSns() + if service_name == "events": + return StateTaskServiceEvents() + else: + raise NotImplementedError(f"Unsupported service: '{service_name}'.") # noqa diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_lambda.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_lambda.py new file mode 100644 index 000000000..4b0a7ee03 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_lambda.py @@ -0,0 +1,96 @@ +from typing import Dict, Final, Optional, Set, Tuple + +from botocore.exceptions import ClientError + +from moto.stepfunctions.parser.api import HistoryEventType, TaskFailedEventDetails +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task import ( + lambda_eval_utils, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + ResourceRuntimePart, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_callback import ( + StateTaskServiceCallback, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails + + +class StateTaskServiceLambda(StateTaskServiceCallback): + _SUPPORTED_API_PARAM_BINDINGS: Final[Dict[str, Set[str]]] = { + "invoke": { + "ClientContext", + "FunctionName", + "InvocationType", + "Qualifier", + "Payload", + # Outside the specification, but supported in practice: + "LogType", + } + } + + def _get_supported_parameters(self) -> Optional[Set[str]]: + return self._SUPPORTED_API_PARAM_BINDINGS.get(self.resource.api_action.lower()) + + @staticmethod + def _error_cause_from_client_error(client_error: ClientError) -> Tuple[str, str]: + error_code: str = client_error.response["Error"]["Code"] + error_msg: str = client_error.response["Error"]["Message"] + response_details = "; ".join( + [ + "Service: AWSLambda", + f"Status Code: {client_error.response['ResponseMetadata']['HTTPStatusCode']}", + f"Error Code: {error_code}", + f"Request ID: {client_error.response['ResponseMetadata']['RequestId']}", + "Proxy: null", + ] + ) + error = f"Lambda.{error_code}" + cause = f"{error_msg} ({response_details})" + return error, cause + + def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: + if isinstance(ex, lambda_eval_utils.LambdaFunctionErrorException): + error = "Exception" + error_name = CustomErrorName(error) + cause = ex.payload + elif isinstance(ex, ClientError): + error, cause = self._error_cause_from_client_error(ex) + error_name = CustomErrorName(error) + else: + return super()._from_error(env=env, ex=ex) + return FailureEvent( + error_name=error_name, + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + error=error, + cause=cause, + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + ) + ), + ) + + def _eval_service_task( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ): + if "Payload" in normalised_parameters: + normalised_parameters["Payload"] = lambda_eval_utils.to_payload_type( + normalised_parameters["Payload"] + ) + lambda_eval_utils.exec_lambda_function( + env=env, + parameters=normalised_parameters, + region=resource_runtime_part.region, + account=resource_runtime_part.account, + ) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_sfn.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_sfn.py new file mode 100644 index 000000000..c2eaa4cd5 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_sfn.py @@ -0,0 +1,220 @@ +import json +from typing import Dict, Final, Optional, Set + +from botocore.exceptions import ClientError + +from moto.stepfunctions.parser.api import ( + DescribeExecutionOutput, + ExecutionStatus, + HistoryEventType, + TaskFailedEventDetails, +) +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name import ( + StatesErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + ResourceRuntimePart, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_callback import ( + StateTaskServiceCallback, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.utils.boto_client import boto_client_for +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str + + +class StateTaskServiceSfn(StateTaskServiceCallback): + _SUPPORTED_API_PARAM_BINDINGS: Final[Dict[str, Set[str]]] = { + "startexecution": {"Input", "Name", "StateMachineArn"} + } + + def _get_supported_parameters(self) -> Optional[Set[str]]: + return self._SUPPORTED_API_PARAM_BINDINGS.get(self.resource.api_action.lower()) + + def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: + if isinstance(ex, ClientError): + error_code = ex.response["Error"]["Code"] + error_name: str = f"StepFunctions.{error_code}Exception" + error_cause_details = [ + "Service: AWSStepFunctions", + f"Status Code: {ex.response['ResponseMetadata']['HTTPStatusCode']}", + f"Error Code: {error_code}", + f"Request ID: {ex.response['ResponseMetadata']['RequestId']}", + "Proxy: null", # TODO: investigate this proxy value. + ] + if "HostId" in ex.response["ResponseMetadata"]: + error_cause_details.append( + f'Extended Request ID: {ex.response["ResponseMetadata"]["HostId"]}' + ) + error_cause: str = ( + f"{ex.response['Error']['Message']} ({'; '.join(error_cause_details)})" + ) + return FailureEvent( + error_name=CustomErrorName(error_name), + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + error=error_name, + cause=error_cause, + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + ) + ), + ) + return super()._from_error(env=env, ex=ex) + + def _normalise_parameters( + self, + parameters: dict, + boto_service_name: Optional[str] = None, + service_action_name: Optional[str] = None, + ) -> None: + if service_action_name is None: + if self._get_boto_service_action() == "start_execution": + optional_input = parameters.get("Input") + if not isinstance(optional_input, str): + # AWS Sfn's documentation states: + # If you don't include any JSON input data, you still must include the two braces. + if optional_input is None: + optional_input = {} + parameters["Input"] = to_json_str( + optional_input, separators=(",", ":") + ) + super()._normalise_parameters( + parameters=parameters, + boto_service_name=boto_service_name, + service_action_name=service_action_name, + ) + + @staticmethod + def _sync2_api_output_of(typ: type, value: json) -> None: + def _replace_with_json_if_str(key: str) -> None: + inner_value = value.get(key) + if isinstance(inner_value, str): + value[key] = json.loads(inner_value) + + if typ == DescribeExecutionOutput: + _replace_with_json_if_str("input") + _replace_with_json_if_str("output") + + def _eval_service_task( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ): + service_name = self._get_boto_service_name() + api_action = self._get_boto_service_action() + sfn_client = boto_client_for( + region=resource_runtime_part.region, + account=resource_runtime_part.account, + service=service_name, + ) + response = getattr(sfn_client, api_action)(**normalised_parameters) + response.pop("ResponseMetadata", None) + env.stack.append(response) + + def _sync_to_start_machine( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + sync2_response: bool, + ) -> None: + sfn_client = boto_client_for( + region=resource_runtime_part.region, + account=resource_runtime_part.account, + service="stepfunctions", + ) + submission_output: dict = env.stack.pop() + execution_arn: str = submission_output["ExecutionArn"] + + def _has_terminated() -> Optional[dict]: + describe_execution_output = sfn_client.describe_execution( + executionArn=execution_arn + ) + execution_status: ExecutionStatus = describe_execution_output["status"] + + if execution_status != ExecutionStatus.RUNNING: + if sync2_response: + self._sync2_api_output_of( + typ=DescribeExecutionOutput, value=describe_execution_output + ) + self._normalise_response( + response=describe_execution_output, + service_action_name="describe_execution", + ) + if execution_status == ExecutionStatus.SUCCEEDED: + return describe_execution_output + else: + raise FailureEventException( + FailureEvent( + error_name=StatesErrorName( + typ=StatesErrorNameType.StatesTaskFailed + ), + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + error=StatesErrorNameType.StatesTaskFailed.to_name(), + cause=to_json_str(describe_execution_output), + ) + ), + ) + ) + return None + + termination_output: Optional[dict] = None + while env.is_running() and not termination_output: + termination_output: Optional[dict] = _has_terminated() + + env.stack.append(termination_output) + + def _sync( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ) -> None: + if self._get_boto_service_action() == "start_execution": + return self._sync_to_start_machine( + env=env, + resource_runtime_part=resource_runtime_part, + sync2_response=False, + ) + else: + super()._sync( + env=env, + resource_runtime_part=resource_runtime_part, + normalised_parameters=normalised_parameters, + ) + + def _sync2( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ) -> None: + if self._get_boto_service_action() == "start_execution": + return self._sync_to_start_machine( + env=env, + resource_runtime_part=resource_runtime_part, + sync2_response=True, + ) + else: + super()._sync2( + env=env, + resource_runtime_part=resource_runtime_part, + normalised_parameters=normalised_parameters, + ) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_sns.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_sns.py new file mode 100644 index 000000000..aaa5e717e --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_sns.py @@ -0,0 +1,97 @@ +from typing import Dict, Final, Optional, Set + +from botocore.exceptions import ClientError + +from moto.stepfunctions.parser.api import HistoryEventType, TaskFailedEventDetails +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + ResourceRuntimePart, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_callback import ( + StateTaskServiceCallback, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.utils.boto_client import boto_client_for +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str + + +class StateTaskServiceSns(StateTaskServiceCallback): + _SUPPORTED_API_PARAM_BINDINGS: Final[Dict[str, Set[str]]] = { + "publish": { + "Message", + "MessageAttributes", + "MessageStructure", + "PhoneNumber", + "Subject", + "TargetArn", + "TopicArn", + } + } + + def _get_supported_parameters(self) -> Optional[Set[str]]: + return self._SUPPORTED_API_PARAM_BINDINGS.get(self.resource.api_action.lower()) + + def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: + if isinstance(ex, ClientError): + error_code = ex.response["Error"]["Code"] + + exception_name = error_code + if not exception_name.endswith("Exception"): + exception_name += "Exception" + error_name = f"SNS.{exception_name}" + + error_message = ex.response["Error"]["Message"] + status_code = ex.response["ResponseMetadata"]["HTTPStatusCode"] + request_id = ex.response["ResponseMetadata"]["RequestId"] + error_cause = ( + f"{error_message} " + f"(Service: AmazonSNS; " + f"Status Code: {status_code}; " + f"Error Code: {error_code}; " + f"Request ID: {request_id}; " + f"Proxy: null)" + ) + + return FailureEvent( + error_name=CustomErrorName(error_name=error_name), + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + error=error_name, + cause=error_cause, + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + ) + ), + ) + return super()._from_error(env=env, ex=ex) + + def _eval_service_task( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ): + service_name = self._get_boto_service_name() + api_action = self._get_boto_service_action() + sns_client = boto_client_for( + region=resource_runtime_part.region, + account=resource_runtime_part.account, + service=service_name, + ) + + # Optimised integration automatically stringifies + if "Message" in normalised_parameters and not isinstance( + message := normalised_parameters["Message"], str + ): + normalised_parameters["Message"] = to_json_str(message) + + response = getattr(sns_client, api_action)(**normalised_parameters) + response.pop("ResponseMetadata", None) + env.stack.append(response) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_sqs.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_sqs.py new file mode 100644 index 000000000..eb1548a90 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/service/state_task_service_sqs.py @@ -0,0 +1,98 @@ +from typing import Any, Dict, Final, Optional, Set + +from botocore.exceptions import ClientError + +from moto.stepfunctions.parser.api import HistoryEventType, TaskFailedEventDetails +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + ResourceRuntimePart, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_callback import ( + StateTaskServiceCallback, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.utils.boto_client import boto_client_for +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str + + +class StateTaskServiceSqs(StateTaskServiceCallback): + _ERROR_NAME_CLIENT: Final[str] = "SQS.SdkClientException" + _ERROR_NAME_AWS: Final[str] = "SQS.AmazonSQSException" + + _SUPPORTED_API_PARAM_BINDINGS: Final[Dict[str, Set[str]]] = { + "sendmessage": { + "DelaySeconds", + "MessageAttribute", + "MessageBody", + "MessageDeduplicationId", + "MessageGroupId", + "QueueUrl", + } + } + + def _get_supported_parameters(self) -> Optional[Set[str]]: + return self._SUPPORTED_API_PARAM_BINDINGS.get(self.resource.api_action.lower()) + + def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: + if isinstance(ex, ClientError): + return FailureEvent( + error_name=CustomErrorName(self._ERROR_NAME_CLIENT), + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=TaskFailedEventDetails( + error=self._ERROR_NAME_CLIENT, + cause=ex.response["Error"][ + "Message" + ], # TODO: update to report expected cause. + resource=self._get_sfn_resource(), + resourceType=self._get_sfn_resource_type(), + ) + ), + ) + return super()._from_error(env=env, ex=ex) + + def _normalise_response( + self, + response: Any, + boto_service_name: Optional[str] = None, + service_action_name: Optional[str] = None, + ) -> None: + super()._normalise_response( + response=response, + boto_service_name=boto_service_name, + service_action_name=service_action_name, + ) + # Normalise output value key to SFN standard for Md5OfMessageBody. + if response and "Md5OfMessageBody" in response: + md5_message_body = response.pop("Md5OfMessageBody") + response["MD5OfMessageBody"] = md5_message_body + + def _eval_service_task( + self, + env: Environment, + resource_runtime_part: ResourceRuntimePart, + normalised_parameters: dict, + ): + # TODO: Stepfunctions automatically dumps to json MessageBody's definitions. + # Are these other similar scenarios? + if "MessageBody" in normalised_parameters: + message_body = normalised_parameters["MessageBody"] + if message_body is not None and not isinstance(message_body, str): + normalised_parameters["MessageBody"] = to_json_str(message_body) + + service_name = self._get_boto_service_name() + api_action = self._get_boto_service_action() + sqs_client = boto_client_for( + region=resource_runtime_part.region, + account=resource_runtime_part.account, + service=service_name, + ) + response = getattr(sqs_client, api_action)(**normalised_parameters) + response.pop("ResponseMetadata", None) + env.stack.append(response) diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/state_task.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/state_task.py new file mode 100644 index 000000000..f076d9250 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/state_task.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +import abc +from typing import List, Optional + +from moto.stepfunctions.parser.api import HistoryEventType, TaskTimedOutEventDetails +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name import ( + StatesErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from moto.stepfunctions.parser.asl.component.common.parameters import Parameters +from moto.stepfunctions.parser.asl.component.state.state_execution.execute_state import ( + ExecutionState, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + Resource, +) +from moto.stepfunctions.parser.asl.component.state.state_props import StateProps +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails + + +class StateTask(ExecutionState, abc.ABC): + resource: Resource + parameters: Optional[Parameters] + + def __init__(self): + super(StateTask, self).__init__( + state_entered_event_type=HistoryEventType.TaskStateEntered, + state_exited_event_type=HistoryEventType.TaskStateExited, + ) + # Parameters (Optional) + # Used to state_pass information to the API actions of connected resources. The parameters can use a mix of static + # JSON and JsonPath. + self.parameters = None + + def from_state_props(self, state_props: StateProps) -> None: + super(StateTask, self).from_state_props(state_props) + self.parameters = state_props.get(Parameters) + self.resource = state_props.get(Resource) + + def _get_supported_parameters(self) -> Optional[Set[str]]: # noqa + return None + + def _eval_parameters(self, env: Environment) -> dict: + # Eval raw parameters. + parameters = dict() + if self.parameters: + self.parameters.eval(env=env) + parameters = env.stack.pop() + + # Handle supported parameters. + supported_parameters = self._get_supported_parameters() + if supported_parameters: + unsupported_parameters: List[str] = [ + parameter + for parameter in parameters.keys() + if parameter not in supported_parameters + ] + for unsupported_parameter in unsupported_parameters: + parameters.pop(unsupported_parameter, None) + + return parameters + + def _get_timed_out_failure_event(self) -> FailureEvent: + return FailureEvent( + error_name=StatesErrorName(typ=StatesErrorNameType.StatesTimeout), + event_type=HistoryEventType.TaskTimedOut, + event_details=EventDetails( + taskTimedOutEventDetails=TaskTimedOutEventDetails( + error=StatesErrorNameType.StatesTimeout.to_name(), + ) + ), + ) + + def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: + if isinstance(ex, TimeoutError): + return self._get_timed_out_failure_event() + return super()._from_error(env=env, ex=ex) + + def _eval_body(self, env: Environment) -> None: + super(StateTask, self)._eval_body(env=env) + env.context_object_manager.context_object["Task"] = None diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/state_task_factory.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/state_task_factory.py new file mode 100644 index 000000000..226ffb77e --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/state_task_factory.py @@ -0,0 +1,28 @@ +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + LambdaResource, + Resource, + ServiceResource, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.state_task_service_factory import ( + state_task_service_for, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.state_task import ( + StateTask, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.state_task_lambda import ( + StateTaskLambda, +) + + +def state_task_for(resource: Resource) -> StateTask: + if not resource: + raise ValueError("No Resource declaration in State Task.") + if isinstance(resource, LambdaResource): + state = StateTaskLambda() + elif isinstance(resource, ServiceResource): + state = state_task_service_for(service_name=resource.service_name) + else: + raise NotImplementedError( + f"Resource of type '{type(resource)}' are not supported: '{resource}'." + ) + return state diff --git a/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/state_task_lambda.py b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/state_task_lambda.py new file mode 100644 index 000000000..2cb265f9f --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_execution/state_task/state_task_lambda.py @@ -0,0 +1,141 @@ +from botocore.exceptions import ClientError + +from moto.stepfunctions.parser.api import ( + HistoryEventExecutionDataDetails, + HistoryEventType, + LambdaFunctionFailedEventDetails, + LambdaFunctionScheduledEventDetails, + LambdaFunctionSucceededEventDetails, + LambdaFunctionTimedOutEventDetails, +) +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name import ( + StatesErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task import ( + lambda_eval_utils, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + LambdaResource, + ResourceRuntimePart, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.state_task import ( + StateTask, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str + + +class StateTaskLambda(StateTask): + resource: LambdaResource + + def _from_error(self, env: Environment, ex: Exception) -> FailureEvent: + if isinstance(ex, TimeoutError): + return FailureEvent( + error_name=StatesErrorName(typ=StatesErrorNameType.StatesTimeout), + event_type=HistoryEventType.LambdaFunctionTimedOut, + event_details=EventDetails( + lambdaFunctionTimedOutEventDetails=LambdaFunctionTimedOutEventDetails( + error=StatesErrorNameType.StatesTimeout.to_name(), + ) + ), + ) + + error = "Exception" + if isinstance(ex, lambda_eval_utils.LambdaFunctionErrorException): + error_name = CustomErrorName(error) + cause = ex.payload + elif isinstance(ex, ClientError): + error_name = CustomErrorName(error) + cause = ex.response["Error"]["Message"] + else: + error_name = StatesErrorName(StatesErrorNameType.StatesTaskFailed) + cause = str(ex) + + return FailureEvent( + error_name=error_name, + event_type=HistoryEventType.LambdaFunctionFailed, + event_details=EventDetails( + lambdaFunctionFailedEventDetails=LambdaFunctionFailedEventDetails( + error=error, + cause=cause, + ) + ), + ) + + def _eval_parameters(self, env: Environment) -> dict: + if self.parameters: + self.parameters.eval(env=env) + payload = env.stack.pop() + parameters = dict( + FunctionName=self.resource.resource_arn, + InvocationType="RequestResponse", + Payload=payload, + ) + return parameters + + def _eval_execution(self, env: Environment) -> None: + parameters = self._eval_parameters(env=env) + payload = parameters["Payload"] + + scheduled_event_details = LambdaFunctionScheduledEventDetails( + resource=self.resource.resource_arn, + input=to_json_str(payload), + inputDetails=HistoryEventExecutionDataDetails( + truncated=False # Always False for api calls. + ), + ) + if not self.timeout.is_default_value(): + self.timeout.eval(env=env) + timeout_seconds = env.stack.pop() + scheduled_event_details["timeoutInSeconds"] = timeout_seconds + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.LambdaFunctionScheduled, + event_detail=EventDetails( + lambdaFunctionScheduledEventDetails=scheduled_event_details + ), + ) + + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.LambdaFunctionStarted, + ) + + self.resource.eval(env=env) + resource_runtime_part: ResourceRuntimePart = env.stack.pop() + + parameters["Payload"] = lambda_eval_utils.to_payload_type(parameters["Payload"]) + lambda_eval_utils.exec_lambda_function( + env=env, + parameters=parameters, + region=resource_runtime_part.region, + account=resource_runtime_part.account, + ) + + # In lambda invocations, only payload is passed on as output. + output = env.stack.pop() + output_payload = output["Payload"] + env.stack.append(output_payload) + + env.event_history.add_event( + context=env.event_history_context, + hist_type_event=HistoryEventType.LambdaFunctionSucceeded, + event_detail=EventDetails( + lambdaFunctionSucceededEventDetails=LambdaFunctionSucceededEventDetails( + output=to_json_str(output_payload), + outputDetails=HistoryEventExecutionDataDetails( + truncated=False # Always False for api calls. + ), + ) + ), + ) diff --git a/moto/stepfunctions/parser/asl/component/state/state_fail/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_fail/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_fail/state_fail.py b/moto/stepfunctions/parser/asl/component/state/state_fail/state_fail.py new file mode 100644 index 000000000..9fcfce842 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_fail/state_fail.py @@ -0,0 +1,48 @@ +from typing import Optional + +from moto.stepfunctions.parser.api import HistoryEventType, TaskFailedEventDetails +from moto.stepfunctions.parser.asl.component.common.cause_decl import CauseDecl +from moto.stepfunctions.parser.asl.component.common.error_decl import ErrorDecl +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.failure_event import ( + FailureEvent, + FailureEventException, +) +from moto.stepfunctions.parser.asl.component.state.state import CommonStateField +from moto.stepfunctions.parser.asl.component.state.state_props import StateProps +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails + + +class StateFail(CommonStateField): + def __init__(self): + super().__init__( + state_entered_event_type=HistoryEventType.FailStateEntered, + state_exited_event_type=None, + ) + self.cause: Optional[CauseDecl] = None + self.error: Optional[ErrorDecl] = None + + def from_state_props(self, state_props: StateProps) -> None: + super(StateFail, self).from_state_props(state_props) + self.cause = state_props.get(CauseDecl) + self.error = state_props.get(ErrorDecl) + + def _eval_state(self, env: Environment) -> None: + task_failed_event_details = TaskFailedEventDetails() + if self.error: + task_failed_event_details["error"] = self.error.error + if self.cause: + task_failed_event_details["cause"] = self.cause.cause + + error_name = CustomErrorName(self.error.error) if self.error else None + failure_event = FailureEvent( + error_name=error_name, + event_type=HistoryEventType.TaskFailed, + event_details=EventDetails( + taskFailedEventDetails=task_failed_event_details + ), + ) + raise FailureEventException(failure_event=failure_event) diff --git a/moto/stepfunctions/parser/asl/component/state/state_pass/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_pass/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_pass/result.py b/moto/stepfunctions/parser/asl/component/state/state_pass/result.py new file mode 100644 index 000000000..b9d6edea4 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_pass/result.py @@ -0,0 +1,8 @@ +import json + +from moto.stepfunctions.parser.asl.component.component import Component + + +class Result(Component): + def __init__(self, result_obj: json): + self.result_obj: json = result_obj diff --git a/moto/stepfunctions/parser/asl/component/state/state_pass/state_pass.py b/moto/stepfunctions/parser/asl/component/state/state_pass/state_pass.py new file mode 100644 index 000000000..106845a23 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_pass/state_pass.py @@ -0,0 +1,78 @@ +from typing import Optional + +from moto.stepfunctions.parser.api import ( + HistoryEventExecutionDataDetails, + HistoryEventType, + StateEnteredEventDetails, + StateExitedEventDetails, +) +from moto.stepfunctions.parser.asl.component.common.parameters import Parameters +from moto.stepfunctions.parser.asl.component.common.path.result_path import ResultPath +from moto.stepfunctions.parser.asl.component.state.state import CommonStateField +from moto.stepfunctions.parser.asl.component.state.state_pass.result import Result +from moto.stepfunctions.parser.asl.component.state.state_props import StateProps +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str + + +class StatePass(CommonStateField): + def __init__(self): + super(StatePass, self).__init__( + state_entered_event_type=HistoryEventType.PassStateEntered, + state_exited_event_type=HistoryEventType.PassStateExited, + ) + + # Result (Optional) + # Refers to the output of a virtual state_task that is passed on to the next state. If you include the ResultPath + # field in your state machine definition, Result is placed as specified by ResultPath and passed on to the + self.result: Optional[Result] = None + + # ResultPath (Optional) + # Specifies where to place the output (relative to the input) of the virtual state_task specified in Result. The input + # is further filtered as specified by the OutputPath field (if present) before being used as the state's output. + self.result_path: Optional[ResultPath] = None + + # Parameters (Optional) + # Creates a collection of key-value pairs that will be passed as input. You can specify Parameters as a static + # value or select from the input using a path. + self.parameters: Optional[Parameters] = None + + def from_state_props(self, state_props: StateProps) -> None: + super(StatePass, self).from_state_props(state_props) + self.result = state_props.get(Result) + self.result_path = state_props.get(ResultPath) or ResultPath( + result_path_src=ResultPath.DEFAULT_PATH + ) + self.parameters = state_props.get(Parameters) + + def _get_state_entered_event_details( + self, env: Environment + ) -> StateEnteredEventDetails: + return StateEnteredEventDetails( + name=self.name, + input=to_json_str(env.inp, separators=(",", ":")), + inputDetails=HistoryEventExecutionDataDetails( + truncated=False # Always False for api calls. + ), + ) + + def _get_state_exited_event_details( + self, env: Environment + ) -> StateExitedEventDetails: + return StateExitedEventDetails( + name=self.name, + output=to_json_str(env.inp, separators=(",", ":")), + outputDetails=HistoryEventExecutionDataDetails( + truncated=False # Always False for api calls. + ), + ) + + def _eval_state(self, env: Environment) -> None: + if self.parameters: + self.parameters.eval(env=env) + + if self.result: + env.stack.append(self.result.result_obj) + + if self.result_path: + self.result_path.eval(env) diff --git a/moto/stepfunctions/parser/asl/component/state/state_props.py b/moto/stepfunctions/parser/asl/component/state/state_props.py new file mode 100644 index 000000000..6980f2226 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_props.py @@ -0,0 +1,49 @@ +from typing import Any + +from moto.stepfunctions.parser.asl.component.common.flow.end import End +from moto.stepfunctions.parser.asl.component.common.flow.next import Next +from moto.stepfunctions.parser.asl.component.common.timeouts.heartbeat import Heartbeat +from moto.stepfunctions.parser.asl.component.common.timeouts.timeout import Timeout +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.max_items_decl import ( + MaxItemsDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + Resource, +) +from moto.stepfunctions.parser.asl.component.state.state_wait.wait_function.wait_function import ( + WaitFunction, +) +from moto.stepfunctions.parser.asl.parse.typed_props import TypedProps + + +class StateProps(TypedProps): + _UNIQUE_SUBINSTANCES = { + Resource, + WaitFunction, + Timeout, + Heartbeat, + MaxItemsDecl, + } + name: str + + def add(self, instance: Any) -> None: + inst_type = type(instance) + + # End-Next conflicts: + if inst_type == End and Next in self._instance_by_type: + raise ValueError( + f"End redefines Next, from '{self.get(Next)}' to '{instance}'." + ) + if inst_type == Next and End in self._instance_by_type: + raise ValueError( + f"Next redefines End, from '{self.get(End)}' to '{instance}'." + ) + + # Subclasses + for typ in self._UNIQUE_SUBINSTANCES: + if issubclass(inst_type, typ): + super()._add(typ, instance) + return + + # Base and delegate to preprocessor. + super().add(instance) diff --git a/moto/stepfunctions/parser/asl/component/state/state_succeed/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_succeed/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_succeed/state_succeed.py b/moto/stepfunctions/parser/asl/component/state/state_succeed/state_succeed.py new file mode 100644 index 000000000..c7d09cf2a --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_succeed/state_succeed.py @@ -0,0 +1,31 @@ +from moto.stepfunctions.parser.api import HistoryEventType +from moto.stepfunctions.parser.asl.component.common.flow.end import End +from moto.stepfunctions.parser.asl.component.common.flow.next import Next +from moto.stepfunctions.parser.asl.component.state.state import CommonStateField +from moto.stepfunctions.parser.asl.component.state.state_continue_with import ( + ContinueWithSuccess, +) +from moto.stepfunctions.parser.asl.component.state.state_props import StateProps +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class StateSucceed(CommonStateField): + def __init__(self): + super().__init__( + state_entered_event_type=HistoryEventType.SucceedStateEntered, + state_exited_event_type=HistoryEventType.SucceedStateExited, + ) + + def from_state_props(self, state_props: StateProps) -> None: + super(StateSucceed, self).from_state_props(state_props) + # TODO: assert all other fields are undefined? + + # No Next or End field: Succeed states are terminal states. + if state_props.get(Next) or state_props.get(End): + raise ValueError( + f"No Next or End field: Succeed states are terminal states: with state '{self}'." + ) + self.continue_with = ContinueWithSuccess() + + def _eval_state(self, env: Environment) -> None: + pass diff --git a/moto/stepfunctions/parser/asl/component/state/state_type.py b/moto/stepfunctions/parser/asl/component/state/state_type.py new file mode 100644 index 000000000..b437d993b --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_type.py @@ -0,0 +1,14 @@ +from enum import Enum + +from moto.stepfunctions.parser.asl.antlr.runtime.ASLLexer import ASLLexer + + +class StateType(Enum): + Task = ASLLexer.TASK + Pass = ASLLexer.PASS + Choice = ASLLexer.CHOICE + Fail = ASLLexer.FAIL + Succeed = ASLLexer.SUCCEED + Wait = ASLLexer.WAIT + Map = ASLLexer.MAP + Parallel = ASLLexer.PARALLEL diff --git a/moto/stepfunctions/parser/asl/component/state/state_wait/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_wait/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_wait/state_wait.py b/moto/stepfunctions/parser/asl/component/state/state_wait/state_wait.py new file mode 100644 index 000000000..94a4333bf --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_wait/state_wait.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +from moto.stepfunctions.parser.api import HistoryEventType +from moto.stepfunctions.parser.asl.component.state.state import CommonStateField +from moto.stepfunctions.parser.asl.component.state.state_props import StateProps +from moto.stepfunctions.parser.asl.component.state.state_wait.wait_function.wait_function import ( + WaitFunction, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class StateWait(CommonStateField): + wait_function: WaitFunction + + def __init__(self): + super().__init__( + state_entered_event_type=HistoryEventType.WaitStateEntered, + state_exited_event_type=HistoryEventType.WaitStateExited, + ) + + def from_state_props(self, state_props: StateProps) -> None: + super(StateWait, self).from_state_props(state_props) + self.wait_function = state_props.get( + typ=WaitFunction, + raise_on_missing=ValueError( + f"Undefined WaitFunction for StateWait: '{self}'." + ), + ) + + def _eval_state(self, env: Environment) -> None: + self.wait_function.eval(env) diff --git a/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/__init__.py b/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/seconds.py b/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/seconds.py new file mode 100644 index 000000000..67138c617 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/seconds.py @@ -0,0 +1,18 @@ +from typing import Final + +from moto.stepfunctions.parser.asl.component.state.state_wait.wait_function.wait_function import ( + WaitFunction, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class Seconds(WaitFunction): + # Seconds + # A time, in seconds, to state_wait before beginning the state specified in the Next + # field. You must specify time as a positive, integer value. + + def __init__(self, seconds: int): + self.seconds: Final[int] = seconds + + def _get_wait_seconds(self, env: Environment) -> int: + return self.seconds diff --git a/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/seconds_path.py b/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/seconds_path.py new file mode 100644 index 000000000..620856bce --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/seconds_path.py @@ -0,0 +1,23 @@ +from typing import Final + +from jsonpath_ng import parse + +from moto.stepfunctions.parser.asl.component.state.state_wait.wait_function.wait_function import ( + WaitFunction, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class SecondsPath(WaitFunction): + # SecondsPath + # A time, in seconds, to state_wait before beginning the state specified in the Next + # field, specified using a path from the state's input data. + # You must specify an integer value for this field. + + def __init__(self, path: str): + self.path: Final[str] = path + + def _get_wait_seconds(self, env: Environment) -> int: + input_expr = parse(self.path) + seconds = input_expr.find(env.inp) + return seconds diff --git a/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/timestamp.py b/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/timestamp.py new file mode 100644 index 000000000..df6c240e6 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/timestamp.py @@ -0,0 +1,33 @@ +import datetime +from typing import Final + +from moto.stepfunctions.parser.asl.component.state.state_wait.wait_function.wait_function import ( + WaitFunction, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment + + +class Timestamp(WaitFunction): + # Timestamp + # An absolute time to state_wait until beginning the state specified in the Next field. + # Timestamps must conform to the RFC3339 profile of ISO 8601, with the further + # restrictions that an uppercase T must separate the date and time portions, and + # an uppercase Z must denote that a numeric time zone offset is not present, for + # example, 2016-08-18T17:33:00Z. + # Note + # Currently, if you specify the state_wait time as a timestamp, Step Functions considers + # the time value up to seconds and truncates milliseconds. + + TIMESTAMP_FORMAT: Final[str] = "%Y-%m-%dT%H:%M:%SZ" + + def __init__(self, timestamp): + self.timestamp: Final[datetime.datetime] = timestamp + + @staticmethod + def parse_timestamp(timestamp: str) -> datetime.datetime: + return datetime.datetime.strptime(timestamp, Timestamp.TIMESTAMP_FORMAT) + + def _get_wait_seconds(self, env: Environment) -> int: + delta = self.timestamp - datetime.datetime.today() + delta_sec = int(delta.total_seconds()) + return delta_sec diff --git a/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/timestamp_path.py b/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/timestamp_path.py new file mode 100644 index 000000000..08777511b --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/timestamp_path.py @@ -0,0 +1,30 @@ +import datetime +from typing import Final + +from moto.stepfunctions.parser.asl.component.state.state_wait.wait_function.timestamp import ( + Timestamp, +) +from moto.stepfunctions.parser.asl.component.state.state_wait.wait_function.wait_function import ( + WaitFunction, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.utils.json_path import JSONPathUtils + + +class TimestampPath(WaitFunction): + # TimestampPath + # An absolute time to state_wait until beginning the state specified in the Next field, + # specified using a path from the state's input data. + + def __init__(self, path: str): + self.path: Final[str] = path + + def _get_wait_seconds(self, env: Environment) -> int: + inp = env.stack[-1] + timestamp_str = JSONPathUtils.extract_json(self.path, inp) + timestamp = datetime.datetime.strptime( + timestamp_str, Timestamp.TIMESTAMP_FORMAT + ) + delta = timestamp - datetime.datetime.today() + delta_sec = int(delta.total_seconds()) + return delta_sec diff --git a/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/wait_function.py b/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/wait_function.py new file mode 100644 index 000000000..01a9233e2 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/state/state_wait/wait_function/wait_function.py @@ -0,0 +1,39 @@ +import abc +import logging +import time + +from moto.stepfunctions.parser.asl.component.eval_component import EvalComponent +from moto.stepfunctions.parser.asl.eval.environment import Environment + +LOG = logging.getLogger(__name__) + + +class WaitFunction(EvalComponent, abc.ABC): + @abc.abstractmethod + def _get_wait_seconds(self, env: Environment) -> int: + ... + + def _wait_interval(self, env: Environment, wait_seconds: int) -> None: + t0 = time.time() + if wait_seconds > 0: + env.program_state_event.wait(wait_seconds) + t1 = time.time() + round_sec_waited = int(t1 - t0) + wait_seconds_delta = wait_seconds - round_sec_waited + if wait_seconds_delta <= 0: + return + elif env.is_running(): + # Unrelated interrupt: continue waiting. + LOG.warning( + f"Wait function '{self}' successfully reentered waiting for " + f"another '{wait_seconds_delta}' seconds." + ) + return self._wait_interval(env=env, wait_seconds=wait_seconds_delta) + else: + LOG.info( + f"Wait function '{self}' successfully interrupted after '{round_sec_waited}' seconds." + ) + + def _eval_body(self, env: Environment) -> None: + w_sec = self._get_wait_seconds(env=env) + self._wait_interval(env=env, wait_seconds=w_sec) diff --git a/moto/stepfunctions/parser/asl/component/states.py b/moto/stepfunctions/parser/asl/component/states.py new file mode 100644 index 000000000..0c041d695 --- /dev/null +++ b/moto/stepfunctions/parser/asl/component/states.py @@ -0,0 +1,7 @@ +from moto.stepfunctions.parser.asl.component.component import Component +from moto.stepfunctions.parser.asl.component.state.state import CommonStateField + + +class States(Component): + def __init__(self): + self.states: dict[str, CommonStateField] = dict() diff --git a/moto/stepfunctions/parser/asl/eval/__init__.py b/moto/stepfunctions/parser/asl/eval/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/eval/aws_execution_details.py b/moto/stepfunctions/parser/asl/eval/aws_execution_details.py new file mode 100644 index 000000000..495d870ae --- /dev/null +++ b/moto/stepfunctions/parser/asl/eval/aws_execution_details.py @@ -0,0 +1,12 @@ +from typing import Final + + +class AWSExecutionDetails: + account: Final[str] + region: Final[str] + role_arn: Final[str] + + def __init__(self, account: str, region: str, role_arn: str): + self.account = account + self.region = region + self.role_arn = role_arn diff --git a/moto/stepfunctions/parser/asl/eval/callback/__init__.py b/moto/stepfunctions/parser/asl/eval/callback/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/eval/callback/callback.py b/moto/stepfunctions/parser/asl/eval/callback/callback.py new file mode 100644 index 000000000..24569ac47 --- /dev/null +++ b/moto/stepfunctions/parser/asl/eval/callback/callback.py @@ -0,0 +1,173 @@ +import abc +from collections import OrderedDict +from threading import Event +from typing import Dict, Final, Optional + +from moto.moto_api._internal import mock_random + +CallbackId = str + + +class CallbackOutcome(abc.ABC): + callback_id: Final[CallbackId] + + def __init__(self, callback_id: str): + self.callback_id = callback_id + + +class CallbackOutcomeSuccess(CallbackOutcome): + output: Final[str] + + def __init__(self, callback_id: CallbackId, output: str): + super().__init__(callback_id=callback_id) + self.output = output + + +class CallbackOutcomeFailure(CallbackOutcome): + error: Final[str] + cause: Final[str] + + def __init__(self, callback_id: CallbackId, error: str, cause: str): + super().__init__(callback_id=callback_id) + self.error = error + self.cause = cause + + +class CallbackTimeoutError(TimeoutError): + pass + + +class CallbackConsumerError(abc.ABC): + ... + + +class CallbackConsumerTimeout(CallbackConsumerError): + pass + + +class CallbackConsumerLeft(CallbackConsumerError): + pass + + +class HeartbeatEndpoint: + _next_heartbeat_event: Final[Event] + _heartbeat_seconds: Final[int] + + def __init__(self, heartbeat_seconds: int): + self._next_heartbeat_event = Event() + self._heartbeat_seconds = heartbeat_seconds + + def clear_and_wait(self) -> bool: + self._next_heartbeat_event.clear() + return self._next_heartbeat_event.wait(timeout=self._heartbeat_seconds) + + def notify(self): + self._next_heartbeat_event.set() + + +class HeartbeatTimeoutError(TimeoutError): + pass + + +class CallbackEndpoint: + callback_id: Final[CallbackId] + _notify_event: Final[Event] + _outcome: Optional[CallbackOutcome] + consumer_error: Optional[CallbackConsumerError] + _heartbeat_endpoint: Optional[HeartbeatEndpoint] + + def __init__(self, callback_id: CallbackId): + self.callback_id = callback_id + self._notify_event = Event() + self._outcome = None + self.consumer_error = None + self._heartbeat_endpoint = None + + def setup_heartbeat_endpoint(self, heartbeat_seconds: int) -> HeartbeatEndpoint: + self._heartbeat_endpoint = HeartbeatEndpoint( + heartbeat_seconds=heartbeat_seconds + ) + return self._heartbeat_endpoint + + def notify(self, outcome: CallbackOutcome): + self._outcome = outcome + self._notify_event.set() + if self._heartbeat_endpoint: + self._heartbeat_endpoint.notify() + + def notify_heartbeat(self) -> bool: + if not self._heartbeat_endpoint: + return False + self._heartbeat_endpoint.notify() + return True + + def wait(self, timeout: Optional[float] = None) -> Optional[CallbackOutcome]: + self._notify_event.wait(timeout=timeout) + return self._outcome + + def get_outcome(self) -> Optional[CallbackOutcome]: + return self._outcome + + def report(self, consumer_error: CallbackConsumerError) -> None: + self.consumer_error = consumer_error + + +class CallbackNotifyConsumerError(RuntimeError): + callback_consumer_error: CallbackConsumerError + + def __init__(self, callback_consumer_error: CallbackConsumerError): + self.callback_consumer_error = callback_consumer_error + + +class CallbackOutcomeFailureError(RuntimeError): + callback_outcome_failure: CallbackOutcomeFailure + + def __init__(self, callback_outcome_failure: CallbackOutcomeFailure): + self.callback_outcome_failure = callback_outcome_failure + + +class CallbackPoolManager: + _pool: Dict[CallbackId, CallbackEndpoint] + + def __init__(self): + self._pool = OrderedDict() + + def get(self, callback_id: CallbackId) -> Optional[CallbackEndpoint]: + return self._pool.get(callback_id) + + def add(self, callback_id: CallbackId) -> CallbackEndpoint: + if callback_id in self._pool: + raise ValueError("Duplicate callback token id value.") + callback_endpoint = CallbackEndpoint(callback_id=callback_id) + self._pool[callback_id] = callback_endpoint + return callback_endpoint + + def generate(self) -> CallbackEndpoint: + return self.add(str(mock_random.uuid4())) + + def notify(self, callback_id: CallbackId, outcome: CallbackOutcome) -> bool: + callback_endpoint = self._pool.get(callback_id, None) + if callback_endpoint is None: + return False + + consumer_error: Optional[ + CallbackConsumerError + ] = callback_endpoint.consumer_error + if consumer_error is not None: + raise CallbackNotifyConsumerError(callback_consumer_error=consumer_error) + + callback_endpoint.notify(outcome=outcome) + return True + + def heartbeat(self, callback_id: CallbackId) -> bool: + callback_endpoint = self._pool.get(callback_id, None) + if callback_endpoint is None: + return False + + consumer_error: Optional[ + CallbackConsumerError + ] = callback_endpoint.consumer_error + if consumer_error is not None: + raise CallbackNotifyConsumerError(callback_consumer_error=consumer_error) + + return callback_endpoint.notify_heartbeat() diff --git a/moto/stepfunctions/parser/asl/eval/contextobject/__init__.py b/moto/stepfunctions/parser/asl/eval/contextobject/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/eval/contextobject/contex_object.py b/moto/stepfunctions/parser/asl/eval/contextobject/contex_object.py new file mode 100644 index 000000000..96538aea0 --- /dev/null +++ b/moto/stepfunctions/parser/asl/eval/contextobject/contex_object.py @@ -0,0 +1,62 @@ +from typing import Any, Final, Optional, TypedDict + +from moto.moto_api._internal import mock_random + + +class Execution(TypedDict): + Id: str + Input: Optional[dict] + Name: str + RoleArn: str + StartTime: str # Format: ISO 8601. + + +class State(TypedDict): + EnteredTime: str # Format: ISO 8601. + Name: str + RetryCount: int + + +class StateMachine(TypedDict): + Id: str + Name: str + + +class Task(TypedDict): + Token: str + + +class Item(TypedDict): + # Contains the index number for the array item that is being currently processed. + Index: int + # Contains the array item being processed. + Value: Optional[Any] + + +class Map(TypedDict): + Item: Item + + +class ContextObject(TypedDict): + Execution: Execution + State: Optional[State] + StateMachine: StateMachine + Task: Optional[Task] # Null if the Parameters field is outside a task state. + Map: Optional[Map] # Only available when processing a Map state. + + +class ContextObjectManager: + context_object: Final[ContextObject] + + def __init__(self, context_object: ContextObject): + self.context_object = context_object + + def update_task_token(self) -> str: + new_token = str(mock_random.uuid4()) + self.context_object["Task"] = Task(Token=new_token) + return new_token + + +class ContextObjectInitData(TypedDict): + Execution: Execution + StateMachine: StateMachine diff --git a/moto/stepfunctions/parser/asl/eval/count_down_latch.py b/moto/stepfunctions/parser/asl/eval/count_down_latch.py new file mode 100644 index 000000000..46ada63f6 --- /dev/null +++ b/moto/stepfunctions/parser/asl/eval/count_down_latch.py @@ -0,0 +1,21 @@ +import threading + + +class CountDownLatch: + # TODO: add timeout support. + def __init__(self, num: int): + self._num: int = num + self.lock = threading.Condition() + + def count_down(self) -> None: + self.lock.acquire() + self._num -= 1 + if self._num <= 0: + self.lock.notify_all() + self.lock.release() + + def wait(self) -> None: + self.lock.acquire() + while self._num > 0: + self.lock.wait() + self.lock.release() diff --git a/moto/stepfunctions/parser/asl/eval/environment.py b/moto/stepfunctions/parser/asl/eval/environment.py new file mode 100644 index 000000000..1992449aa --- /dev/null +++ b/moto/stepfunctions/parser/asl/eval/environment.py @@ -0,0 +1,200 @@ +from __future__ import annotations + +import copy +import logging +import threading +from typing import Any, Dict, Final, List, Optional + +from moto.stepfunctions.parser.api import ExecutionFailedEventDetails, Timestamp +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.map_run_record import ( + MapRunRecordPoolManager, +) +from moto.stepfunctions.parser.asl.eval.aws_execution_details import AWSExecutionDetails +from moto.stepfunctions.parser.asl.eval.callback.callback import CallbackPoolManager +from moto.stepfunctions.parser.asl.eval.contextobject.contex_object import ( + ContextObject, + ContextObjectInitData, + ContextObjectManager, +) +from moto.stepfunctions.parser.asl.eval.event.event_history import ( + EventHistory, + EventHistoryContext, +) +from moto.stepfunctions.parser.asl.eval.program_state import ( + ProgramEnded, + ProgramError, + ProgramRunning, + ProgramState, + ProgramStopped, + ProgramTimedOut, +) + +LOG = logging.getLogger(__name__) + + +class Environment: + _state_mutex: Final[threading.RLock()] + _program_state: Optional[ProgramState] + program_state_event: Final[threading.Event()] + + event_history: EventHistory + event_history_context: Final[EventHistoryContext] + aws_execution_details: Final[AWSExecutionDetails] + callback_pool_manager: CallbackPoolManager + map_run_record_pool_manager: MapRunRecordPoolManager + context_object_manager: Final[ContextObjectManager] + + _frames: Final[List[Environment]] + _is_frame: bool = False + + heap: Dict[str, Any] = dict() + stack: List[Any] = list() + inp: Optional[Any] = None + + def __init__( + self, + aws_execution_details: AWSExecutionDetails, + context_object_init: ContextObjectInitData, + event_history_context: EventHistoryContext, + ): + super(Environment, self).__init__() + self._state_mutex = threading.RLock() + self._program_state = None + self.program_state_event = threading.Event() + + self.event_history = EventHistory() + self.event_history_context = event_history_context + self.aws_execution_details = aws_execution_details + self.callback_pool_manager = CallbackPoolManager() + self.map_run_record_pool_manager = MapRunRecordPoolManager() + self.context_object_manager = ContextObjectManager( + context_object=ContextObject( + Execution=context_object_init["Execution"], + StateMachine=context_object_init["StateMachine"], + ) + ) + + self._frames = list() + self._is_frame = False + + self.heap = dict() + self.stack = list() + self.inp = None + + @classmethod + def as_frame_of( + cls, env: Environment, event_history_frame_cache: EventHistoryContext + ): + context_object_init = ContextObjectInitData( + Execution=env.context_object_manager.context_object["Execution"], + StateMachine=env.context_object_manager.context_object["StateMachine"], + ) + frame = cls( + aws_execution_details=env.aws_execution_details, + context_object_init=context_object_init, + event_history_context=event_history_frame_cache, + ) + frame._is_frame = True + frame.event_history = env.event_history + if "State" in env.context_object_manager.context_object: + frame.context_object_manager.context_object["State"] = copy.deepcopy( + env.context_object_manager.context_object["State"] + ) + frame.callback_pool_manager = env.callback_pool_manager + frame.map_run_record_pool_manager = env.map_run_record_pool_manager + frame.heap = env.heap + frame._program_state = copy.deepcopy(env._program_state) + return frame + + @property + def next_state_name(self) -> Optional[str]: + next_state_name: Optional[str] = None + if isinstance(self._program_state, ProgramRunning): + next_state_name = self._program_state.next_state_name + return next_state_name + + @next_state_name.setter + def next_state_name(self, next_state_name: str) -> None: + if self._program_state is None: + self._program_state = ProgramRunning() + + if isinstance(self._program_state, ProgramRunning): + self._program_state.next_state_name = next_state_name + else: + raise RuntimeError( + f"Could not set NextState value when in state '{type(self._program_state)}'." + ) + + def program_state(self) -> ProgramState: + return copy.deepcopy(self._program_state) + + def is_running(self) -> bool: + return isinstance(self._program_state, ProgramRunning) + + def set_ended(self) -> None: + with self._state_mutex: + if isinstance(self._program_state, ProgramRunning): + self._program_state = ProgramEnded() + for frame in self._frames: + frame.set_ended() + self.program_state_event.set() + self.program_state_event.clear() + + def set_error(self, error: ExecutionFailedEventDetails) -> None: + with self._state_mutex: + self._program_state = ProgramError(error=error) + for frame in self._frames: + frame.set_error(error=error) + self.program_state_event.set() + self.program_state_event.clear() + + def set_timed_out(self) -> None: + with self._state_mutex: + self._program_state = ProgramTimedOut() + for frame in self._frames: + frame.set_timed_out() + self.program_state_event.set() + self.program_state_event.clear() + + def set_stop( + self, stop_date: Timestamp, cause: Optional[str], error: Optional[str] + ) -> None: + with self._state_mutex: + if isinstance(self._program_state, ProgramRunning): + self._program_state = ProgramStopped( + stop_date=stop_date, cause=cause, error=error + ) + for frame in self._frames: + frame.set_stop(stop_date=stop_date, cause=cause, error=error) + self.program_state_event.set() + self.program_state_event.clear() + else: + raise RuntimeError("Cannot stop non running ProgramState.") + + def open_frame( + self, event_history_context: Optional[EventHistoryContext] = None + ) -> Environment: + with self._state_mutex: + # The default logic provisions for child frame to extend the source frame event id. + if event_history_context is None: + event_history_context = EventHistoryContext( + previous_event_id=self.event_history_context.source_event_id + ) + + frame = Environment.as_frame_of(self, event_history_context) + self._frames.append(frame) + return frame + + def close_frame(self, frame: Environment) -> None: + with self._state_mutex: + if frame in self._frames: + self._frames.remove(frame) + self.event_history_context.integrate(frame.event_history_context) + + def delete_frame(self, frame: Environment) -> None: + with self._state_mutex: + if frame in self._frames: + self._frames.remove(frame) + + def is_frame(self) -> bool: + return self._is_frame diff --git a/moto/stepfunctions/parser/asl/eval/event/__init__.py b/moto/stepfunctions/parser/asl/eval/event/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/eval/event/event_detail.py b/moto/stepfunctions/parser/asl/eval/event/event_detail.py new file mode 100644 index 000000000..62305043b --- /dev/null +++ b/moto/stepfunctions/parser/asl/eval/event/event_detail.py @@ -0,0 +1,76 @@ +from typing import Optional, TypedDict + +from moto.stepfunctions.parser.api import ( + ActivityFailedEventDetails, + ActivityScheduledEventDetails, + ActivityScheduleFailedEventDetails, + ActivityStartedEventDetails, + ActivitySucceededEventDetails, + ActivityTimedOutEventDetails, + ExecutionAbortedEventDetails, + ExecutionFailedEventDetails, + ExecutionStartedEventDetails, + ExecutionSucceededEventDetails, + ExecutionTimedOutEventDetails, + LambdaFunctionFailedEventDetails, + LambdaFunctionScheduledEventDetails, + LambdaFunctionScheduleFailedEventDetails, + LambdaFunctionStartFailedEventDetails, + LambdaFunctionSucceededEventDetails, + LambdaFunctionTimedOutEventDetails, + MapIterationEventDetails, + MapRunFailedEventDetails, + MapRunStartedEventDetails, + MapStateStartedEventDetails, + StateEnteredEventDetails, + StateExitedEventDetails, + TaskFailedEventDetails, + TaskScheduledEventDetails, + TaskStartedEventDetails, + TaskStartFailedEventDetails, + TaskSubmitFailedEventDetails, + TaskSubmittedEventDetails, + TaskSucceededEventDetails, + TaskTimedOutEventDetails, +) + + +class EventDetails(TypedDict): + activityFailedEventDetails: Optional[ActivityFailedEventDetails] + activityScheduleFailedEventDetails: Optional[ActivityScheduleFailedEventDetails] + activityScheduledEventDetails: Optional[ActivityScheduledEventDetails] + activityStartedEventDetails: Optional[ActivityStartedEventDetails] + activitySucceededEventDetails: Optional[ActivitySucceededEventDetails] + activityTimedOutEventDetails: Optional[ActivityTimedOutEventDetails] + taskFailedEventDetails: Optional[TaskFailedEventDetails] + taskScheduledEventDetails: Optional[TaskScheduledEventDetails] + taskStartFailedEventDetails: Optional[TaskStartFailedEventDetails] + taskStartedEventDetails: Optional[TaskStartedEventDetails] + taskSubmitFailedEventDetails: Optional[TaskSubmitFailedEventDetails] + taskSubmittedEventDetails: Optional[TaskSubmittedEventDetails] + taskSucceededEventDetails: Optional[TaskSucceededEventDetails] + taskTimedOutEventDetails: Optional[TaskTimedOutEventDetails] + executionFailedEventDetails: Optional[ExecutionFailedEventDetails] + executionStartedEventDetails: Optional[ExecutionStartedEventDetails] + executionSucceededEventDetails: Optional[ExecutionSucceededEventDetails] + executionAbortedEventDetails: Optional[ExecutionAbortedEventDetails] + executionTimedOutEventDetails: Optional[ExecutionTimedOutEventDetails] + mapStateStartedEventDetails: Optional[MapStateStartedEventDetails] + mapIterationStartedEventDetails: Optional[MapIterationEventDetails] + mapIterationSucceededEventDetails: Optional[MapIterationEventDetails] + mapIterationFailedEventDetails: Optional[MapIterationEventDetails] + mapIterationAbortedEventDetails: Optional[MapIterationEventDetails] + lambdaFunctionFailedEventDetails: Optional[LambdaFunctionFailedEventDetails] + lambdaFunctionScheduleFailedEventDetails: Optional[ + LambdaFunctionScheduleFailedEventDetails + ] + lambdaFunctionScheduledEventDetails: Optional[LambdaFunctionScheduledEventDetails] + lambdaFunctionStartFailedEventDetails: Optional[ + LambdaFunctionStartFailedEventDetails + ] + lambdaFunctionSucceededEventDetails: Optional[LambdaFunctionSucceededEventDetails] + lambdaFunctionTimedOutEventDetails: Optional[LambdaFunctionTimedOutEventDetails] + stateEnteredEventDetails: Optional[StateEnteredEventDetails] + stateExitedEventDetails: Optional[StateExitedEventDetails] + mapRunStartedEventDetails: Optional[MapRunStartedEventDetails] + mapRunFailedEventDetails: Optional[MapRunFailedEventDetails] diff --git a/moto/stepfunctions/parser/asl/eval/event/event_history.py b/moto/stepfunctions/parser/asl/eval/event/event_history.py new file mode 100644 index 000000000..a23daece2 --- /dev/null +++ b/moto/stepfunctions/parser/asl/eval/event/event_history.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +import copy +import threading +from typing import Final, Optional + +from moto.core.utils import iso_8601_datetime_with_milliseconds +from moto.stepfunctions.parser.api import ( + HistoryEvent, + HistoryEventList, + HistoryEventType, + Timestamp, +) +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails + + +class EventHistoryContext: + # The '0' event is the source event id of the program execution. + _PROGRAM_START_EVENT_ID: Final[int] = 0 + + source_event_id: int + last_published_event_id: int + + def __init__(self, previous_event_id: int): + self.source_event_id = previous_event_id + self.last_published_event_id = previous_event_id + + @classmethod + def of_program_start(cls) -> EventHistoryContext: + return cls(previous_event_id=cls._PROGRAM_START_EVENT_ID) + + def integrate(self, other: EventHistoryContext) -> None: + self.source_event_id = max(self.source_event_id, other.source_event_id) + self.last_published_event_id = max( + self.last_published_event_id, other.last_published_event_id + ) + + +class EventIdGenerator: + _next_id: int + + def __init__(self): + self._next_id = 1 + + def get(self) -> int: + next_id = self._next_id + self._next_id += 1 + return next_id + + +class EventHistory: + _mutex: Final[threading.Lock] + _history_event_list: Final[HistoryEventList] + _event_id_gen: EventIdGenerator + + def __init__(self): + self._mutex = threading.Lock() + self._history_event_list = list() + self._event_id_gen = EventIdGenerator() + + def add_event( + self, + context: EventHistoryContext, + hist_type_event: HistoryEventType, + event_detail: Optional[EventDetails] = None, + timestamp: Timestamp = None, + update_source_event_id: bool = True, + ) -> int: + with self._mutex: + event_id: int = self._event_id_gen.get() + history_event = HistoryEvent() + if event_detail: + history_event.update(event_detail) + history_event["id"] = event_id + history_event["previousEventId"] = context.source_event_id + history_event["type"] = hist_type_event + history_event["timestamp"] = ( + timestamp or iso_8601_datetime_with_milliseconds() + ) + self._history_event_list.append(history_event) + context.last_published_event_id = event_id + if update_source_event_id: + context.source_event_id = event_id + return event_id + + def get_event_history(self) -> HistoryEventList: + with self._mutex: + return copy.deepcopy(self._history_event_list) diff --git a/moto/stepfunctions/parser/asl/eval/program_state.py b/moto/stepfunctions/parser/asl/eval/program_state.py new file mode 100644 index 000000000..5a91bcfa8 --- /dev/null +++ b/moto/stepfunctions/parser/asl/eval/program_state.py @@ -0,0 +1,60 @@ +import abc +from typing import Final, Optional + +from moto.stepfunctions.parser.api import ExecutionFailedEventDetails, Timestamp + + +class ProgramState(abc.ABC): + ... + + +class ProgramEnded(ProgramState): + pass + + +class ProgramStopped(ProgramState): + def __init__( + self, stop_date: Timestamp, error: Optional[str], cause: Optional[str] + ): + super().__init__() + self.stop_date: Timestamp = stop_date + self.error: Optional[str] = error + self.cause: Optional[str] = cause + + +class ProgramRunning(ProgramState): + def __init__(self): + super().__init__() + self._next_state_name: Optional[str] = None + + @property + def next_state_name(self) -> str: + next_state_name = self._next_state_name + if next_state_name is None: + raise RuntimeError( + "Could not retrieve NextState from uninitialised ProgramState." + ) + return next_state_name + + @next_state_name.setter + def next_state_name(self, next_state_name) -> None: + if not self._validate_next_state_name(next_state_name): + raise ValueError(f"No such NextState '{next_state_name}'.") + self._next_state_name = next_state_name + + @staticmethod + def _validate_next_state_name(next_state_name: Optional[str]) -> bool: + # TODO. + return bool(next_state_name) + + +class ProgramError(ProgramState): + error: Final[Optional[ExecutionFailedEventDetails]] + + def __init__(self, error: Optional[ExecutionFailedEventDetails]): + super().__init__() + self.error = error + + +class ProgramTimedOut(ProgramState): + pass diff --git a/moto/stepfunctions/parser/asl/parse/__init__.py b/moto/stepfunctions/parser/asl/parse/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/parse/asl_parser.py b/moto/stepfunctions/parser/asl/parse/asl_parser.py new file mode 100644 index 000000000..5b84645fc --- /dev/null +++ b/moto/stepfunctions/parser/asl/parse/asl_parser.py @@ -0,0 +1,71 @@ +import abc +from typing import Final, List + +from antlr4 import CommonTokenStream, InputStream +from antlr4.error.ErrorListener import ErrorListener + +from moto.stepfunctions.parser.asl.antlr.runtime.ASLLexer import ASLLexer +from moto.stepfunctions.parser.asl.antlr.runtime.ASLParser import ASLParser +from moto.stepfunctions.parser.asl.component.program.program import Program +from moto.stepfunctions.parser.asl.parse.preprocessor import Preprocessor + + +class SyntaxErrorListener(ErrorListener): + errors: Final[List[str]] + + def __init__(self): + super().__init__() + self.errors = list() + + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): + log_parts = [f"line {line}:{column}"] + if offendingSymbol is not None and offendingSymbol.text: + log_parts.append(f"at {offendingSymbol.text}") + if msg: + log_parts.append(msg) + error_log = ", ".join(log_parts) + self.errors.append(error_log) + + +class ASLParserException(Exception): + errors: Final[List[str]] + + def __init__(self, errors: List[str]): + self.errors = errors + + def __str__(self): + return repr(self) + + def __repr__(self): + if not self.errors: + error_str = "No error details available" + elif len(self.errors) == 1: + error_str = self.errors[0] + else: + error_str = str(self.errors) + return f"ASLParserException {error_str}" + + +class AmazonStateLanguageParser(abc.ABC): + @staticmethod + def parse(src: str) -> Program: + # Attempt to build the AST and look out for syntax errors. + syntax_error_listener = SyntaxErrorListener() + + input_stream = InputStream(src) + lexer = ASLLexer(input_stream) + stream = CommonTokenStream(lexer) + parser = ASLParser(stream) + parser.removeErrorListeners() + parser.addErrorListener(syntax_error_listener) + tree = parser.program_decl() + + errors = syntax_error_listener.errors + if errors: + raise ASLParserException(errors=errors) + + # Attempt to preprocess the AST into evaluation components. + preprocessor = Preprocessor() + program = preprocessor.visit(tree) + + return program diff --git a/moto/stepfunctions/parser/asl/parse/intrinsic/__init__.py b/moto/stepfunctions/parser/asl/parse/intrinsic/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/parse/intrinsic/intrinsic_parser.py b/moto/stepfunctions/parser/asl/parse/intrinsic/intrinsic_parser.py new file mode 100644 index 000000000..c37de49f9 --- /dev/null +++ b/moto/stepfunctions/parser/asl/parse/intrinsic/intrinsic_parser.py @@ -0,0 +1,25 @@ +import abc + +from antlr4 import CommonTokenStream, InputStream + +from moto.stepfunctions.parser.asl.antlr.runtime.ASLIntrinsicLexer import ( + ASLIntrinsicLexer, +) +from moto.stepfunctions.parser.asl.antlr.runtime.ASLIntrinsicParser import ( + ASLIntrinsicParser, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.function import Function +from moto.stepfunctions.parser.asl.parse.intrinsic.preprocessor import Preprocessor + + +class IntrinsicParser(abc.ABC): + @staticmethod + def parse(src: str) -> Function: + input_stream = InputStream(src) + lexer = ASLIntrinsicLexer(input_stream) + stream = CommonTokenStream(lexer) + parser = ASLIntrinsicParser(stream) + tree = parser.func_decl() + preprocessor = Preprocessor() + function: Function = preprocessor.visit(tree) + return function diff --git a/moto/stepfunctions/parser/asl/parse/intrinsic/preprocessor.py b/moto/stepfunctions/parser/asl/parse/intrinsic/preprocessor.py new file mode 100644 index 000000000..d11177c26 --- /dev/null +++ b/moto/stepfunctions/parser/asl/parse/intrinsic/preprocessor.py @@ -0,0 +1,153 @@ +import re +from typing import List, Optional + +from antlr4.tree.Tree import ParseTree, TerminalNodeImpl + +from moto.stepfunctions.parser.asl.antlr.runtime.ASLIntrinsicLexer import ( + ASLIntrinsicLexer, +) +from moto.stepfunctions.parser.asl.antlr.runtime.ASLIntrinsicParser import ( + ASLIntrinsicParser, +) +from moto.stepfunctions.parser.asl.antlr.runtime.ASLIntrinsicParserVisitor import ( + ASLIntrinsicParserVisitor, +) +from moto.stepfunctions.parser.asl.antlt4utils.antlr4utils import Antlr4Utils +from moto.stepfunctions.parser.asl.component.component import Component +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument import ( + FunctionArgument, +) +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_bool import ( + FunctionArgumentBool, +) +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_context_path import ( + FunctionArgumentContextPath, +) +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_float import ( + FunctionArgumentFloat, +) +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_function import ( + FunctionArgumentFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_int import ( + FunctionArgumentInt, +) +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_json_path import ( + FunctionArgumentJsonPath, +) +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_list import ( + FunctionArgumentList, +) +from moto.stepfunctions.parser.asl.component.intrinsic.argument.function_argument_string import ( + FunctionArgumentString, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.function import Function +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.factory import ( + StatesFunctionFactory, +) +from moto.stepfunctions.parser.asl.component.intrinsic.function.statesfunction.states_function import ( + StatesFunction, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.state_function_name_types import ( + StatesFunctionNameType, +) +from moto.stepfunctions.parser.asl.component.intrinsic.functionname.states_function_name import ( + StatesFunctionName, +) + + +class Preprocessor(ASLIntrinsicParserVisitor): + @staticmethod + def _replace_escaped_characters(match): + escaped_char = match.group(1) + if escaped_char.isalpha(): + replacements = {"n": "\n", "t": "\t", "r": "\r"} + return replacements.get(escaped_char, escaped_char) + else: + return match.group(0) + + @staticmethod + def _text_of_str(parse_tree: ParseTree) -> str: + pt = Antlr4Utils.is_production(parse_tree) or Antlr4Utils.is_terminal( + parse_tree + ) + inner_str = pt.getText() + inner_str = inner_str[1:-1] + inner_str = re.sub( + r"\\(.)", Preprocessor._replace_escaped_characters, inner_str + ) + return inner_str + + def visitFunc_arg_int( + self, ctx: ASLIntrinsicParser.Func_arg_intContext + ) -> FunctionArgumentInt: + integer = int(ctx.INT().getText()) + return FunctionArgumentInt(integer=integer) + + def visitFunc_arg_float( + self, ctx: ASLIntrinsicParser.Func_arg_floatContext + ) -> FunctionArgumentFloat: + number = float(ctx.INT().getText()) + return FunctionArgumentFloat(number=number) + + def visitFunc_arg_string( + self, ctx: ASLIntrinsicParser.Func_arg_stringContext + ) -> FunctionArgumentString: + text: str = self._text_of_str(ctx.STRING()) + return FunctionArgumentString(string=text) + + def visitContext_path( + self, ctx: ASLIntrinsicParser.Context_pathContext + ) -> FunctionArgumentContextPath: + json_path: str = ctx.json_path().getText() + return FunctionArgumentContextPath(json_path=json_path) + + def visitFunc_arg_json_path( + self, ctx: ASLIntrinsicParser.Func_arg_json_pathContext + ) -> FunctionArgumentJsonPath: + json_path: str = ctx.getText() + return FunctionArgumentJsonPath(json_path=json_path) + + def visitFunc_arg_func_decl( + self, ctx: ASLIntrinsicParser.Func_arg_func_declContext + ) -> FunctionArgumentFunction: + function: Function = self.visit(ctx.func_decl()) + return FunctionArgumentFunction(function=function) + + def visitFunc_arg_bool( + self, ctx: ASLIntrinsicParser.Func_arg_boolContext + ) -> FunctionArgumentBool: + bool_term: TerminalNodeImpl = ctx.children[0] + bool_term_rule: int = bool_term.getSymbol().type + bool_val: bool = bool_term_rule == ASLIntrinsicLexer.TRUE + return FunctionArgumentBool(boolean=bool_val) + + def visitFunc_arg_list( + self, ctx: ASLIntrinsicParser.Func_arg_listContext + ) -> FunctionArgumentList: + arg_list: List[FunctionArgument] = list() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + if isinstance(cmp, FunctionArgument): + arg_list.append(cmp) + return FunctionArgumentList(arg_list=arg_list) + + def visitState_fun_name( + self, ctx: ASLIntrinsicParser.State_fun_nameContext + ) -> StatesFunctionName: + tok_typ: int = ctx.children[0].symbol.type + name_typ = StatesFunctionNameType(tok_typ) + return StatesFunctionName(function_type=name_typ) + + def visitStates_func_decl( + self, ctx: ASLIntrinsicParser.States_func_declContext + ) -> StatesFunction: + func_name: StatesFunctionName = self.visit(ctx.state_fun_name()) + arg_list: FunctionArgumentList = self.visit(ctx.func_arg_list()) + func: StatesFunction = StatesFunctionFactory.from_name( + func_name=func_name, arg_list=arg_list + ) + return func + + def visitFunc_decl(self, ctx: ASLIntrinsicParser.Func_declContext) -> Function: + return self.visit(ctx.children[0]) diff --git a/moto/stepfunctions/parser/asl/parse/preprocessor.py b/moto/stepfunctions/parser/asl/parse/preprocessor.py new file mode 100644 index 000000000..590e5e187 --- /dev/null +++ b/moto/stepfunctions/parser/asl/parse/preprocessor.py @@ -0,0 +1,910 @@ +import json +from typing import List, Optional + +from antlr4 import ParserRuleContext +from antlr4.tree.Tree import ParseTree, TerminalNodeImpl + +from moto.stepfunctions.parser.asl.antlr.runtime.ASLLexer import ASLLexer +from moto.stepfunctions.parser.asl.antlr.runtime.ASLParser import ASLParser +from moto.stepfunctions.parser.asl.antlr.runtime.ASLParserVisitor import ( + ASLParserVisitor, +) +from moto.stepfunctions.parser.asl.antlt4utils.antlr4utils import Antlr4Utils +from moto.stepfunctions.parser.asl.component.common.catch.catch_decl import CatchDecl +from moto.stepfunctions.parser.asl.component.common.catch.catcher_decl import ( + CatcherDecl, +) +from moto.stepfunctions.parser.asl.component.common.catch.catcher_props import ( + CatcherProps, +) +from moto.stepfunctions.parser.asl.component.common.cause_decl import CauseDecl +from moto.stepfunctions.parser.asl.component.common.comment import Comment +from moto.stepfunctions.parser.asl.component.common.error_decl import ErrorDecl +from moto.stepfunctions.parser.asl.component.common.error_name.custom_error_name import ( + CustomErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.error_equals_decl import ( + ErrorEqualsDecl, +) +from moto.stepfunctions.parser.asl.component.common.error_name.error_name import ( + ErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name import ( + StatesErrorName, +) +from moto.stepfunctions.parser.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from moto.stepfunctions.parser.asl.component.common.flow.end import End +from moto.stepfunctions.parser.asl.component.common.flow.next import Next +from moto.stepfunctions.parser.asl.component.common.flow.start_at import StartAt +from moto.stepfunctions.parser.asl.component.common.parameters import Parameters +from moto.stepfunctions.parser.asl.component.common.path.input_path import InputPath +from moto.stepfunctions.parser.asl.component.common.path.items_path import ItemsPath +from moto.stepfunctions.parser.asl.component.common.path.output_path import OutputPath +from moto.stepfunctions.parser.asl.component.common.path.result_path import ResultPath +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payload_value import ( + PayloadValue, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadarr.payload_arr import ( + PayloadArr, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadbinding.payload_binding import ( + PayloadBinding, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadbinding.payload_binding_intrinsic_func import ( + PayloadBindingIntrinsicFunc, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadbinding.payload_binding_path import ( + PayloadBindingPath, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadbinding.payload_binding_path_context_obj import ( + PayloadBindingPathContextObj, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadbinding.payload_binding_value import ( + PayloadBindingValue, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadtmpl.payload_tmpl import ( + PayloadTmpl, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadvaluelit.payload_value_bool import ( + PayloadValueBool, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadvaluelit.payload_value_float import ( + PayloadValueFloat, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadvaluelit.payload_value_int import ( + PayloadValueInt, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadvaluelit.payload_value_null import ( + PayloadValueNull, +) +from moto.stepfunctions.parser.asl.component.common.payload.payloadvalue.payloadvaluelit.payload_value_str import ( + PayloadValueStr, +) +from moto.stepfunctions.parser.asl.component.common.result_selector import ( + ResultSelector, +) +from moto.stepfunctions.parser.asl.component.common.retry.backoff_rate_decl import ( + BackoffRateDecl, +) +from moto.stepfunctions.parser.asl.component.common.retry.interval_seconds_decl import ( + IntervalSecondsDecl, +) +from moto.stepfunctions.parser.asl.component.common.retry.max_attempts_decl import ( + MaxAttemptsDecl, +) +from moto.stepfunctions.parser.asl.component.common.retry.retrier_decl import ( + RetrierDecl, +) +from moto.stepfunctions.parser.asl.component.common.retry.retrier_props import ( + RetrierProps, +) +from moto.stepfunctions.parser.asl.component.common.retry.retry_decl import RetryDecl +from moto.stepfunctions.parser.asl.component.common.timeouts.heartbeat import ( + HeartbeatSeconds, + HeartbeatSecondsPath, +) +from moto.stepfunctions.parser.asl.component.common.timeouts.timeout import ( + TimeoutSeconds, + TimeoutSecondsPath, +) +from moto.stepfunctions.parser.asl.component.common.version import Version +from moto.stepfunctions.parser.asl.component.component import Component +from moto.stepfunctions.parser.asl.component.program.program import Program +from moto.stepfunctions.parser.asl.component.state.state import CommonStateField +from moto.stepfunctions.parser.asl.component.state.state_choice.choice_rule import ( + ChoiceRule, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.choices_decl import ( + ChoicesDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison_composite import ( + ComparisonComposite, + ComparisonCompositeAnd, + ComparisonCompositeNot, + ComparisonCompositeOr, + ComparisonCompositeProps, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison_func import ( + ComparisonFunc, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison_operator_type import ( + ComparisonOperatorType, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.comparison_variable import ( + ComparisonVariable, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.comparison.variable import ( + Variable, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.default_decl import ( + DefaultDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_choice.state_choice import ( + StateChoice, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.execution_type import ( + ExecutionType, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.item_reader_decl import ( + ItemReader, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.csv_header_location import ( + CSVHeaderLocation, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.csv_headers import ( + CSVHeaders, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.input_type import ( + InputType, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.max_items_decl import ( + MaxItems, + MaxItemsDecl, + MaxItemsPath, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_reader.reader_config.reader_config_decl import ( + ReaderConfig, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.item_selector import ( + ItemSelector, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.item_processor_decl import ( + ItemProcessorDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.processor_config import ( + ProcessorConfig, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.iterator.iterator_decl import ( + IteratorDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.max_concurrency import ( + MaxConcurrency, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.mode import ( + Mode, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.state_map import ( + StateMap, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_parallel.branches_decl import ( + BranchesDecl, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_parallel.state_parallel import ( + StateParallel, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.service.resource import ( + Resource, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_task.state_task_factory import ( + state_task_for, +) +from moto.stepfunctions.parser.asl.component.state.state_fail.state_fail import ( + StateFail, +) +from moto.stepfunctions.parser.asl.component.state.state_pass.result import Result +from moto.stepfunctions.parser.asl.component.state.state_pass.state_pass import ( + StatePass, +) +from moto.stepfunctions.parser.asl.component.state.state_props import StateProps +from moto.stepfunctions.parser.asl.component.state.state_succeed.state_succeed import ( + StateSucceed, +) +from moto.stepfunctions.parser.asl.component.state.state_type import StateType +from moto.stepfunctions.parser.asl.component.state.state_wait.state_wait import ( + StateWait, +) +from moto.stepfunctions.parser.asl.component.state.state_wait.wait_function.seconds import ( + Seconds, +) +from moto.stepfunctions.parser.asl.component.state.state_wait.wait_function.seconds_path import ( + SecondsPath, +) +from moto.stepfunctions.parser.asl.component.state.state_wait.wait_function.timestamp import ( + Timestamp, +) +from moto.stepfunctions.parser.asl.component.state.state_wait.wait_function.timestamp_path import ( + TimestampPath, +) +from moto.stepfunctions.parser.asl.component.states import States +from moto.stepfunctions.parser.asl.parse.typed_props import TypedProps + + +class Preprocessor(ASLParserVisitor): + @staticmethod + def _inner_string_of(parse_tree: ParseTree) -> Optional[str]: + if Antlr4Utils.is_terminal(parse_tree, ASLLexer.NULL): + return None + pt = Antlr4Utils.is_production(parse_tree) or Antlr4Utils.is_terminal( + parse_tree + ) + inner_str = pt.getText() + if inner_str.startswith('"') and inner_str.endswith('"'): + inner_str = inner_str[1:-1] + return inner_str + + def visitComment_decl(self, ctx: ASLParser.Comment_declContext) -> Comment: + inner_str = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return Comment(comment=inner_str) + + def visitVersion_decl(self, ctx: ASLParser.Version_declContext) -> Version: + version_str = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return Version(version=version_str) + + def visitStartat_decl(self, ctx: ASLParser.Startat_declContext) -> StartAt: + inner_str = self._inner_string_of( + parse_tree=ctx.keyword_or_string(), + ) + return StartAt(start_at_name=inner_str) + + def visitStates_decl(self, ctx: ASLParser.States_declContext) -> States: + states = States() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + if isinstance(cmp, CommonStateField): + # TODO move check to setter or checker layer? + if cmp.name in states.states: + raise ValueError(f"State redefinition {child.getText()}") + states.states[cmp.name] = cmp + return states + + def visitType_decl(self, ctx: ASLParser.Type_declContext) -> StateType: + return self.visit(ctx.state_type()) + + def visitState_type(self, ctx: ASLParser.State_typeContext) -> StateType: + state_type: int = ctx.children[0].symbol.type + return StateType(state_type) + + def visitResource_decl(self, ctx: ASLParser.Resource_declContext) -> Resource: + inner_str = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return Resource.from_resource_arn(inner_str) + + def visitEnd_decl(self, ctx: ASLParser.End_declContext) -> End: + bool_child: ParseTree = ctx.children[-1] + bool_term: Optional[TerminalNodeImpl] = Antlr4Utils.is_terminal(bool_child) + if bool_term is None: + raise ValueError( + f"Could not derive End from declaration context '{ctx.getText()}'" + ) + bool_term_rule: int = bool_term.getSymbol().type + is_end = bool_term_rule == ASLLexer.TRUE + return End(is_end=is_end) + + def visitNext_decl(self, ctx: ASLParser.Next_declContext) -> Next: + inner_str = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return Next(name=inner_str) + + def visitResult_path_decl( + self, ctx: ASLParser.Result_path_declContext + ) -> ResultPath: + inner_str = self._inner_string_of(parse_tree=ctx.children[-1]) + return ResultPath(result_path_src=inner_str) + + def visitInput_path_decl(self, ctx: ASLParser.Input_path_declContext) -> InputPath: + inner_str = self._inner_string_of(parse_tree=ctx.children[-1]) + return InputPath(input_path_src=inner_str) + + def visitOutput_path_decl(self, ctx: ASLParser.Output_path_declContext): + inner_str = self._inner_string_of(parse_tree=ctx.children[-1]) + return OutputPath(output_path=inner_str) + + def visitResult_decl(self, ctx: ASLParser.Result_declContext) -> Result: + json_decl = ctx.json_value_decl() + json_str: str = json_decl.getText() + json_obj: json = json.loads(json_str) + return Result(result_obj=json_obj) + + def visitParameters_decl(self, ctx: ASLParser.Parameters_declContext) -> Parameters: + payload_tmpl: PayloadTmpl = self.visit(ctx.payload_tmpl_decl()) + return Parameters(payload_tmpl=payload_tmpl) + + def visitTimeout_seconds_decl( + self, ctx: ASLParser.Timeout_seconds_declContext + ) -> TimeoutSeconds: + seconds = int(ctx.INT().getText()) + return TimeoutSeconds(timeout_seconds=seconds) + + def visitTimeout_seconds_path_decl( + self, ctx: ASLParser.Timeout_seconds_path_declContext + ) -> TimeoutSecondsPath: + path: str = self._inner_string_of(parse_tree=ctx.STRINGPATH()) + return TimeoutSecondsPath(path=path) + + def visitHeartbeat_seconds_decl( + self, ctx: ASLParser.Heartbeat_seconds_declContext + ) -> HeartbeatSeconds: + seconds = int(ctx.INT().getText()) + return HeartbeatSeconds(heartbeat_seconds=seconds) + + def visitHeartbeat_seconds_path_decl( + self, ctx: ASLParser.Heartbeat_seconds_path_declContext + ) -> HeartbeatSecondsPath: + path: str = self._inner_string_of(parse_tree=ctx.STRINGPATH()) + return HeartbeatSecondsPath(path=path) + + def visitResult_selector_decl( + self, ctx: ASLParser.Result_selector_declContext + ) -> ResultSelector: + payload_tmpl: PayloadTmpl = self.visit(ctx.payload_tmpl_decl()) + return ResultSelector(payload_tmpl=payload_tmpl) + + def visitBranches_decl(self, ctx: ASLParser.Branches_declContext) -> BranchesDecl: + programs: List[Program] = [] + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + if isinstance(cmp, Program): + programs.append(cmp) + return BranchesDecl(programs=programs) + + def visitState_decl_body(self, ctx: ASLParser.State_decl_bodyContext) -> StateProps: + state_props = StateProps() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + state_props.add(cmp) + return state_props + + def visitState_decl(self, ctx: ASLParser.State_declContext) -> CommonStateField: + state_name = self._inner_string_of(parse_tree=ctx.state_name()) + state_props: StateProps = self.visit(ctx.state_decl_body()) + state_props.name = state_name + return self._common_state_field_of(state_props=state_props) + + @staticmethod + def _common_state_field_of(state_props: StateProps) -> CommonStateField: + # TODO: use subtype loading strategy. + if state_props.get(StateType) == StateType.Task: + resource: Resource = state_props.get(Resource) + state = state_task_for(resource) + elif state_props.get(StateType) == StateType.Pass: + state = StatePass() + elif state_props.get(StateType) == StateType.Choice: + state = StateChoice() + elif state_props.get(StateType) == StateType.Fail: + state = StateFail() + elif state_props.get(StateType) == StateType.Succeed: + state = StateSucceed() + elif state_props.get(StateType) == StateType.Wait: + state = StateWait() + elif state_props.get(StateType) == StateType.Map: + state = StateMap() + elif state_props.get(StateType) == StateType.Parallel: + state = StateParallel() + elif state_props.get(StateType) is None: + raise TypeError("No Type declaration for State in context.") + else: + raise TypeError( + f"Unknown StateType value '{state_props.get(StateType)}' in StateProps object in context." # noqa + ) + state.from_state_props(state_props) + return state + + def visitVariable_decl(self, ctx: ASLParser.Variable_declContext) -> Variable: + value: str = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return Variable(value=value) + + def visitComparison_op( + self, ctx: ASLParser.Comparison_opContext + ) -> ComparisonOperatorType: + try: + operator_type: int = ctx.children[0].symbol.type + return ComparisonOperatorType(operator_type) + except Exception: + raise ValueError( + f"Could not derive ComparisonOperator from context '{ctx.getText()}'." + ) + + def visitComparison_func( + self, ctx: ASLParser.Comparison_funcContext + ) -> ComparisonFunc: + comparison_op: ComparisonOperatorType = self.visit(ctx.comparison_op()) + + json_decl = ctx.json_value_decl() + json_str: str = json_decl.getText() + json_obj: json = json.loads(json_str) + + return ComparisonFunc(operator=comparison_op, value=json_obj) + + def visitDefault_decl(self, ctx: ASLParser.Default_declContext) -> DefaultDecl: + state_name = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return DefaultDecl(state_name=state_name) + + def visitChoice_operator( + self, ctx: ASLParser.Choice_operatorContext + ) -> ComparisonComposite.ChoiceOp: + pt: Optional[TerminalNodeImpl] = Antlr4Utils.is_terminal(ctx.children[0]) + if not pt: + raise ValueError( + f"Could not derive ChoiceOperator in block '{ctx.getText()}'." + ) + return ComparisonComposite.ChoiceOp(pt.symbol.type) + + def visitComparison_composite( + self, ctx: ASLParser.Comparison_compositeContext + ) -> ComparisonComposite: + choice_op: ComparisonComposite.ChoiceOp = self.visit(ctx.choice_operator()) + rules: List[ChoiceRule] = list() + for child in ctx.children[1:]: + cmp: Optional[Component] = self.visit(child) + if not cmp: + continue + elif isinstance(cmp, ChoiceRule): + rules.append(cmp) + + if choice_op == ComparisonComposite.ChoiceOp.Not: + if len(rules) != 1: + raise ValueError( + f"ComparisonCompositeNot must carry only one ComparisonCompositeStmt in: '{ctx.getText()}'." + ) + return ComparisonCompositeNot(rule=rules[0]) + elif choice_op == ComparisonComposite.ChoiceOp.And: + return ComparisonCompositeAnd(rules=rules) + elif choice_op == ComparisonComposite.ChoiceOp.Or: + return ComparisonCompositeOr(rules=rules) + + def visitChoice_rule_comparison_composite( + self, ctx: ASLParser.Choice_rule_comparison_compositeContext + ) -> ChoiceRule: + composite_stmts = ComparisonCompositeProps() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + composite_stmts.add(cmp) + return ChoiceRule( + comparison=composite_stmts.get( + typ=ComparisonComposite, + raise_on_missing=ValueError( + f"Expecting a 'ComparisonComposite' definition at '{ctx.getText()}'." + ), + ), + next_stmt=composite_stmts.get(Next), + ) + + def visitChoice_rule_comparison_variable( + self, ctx: ASLParser.Choice_rule_comparison_variableContext + ) -> ChoiceRule: + comparison_stmts = TypedProps() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + comparison_stmts.add(cmp) + variable: Variable = comparison_stmts.get( + typ=Variable, + raise_on_missing=ValueError( + f"Expected a Variable declaration in '{ctx.getText()}'." + ), + ) + comparison_func: ComparisonFunc = comparison_stmts.get( + typ=ComparisonFunc, + raise_on_missing=ValueError( + f"Expected a ComparisonFunc declaration in '{ctx.getText()}'." + ), + ) + comparison_variable = ComparisonVariable( + variable=variable, func=comparison_func + ) + return ChoiceRule( + comparison=comparison_variable, next_stmt=comparison_stmts.get(Next) + ) + + def visitChoices_decl(self, ctx: ASLParser.Choices_declContext) -> ChoicesDecl: + rules: List[ChoiceRule] = list() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + if not cmp: + continue + elif isinstance(cmp, ChoiceRule): + rules.append(cmp) + return ChoicesDecl(rules=rules) + + def visitError_decl(self, ctx: ASLParser.Error_declContext) -> ErrorDecl: + error = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return ErrorDecl(error=error) + + def visitCause_decl(self, ctx: ASLParser.Cause_declContext) -> CauseDecl: + cause = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return CauseDecl(cause=cause) + + def visitSeconds_decl(self, ctx: ASLParser.Seconds_declContext) -> Seconds: + return Seconds(seconds=int(ctx.INT().getText())) + + def visitSeconds_path_decl( + self, ctx: ASLParser.Seconds_path_declContext + ) -> SecondsPath: + path = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return SecondsPath(path=path) + + def visitItems_path_decl(self, ctx: ASLParser.Items_path_declContext) -> ItemsPath: + path = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return ItemsPath(items_path_src=path) + + def visitMax_concurrency_decl( + self, ctx: ASLParser.Max_concurrency_declContext + ) -> MaxConcurrency: + return MaxConcurrency(num=int(ctx.INT().getText())) + + def visitMode_decl(self, ctx: ASLParser.Mode_declContext) -> Mode: + mode_type: int = self.visit(ctx.mode_type()) + return Mode(mode_type) + + def visitMode_type(self, ctx: ASLParser.Mode_typeContext) -> int: + return ctx.children[0].symbol.type + + def visitExecution_decl( + self, ctx: ASLParser.Execution_declContext + ) -> ExecutionType: + execution_type: int = self.visit(ctx.execution_type()) + return ExecutionType(execution_type) + + def visitExecution_type(self, ctx: ASLParser.Execution_typeContext) -> int: + return ctx.children[0].symbol.type + + def visitTimestamp_decl(self, ctx: ASLParser.Seconds_path_declContext) -> Timestamp: + timestamp_str = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + timestamp = Timestamp.parse_timestamp(timestamp_str) + return Timestamp(timestamp=timestamp) + + def visitTimestamp_path_decl( + self, ctx: ASLParser.Timestamp_path_declContext + ) -> TimestampPath: + path = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return TimestampPath(path=path) + + def visitProcessor_config_decl( + self, ctx: ASLParser.Processor_config_declContext + ) -> ProcessorConfig: + props = TypedProps() + for child in ctx.children: + cmp = self.visit(child) + props.add(cmp) + return ProcessorConfig( + mode=props.get(typ=Mode) or ProcessorConfig.DEFAULT_MODE, + execution_type=props.get(typ=ExecutionType) + or ProcessorConfig.DEFAULT_EXECUTION_TYPE, + ) + + def visitItem_processor_item( + self, ctx: ASLParser.Item_processor_itemContext + ) -> Component: + return self.visit(ctx.children[0]) + + def visitItem_processor_decl( + self, ctx: ASLParser.Item_processor_declContext + ) -> ItemProcessorDecl: + props = TypedProps() + for child in ctx.children: + cmp = self.visit(child) + props.add(cmp) + return ItemProcessorDecl( + comment=props.get(typ=Comment), + start_at=props.get( + typ=StartAt, + raise_on_missing=ValueError( + f"Expected a StartAt declaration at '{ctx.getText()}'." + ), + ), + states=props.get( + typ=States, + raise_on_missing=ValueError( + f"Expected a States declaration at '{ctx.getText()}'." + ), + ), + processor_config=props.get(typ=ProcessorConfig), + ) + + def visitIterator_decl(self, ctx: ASLParser.Iterator_declContext) -> IteratorDecl: + props = TypedProps() + for child in ctx.children: + cmp = self.visit(child) + props.add(cmp) + return IteratorDecl( + comment=props.get(typ=Comment), + start_at=props.get( + typ=StartAt, + raise_on_missing=ValueError( + f"Expected a StartAt declaration at '{ctx.getText()}'." + ), + ), + states=props.get( + typ=States, + raise_on_missing=ValueError( + f"Expected a States declaration at '{ctx.getText()}'." + ), + ), + ) + + def visitItem_selector_decl( + self, ctx: ASLParser.Item_selector_declContext + ) -> ItemSelector: + payload_tmpl: PayloadTmpl = self.visit(ctx.payload_tmpl_decl()) + return ItemSelector(payload_tmpl=payload_tmpl) + + def visitItem_reader_decl( + self, ctx: ASLParser.Item_reader_declContext + ) -> ItemReader: + props = StateProps() + for child in ctx.children[3:-1]: + cmp = self.visit(child) + props.add(cmp) + resource: Resource = props.get( + typ=Resource, + raise_on_missing=ValueError( + f"Expected a Resource declaration at '{ctx.getText()}'." + ), + ) + return ItemReader( + resource=resource, + parameters=props.get(Parameters), + reader_config=props.get(ReaderConfig), + ) + + def visitReader_config_decl( + self, ctx: ASLParser.Reader_config_declContext + ) -> ReaderConfig: + props = TypedProps() + for child in ctx.children: + cmp = self.visit(child) + props.add(cmp) + return ReaderConfig( + input_type=props.get( + typ=InputType, + raise_on_missing=ValueError( + f"Expected a InputType declaration at '{ctx.getText()}'." + ), + ), + max_items=props.get(typ=MaxItemsDecl), + csv_header_location=props.get(CSVHeaderLocation), + csv_headers=props.get(CSVHeaders), + ) + + def visitInput_type_decl(self, ctx: ASLParser.Input_type_declContext) -> InputType: + input_type = self._inner_string_of(ctx.keyword_or_string()) + return InputType(input_type=input_type) + + def visitCsv_header_location_decl( + self, ctx: ASLParser.Csv_header_location_declContext + ) -> CSVHeaderLocation: + value = self._inner_string_of(ctx.keyword_or_string()) + return CSVHeaderLocation(csv_header_location_value=value) + + def visitCsv_headers_decl( + self, ctx: ASLParser.Csv_headers_declContext + ) -> CSVHeaders: + csv_headers: List[str] = list() + for child in ctx.children[3:-1]: + maybe_str = Antlr4Utils.is_production( + pt=child, rule_index=ASLParser.RULE_keyword_or_string + ) + if maybe_str is not None: + csv_headers.append(self._inner_string_of(maybe_str)) + # TODO: check for empty headers behaviour. + return CSVHeaders(header_names=csv_headers) + + def visitMax_items_path_decl( + self, ctx: ASLParser.Max_items_path_declContext + ) -> MaxItemsPath: + path: str = self._inner_string_of(parse_tree=ctx.STRINGPATH()) + return MaxItemsPath(path=path) + + def visitMax_items_decl(self, ctx: ASLParser.Max_items_declContext) -> MaxItems: + return MaxItems(max_items=int(ctx.INT().getText())) + + def visitRetry_decl(self, ctx: ASLParser.Retry_declContext) -> RetryDecl: + retriers: List[RetrierDecl] = list() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + if isinstance(cmp, RetrierDecl): + retriers.append(cmp) + return RetryDecl(retriers=retriers) + + def visitRetrier_decl(self, ctx: ASLParser.Retrier_declContext) -> RetrierDecl: + props = RetrierProps() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + props.add(cmp) + return RetrierDecl.from_retrier_props(props=props) + + def visitRetrier_stmt(self, ctx: ASLParser.Retrier_stmtContext): + return self.visit(ctx.children[0]) + + def visitError_equals_decl( + self, ctx: ASLParser.Error_equals_declContext + ) -> ErrorEqualsDecl: + error_names: List[ErrorName] = list() + for child in ctx.children: + cmp = self.visit(child) + if isinstance(cmp, ErrorName): + error_names.append(cmp) + return ErrorEqualsDecl(error_names=error_names) + + def visitError_name(self, ctx: ASLParser.Error_nameContext) -> ErrorName: + pt = ctx.children[0] + + # Case: StatesErrorName. + prc: Optional[ParserRuleContext] = Antlr4Utils.is_production( + pt=pt, rule_index=ASLParser.RULE_states_error_name + ) + if prc: + return self.visit(prc) + + # Case CustomErrorName. + error_name = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return CustomErrorName(error_name=error_name) + + def visitStates_error_name( + self, ctx: ASLParser.States_error_nameContext + ) -> StatesErrorName: + pt: Optional[TerminalNodeImpl] = Antlr4Utils.is_terminal(ctx.children[0]) + if not pt: + raise ValueError(f"Could not derive ErrorName in block '{ctx.getText()}'.") + states_error_name_type = StatesErrorNameType(pt.symbol.type) + return StatesErrorName(states_error_name_type) + + def visitInterval_seconds_decl( + self, ctx: ASLParser.Interval_seconds_declContext + ) -> IntervalSecondsDecl: + return IntervalSecondsDecl(seconds=int(ctx.INT().getText())) + + def visitMax_attempts_decl( + self, ctx: ASLParser.Max_attempts_declContext + ) -> MaxAttemptsDecl: + return MaxAttemptsDecl(attempts=int(ctx.INT().getText())) + + def visitBackoff_rate_decl( + self, ctx: ASLParser.Backoff_rate_declContext + ) -> BackoffRateDecl: + return BackoffRateDecl(rate=float(ctx.children[-1].getText())) + + def visitCatch_decl(self, ctx: ASLParser.Catch_declContext) -> CatchDecl: + catchers: List[CatcherDecl] = list() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + if isinstance(cmp, CatcherDecl): + catchers.append(cmp) + return CatchDecl(catchers=catchers) + + def visitCatcher_decl(self, ctx: ASLParser.Catcher_declContext) -> CatcherDecl: + props = CatcherProps() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + props.add(cmp) + return CatcherDecl.from_catcher_props(props=props) + + def visitPayload_value_float( + self, ctx: ASLParser.Payload_value_floatContext + ) -> PayloadValueFloat: + return PayloadValueFloat(val=float(ctx.NUMBER().getText())) + + def visitPayload_value_int( + self, ctx: ASLParser.Payload_value_intContext + ) -> PayloadValueInt: + return PayloadValueInt(val=int(ctx.INT().getText())) + + def visitPayload_value_bool( + self, ctx: ASLParser.Payload_value_boolContext + ) -> PayloadValueBool: + bool_child: ParseTree = ctx.children[0] + bool_term: Optional[TerminalNodeImpl] = Antlr4Utils.is_terminal(bool_child) + if bool_term is None: + raise ValueError( + f"Could not derive PayloadValueBool from declaration context '{ctx.getText()}'." + ) + bool_term_rule: int = bool_term.getSymbol().type + bool_val: bool = bool_term_rule == ASLLexer.TRUE + return PayloadValueBool(val=bool_val) + + def visitPayload_value_null( + self, ctx: ASLParser.Payload_value_nullContext + ) -> PayloadValueNull: + return PayloadValueNull() + + def visitPayload_value_str( + self, ctx: ASLParser.Payload_value_strContext + ) -> PayloadValueStr: + str_val = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + return PayloadValueStr(val=str_val) + + def visitPayload_binding_path( + self, ctx: ASLParser.Payload_binding_pathContext + ) -> PayloadBindingPath: + string_dollar: str = self._inner_string_of(parse_tree=ctx.STRINGDOLLAR()) + string_path: str = self._inner_string_of(parse_tree=ctx.STRINGPATH()) + return PayloadBindingPath.from_raw( + string_dollar=string_dollar, string_path=string_path + ) + + def visitPayload_binding_path_context_obj( + self, ctx: ASLParser.Payload_binding_path_context_objContext + ) -> PayloadBindingPathContextObj: + string_dollar: str = self._inner_string_of(parse_tree=ctx.STRINGDOLLAR()) + string_path_context_obj: str = self._inner_string_of( + parse_tree=ctx.STRINGPATHCONTEXTOBJ() + ) + return PayloadBindingPathContextObj.from_raw( + string_dollar=string_dollar, string_path_context_obj=string_path_context_obj + ) + + def visitPayload_binding_intrinsic_func( + self, ctx: ASLParser.Payload_binding_intrinsic_funcContext + ) -> PayloadBindingIntrinsicFunc: + string_dollar: str = self._inner_string_of(parse_tree=ctx.STRINGDOLLAR()) + intrinsic_func: str = self._inner_string_of(parse_tree=ctx.intrinsic_func()) + return PayloadBindingIntrinsicFunc.from_raw( + string_dollar=string_dollar, intrinsic_func=intrinsic_func + ) + + def visitPayload_binding_value( + self, ctx: ASLParser.Payload_binding_valueContext + ) -> PayloadBindingValue: + field: str = self._inner_string_of(parse_tree=ctx.keyword_or_string()) + value: PayloadValue = self.visit(ctx.payload_value_decl()) + return PayloadBindingValue(field=field, value=value) + + def visitPayload_arr_decl( + self, ctx: ASLParser.Payload_arr_declContext + ) -> PayloadArr: + payload_values: List[PayloadValue] = list() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + if isinstance(cmp, PayloadValue): + payload_values.append(cmp) + return PayloadArr(payload_values=payload_values) + + def visitPayload_tmpl_decl( + self, ctx: ASLParser.Payload_tmpl_declContext + ) -> PayloadTmpl: + payload_bindings: List[PayloadBinding] = list() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + if isinstance(cmp, PayloadBinding): + payload_bindings.append(cmp) + return PayloadTmpl(payload_bindings=payload_bindings) + + def visitPayload_value_decl( + self, ctx: ASLParser.Payload_value_declContext + ) -> PayloadValue: + value = ctx.children[0] + return self.visit(value) + + def visitProgram_decl(self, ctx: ASLParser.Program_declContext) -> Program: + props = TypedProps() + for child in ctx.children: + cmp: Optional[Component] = self.visit(child) + props.add(cmp) + + program = Program( + start_at=props.get( + typ=StartAt, + raise_on_missing=ValueError( + f"No '{StartAt}' definition for Program in context: '{ctx.getText()}'." + ), + ), + states=props.get( + typ=States, + raise_on_missing=ValueError( + f"No '{States}' definition for Program in context: '{ctx.getText()}'." + ), + ), + timeout_seconds=props.get(TimeoutSeconds), + comment=props.get(typ=Comment), + version=props.get(typ=Version), + ) + return program diff --git a/moto/stepfunctions/parser/asl/parse/typed_props.py b/moto/stepfunctions/parser/asl/parse/typed_props.py new file mode 100644 index 000000000..4e66570c9 --- /dev/null +++ b/moto/stepfunctions/parser/asl/parse/typed_props.py @@ -0,0 +1,32 @@ +from collections import OrderedDict +from typing import Any, Dict, Optional + + +class TypedProps: + def __init__(self): + self._instance_by_type: Dict[type, Any] = OrderedDict() + + def add(self, instance: Any) -> None: + self._add(type(instance), instance) + + def _add(self, typ: type, instance: Any) -> None: + if instance is None: + return + if typ in self._instance_by_type: + raise ValueError( + f"Redefinition of type '{typ}', from '{self._instance_by_type[typ]}' to '{instance}'." + ) + self._instance_by_type[typ] = instance + + def get( + self, typ: type, raise_on_missing: Optional[Exception] = None + ) -> Optional[Any]: + if raise_on_missing and typ not in self._instance_by_type: + raise raise_on_missing + return self._instance_by_type.get(typ) + + def __repr__(self): + return str(self._instance_by_type) + + def __str__(self): + return repr(self) diff --git a/moto/stepfunctions/parser/asl/utils/__init__.py b/moto/stepfunctions/parser/asl/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/asl/utils/boto_client.py b/moto/stepfunctions/parser/asl/utils/boto_client.py new file mode 100644 index 000000000..912a835c3 --- /dev/null +++ b/moto/stepfunctions/parser/asl/utils/boto_client.py @@ -0,0 +1,29 @@ +import boto3 +from botocore.client import BaseClient +from botocore.config import Config + +from moto.core.models import botocore_stubber +from moto.settings import moto_server_port +from moto.stepfunctions.parser.asl.component.common.timeouts.timeout import ( + TimeoutSeconds, +) + + +def boto_client_for(region: str, account: str, service: str) -> BaseClient: + intercepting_boto_calls = botocore_stubber.enabled + kwargs = {} + if not intercepting_boto_calls: + kwargs["endpoint_url"] = f"http://localhost:{moto_server_port()}" + return boto3.client( + aws_access_key_id=account, + region_name=region, + service_name=service, + aws_secret_access_key="sk", + config=Config( + parameter_validation=False, + retries={"max_attempts": 0, "total_max_attempts": 1}, + connect_timeout=TimeoutSeconds.DEFAULT_TIMEOUT_SECONDS, + read_timeout=TimeoutSeconds.DEFAULT_TIMEOUT_SECONDS, + ), + **kwargs, + ) diff --git a/moto/stepfunctions/parser/asl/utils/encoding.py b/moto/stepfunctions/parser/asl/utils/encoding.py new file mode 100644 index 000000000..2c8846fba --- /dev/null +++ b/moto/stepfunctions/parser/asl/utils/encoding.py @@ -0,0 +1,16 @@ +import datetime +import json +from json import JSONEncoder +from typing import Any, Optional, Tuple + + +class _DateTimeEncoder(JSONEncoder): + def default(self, o): + if isinstance(o, (datetime.date, datetime.datetime)): + return o.isoformat() + else: + return str(o) + + +def to_json_str(obj: Any, separators: Optional[Tuple[str, str]] = None) -> str: + return json.dumps(obj, cls=_DateTimeEncoder, separators=separators) diff --git a/moto/stepfunctions/parser/asl/utils/json_path.py b/moto/stepfunctions/parser/asl/utils/json_path.py new file mode 100644 index 000000000..3df6c9189 --- /dev/null +++ b/moto/stepfunctions/parser/asl/utils/json_path.py @@ -0,0 +1,21 @@ +import json + +from jsonpath_ng import parse + +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str + + +class JSONPathUtils: + @staticmethod + def extract_json(path: str, data: json) -> json: + input_expr = parse(path) + find_res = [match.value for match in input_expr.find(data)] + if find_res == list(): + raise RuntimeError( + f"The JSONPath {path} could not be found in the input {to_json_str(data)}" + ) + if len(find_res) == 1: + value = find_res[0] + else: + value = find_res + return value diff --git a/moto/stepfunctions/parser/backend/__init__.py b/moto/stepfunctions/parser/backend/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/backend/execution.py b/moto/stepfunctions/parser/backend/execution.py new file mode 100644 index 000000000..5cfe66262 --- /dev/null +++ b/moto/stepfunctions/parser/backend/execution.py @@ -0,0 +1,186 @@ +from __future__ import annotations + +import datetime +import logging +from typing import Optional + +from moto.core.utils import iso_8601_datetime_with_milliseconds +from moto.stepfunctions.models import Execution as SimpleExecution +from moto.stepfunctions.models import StateMachine +from moto.stepfunctions.parser.api import ( + CloudWatchEventsExecutionDataDetails, + DescribeStateMachineForExecutionOutput, + ExecutionListItem, + ExecutionStatus, + InvalidName, + TraceHeader, +) +from moto.stepfunctions.parser.asl.eval.aws_execution_details import AWSExecutionDetails +from moto.stepfunctions.parser.asl.eval.contextobject.contex_object import ( + ContextObjectInitData, +) +from moto.stepfunctions.parser.asl.eval.contextobject.contex_object import ( + Execution as ContextObjectExecution, +) +from moto.stepfunctions.parser.asl.eval.contextobject.contex_object import ( + StateMachine as ContextObjectStateMachine, +) +from moto.stepfunctions.parser.asl.eval.program_state import ( + ProgramEnded, + ProgramError, + ProgramState, + ProgramStopped, + ProgramTimedOut, +) +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str +from moto.stepfunctions.parser.backend.execution_worker import ExecutionWorker +from moto.stepfunctions.parser.backend.execution_worker_comm import ExecutionWorkerComm +from moto.stepfunctions.parser.backend.state_machine import ( + StateMachineInstance, + StateMachineVersion, +) + +LOG = logging.getLogger(__name__) + + +class BaseExecutionWorkerComm(ExecutionWorkerComm): + def __init__(self, execution: Execution): + self.execution: Execution = execution + + def terminated(self) -> None: + exit_program_state: ProgramState = ( + self.execution.exec_worker.env.program_state() + ) + self.execution.stop_date = iso_8601_datetime_with_milliseconds() + if isinstance(exit_program_state, ProgramEnded): + self.execution.status = ExecutionStatus.SUCCEEDED + self.execution.output = to_json_str( + self.execution.exec_worker.env.inp, separators=(",", ":") + ) + elif isinstance(exit_program_state, ProgramStopped): + self.execution.status = ExecutionStatus.ABORTED + elif isinstance(exit_program_state, ProgramError): + self.execution.status = ExecutionStatus.FAILED + self.execution.error = exit_program_state.error.get("error") + self.execution.cause = exit_program_state.error.get("cause") + elif isinstance(exit_program_state, ProgramTimedOut): + self.execution.status = ExecutionStatus.TIMED_OUT + else: + raise RuntimeWarning( + f"Execution ended with unsupported ProgramState type '{type(exit_program_state)}'." + ) + + +class Execution(SimpleExecution): + def __init__( + self, + name: str, + role_arn: str, + account_id: str, + region_name: str, + state_machine: StateMachine, + input_data: Optional[dict] = None, + trace_header: Optional[TraceHeader] = None, + ): + super().__init__( + region_name=region_name, + account_id=account_id, + state_machine_name=state_machine.name, + state_machine_arn=state_machine.arn, + execution_name=name, + execution_input=input_data, + ) + self.role_arn = role_arn + self.state_machine = state_machine + self.input_data = input_data + self.input_details = CloudWatchEventsExecutionDataDetails(included=True) + self.trace_header = trace_header + self.status = None + self.output_details = CloudWatchEventsExecutionDataDetails(included=True) + self.exec_worker: Optional[ExecutionWorker] = None + + def to_describe_state_machine_for_execution_output( + self, + ) -> DescribeStateMachineForExecutionOutput: + state_machine: StateMachineInstance = self.state_machine + state_machine_arn = ( + state_machine.source_arn + if isinstance(state_machine, StateMachineVersion) + else state_machine.arn + ) + out = DescribeStateMachineForExecutionOutput( + stateMachineArn=state_machine_arn, + name=state_machine.name, + definition=state_machine.definition, + roleArn=self.role_arn, + # The date and time the state machine associated with an execution was updated. + updateDate=state_machine.create_date, + ) + revision_id = self.state_machine.revision_id + if self.state_machine.revision_id: + out["revisionId"] = revision_id + return out + + def to_execution_list_item(self) -> ExecutionListItem: + if isinstance(self.state_machine, StateMachineVersion): + state_machine_arn = self.state_machine.source_arn + state_machine_version_arn = self.state_machine.arn + else: + state_machine_arn = self.state_machine.arn + state_machine_version_arn = None + + item = ExecutionListItem( + executionArn=self.execution_arn, + stateMachineArn=state_machine_arn, + name=self.name, + status=self.status, + startDate=self.start_date, + stopDate=self.stop_date, + ) + if state_machine_version_arn is not None: + item["stateMachineVersionArn"] = state_machine_version_arn + return item + + def to_history_output(self): + return self.exec_worker.env.event_history.get_event_history() + + @staticmethod + def _to_serialized_date(timestamp: datetime.datetime) -> str: + """See test in tests.aws.services.stepfunctions.v2.base.test_base.TestSnfBase.test_execution_dateformat""" + return f'{timestamp.astimezone(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]}Z' + + def start(self) -> None: + # TODO: checks exec_worker does not exists already? + if self.exec_worker: + raise InvalidName() # TODO. + self.exec_worker = ExecutionWorker( + definition=self.state_machine.definition, + input_data=self.input_data, + exec_comm=BaseExecutionWorkerComm(self), + context_object_init=ContextObjectInitData( + Execution=ContextObjectExecution( + Id=self.execution_arn, + Input=self.input_data, + Name=self.name, + RoleArn=self.role_arn, + StartTime=self.start_date, + ), + StateMachine=ContextObjectStateMachine( + Id=self.state_machine.arn, + Name=self.state_machine.name, + ), + ), + aws_execution_details=AWSExecutionDetails( + account=self.account_id, region=self.region_name, role_arn=self.role_arn + ), + ) + self.status = ExecutionStatus.RUNNING + self.exec_worker.start() + + def stop( + self, stop_date: datetime.datetime, error: Optional[str], cause: Optional[str] + ): + exec_worker: Optional[ExecutionWorker] = self.exec_worker + if not exec_worker: + raise RuntimeError("No running executions.") + exec_worker.stop(stop_date=stop_date, cause=cause, error=error) diff --git a/moto/stepfunctions/parser/backend/execution_worker.py b/moto/stepfunctions/parser/backend/execution_worker.py new file mode 100644 index 000000000..a6ec968e8 --- /dev/null +++ b/moto/stepfunctions/parser/backend/execution_worker.py @@ -0,0 +1,84 @@ +import copy +import datetime +from threading import Thread +from typing import Final, Optional + +from moto.stepfunctions.parser.api import ( + Definition, + ExecutionStartedEventDetails, + HistoryEventExecutionDataDetails, + HistoryEventType, +) +from moto.stepfunctions.parser.asl.component.program.program import Program +from moto.stepfunctions.parser.asl.eval.aws_execution_details import AWSExecutionDetails +from moto.stepfunctions.parser.asl.eval.contextobject.contex_object import ( + ContextObjectInitData, +) +from moto.stepfunctions.parser.asl.eval.environment import Environment +from moto.stepfunctions.parser.asl.eval.event.event_detail import EventDetails +from moto.stepfunctions.parser.asl.eval.event.event_history import EventHistoryContext +from moto.stepfunctions.parser.asl.parse.asl_parser import AmazonStateLanguageParser +from moto.stepfunctions.parser.asl.utils.encoding import to_json_str +from moto.stepfunctions.parser.backend.execution_worker_comm import ExecutionWorkerComm + + +class ExecutionWorker: + env: Optional[Environment] + _definition: Definition + _input_data: Optional[dict] + _exec_comm: Final[ExecutionWorkerComm] + _context_object_init: Final[ContextObjectInitData] + _aws_execution_details: Final[AWSExecutionDetails] + + def __init__( + self, + definition: Definition, + input_data: Optional[dict], + context_object_init: ContextObjectInitData, + aws_execution_details: AWSExecutionDetails, + exec_comm: ExecutionWorkerComm, + ): + self._definition = definition + self._input_data = input_data + self._exec_comm = exec_comm + self._context_object_init = context_object_init + self._aws_execution_details = aws_execution_details + self.env = None + + def _execution_logic(self) -> None: + program: Program = AmazonStateLanguageParser.parse(self._definition) + self.env = Environment( + aws_execution_details=self._aws_execution_details, + context_object_init=self._context_object_init, + event_history_context=EventHistoryContext.of_program_start(), + ) + self.env.inp = copy.deepcopy( + self._input_data + ) # The program will mutate the input_data, which is otherwise constant in regard to the execution value. + + self.env.event_history.add_event( + context=self.env.event_history_context, + hist_type_event=HistoryEventType.ExecutionStarted, + event_detail=EventDetails( + executionStartedEventDetails=ExecutionStartedEventDetails( + input=to_json_str(self.env.inp), + inputDetails=HistoryEventExecutionDataDetails( + truncated=False + ), # Always False for api calls. + roleArn=self._aws_execution_details.role_arn, + ) + ), + update_source_event_id=False, + ) + + program.eval(self.env) + + self._exec_comm.terminated() + + def start(self) -> None: + Thread(target=self._execution_logic).start() + + def stop( + self, stop_date: datetime.datetime, error: Optional[str], cause: Optional[str] + ) -> None: + self.env.set_stop(stop_date=stop_date, cause=cause, error=error) diff --git a/moto/stepfunctions/parser/backend/execution_worker_comm.py b/moto/stepfunctions/parser/backend/execution_worker_comm.py new file mode 100644 index 000000000..4602d1339 --- /dev/null +++ b/moto/stepfunctions/parser/backend/execution_worker_comm.py @@ -0,0 +1,13 @@ +import abc + + +class ExecutionWorkerComm(abc.ABC): + """ + Defines abstract callbacks for Execution's workers to report their progress, such as termination. + Execution instances define custom callbacks routines to update their state according to the latest + relevant state machine evaluation steps. + """ + + @abc.abstractmethod + def terminated(self) -> None: + ... diff --git a/moto/stepfunctions/parser/backend/state_machine.py b/moto/stepfunctions/parser/backend/state_machine.py new file mode 100644 index 000000000..93863677a --- /dev/null +++ b/moto/stepfunctions/parser/backend/state_machine.py @@ -0,0 +1,238 @@ +from __future__ import annotations + +import abc +import datetime +import json +from collections import OrderedDict +from typing import Dict, Final, Optional + +from moto.moto_api._internal import mock_random +from moto.stepfunctions.parser.api import ( + Definition, + DescribeStateMachineOutput, + LoggingConfiguration, + Name, + RevisionId, + StateMachineListItem, + StateMachineStatus, + StateMachineType, + StateMachineVersionListItem, + Tag, + TagKeyList, + TagList, + TracingConfiguration, + ValidationException, +) + + +class StateMachineInstance: + name: Name + arn: str + revision_id: Optional[RevisionId] + definition: Definition + role_arn: str + create_date: datetime.datetime + sm_type: StateMachineType + logging_config: Optional[LoggingConfiguration] + tags: Optional[TagList] + tracing_config: Optional[TracingConfiguration] + + def __init__( + self, + name: Name, + arn: str, + definition: Definition, + role_arn: str, + create_date: Optional[datetime.datetime] = None, + sm_type: Optional[StateMachineType] = None, + logging_config: Optional[LoggingConfiguration] = None, + tags: Optional[TagList] = None, + tracing_config: Optional[TracingConfiguration] = None, + ): + self.name = name + self.arn = arn + self.revision_id = None + self.definition = definition + self.role_arn = role_arn + self.create_date = create_date or datetime.datetime.now( + tz=datetime.timezone.utc + ) + self.sm_type = sm_type or StateMachineType.STANDARD + self.logging_config = logging_config + self.tags = tags + self.tracing_config = tracing_config + + def describe(self) -> DescribeStateMachineOutput: + describe_output = DescribeStateMachineOutput( + stateMachineArn=self.arn, + name=self.name, + status=StateMachineStatus.ACTIVE, + definition=self.definition, + roleArn=self.role_arn, + type=self.sm_type, + creationDate=self.create_date, + loggingConfiguration=self.logging_config, + ) + if self.revision_id: + describe_output["revisionId"] = self.revision_id + return describe_output + + @abc.abstractmethod + def itemise(self): + ... + + +class TagManager: + _tags: Final[Dict[str, Optional[str]]] + + def __init__(self): + self._tags = OrderedDict() + + @staticmethod + def _validate_key_value(key: str) -> None: + if not key: + raise ValidationException() + + @staticmethod + def _validate_tag_value(value: str) -> None: + if value is None: + raise ValidationException() + + def add_all(self, tags: TagList) -> None: + for tag in tags: + tag_key = tag["key"] + tag_value = tag["value"] + self._validate_key_value(key=tag_key) + self._validate_tag_value(value=tag_value) + self._tags[tag_key] = tag_value + + def remove_all(self, keys: TagKeyList): + for key in keys: + self._validate_key_value(key=key) + self._tags.pop(key, None) + + def to_tag_list(self) -> TagList: + tag_list = list() + for key, value in self._tags.items(): + tag_list.append(Tag(key=key, value=value)) + return tag_list + + +class StateMachineRevision(StateMachineInstance): + _next_version_number: int + versions: Final[Dict[RevisionId, str]] + tag_manager: Final[TagManager] + + def __init__( + self, + name: Name, + arn: str, + definition: Definition, + role_arn: str, + create_date: Optional[datetime.datetime] = None, + sm_type: Optional[StateMachineType] = None, + logging_config: Optional[LoggingConfiguration] = None, + tags: Optional[TagList] = None, + tracing_config: Optional[TracingConfiguration] = None, + ): + super().__init__( + name, + arn, + definition, + role_arn, + create_date, + sm_type, + logging_config, + tags, + tracing_config, + ) + self.versions = dict() + self._version_number = 0 + self.tag_manager = TagManager() + + def create_revision( + self, definition: Optional[str], role_arn: Optional[str] + ) -> Optional[RevisionId]: + update_definition = definition and json.loads(definition) != json.loads( + self.definition + ) + if update_definition: + self.definition = definition + + update_role_arn = role_arn and role_arn != self.role_arn + if update_role_arn: + self.role_arn = role_arn + + if any([update_definition, update_role_arn]): + self.revision_id = str(mock_random.uuid4()) + + return self.revision_id + + def create_version( + self, description: Optional[str] + ) -> Optional[StateMachineVersion]: + if self.revision_id not in self.versions: + self._version_number += 1 + version = StateMachineVersion( + self, version=self._version_number, description=description + ) + self.versions[self.revision_id] = version.arn + + return version + return None + + def delete_version(self, state_machine_version_arn: str) -> None: + source_revision_id = None + for revision_id, version_arn in self.versions.items(): + if version_arn == state_machine_version_arn: + source_revision_id = revision_id + break + self.versions.pop(source_revision_id, None) + + def itemise(self) -> StateMachineListItem: + return StateMachineListItem( + stateMachineArn=self.arn, + name=self.name, + type=self.sm_type, + creationDate=self.create_date, + ) + + +class StateMachineVersion(StateMachineInstance): + source_arn: str + version: int + description: Optional[str] + + def __init__( + self, + state_machine_revision: StateMachineRevision, + version: int, + description: Optional[str], + ): + version_arn = f"{state_machine_revision.arn}:{version}" + super().__init__( + name=state_machine_revision.name, + arn=version_arn, + definition=state_machine_revision.definition, + role_arn=state_machine_revision.role_arn, + create_date=datetime.datetime.now(tz=datetime.timezone.utc), + sm_type=state_machine_revision.sm_type, + logging_config=state_machine_revision.logging_config, + tags=state_machine_revision.tags, + tracing_config=state_machine_revision.tracing_config, + ) + self.source_arn = state_machine_revision.arn + self.revision_id = state_machine_revision.revision_id + self.version = version + self.description = description + + def describe(self) -> DescribeStateMachineOutput: + describe_output: DescribeStateMachineOutput = super().describe() + if self.description: + describe_output["description"] = self.description + return describe_output + + def itemise(self) -> StateMachineVersionListItem: + return StateMachineVersionListItem( + stateMachineVersionArn=self.arn, creationDate=self.create_date + ) diff --git a/moto/stepfunctions/parser/models.py b/moto/stepfunctions/parser/models.py new file mode 100644 index 000000000..eed8a4fd8 --- /dev/null +++ b/moto/stepfunctions/parser/models.py @@ -0,0 +1,256 @@ +import copy +import json +from typing import Any, Dict, List, Optional + +from moto.core.common_models import BackendDict +from moto.stepfunctions.models import StateMachine, StepFunctionBackend +from moto.stepfunctions.parser.api import ( + Definition, + ExecutionStatus, + GetExecutionHistoryOutput, + InvalidDefinition, + InvalidExecutionInput, + InvalidToken, + LoggingConfiguration, + MissingRequiredParameter, + Name, + Publish, + ResourceNotFound, + SendTaskFailureOutput, + SendTaskHeartbeatOutput, + SendTaskSuccessOutput, + SensitiveCause, + SensitiveData, + SensitiveError, + TaskDoesNotExist, + TaskTimedOut, + TaskToken, + TraceHeader, + TracingConfiguration, + VersionDescription, +) +from moto.stepfunctions.parser.asl.component.state.state_execution.state_map.iteration.itemprocessor.map_run_record import ( + MapRunRecord, +) +from moto.stepfunctions.parser.asl.eval.callback.callback import ( + CallbackConsumerTimeout, + CallbackNotifyConsumerError, + CallbackOutcomeFailure, + CallbackOutcomeSuccess, +) +from moto.stepfunctions.parser.asl.parse.asl_parser import ( + AmazonStateLanguageParser, + ASLParserException, +) +from moto.stepfunctions.parser.backend.execution import Execution + + +class StepFunctionsParserBackend(StepFunctionBackend): + def _get_executions(self, execution_status: Optional[ExecutionStatus] = None): + executions = [] + for sm in self.state_machines: + for execution in sm.executions: + if execution_status is None or execution_status == execution.status: + executions.append(execution) + return executions + + def _revision_by_name(self, name: str) -> Optional[StateMachine]: + for state_machine in self.state_machines: + if state_machine.name == name: + return state_machine + return None + + @staticmethod + def _validate_definition(definition: str): + # Validate + # TODO: pass through static analyser. + try: + AmazonStateLanguageParser.parse(definition) + except ASLParserException as asl_parser_exception: + invalid_definition = InvalidDefinition() + invalid_definition.message = repr(asl_parser_exception) + raise invalid_definition + except Exception as exception: + exception_name = exception.__class__.__name__ + exception_args = list(exception.args) + invalid_definition = InvalidDefinition() + invalid_definition.message = f"Error={exception_name} Args={exception_args} in definition '{definition}'." + raise invalid_definition + + def create_state_machine( + self, + name: str, + definition: str, + roleArn: str, + tags: Optional[List[Dict[str, str]]] = None, + ) -> StateMachine: + + StepFunctionsParserBackend._validate_definition(definition=definition) + + return super().create_state_machine( + name=name, definition=definition, roleArn=roleArn, tags=tags + ) + + def send_task_heartbeat(self, task_token: TaskToken) -> SendTaskHeartbeatOutput: + running_executions = self._get_executions(ExecutionStatus.RUNNING) + for execution in running_executions: + try: + if execution.exec_worker.env.callback_pool_manager.heartbeat( + callback_id=task_token + ): + return + except CallbackNotifyConsumerError as consumer_error: + if isinstance(consumer_error, CallbackConsumerTimeout): + raise TaskTimedOut() + else: + raise TaskDoesNotExist() + raise InvalidToken() + + def send_task_success( + self, task_token: TaskToken, output: SensitiveData + ) -> SendTaskSuccessOutput: + outcome = CallbackOutcomeSuccess(callback_id=task_token, output=output) + running_executions = self._get_executions(ExecutionStatus.RUNNING) + for execution in running_executions: + try: + if execution.exec_worker.env.callback_pool_manager.notify( + callback_id=task_token, outcome=outcome + ): + return + except CallbackNotifyConsumerError as consumer_error: + if isinstance(consumer_error, CallbackConsumerTimeout): + raise TaskTimedOut() + else: + raise TaskDoesNotExist() + raise InvalidToken() + + def send_task_failure( + self, + task_token: TaskToken, + error: SensitiveError = None, + cause: SensitiveCause = None, + ) -> SendTaskFailureOutput: + outcome = CallbackOutcomeFailure( + callback_id=task_token, error=error, cause=cause + ) + for execution in self._get_executions(): + try: + if execution.exec_worker.env.callback_pool_manager.notify( + callback_id=task_token, outcome=outcome + ): + return SendTaskFailureOutput() + except CallbackNotifyConsumerError as consumer_error: + if isinstance(consumer_error, CallbackConsumerTimeout): + raise TaskTimedOut() + else: + raise TaskDoesNotExist() + raise InvalidToken() + + def start_execution( + self, + state_machine_arn: str, + name: Name = None, + execution_input: SensitiveData = None, + trace_header: TraceHeader = None, + ) -> Execution: + state_machine = self.describe_state_machine(state_machine_arn) + + # Update event change parameters about the state machine and should not affect those about this execution. + state_machine_clone = copy.deepcopy(state_machine) + + if execution_input is None: + input_data = dict() + else: + try: + input_data = json.loads(execution_input) + except Exception as ex: + raise InvalidExecutionInput( + str(ex) + ) # TODO: report parsing error like AWS. + + exec_name = name # TODO: validate name format + + execution = Execution( + name=exec_name, + role_arn=state_machine_clone.roleArn, + account_id=self.account_id, + region_name=self.region_name, + state_machine=state_machine_clone, + input_data=input_data, + trace_header=trace_header, + ) + state_machine.executions.append(execution) + + execution.start() + return execution + + def update_state_machine( + self, + arn: str, + definition: Definition = None, + role_arn: str = None, + logging_configuration: LoggingConfiguration = None, + tracing_configuration: TracingConfiguration = None, + publish: Publish = None, + version_description: VersionDescription = None, + ) -> StateMachine: + if not any( + [definition, role_arn, logging_configuration, tracing_configuration] + ): + raise MissingRequiredParameter( + "Either the definition, the role ARN, the LoggingConfiguration, or the TracingConfiguration must be specified" + ) + + if definition is not None: + self._validate_definition(definition=definition) + + return super().update_state_machine(arn, definition, role_arn) + + def describe_map_run(self, map_run_arn: str) -> Dict[str, Any]: + for execution in self._get_executions(): + map_run_record: Optional[ + MapRunRecord + ] = execution.exec_worker.env.map_run_record_pool_manager.get(map_run_arn) + if map_run_record is not None: + return map_run_record.describe() + raise ResourceNotFound() + + def list_map_runs(self, execution_arn: str) -> Dict[str, Any]: + """ + Pagination is not yet implemented + """ + execution = self.describe_execution(execution_arn=execution_arn) + map_run_records: List[ + MapRunRecord + ] = execution.exec_worker.env.map_run_record_pool_manager.get_all() + return dict( + mapRuns=[map_run_record.to_json() for map_run_record in map_run_records] + ) + + def update_map_run( + self, + map_run_arn: str, + max_concurrency: int, + tolerated_failure_count: str, + tolerated_failure_percentage: str, + ) -> None: + # TODO: investigate behaviour of empty requests. + for execution in self._get_executions(): + map_run_record = execution.exec_worker.env.map_run_record_pool_manager.get( + map_run_arn + ) + if map_run_record is not None: + map_run_record.update( + max_concurrency=max_concurrency, + tolerated_failure_count=tolerated_failure_count, + tolerated_failure_percentage=tolerated_failure_percentage, + ) + return + raise ResourceNotFound() + + def get_execution_history(self, execution_arn: str) -> GetExecutionHistoryOutput: + execution = self.describe_execution(execution_arn=execution_arn) + return execution.to_history_output() + + +stepfunctions_parser_backends = BackendDict(StepFunctionsParserBackend, "stepfunctions") diff --git a/moto/stepfunctions/parser/resource_providers/__init__.py b/moto/stepfunctions/parser/resource_providers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_activity.py b/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_activity.py new file mode 100644 index 000000000..9cd78dad5 --- /dev/null +++ b/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_activity.py @@ -0,0 +1,119 @@ +# LocalStack Resource Provider Scaffolding v2 +from __future__ import annotations + +from pathlib import Path +from typing import List, Optional, TypedDict + +import localstack.services.cloudformation.provider_utils as util +from localstack.services.cloudformation.resource_provider import ( + OperationStatus, + ProgressEvent, + ResourceProvider, + ResourceRequest, +) + + +class StepFunctionsActivityProperties(TypedDict): + Name: Optional[str] + Arn: Optional[str] + Tags: Optional[List[TagsEntry]] + + +class TagsEntry(TypedDict): + Key: Optional[str] + Value: Optional[str] + + +REPEATED_INVOCATION = "repeated_invocation" + + +class StepFunctionsActivityProvider(ResourceProvider[StepFunctionsActivityProperties]): + TYPE = "AWS::StepFunctions::Activity" # Autogenerated. Don't change + SCHEMA = util.get_schema_path(Path(__file__)) # Autogenerated. Don't change + + def create( + self, + request: ResourceRequest[StepFunctionsActivityProperties], + ) -> ProgressEvent[StepFunctionsActivityProperties]: + """ + Create a new resource. + + Primary identifier fields: + - /properties/Arn + + Required properties: + - Name + + Create-only properties: + - /properties/Name + + Read-only properties: + - /properties/Arn + + IAM permissions required: + - states:CreateActivity + + """ + model = request.desired_state + step_functions = request.aws_client_factory.stepfunctions + if not model.get("Tags"): + response = step_functions.create_activity(name=model["Name"]) + else: + response = step_functions.create_activity( + name=model["Name"], tags=model["Tags"] + ) + model["Arn"] = response["activityArn"] + + return ProgressEvent( + status=OperationStatus.SUCCESS, + resource_model=model, + custom_context=request.custom_context, + ) + + def read( + self, + request: ResourceRequest[StepFunctionsActivityProperties], + ) -> ProgressEvent[StepFunctionsActivityProperties]: + """ + Fetch resource information + + IAM permissions required: + - states:DescribeActivity + - states:ListTagsForResource + """ + raise NotImplementedError + + def delete( + self, + request: ResourceRequest[StepFunctionsActivityProperties], + ) -> ProgressEvent[StepFunctionsActivityProperties]: + """ + Delete a resource + + IAM permissions required: + - states:DeleteActivity + """ + model = request.desired_state + step_functions = request.aws_client_factory.stepfunctions + + step_functions.delete_activity(activityArn=model["Arn"]) + + return ProgressEvent( + status=OperationStatus.SUCCESS, + resource_model=model, + custom_context=request.custom_context, + ) + + def update( + self, + request: ResourceRequest[StepFunctionsActivityProperties], + ) -> ProgressEvent[StepFunctionsActivityProperties]: + """ + Update a resource + + IAM permissions required: + - states:ListTagsForResource + - states:TagResource + - states:UntagResource + """ + raise NotImplementedError diff --git a/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_activity.schema.json b/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_activity.schema.json new file mode 100644 index 000000000..9a1f2bb15 --- /dev/null +++ b/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_activity.schema.json @@ -0,0 +1,92 @@ +{ + "typeName": "AWS::StepFunctions::Activity", + "description": "Resource schema for Activity", + "sourceUrl": "https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-stepfunctions.git", + "definitions": { + "TagsEntry": { + "type": "object", + "properties": { + "Key": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "Value": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + }, + "additionalProperties": false, + "required": [ + "Key", + "Value" + ] + } + }, + "properties": { + "Arn": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "Name": { + "type": "string", + "minLength": 1, + "maxLength": 80 + }, + "Tags": { + "type": "array", + "uniqueItems": false, + "insertionOrder": false, + "items": { + "$ref": "#/definitions/TagsEntry" + } + } + }, + "additionalProperties": false, + "tagging": { + "taggable": true, + "tagOnCreate": true, + "tagUpdatable": true, + "cloudFormationSystemTags": true, + "tagProperty": "/properties/Tags" + }, + "required": [ + "Name" + ], + "primaryIdentifier": [ + "/properties/Arn" + ], + "readOnlyProperties": [ + "/properties/Arn" + ], + "createOnlyProperties": [ + "/properties/Name" + ], + "handlers": { + "create": { + "permissions": [ + "states:CreateActivity" + ] + }, + "read": { + "permissions": [ + "states:DescribeActivity", + "states:ListTagsForResource" + ] + }, + "update": { + "permissions": [ + "states:ListTagsForResource", + "states:TagResource", + "states:UntagResource" + ] + }, + "delete": { + "permissions": [ + "states:DeleteActivity" + ] + } + } +} diff --git a/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_activity_plugin.py b/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_activity_plugin.py new file mode 100644 index 000000000..b8f889146 --- /dev/null +++ b/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_activity_plugin.py @@ -0,0 +1,20 @@ +from typing import Optional, Type + +from localstack.services.cloudformation.resource_provider import ( + CloudFormationResourceProviderPlugin, + ResourceProvider, +) + + +class StepFunctionsActivityProviderPlugin(CloudFormationResourceProviderPlugin): + name = "AWS::StepFunctions::Activity" + + def __init__(self): + self.factory: Optional[Type[ResourceProvider]] = None + + def load(self): + from localstack.services.stepfunctions.resource_providers.aws_stepfunctions_activity import ( + StepFunctionsActivityProvider, + ) + + self.factory = StepFunctionsActivityProvider diff --git a/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_statemachine.py b/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_statemachine.py new file mode 100644 index 000000000..51a8bbc11 --- /dev/null +++ b/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_statemachine.py @@ -0,0 +1,238 @@ +# LocalStack Resource Provider Scaffolding v2 +from __future__ import annotations + +import json +import re +from pathlib import Path +from typing import Dict, List, Optional, TypedDict + +import localstack.services.cloudformation.provider_utils as util +from localstack.services.cloudformation.resource_provider import ( + LOG, + OperationStatus, + ProgressEvent, + ResourceProvider, + ResourceRequest, +) +from localstack.utils.strings import to_str + + +class StepFunctionsStateMachineProperties(TypedDict): + RoleArn: Optional[str] + Arn: Optional[str] + Definition: Optional[dict] + DefinitionS3Location: Optional[S3Location] + DefinitionString: Optional[str] + DefinitionSubstitutions: Optional[dict] + LoggingConfiguration: Optional[LoggingConfiguration] + Name: Optional[str] + StateMachineName: Optional[str] + StateMachineRevisionId: Optional[str] + StateMachineType: Optional[str] + Tags: Optional[List[TagsEntry]] + TracingConfiguration: Optional[TracingConfiguration] + + +class CloudWatchLogsLogGroup(TypedDict): + LogGroupArn: Optional[str] + + +class LogDestination(TypedDict): + CloudWatchLogsLogGroup: Optional[CloudWatchLogsLogGroup] + + +class LoggingConfiguration(TypedDict): + Destinations: Optional[List[LogDestination]] + IncludeExecutionData: Optional[bool] + Level: Optional[str] + + +class TracingConfiguration(TypedDict): + Enabled: Optional[bool] + + +class S3Location(TypedDict): + Bucket: Optional[str] + Key: Optional[str] + Version: Optional[str] + + +class TagsEntry(TypedDict): + Key: Optional[str] + Value: Optional[str] + + +REPEATED_INVOCATION = "repeated_invocation" + + +class StepFunctionsStateMachineProvider( + ResourceProvider[StepFunctionsStateMachineProperties] +): + TYPE = "AWS::StepFunctions::StateMachine" # Autogenerated. Don't change + SCHEMA = util.get_schema_path(Path(__file__)) # Autogenerated. Don't change + + def create( + self, + request: ResourceRequest[StepFunctionsStateMachineProperties], + ) -> ProgressEvent[StepFunctionsStateMachineProperties]: + """ + Create a new resource. + + Primary identifier fields: + - /properties/Arn + + Required properties: + - RoleArn + + Create-only properties: + - /properties/StateMachineName + - /properties/StateMachineType + + Read-only properties: + - /properties/Arn + - /properties/Name + - /properties/StateMachineRevisionId + + IAM permissions required: + - states:CreateStateMachine + - iam:PassRole + - s3:GetObject + + """ + model = request.desired_state + step_function = request.aws_client_factory.stepfunctions + + if not model.get("StateMachineName"): + model["StateMachineName"] = util.generate_default_name( + stack_name=request.stack_name, + logical_resource_id=request.logical_resource_id, + ) + + params = { + "name": model.get("StateMachineName"), + "roleArn": model.get("RoleArn"), + "type": model.get("StateMachineType", "STANDARD"), + } + + # get definition + s3_client = request.aws_client_factory.s3 + + definition_str = self._get_definition(model, s3_client) + + params["definition"] = definition_str + + response = step_function.create_state_machine(**params) + + model["Arn"] = response["stateMachineArn"] + model["Name"] = model["StateMachineName"] + + return ProgressEvent( + status=OperationStatus.SUCCESS, + resource_model=model, + custom_context=request.custom_context, + ) + + def _get_definition(self, model, s3_client): + if "DefinitionString" in model: + definition_str = model.get("DefinitionString") + elif "DefinitionS3Location" in model: + # TODO: currently not covered by tests - add a test to mimick the behavior of "sam deploy ..." + s3_location = model.get("DefinitionS3Location") + LOG.debug("Fetching state machine definition from S3: %s", s3_location) + result = s3_client.get_object( + Bucket=s3_location["Bucket"], Key=s3_location["Key"] + ) + definition_str = to_str(result["Body"].read()) + elif "Definition" in model: + definition = model.get("Definition") + definition_str = json.dumps(definition) + else: + definition_str = None + + substitutions = model.get("DefinitionSubstitutions") + if substitutions is not None: + definition_str = _apply_substitutions(definition_str, substitutions) + return definition_str + + def read( + self, + request: ResourceRequest[StepFunctionsStateMachineProperties], + ) -> ProgressEvent[StepFunctionsStateMachineProperties]: + """ + Fetch resource information + + IAM permissions required: + - states:DescribeStateMachine + - states:ListTagsForResource + """ + raise NotImplementedError + + def delete( + self, + request: ResourceRequest[StepFunctionsStateMachineProperties], + ) -> ProgressEvent[StepFunctionsStateMachineProperties]: + """ + Delete a resource + + IAM permissions required: + - states:DeleteStateMachine + - states:DescribeStateMachine + """ + model = request.desired_state + step_function = request.aws_client_factory.stepfunctions + + step_function.delete_state_machine(stateMachineArn=model["Arn"]) + + return ProgressEvent( + status=OperationStatus.SUCCESS, + resource_model=model, + custom_context=request.custom_context, + ) + + def update( + self, + request: ResourceRequest[StepFunctionsStateMachineProperties], + ) -> ProgressEvent[StepFunctionsStateMachineProperties]: + """ + Update a resource + + IAM permissions required: + - states:UpdateStateMachine + - states:TagResource + - states:UntagResource + - states:ListTagsForResource + - iam:PassRole + """ + model = request.desired_state + step_function = request.aws_client_factory.stepfunctions + + if not model.get("Arn"): + model["Arn"] = request.previous_state["Arn"] + + params = { + "stateMachineArn": model["Arn"], + "definition": model["DefinitionString"], + } + + step_function.update_state_machine(**params) + + return ProgressEvent( + status=OperationStatus.SUCCESS, + resource_model=model, + custom_context=request.custom_context, + ) + + +def _apply_substitutions(definition: str, substitutions: Dict[str, str]) -> str: + substitution_regex = re.compile( + "\\${[a-zA-Z0-9_]+}" + ) # might be a bit too strict in some cases + tokens = substitution_regex.findall(definition) + result = definition + for token in tokens: + raw_token = token[2:-1] # strip ${ and } + if raw_token not in substitutions.keys(): + raise + result = result.replace(token, substitutions[raw_token]) + + return result diff --git a/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_statemachine.schema.json b/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_statemachine.schema.json new file mode 100644 index 000000000..607e1a9bc --- /dev/null +++ b/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_statemachine.schema.json @@ -0,0 +1,250 @@ +{ + "typeName": "AWS::StepFunctions::StateMachine", + "description": "Resource schema for StateMachine", + "sourceUrl": "https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-stepfunctions.git", + "definitions": { + "TagsEntry": { + "type": "object", + "properties": { + "Key": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "Value": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + }, + "additionalProperties": false, + "required": [ + "Key", + "Value" + ] + }, + "CloudWatchLogsLogGroup": { + "type": "object", + "additionalProperties": false, + "properties": { + "LogGroupArn": { + "type": "string", + "minLength": 1, + "maxLength": 256 + } + } + }, + "LogDestination": { + "type": "object", + "additionalProperties": false, + "properties": { + "CloudWatchLogsLogGroup": { + "$ref": "#/definitions/CloudWatchLogsLogGroup" + } + } + }, + "LoggingConfiguration": { + "type": "object", + "additionalProperties": false, + "properties": { + "Level": { + "type": "string", + "enum": [ + "ALL", + "ERROR", + "FATAL", + "OFF" + ] + }, + "IncludeExecutionData": { + "type": "boolean" + }, + "Destinations": { + "type": "array", + "minItems": 1, + "insertionOrder": false, + "items": { + "$ref": "#/definitions/LogDestination" + } + } + } + }, + "TracingConfiguration": { + "type": "object", + "additionalProperties": false, + "properties": { + "Enabled": { + "type": "boolean" + } + } + }, + "S3Location": { + "type": "object", + "additionalProperties": false, + "properties": { + "Bucket": { + "type": "string" + }, + "Key": { + "type": "string" + }, + "Version": { + "type": "string" + } + }, + "required": [ + "Bucket", + "Key" + ] + }, + "DefinitionSubstitutions": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + ".*": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + }, + { + "type": "boolean" + } + ] + } + }, + "minProperties": 1 + }, + "Definition": { + "type": "object", + "minProperties": 1 + } + }, + "properties": { + "Arn": { + "type": "string", + "minLength": 1, + "maxLength": 2048 + }, + "Name": { + "type": "string", + "minLength": 1, + "maxLength": 80 + }, + "DefinitionString": { + "type": "string", + "minLength": 1, + "maxLength": 1048576 + }, + "RoleArn": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "StateMachineName": { + "type": "string", + "minLength": 1, + "maxLength": 80 + }, + "StateMachineType": { + "type": "string", + "enum": [ + "STANDARD", + "EXPRESS" + ] + }, + "StateMachineRevisionId": { + "type": "string", + "minLength": 1, + "maxLength": 256 + }, + "LoggingConfiguration": { + "$ref": "#/definitions/LoggingConfiguration" + }, + "TracingConfiguration": { + "$ref": "#/definitions/TracingConfiguration" + }, + "DefinitionS3Location": { + "$ref": "#/definitions/S3Location" + }, + "DefinitionSubstitutions": { + "$ref": "#/definitions/DefinitionSubstitutions" + }, + "Definition": { + "$ref": "#/definitions/Definition" + }, + "Tags": { + "type": "array", + "uniqueItems": false, + "insertionOrder": false, + "items": { + "$ref": "#/definitions/TagsEntry" + } + } + }, + "required": [ + "RoleArn" + ], + "tagging": { + "taggable": true, + "tagOnCreate": true, + "tagUpdatable": true, + "cloudFormationSystemTags": true, + "tagProperty": "/properties/Tags" + }, + "additionalProperties": false, + "readOnlyProperties": [ + "/properties/Arn", + "/properties/Name", + "/properties/StateMachineRevisionId" + ], + "createOnlyProperties": [ + "/properties/StateMachineName", + "/properties/StateMachineType" + ], + "writeOnlyProperties": [ + "/properties/Definition", + "/properties/DefinitionS3Location", + "/properties/DefinitionSubstitutions" + ], + "primaryIdentifier": [ + "/properties/Arn" + ], + "handlers": { + "create": { + "permissions": [ + "states:CreateStateMachine", + "iam:PassRole", + "s3:GetObject" + ] + }, + "read": { + "permissions": [ + "states:DescribeStateMachine", + "states:ListTagsForResource" + ] + }, + "update": { + "permissions": [ + "states:UpdateStateMachine", + "states:TagResource", + "states:UntagResource", + "states:ListTagsForResource", + "iam:PassRole" + ] + }, + "delete": { + "permissions": [ + "states:DeleteStateMachine", + "states:DescribeStateMachine" + ] + }, + "list": { + "permissions": [ + "states:ListStateMachines" + ] + } + } +} diff --git a/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_statemachine_plugin.py b/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_statemachine_plugin.py new file mode 100644 index 000000000..744ff8120 --- /dev/null +++ b/moto/stepfunctions/parser/resource_providers/aws_stepfunctions_statemachine_plugin.py @@ -0,0 +1,20 @@ +from typing import Optional, Type + +from localstack.services.cloudformation.resource_provider import ( + CloudFormationResourceProviderPlugin, + ResourceProvider, +) + + +class StepFunctionsStateMachineProviderPlugin(CloudFormationResourceProviderPlugin): + name = "AWS::StepFunctions::StateMachine" + + def __init__(self): + self.factory: Optional[Type[ResourceProvider]] = None + + def load(self): + from localstack.services.stepfunctions.resource_providers.aws_stepfunctions_statemachine import ( + StepFunctionsStateMachineProvider, + ) + + self.factory = StepFunctionsStateMachineProvider diff --git a/moto/stepfunctions/parser/utils.py b/moto/stepfunctions/parser/utils.py new file mode 100644 index 000000000..c5181118b --- /dev/null +++ b/moto/stepfunctions/parser/utils.py @@ -0,0 +1,82 @@ +import re +from typing import Dict, List, Set, Type + +TMP_THREADS = [] + + +def is_list_or_tuple(obj) -> bool: + return isinstance(obj, (list, tuple)) + + +def select_attributes(obj: Dict, attributes: List[str]) -> Dict: + """Select a subset of attributes from the given dict (returns a copy)""" + attributes = attributes if is_list_or_tuple(attributes) else [attributes] + return {k: v for k, v in obj.items() if k in attributes} + + +class SubtypesInstanceManager: + """Simple instance manager base class that scans the subclasses of a base type for concrete named + implementations, and lazily creates and returns (singleton) instances on demand.""" + + _instances: Dict[str, "SubtypesInstanceManager"] + + @classmethod + def get(cls, subtype_name: str): + instances = cls.instances() + base_type = cls.get_base_type() + instance = instances.get(subtype_name) + if instance is None: + # lazily load subtype instance (required if new plugins are dynamically loaded at runtime) + for clazz in get_all_subclasses(base_type): + impl_name = clazz.impl_name() + if impl_name not in instances: + instances[impl_name] = clazz() + instance = instances.get(subtype_name) + return instance + + @classmethod + def instances(cls) -> Dict[str, "SubtypesInstanceManager"]: + base_type = cls.get_base_type() + if not hasattr(base_type, "_instances"): + base_type._instances = {} + return base_type._instances + + @staticmethod + def impl_name() -> str: + """Name of this concrete subtype - to be implemented by subclasses.""" + raise NotImplementedError + + @classmethod + def get_base_type(cls) -> Type: + """Get the base class for which instances are being managed - can be customized by subtypes.""" + return cls + + +def to_str(obj, encoding: str = "utf-8", errors="strict") -> str: + """If ``obj`` is an instance of ``binary_type``, return + ``obj.decode(encoding, errors)``, otherwise return ``obj``""" + return obj.decode(encoding, errors) if isinstance(obj, bytes) else obj + + +_re_camel_to_snake_case = re.compile("((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))") + + +def camel_to_snake_case(string: str) -> str: + return _re_camel_to_snake_case.sub(r"_\1", string).replace("__", "_").lower() + + +def snake_to_camel_case(string: str, capitalize_first: bool = True) -> str: + components = string.split("_") + start_idx = 0 if capitalize_first else 1 + components = [x.title() for x in components[start_idx:]] + return "".join(components) + + +def get_all_subclasses(clazz: Type) -> Set[Type]: + """Recursively get all subclasses of the given class.""" + result = set() + subs = clazz.__subclasses__() + for sub in subs: + result.add(sub) + result.update(get_all_subclasses(sub)) + return result diff --git a/moto/stepfunctions/responses.py b/moto/stepfunctions/responses.py index 9335d7805..a505076e7 100644 --- a/moto/stepfunctions/responses.py +++ b/moto/stepfunctions/responses.py @@ -1,9 +1,11 @@ import json from moto.core.common_types import TYPE_RESPONSE +from moto.core.config import default_user_config from moto.core.responses import BaseResponse from .models import StepFunctionBackend, stepfunctions_backends +from .parser.api import ExecutionStatus class StepFunctionResponse(BaseResponse): @@ -12,7 +14,12 @@ class StepFunctionResponse(BaseResponse): @property def stepfunction_backend(self) -> StepFunctionBackend: - return stepfunctions_backends[self.current_account][self.region] + if default_user_config.get("stepfunctions", {}).get("execute_state_machine", False): + from .parser.models import stepfunctions_parser_backends + + return stepfunctions_parser_backends[self.current_account][self.region] + else: + return stepfunctions_backends[self.current_account][self.region] def create_state_machine(self) -> TYPE_RESPONSE: name = self._get_param("name") @@ -146,19 +153,26 @@ class StepFunctionResponse(BaseResponse): execution = self.stepfunction_backend.describe_execution(arn) response = { "executionArn": arn, - "input": execution.execution_input, + "input": json.dumps(execution.execution_input), "name": execution.name, "startDate": execution.start_date, "stateMachineArn": execution.state_machine_arn, "status": execution.status, "stopDate": execution.stop_date, } + if execution.status == ExecutionStatus.SUCCEEDED: + response["output"] = execution.output + response["outputDetails"] = execution.output_details + if execution.error is not None: + response["error"] = execution.error + if execution.cause is not None: + response["cause"] = execution.cause return 200, {}, json.dumps(response) def describe_state_machine_for_execution(self) -> TYPE_RESPONSE: arn = self._get_param("executionArn") - execution = self.stepfunction_backend.describe_execution(arn) - return self._describe_state_machine(execution.state_machine_arn) + sm = self.stepfunction_backend.describe_state_machine_for_execution(arn) + return self._describe_state_machine(sm.arn) def stop_execution(self) -> TYPE_RESPONSE: arn = self._get_param("executionArn") @@ -173,3 +187,42 @@ class StepFunctionResponse(BaseResponse): ) response = {"events": execution_history} return 200, {}, json.dumps(response) + + def send_task_failure(self) -> TYPE_RESPONSE: + task_token = self._get_param("taskToken") + self.stepfunction_backend.send_task_failure(task_token) + return 200, {}, "{}" + + def send_task_heartbeat(self) -> TYPE_RESPONSE: + task_token = self._get_param("taskToken") + self.stepfunction_backend.send_task_heartbeat(task_token) + return 200, {}, "{}" + + def send_task_success(self) -> TYPE_RESPONSE: + task_token = self._get_param("taskToken") + outcome = self._get_param("outcome") + self.stepfunction_backend.send_task_success(task_token, outcome) + return 200, {}, "{}" + + def list_map_runs(self) -> TYPE_RESPONSE: + execution_arn = self._get_param("executionArn") + runs = self.stepfunction_backend.list_map_runs(execution_arn) + return 200, {}, json.dumps(runs) + + def describe_map_run(self) -> TYPE_RESPONSE: + map_run_arn = self._get_param("mapRunArn") + run = self.stepfunction_backend.describe_map_run(map_run_arn) + return 200, {}, json.dumps(run) + + def update_map_run(self) -> TYPE_RESPONSE: + map_run_arn = self._get_param("mapRunArn") + max_concurrency = self._get_param("maxConcurrency") + tolerated_failure_count = self._get_param("toleratedFailureCount") + tolerated_failure_percentage = self._get_param("toleratedFailurePercentage") + self.stepfunction_backend.update_map_run( + map_run_arn, + max_concurrency, + tolerated_failure_count=tolerated_failure_count, + tolerated_failure_percentage=tolerated_failure_percentage, + ) + return 200, {}, "{}" diff --git a/scripts/ci_moto_server.sh b/scripts/ci_moto_server.sh index 3a5f86ea2..f881342c4 100755 --- a/scripts/ci_moto_server.sh +++ b/scripts/ci_moto_server.sh @@ -2,4 +2,4 @@ set -e pip install $(ls /moto/dist/moto*.gz)[server,all] -moto_server -H 0.0.0.0 | tee /moto/server_output.log 2>&1 +moto_server -H 0.0.0.0 2>&1 | tee /moto/server_output.log diff --git a/setup.cfg b/setup.cfg index b13853a1a..2a5689a07 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,7 +44,9 @@ moto = py.typed [options.extras_require] all = + antlr4-python3-runtime joserfc>=0.9.0 + jsonpath_ng docker>=3.0.0 graphql-core PyYAML>=5.1 @@ -57,7 +59,9 @@ all = setuptools multipart proxy = + antlr4-python3-runtime joserfc>=0.9.0 + jsonpath_ng docker>=2.5.1 graphql-core PyYAML>=5.1 @@ -70,7 +74,9 @@ proxy = setuptools multipart server = + antlr4-python3-runtime joserfc>=0.9.0 + jsonpath_ng docker>=3.0.0 graphql-core PyYAML>=5.1 @@ -227,6 +233,8 @@ ssm = PyYAML>=5.1 ssoadmin = stepfunctions = + antlr4-python3-runtime + jsonpath_ng sts = support = swf = @@ -266,6 +274,7 @@ enable = arguments-renamed, deprecated-module, function-redefined, redefined-out [mypy] files= moto, tests/test_core, tests/test_batch_simple +exclude = moto/stepfunctions/parser show_column_numbers=True show_error_codes = True disable_error_code=abstract diff --git a/tests/test_awslambda/utilities.py b/tests/test_awslambda/utilities.py index 89778cbd9..3369865f4 100644 --- a/tests/test_awslambda/utilities.py +++ b/tests/test_awslambda/utilities.py @@ -25,6 +25,8 @@ def get_test_zip_file1(): pfunc = """ def lambda_handler(event, context): print("custom log event") + if "error" in event: + raise Exception('I failed!') return event """ return _process_lambda(pfunc) diff --git a/tests/test_stepfunctions/parser/__init__.py b/tests/test_stepfunctions/parser/__init__.py new file mode 100644 index 000000000..c6f57f99c --- /dev/null +++ b/tests/test_stepfunctions/parser/__init__.py @@ -0,0 +1,158 @@ +import json +import os +from functools import wraps +from time import sleep +from typing import TYPE_CHECKING, Callable, TypeVar +from uuid import uuid4 + +import boto3 +import requests + +from moto import mock_aws, settings +from tests import DEFAULT_ACCOUNT_ID as ACCOUNT_ID +from tests.test_stepfunctions.parser.templates.templates import load_template + +if TYPE_CHECKING: + from typing_extensions import ParamSpec + + P = ParamSpec("P") + +T = TypeVar("T") + + +def aws_verified(func): + """ + Function that is verified to work against AWS. + Can be run against AWS at any time by setting: + MOTO_TEST_ALLOW_AWS_REQUEST=true + + If this environment variable is not set, the function runs in a `mock_aws` context. + """ + + @wraps(func) + def pagination_wrapper(): + allow_aws_request = ( + os.environ.get("MOTO_TEST_ALLOW_AWS_REQUEST", "false").lower() == "true" + ) + + if allow_aws_request: + return func() + else: + with mock_aws(): + requests.post( + f"http://{base_url}/moto-api/config", + json={"stepfunctions": {"execute_state_machine": True}}, + ) + resp = func() + requests.post( + f"http://{base_url}/moto-api/config", + json={"stepfunctions": {"execute_state_machine": False}}, + ) + return resp + + return pagination_wrapper + + +def verify_execution_result( + _verify_result, expected_status, tmpl_name, exec_input=None, sleep_time=0 +): + iam = boto3.client("iam", region_name="us-east-1") + role_name = f"sfn_role_{str(uuid4())[0:6]}" + sfn_role = iam.create_role( + RoleName=role_name, + AssumeRolePolicyDocument=json.dumps(sfn_role_policy), + Path="/", + )["Role"]["Arn"] + iam.put_role_policy( + PolicyDocument=json.dumps(sfn_allow_dynamodb), + PolicyName="allowLambdaInvoke", + RoleName=role_name, + ) + sleep(sleep_time) + + client = boto3.client("stepfunctions", region_name="us-east-1") + execution_arn, state_machine_arn = _start_execution( + client, load_template(tmpl_name), exec_input, sfn_role + ) + for _ in range(10): + execution = client.describe_execution(executionArn=execution_arn) + if execution["status"] == expected_status: + result = _verify_result(client, execution, execution_arn) + if result is not False: + + client.delete_state_machine(stateMachineArn=state_machine_arn) + iam.delete_role_policy( + RoleName=role_name, PolicyName="allowLambdaInvoke" + ) + iam.delete_role(RoleName=role_name) + break + sleep(0.1) + else: + client.delete_state_machine(stateMachineArn=state_machine_arn) + iam.delete_role_policy(RoleName=role_name, PolicyName="allowLambdaInvoke") + iam.delete_role(RoleName=role_name) + assert False, "Should have failed already" + + +def _start_execution(client, definition, exec_input, sfn_role): + name = "sfn_name" + # + response = client.create_state_machine( + name=name, definition=json.dumps(definition), roleArn=sfn_role + ) + state_machine_arn = response["stateMachineArn"] + execution = client.start_execution( + name="exec1", stateMachineArn=state_machine_arn, input=exec_input or "{}" + ) + execution_arn = execution["executionArn"] + return execution_arn, state_machine_arn + + +def _get_default_role(): + return "arn:aws:iam::" + ACCOUNT_ID + ":role/unknown_sf_role" + + +base_url = "localhost:5000" if settings.TEST_SERVER_MODE else "motoapi.amazonaws.com" + + +def enable_sfn_parser(func: "Callable[P, T]") -> "Callable[P, T]": + @wraps(func) + def pagination_wrapper(*args: "P.args", **kwargs: "P.kwargs") -> T: # type: ignore + requests.post( + f"http://{base_url}/moto-api/config", + json={"stepfunctions": {"execute_state_machine": True}}, + ) + try: + res = func(*args, **kwargs) + finally: + requests.post( + f"http://{base_url}/moto-api/config", + json={"stepfunctions": {"execute_state_machine": False}}, + ) + return res + + return pagination_wrapper + + +sfn_role_policy = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"Service": "states.amazonaws.com"}, + "Action": "sts:AssumeRole", + } + ], +} + +sfn_allow_lambda_invoke = { + "Version": "2012-10-17", + "Statement": [ + {"Effect": "Allow", "Action": ["lambda:InvokeFunction"], "Resource": ["*"]} + ], +} + +sfn_allow_dynamodb = { + "Version": "2012-10-17", + "Statement": [{"Effect": "Allow", "Action": ["dynamodb:*"], "Resource": ["*"]}], +} diff --git a/tests/test_stepfunctions/parser/templates/__init__.py b/tests/test_stepfunctions/parser/templates/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_stepfunctions/parser/templates/choice_state_singleton.json b/tests/test_stepfunctions/parser/templates/choice_state_singleton.json new file mode 100644 index 000000000..e3549c1fd --- /dev/null +++ b/tests/test_stepfunctions/parser/templates/choice_state_singleton.json @@ -0,0 +1,28 @@ +{ + "StartAt": "ChoiceStateX", + "States": { + "ChoiceStateX": { + "Type": "Choice", + "Choices": [ + { + "And": [ + { + "Variable": "$.type", + "StringEquals": "Public" + } + ], + "Next": "Public" + } + ], + "Default": "DefaultState" + }, + "Public": { + "Type": "Pass", + "End": true + }, + "DefaultState": { + "Type": "Fail", + "Cause": "No Matches!" + } + } +} \ No newline at end of file diff --git a/tests/test_stepfunctions/parser/templates/map_item_reader.json b/tests/test_stepfunctions/parser/templates/map_item_reader.json new file mode 100644 index 000000000..17dcd881f --- /dev/null +++ b/tests/test_stepfunctions/parser/templates/map_item_reader.json @@ -0,0 +1,36 @@ +{ + "Comment": "MAP_ITEM_READER_BASE_CSV_HEADERS_DECL", + "StartAt": "MapState", + "States": { + "MapState": { + "Type": "Map", + "MaxConcurrency": 1, + "ItemReader": { + "ReaderConfig": { + "InputType": "CSV", + "CSVHeaderLocation": "GIVEN", + "CSVHeaders": ["H1", "H2", "H3"] + }, + "Resource": "arn:aws:states:::s3:getObject", + "Parameters": { + "Bucket.$": "$.Bucket", + "Key.$": "$.Key" + } + }, + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "DISTRIBUTED", + "ExecutionType": "STANDARD" + }, + "StartAt": "PassItem", + "States": { + "PassItem": { + "Type": "Pass", + "End": true + } + } + }, + "End": true + } + } +} \ No newline at end of file diff --git a/tests/test_stepfunctions/parser/templates/map_item_reader_with_header.json b/tests/test_stepfunctions/parser/templates/map_item_reader_with_header.json new file mode 100644 index 000000000..4ac48cc01 --- /dev/null +++ b/tests/test_stepfunctions/parser/templates/map_item_reader_with_header.json @@ -0,0 +1,35 @@ +{ + "Comment": "MAP_ITEM_READER_BASE_CSV_HEADERS_FIRST_LINE", + "StartAt": "MapState", + "States": { + "MapState": { + "Type": "Map", + "MaxConcurrency": 1, + "ItemReader": { + "ReaderConfig": { + "InputType": "CSV", + "CSVHeaderLocation": "FIRST_ROW" + }, + "Resource": "arn:aws:states:::s3:getObject", + "Parameters": { + "Bucket.$": "$.Bucket", + "Key.$": "$.Key" + } + }, + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "DISTRIBUTED", + "ExecutionType": "STANDARD" + }, + "StartAt": "PassItem", + "States": { + "PassItem": { + "Type": "Pass", + "End": true + } + } + }, + "End": true + } + } +} \ No newline at end of file diff --git a/tests/test_stepfunctions/parser/templates/parallel_fail.json b/tests/test_stepfunctions/parser/templates/parallel_fail.json new file mode 100644 index 000000000..8aa1554fa --- /dev/null +++ b/tests/test_stepfunctions/parser/templates/parallel_fail.json @@ -0,0 +1,21 @@ +{ + "Comment": "PARALLEL_STATE_FAIL", + "StartAt": "ParallelState", + "States": { + "ParallelState": { + "Type": "Parallel", + "End": true, + "Branches": [ + { + "StartAt": "Branch1", + "States": { + "Branch1": { + "Type": "Fail", + "Error": "FailureType" + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/tests/test_stepfunctions/parser/templates/parallel_states.json b/tests/test_stepfunctions/parser/templates/parallel_states.json new file mode 100644 index 000000000..d56901f0c --- /dev/null +++ b/tests/test_stepfunctions/parser/templates/parallel_states.json @@ -0,0 +1,56 @@ +{ + "Comment": "PARALLEL_STATE", + "StartAt": "LoadInput", + "States": { + "LoadInput": { + "Type": "Pass", + "Result": [1, 2, 3, 4], + "Next": "ParallelState" + }, + "ParallelState": { + "Type": "Parallel", + "End": true, + "Branches": [ + { + "StartAt": "Branch1", + "States": { + "Branch1": { + "Type": "Pass", + "End": true + } + } + }, + { + "StartAt": "Branch21", + "States": { + "Branch21": { + "Type": "Pass", + "Next": "Branch22" + }, + "Branch22": { + "Type": "Pass", + "End": true + } + } + }, + { + "StartAt": "Branch31", + "States": { + "Branch31": { + "Type": "Pass", + "Next": "Branch32" + }, + "Branch32": { + "Type": "Pass", + "Next": "Branch33" + }, + "Branch33": { + "Type": "Pass", + "End": true + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/tests/test_stepfunctions/parser/templates/parallel_states_catch.json b/tests/test_stepfunctions/parser/templates/parallel_states_catch.json new file mode 100644 index 000000000..a64be89c3 --- /dev/null +++ b/tests/test_stepfunctions/parser/templates/parallel_states_catch.json @@ -0,0 +1,38 @@ +{ + "Comment": "PARALLEL_STATE_CATCH", + "StartAt": "ParallelState", + "States": { + "ParallelState": { + "Type": "Parallel", + "Branches": [ + { + "StartAt": "Branch1", + "States": { + "Branch1": { + "Type": "Fail", + "Error": "FailureType", + "Cause": "Cause description" + } + } + } + ], + "Catch": [ + { + "ErrorEquals": [ + "FailureType" + ], + "Next": "FinalCaught" + } + ], + "Next": "Final" + }, + "FinalCaught": { + "Type": "Pass", + "End": true + }, + "Final": { + "Type": "Pass", + "End": true + } + } +} \ No newline at end of file diff --git a/tests/test_stepfunctions/parser/templates/parallel_states_order.json b/tests/test_stepfunctions/parser/templates/parallel_states_order.json new file mode 100644 index 000000000..bf8e6fc20 --- /dev/null +++ b/tests/test_stepfunctions/parser/templates/parallel_states_order.json @@ -0,0 +1,60 @@ +{ + "Comment": "PARALLEL_STATE_ORDER", + "StartAt": "StartState", + "States": { + "StartState": { + "Type": "Parallel", + "Branches": [ + { + "StartAt": "Branch0", + "States": { + "Branch0": { + "Type": "Pass", + "Result": { + "branch": 0 + }, + "End": true + } + } + }, + { + "StartAt": "Branch1", + "States": { + "Branch1": { + "Type": "Pass", + "Result": { + "branch": 1 + }, + "End": true + } + } + }, + { + "StartAt": "Branch2", + "States": { + "Branch2": { + "Type": "Pass", + "Result": { + "branch": 2 + }, + "End": true + } + } + }, + { + "StartAt": "Branch3", + "States": { + "Branch3": { + "Type": "Pass", + "Result": { + "branch": 3 + }, + "End": true + } + } + } + ], + "End": true + } + } +} \ No newline at end of file diff --git a/tests/test_stepfunctions/parser/templates/services/dynamodb_put_delete_item.json b/tests/test_stepfunctions/parser/templates/services/dynamodb_put_delete_item.json new file mode 100644 index 000000000..7e2b56161 --- /dev/null +++ b/tests/test_stepfunctions/parser/templates/services/dynamodb_put_delete_item.json @@ -0,0 +1,36 @@ +{ + "Comment": "AWS_SDK_DYNAMODB_PUT_DELETE_ITEM", + "StartAt": "PutItem1", + "States": { + "PutItem1": { + "Type": "Task", + "Resource": "arn:aws:states:::aws-sdk:dynamodb:putItem", + "Parameters": { + "TableName.$": "$.TableName", + "Item.$": "$.Item1" + }, + "ResultPath": "$.putItemOutput1", + "Next": "PutItem2" + }, + "PutItem2": { + "Type": "Task", + "Resource": "arn:aws:states:::aws-sdk:dynamodb:putItem", + "Parameters": { + "TableName.$": "$.TableName", + "Item.$": "$.Item2" + }, + "ResultPath": "$.putItemOutput2", + "Next": "DeleteItem" + }, + "DeleteItem": { + "Type": "Task", + "Resource": "arn:aws:states:::aws-sdk:dynamodb:deleteItem", + "ResultPath": "$.deleteItemOutput", + "Parameters": { + "TableName.$": "$.TableName", + "Key.$": "$.Key" + }, + "End": true + } + } +} \ No newline at end of file diff --git a/tests/test_stepfunctions/parser/templates/services/dynamodb_put_item.json b/tests/test_stepfunctions/parser/templates/services/dynamodb_put_item.json new file mode 100644 index 000000000..ed5c3398a --- /dev/null +++ b/tests/test_stepfunctions/parser/templates/services/dynamodb_put_item.json @@ -0,0 +1,16 @@ +{ + "Comment": "AWS_SDK_DYNAMODB_PUT_ITEM", + "StartAt": "PutItem", + "States": { + "PutItem": { + "Type": "Task", + "Resource": "arn:aws:states:::aws-sdk:dynamodb:putItem", + "Parameters": { + "TableName.$": "$.TableName", + "Item.$": "$.Item" + }, + "ResultPath": "$.putItemOutput", + "End": true + } + } +} \ No newline at end of file diff --git a/tests/test_stepfunctions/parser/templates/services/sns_publish.json b/tests/test_stepfunctions/parser/templates/services/sns_publish.json new file mode 100644 index 000000000..546d91d1b --- /dev/null +++ b/tests/test_stepfunctions/parser/templates/services/sns_publish.json @@ -0,0 +1,15 @@ +{ + "Comment": "SNS_PUBLISH", + "StartAt": "Publish", + "States": { + "Publish": { + "Type": "Task", + "Resource": "arn:aws:states:::sns:publish", + "Parameters": { + "TopicArn.$": "$.TopicArn", + "Message.$": "$.Message" + }, + "End": true + } + } +} \ No newline at end of file diff --git a/tests/test_stepfunctions/parser/templates/services/sqs_heartbeat.json b/tests/test_stepfunctions/parser/templates/services/sqs_heartbeat.json new file mode 100644 index 000000000..176e374bc --- /dev/null +++ b/tests/test_stepfunctions/parser/templates/services/sqs_heartbeat.json @@ -0,0 +1,20 @@ +{ + "Comment": "SERVICE_SQS_SEND_AND_WAIT_FOR_TASK_TOKEN_WITH_HEARTBEAT", + "StartAt": "SendMessageWithWait", + "States": { + "SendMessageWithWait": { + "Type": "Task", + "Resource": "arn:aws:states:::sqs:sendMessage.waitForTaskToken", + "TimeoutSeconds": 60, + "HeartbeatSeconds": 5, + "Parameters": { + "QueueUrl.$": "$.QueueUrl", + "MessageBody": { + "Message.$": "$.Message", + "TaskToken.$": "$$.Task.Token" + } + }, + "End": true + } + } +} \ No newline at end of file diff --git a/tests/test_stepfunctions/parser/templates/templates.py b/tests/test_stepfunctions/parser/templates/templates.py new file mode 100644 index 000000000..ccbea7532 --- /dev/null +++ b/tests/test_stepfunctions/parser/templates/templates.py @@ -0,0 +1,11 @@ +import json +import os + +folder = os.path.dirname(os.path.realpath(__file__)) + + +def load_template(name: str): + template = None + with open(os.path.join(folder, name + ".json"), "r") as df: + template = json.load(df) + return template diff --git a/tests/test_stepfunctions/parser/test_choice_state.py b/tests/test_stepfunctions/parser/test_choice_state.py new file mode 100644 index 000000000..a3254ea30 --- /dev/null +++ b/tests/test_stepfunctions/parser/test_choice_state.py @@ -0,0 +1,36 @@ +import json +from unittest import SkipTest + +from moto import mock_aws, settings + +from . import aws_verified, verify_execution_result + + +@mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) +def test_state_machine_with_choice(): + if settings.TEST_SERVER_MODE: + raise SkipTest("Don't need to test this in ServerMode") + tmpl_name = "choice_state_singleton" + exec_input = {"type": "Public"} + + def _verify_result(client, execution, execution_arn): + assert json.loads(execution["input"]) == exec_input + + verify_execution_result( + _verify_result, "SUCCEEDED", tmpl_name, exec_input=json.dumps(exec_input) + ) + + +@aws_verified +def test_state_machine_with_choice_miss(): + if settings.TEST_SERVER_MODE: + raise SkipTest("Don't need to test this in ServerMode") + tmpl_name = "choice_state_singleton" + exec_input = {"type": "Private"} + + def _verify_result(client, execution, execution_arn): + assert execution["cause"] == "No Matches!" + + verify_execution_result( + _verify_result, "FAILED", tmpl_name, exec_input=json.dumps(exec_input) + ) diff --git a/tests/test_stepfunctions/parser/test_map_item.py b/tests/test_stepfunctions/parser/test_map_item.py new file mode 100644 index 000000000..1fe3af596 --- /dev/null +++ b/tests/test_stepfunctions/parser/test_map_item.py @@ -0,0 +1,88 @@ +import json +from unittest import SkipTest + +import boto3 + +from moto import mock_aws, settings + +from . import verify_execution_result + + +@mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) +def test_state_machine_with_map_reader_csv(): + if settings.TEST_SERVER_MODE: + raise SkipTest("Don't need to test this in ServerMode") + + # Prepare CSV + s3 = boto3.client("s3", "us-east-1") + bucket_name = "mybucket" + s3.create_bucket(Bucket=bucket_name) + key = "file.csv" + csv_file = ( + "Value1,Value2,Value3\n" + "Value4,Value5,Value6\n" + ",,,\n" + "true,1,'HelloWorld'\n" + "Null,None,\n" + " \n" + ) + s3.put_object(Bucket=bucket_name, Key=key, Body=csv_file) + + tmpl_name = "map_item_reader" + exec_input = {"Bucket": bucket_name, "Key": key} + + def _verify_result(client, execution, execution_arn): + output = json.loads(execution["output"]) + assert {"H1": "Value1", "H2": "Value2", "H3": "Value3"} in output + assert {"H1": "Value4", "H2": "Value5", "H3": "Value6"} in output + assert {"H1": "", "H2": "", "H3": ""} in output + assert {"H1": "true", "H2": "1", "H3": "'HelloWorld'"} in output + assert {"H1": "Null", "H2": "None", "H3": ""} in output + assert {"H1": " ", "H2": "", "H3": ""} in output + + verify_execution_result( + _verify_result, "SUCCEEDED", tmpl_name, exec_input=json.dumps(exec_input) + ) + + +@mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) +def test_state_machine_with_map_reader_csv_with_header(): + if settings.TEST_SERVER_MODE: + raise SkipTest("Don't need to test this in ServerMode") + + # Prepare CSV + s3 = boto3.client("s3", "us-east-1") + bucket_name = "mybucket" + s3.create_bucket(Bucket=bucket_name) + key = "file.csv" + csv_file = ( + "Col1,Col2,Col3\n" + "Value1,Value2,Value3\n" + "Value4,Value5,Value6\n" + ",,,\n" + "true,1,'HelloWorld'\n" + "Null,None,\n" + " \n" + ) + s3.put_object(Bucket=bucket_name, Key=key, Body=csv_file) + + tmpl_name = "map_item_reader_with_header" + exec_input = {"Bucket": bucket_name, "Key": key} + + def _verify_result(client, execution, execution_arn): + output = json.loads(execution["output"]) + assert {"Col1": "Value1", "Col2": "Value2", "Col3": "Value3"} in output + assert {"Col1": "", "Col2": "", "Col3": ""} in output + + runs = client.list_map_runs(executionArn=execution_arn)["mapRuns"] + assert len(runs) == 1 + assert runs[0]["executionArn"] == execution_arn + + run = client.describe_map_run(mapRunArn=runs[0]["mapRunArn"]) + assert run["itemCounts"]["total"] == 6 + + client.update_map_run(mapRunArn=runs[0]["mapRunArn"], maxConcurrency=4) + + verify_execution_result( + _verify_result, "SUCCEEDED", tmpl_name, exec_input=json.dumps(exec_input) + ) diff --git a/tests/test_stepfunctions/parser/test_parallel_states.py b/tests/test_stepfunctions/parser/test_parallel_states.py new file mode 100644 index 000000000..6b99450df --- /dev/null +++ b/tests/test_stepfunctions/parser/test_parallel_states.py @@ -0,0 +1,72 @@ +import json +from unittest import SkipTest + +from moto import mock_aws, settings + +from . import verify_execution_result + + +@mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) +def test_state_machine_with_parallel_states(): + if settings.TEST_SERVER_MODE: + raise SkipTest("Don't need to test this in ServerMode") + tmpl_name = "parallel_states" + + def _verify_result(client, execution, execution_arn): + assert "stopDate" in execution + assert execution["output"] == "[[1,2,3,4],[1,2,3,4],[1,2,3,4]]" + + history = client.get_execution_history(executionArn=execution_arn) + assert len(history["events"]) == 20 + assert "ParallelStateEntered" in [e["type"] for e in history["events"]] + assert "ParallelStateStarted" in [e["type"] for e in history["events"]] + assert "PassStateExited" in [e["type"] for e in history["events"]] + + verify_execution_result(_verify_result, "SUCCEEDED", tmpl_name) + + +@mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) +def test_state_machine_with_parallel_states_catch_error(): + if settings.TEST_SERVER_MODE: + raise SkipTest("Don't need to test this in ServerMode") + expected_status = "SUCCEEDED" + tmpl_name = "parallel_states_catch" + + def _verify_result(client, execution, execution_arn): + assert "stopDate" in execution + assert json.loads(execution["output"])["Cause"] == "Cause description" + history = client.get_execution_history(executionArn=execution_arn) + assert len(history["events"]) == 9 + assert "ParallelStateEntered" in [e["type"] for e in history["events"]] + assert "ParallelStateStarted" in [e["type"] for e in history["events"]] + assert "ParallelStateFailed" in [e["type"] for e in history["events"]] + + verify_execution_result(_verify_result, expected_status, tmpl_name) + + +@mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) +def test_state_machine_with_parallel_states_error(): + if settings.TEST_SERVER_MODE: + raise SkipTest("Don't need to test this in ServerMode") + + def _verify_result(client, execution, execution_arn): + assert "stopDate" in execution + assert execution["error"] == "FailureType" + + verify_execution_result(_verify_result, "FAILED", "parallel_fail") + + +@mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) +def test_state_machine_with_parallel_states_order(): + if settings.TEST_SERVER_MODE: + raise SkipTest("Don't need to test this in ServerMode") + + def _verify_result(client, execution, execution_arn): + assert json.loads(execution["output"]) == [ + {"branch": 0}, + {"branch": 1}, + {"branch": 2}, + {"branch": 3}, + ] + + verify_execution_result(_verify_result, "SUCCEEDED", "parallel_states_order") diff --git a/tests/test_stepfunctions/parser/test_stepfunctions.py b/tests/test_stepfunctions/parser/test_stepfunctions.py new file mode 100644 index 000000000..2a09a4785 --- /dev/null +++ b/tests/test_stepfunctions/parser/test_stepfunctions.py @@ -0,0 +1,72 @@ +import json +from time import sleep +from unittest import SkipTest + +import boto3 + +from moto import mock_aws, settings +from tests import DEFAULT_ACCOUNT_ID as ACCOUNT_ID + +failure_definition = { + "Comment": "An example of the Amazon States Language using a choice state.", + "StartAt": "DefaultState", + "States": { + "DefaultState": { + "Type": "Fail", + "Error": "DefaultStateError", + "Cause": "No Matches!", + } + }, +} + + +@mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) +def test_state_machine_with_simple_failure_state(): + if settings.TEST_SERVER_MODE: + raise SkipTest("Don't need to test this in ServerMode") + client = boto3.client("stepfunctions", region_name="us-east-1") + execution_arn, state_machine_arn = _start_execution(client, failure_definition) + + for _ in range(5): + execution = client.describe_execution(executionArn=execution_arn) + if execution["status"] == "FAILED": + assert "stopDate" in execution + assert execution["error"] == "DefaultStateError" + assert execution["cause"] == "No Matches!" + + history = client.get_execution_history(executionArn=execution_arn) + assert len(history["events"]) == 3 + assert [e["type"] for e in history["events"]] == [ + "ExecutionStarted", + "FailStateEntered", + "ExecutionFailed", + ] + + executions = client.list_executions(stateMachineArn=state_machine_arn)[ + "executions" + ] + assert len(executions) == 1 + assert executions[0]["executionArn"] == execution_arn + assert executions[0]["stateMachineArn"] == state_machine_arn + assert executions[0]["status"] == "FAILED" + + break + sleep(0.2) + else: + assert False, "Should have failed already" + + +def _start_execution(client, definition): + name = "sfn_name" + # + response = client.create_state_machine( + name=name, definition=json.dumps(definition), roleArn=_get_default_role() + ) + state_machine_arn = response["stateMachineArn"] + execution = client.start_execution(name="exec1", stateMachineArn=state_machine_arn) + execution_arn = execution["executionArn"] + return execution_arn, state_machine_arn + + +def _get_default_role(): + return "arn:aws:iam::" + ACCOUNT_ID + ":role/unknown_sf_role" diff --git a/tests/test_stepfunctions/parser/test_stepfunctions_dynamodb_integration.py b/tests/test_stepfunctions/parser/test_stepfunctions_dynamodb_integration.py new file mode 100644 index 000000000..eceb0dc28 --- /dev/null +++ b/tests/test_stepfunctions/parser/test_stepfunctions_dynamodb_integration.py @@ -0,0 +1,130 @@ +import json +import os +from functools import wraps +from uuid import uuid4 + +import boto3 +import pytest +import requests + +from moto import mock_aws + +from . import base_url, verify_execution_result + + +def aws_verified(func): + """ + Function that is verified to work against AWS. + Can be run against AWS at any time by setting: + MOTO_TEST_ALLOW_AWS_REQUEST=true + + If this environment variable is not set, the function runs in a `mock_aws` context. + + This decorator will: + - Create an IAM-role that can be used by AWSLambda functions table + - Run the test + - Delete the role + """ + + @wraps(func) + def pagination_wrapper(): + table_name = "table_" + str(uuid4())[0:6] + + allow_aws_request = ( + os.environ.get("MOTO_TEST_ALLOW_AWS_REQUEST", "false").lower() == "true" + ) + + if allow_aws_request: + return create_table_and_test(table_name, sleep_time=10) + else: + with mock_aws(): + requests.post( + f"http://{base_url}/moto-api/config", + json={"stepfunctions": {"execute_state_machine": True}}, + ) + resp = create_table_and_test(table_name, sleep_time=0) + requests.post( + f"http://{base_url}/moto-api/config", + json={"stepfunctions": {"execute_state_machine": False}}, + ) + return resp + + def create_table_and_test(table_name, sleep_time): + client = boto3.client("dynamodb", region_name="us-east-1") + + client.create_table( + TableName=table_name, + KeySchema=[{"AttributeName": "id", "KeyType": "HASH"}], + AttributeDefinitions=[{"AttributeName": "id", "AttributeType": "S"}], + ProvisionedThroughput={"ReadCapacityUnits": 1, "WriteCapacityUnits": 5}, + Tags=[{"Key": "environment", "Value": "moto_tests"}], + ) + waiter = client.get_waiter("table_exists") + waiter.wait(TableName=table_name) + try: + resp = func(table_name, sleep_time) + finally: + ### CLEANUP ### + client.delete_table(TableName=table_name) + + return resp + + return pagination_wrapper + + +@aws_verified +@pytest.mark.aws_verified +def test_state_machine_calling_dynamodb_put(table_name=None, sleep_time=0): + dynamodb = boto3.client("dynamodb", "us-east-1") + exec_input = { + "TableName": table_name, + "Item": {"data": {"S": "HelloWorld"}, "id": {"S": "id1"}}, + } + + expected_status = "SUCCEEDED" + tmpl_name = "services/dynamodb_put_item" + + def _verify_result(client, execution, execution_arn): + assert "stopDate" in execution + assert json.loads(execution["input"]) == exec_input + + items = dynamodb.scan(TableName=table_name)["Items"] + assert items == [exec_input["Item"]] + + verify_execution_result( + _verify_result, + expected_status, + tmpl_name, + exec_input=json.dumps(exec_input), + sleep_time=sleep_time, + ) + + +@aws_verified +@pytest.mark.aws_verified +def test_state_machine_calling_dynamodb_put_and_delete(table_name=None, sleep_time=0): + dynamodb = boto3.client("dynamodb", "us-east-1") + exec_input = { + "TableName": table_name, + "Item1": {"data": {"S": "HelloWorld"}, "id": {"S": "id1"}}, + "Item2": {"data": {"S": "HelloWorld"}, "id": {"S": "id2"}}, + "Key": {"id": {"S": "id1"}}, + } + + expected_status = "SUCCEEDED" + tmpl_name = "services/dynamodb_put_delete_item" + + def _verify_result(client, execution, execution_arn): + assert "stopDate" in execution + assert json.loads(execution["input"]) == exec_input + + items = dynamodb.scan(TableName=table_name)["Items"] + assert items == [exec_input["Item2"]] + + verify_execution_result( + _verify_result, + expected_status, + tmpl_name, + exec_input=json.dumps(exec_input), + sleep_time=sleep_time, + ) diff --git a/tests/test_stepfunctions/parser/test_stepfunctions_lambda_integration.py b/tests/test_stepfunctions/parser/test_stepfunctions_lambda_integration.py new file mode 100644 index 000000000..f7b27ed69 --- /dev/null +++ b/tests/test_stepfunctions/parser/test_stepfunctions_lambda_integration.py @@ -0,0 +1,265 @@ +import json +import os +from functools import wraps +from time import sleep +from uuid import uuid4 + +import boto3 +import pytest +import requests +from botocore.exceptions import ClientError + +from moto import mock_aws +from tests.test_awslambda.utilities import ( + get_test_zip_file1, +) + +from . import base_url, sfn_allow_lambda_invoke, sfn_role_policy + +lambda_state_machine = { + "Comment": "A simple AWS Step Functions state machine that calls two Lambda Functions", + "StartAt": "Open Case", + "States": { + "Open Case": {"Type": "Task", "Resource": "TODO", "Next": "Send Email"}, + "Send Email": {"Type": "Task", "Resource": "TODO", "End": True}, + }, +} + + +def aws_verified(func): + """ + Function that is verified to work against AWS. + Can be run against AWS at any time by setting: + MOTO_TEST_ALLOW_AWS_REQUEST=true + + If this environment variable is not set, the function runs in a `mock_aws` context. + + This decorator will: + - Create an IAM-role that can be used by AWSLambda functions table + - Run the test + - Delete the role + """ + + @wraps(func) + def pagination_wrapper(): + role_name = "moto_test_role_" + str(uuid4())[0:6] + + allow_aws_request = ( + os.environ.get("MOTO_TEST_ALLOW_AWS_REQUEST", "false").lower() == "true" + ) + + if allow_aws_request: + return create_role_and_test(role_name, sleep_time=10) + else: + with mock_aws(): + requests.post( + f"http://{base_url}/moto-api/config", + json={"stepfunctions": {"execute_state_machine": True}}, + ) + resp = create_role_and_test(role_name, sleep_time=0) + requests.post( + f"http://{base_url}/moto-api/config", + json={"stepfunctions": {"execute_state_machine": False}}, + ) + return resp + + def create_role_and_test(role_name, sleep_time): + policy_doc = { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "LambdaAssumeRole", + "Effect": "Allow", + "Principal": {"Service": "lambda.amazonaws.com"}, + "Action": "sts:AssumeRole", + } + ], + } + iam = boto3.client("iam", region_name="us-east-1") + iam_role_arn = iam.create_role( + RoleName=role_name, + AssumeRolePolicyDocument=json.dumps(policy_doc), + Path="/", + )["Role"]["Arn"] + + fn_name = f"fn_for_{role_name}" + try: + fn_arn = create_function(iam_role_arn, role_name, fn_name) + + resp = func(fn_name, fn_arn, sleep_time) + finally: + _lambda = boto3.client("lambda", "us-east-1") + _lambda.delete_function(FunctionName=fn_name) + + iam.delete_role(RoleName=role_name) + + return resp + + def create_function(role_arn: str, role_name: str, fn_name: str): + iam = boto3.client("iam", region_name="us-east-1") + + # The waiter is normally used to wait until a resource is ready + wait_for_role = iam.get_waiter("role_exists") + wait_for_role.wait(RoleName=role_name) + + # HOWEVER: + # Just because the role exists, doesn't mean it can be used by Lambda + # The only reliable way to check if our role is ready: + # - try to create a function and see if it succeeds + # + # The alternative is to wait between 5 and 10 seconds, which is not a great solution either + _lambda = boto3.client("lambda", "us-east-1") + for _ in range(15): + try: + fn = _lambda.create_function( + FunctionName=fn_name, + Runtime="python3.11", + Role=role_arn, + Handler="lambda_function.lambda_handler", + Code={"ZipFile": get_test_zip_file1()}, + ) + return fn["FunctionArn"] + + except ClientError: + sleep(1) + raise Exception( + f"Couldn't create test Lambda FN using IAM role {role_name}, probably because it wasn't ready in time" + ) + + return pagination_wrapper + + +@aws_verified +@pytest.mark.aws_verified +def test_state_machine_calling_lambda_fn(fn_name=None, fn_arn=None, sleep_time=0): + definition = lambda_state_machine.copy() + definition["States"]["Open Case"]["Resource"] = fn_arn + definition["States"]["Send Email"]["Resource"] = fn_arn + + iam = boto3.client("iam", region_name="us-east-1") + role_name = f"sfn_role_{str(uuid4())[0:6]}" + sfn_role = iam.create_role( + RoleName=role_name, + AssumeRolePolicyDocument=json.dumps(sfn_role_policy), + Path="/", + )["Role"]["Arn"] + iam.put_role_policy( + PolicyDocument=json.dumps(sfn_allow_lambda_invoke), + PolicyName="allowLambdaInvoke", + RoleName=role_name, + ) + sleep(sleep_time) + + client = boto3.client("stepfunctions", region_name="us-east-1") + name = "sfn_" + str(uuid4())[0:6] + exec_input = {"my": "input"} + # + response = client.create_state_machine( + name=name, definition=json.dumps(definition), roleArn=sfn_role + ) + state_machine_arn = response["stateMachineArn"] + + execution = client.start_execution( + name="exec1", stateMachineArn=state_machine_arn, input=json.dumps(exec_input) + ) + execution_arn = execution["executionArn"] + + for _ in range(10): + execution = client.describe_execution(executionArn=execution_arn) + if execution["status"] == "SUCCEEDED": + assert "stopDate" in execution + assert json.loads(execution["input"]) == exec_input + assert json.loads(execution["output"]) == exec_input + + history = client.get_execution_history(executionArn=execution_arn) + assert len(history["events"]) == 12 + assert [e["type"] for e in history["events"]] == [ + "ExecutionStarted", + "TaskStateEntered", + "LambdaFunctionScheduled", + "LambdaFunctionStarted", + "LambdaFunctionSucceeded", + "TaskStateExited", + "TaskStateEntered", + "LambdaFunctionScheduled", + "LambdaFunctionStarted", + "LambdaFunctionSucceeded", + "TaskStateExited", + "ExecutionSucceeded", + ] + + client.delete_state_machine(stateMachineArn=state_machine_arn) + iam.delete_role_policy(RoleName=role_name, PolicyName="allowLambdaInvoke") + iam.delete_role(RoleName=role_name) + break + sleep(1) + else: + client.delete_state_machine(stateMachineArn=state_machine_arn) + iam.delete_role_policy(RoleName=role_name, PolicyName="allowLambdaInvoke") + iam.delete_role(RoleName=role_name) + assert False, "Should have failed already" + + +@aws_verified +@pytest.mark.aws_verified +def test_state_machine_calling_failing_lambda_fn( + fn_name=None, fn_arn=None, sleep_time=0 +): + definition = lambda_state_machine.copy() + definition["States"]["Open Case"]["Resource"] = fn_arn + definition["States"]["Send Email"]["Resource"] = fn_arn + + iam = boto3.client("iam", region_name="us-east-1") + role_name = f"sfn_role_{str(uuid4())[0:6]}" + sfn_role = iam.create_role( + RoleName=role_name, + AssumeRolePolicyDocument=json.dumps(sfn_role_policy), + Path="/", + )["Role"]["Arn"] + iam.put_role_policy( + PolicyDocument=json.dumps(sfn_allow_lambda_invoke), + PolicyName="allowLambdaInvoke", + RoleName=role_name, + ) + sleep(sleep_time) + + client = boto3.client("stepfunctions", region_name="us-east-1") + name = "sfn_" + str(uuid4())[0:6] + exec_input = {"my": "input", "error": True} + # + response = client.create_state_machine( + name=name, definition=json.dumps(definition), roleArn=sfn_role + ) + state_machine_arn = response["stateMachineArn"] + + execution = client.start_execution( + name="exec1", stateMachineArn=state_machine_arn, input=json.dumps(exec_input) + ) + execution_arn = execution["executionArn"] + + for _ in range(10): + execution = client.describe_execution(executionArn=execution_arn) + if execution["status"] == "FAILED": + assert json.loads(execution["cause"])["errorMessage"] == "I failed!" + + history = client.get_execution_history(executionArn=execution_arn) + assert len(history["events"]) == 6 + assert [e["type"] for e in history["events"]] == [ + "ExecutionStarted", + "TaskStateEntered", + "LambdaFunctionScheduled", + "LambdaFunctionStarted", + "LambdaFunctionFailed", + "ExecutionFailed", + ] + + client.delete_state_machine(stateMachineArn=state_machine_arn) + iam.delete_role_policy(RoleName=role_name, PolicyName="allowLambdaInvoke") + iam.delete_role(RoleName=role_name) + break + sleep(1) + else: + client.delete_state_machine(stateMachineArn=state_machine_arn) + iam.delete_role_policy(RoleName=role_name, PolicyName="allowLambdaInvoke") + iam.delete_role(RoleName=role_name) + assert False, "Should have failed already" diff --git a/tests/test_stepfunctions/parser/test_stepfunctions_sns_integration.py b/tests/test_stepfunctions/parser/test_stepfunctions_sns_integration.py new file mode 100644 index 000000000..26fb4b79b --- /dev/null +++ b/tests/test_stepfunctions/parser/test_stepfunctions_sns_integration.py @@ -0,0 +1,36 @@ +import json +from unittest import SkipTest + +import boto3 + +from moto import mock_aws, settings +from moto.sns.models import sns_backends +from tests import DEFAULT_ACCOUNT_ID + +from . import verify_execution_result + + +@mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) +def test_state_machine_calling_sns_publish(): + if not settings.TEST_DECORATOR_MODE: + raise SkipTest("No point in testing this in ServerMode") + sns = boto3.client("sns", "us-east-1") + topic_arn = sns.create_topic(Name="mytopic")["TopicArn"] + + exec_input = {"TopicArn": topic_arn, "Message": "my msg"} + + expected_status = "SUCCEEDED" + tmpl_name = "services/sns_publish" + + def _verify_result(client, execution, execution_arn): + assert "stopDate" in execution + assert json.loads(execution["input"]) == exec_input + assert "MessageId" in json.loads(execution["output"]) + + backend = sns_backends[DEFAULT_ACCOUNT_ID]["us-east-1"] + topic = list(backend.topics.values())[0] + notification = topic.sent_notifications[0] + _, msg, _, _, _ = notification + assert msg == "my msg" + + verify_execution_result(_verify_result, expected_status, tmpl_name, exec_input=json.dumps(exec_input)) diff --git a/tests/test_stepfunctions/parser/test_stepfunctions_sqs_integration.py b/tests/test_stepfunctions/parser/test_stepfunctions_sqs_integration.py new file mode 100644 index 000000000..393425e32 --- /dev/null +++ b/tests/test_stepfunctions/parser/test_stepfunctions_sqs_integration.py @@ -0,0 +1,72 @@ +import json +from unittest import SkipTest +from uuid import uuid4 + +import boto3 + +from moto import mock_aws, settings + +from . import verify_execution_result + + +@mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) +def test_state_machine_calling_sqs_with_heartbeat(): + if not settings.TEST_DECORATOR_MODE: + raise SkipTest("No point in testing this in ServerMode") + sqs = boto3.client("sqs", "us-east-1") + sfn = boto3.client("stepfunctions", "us-east-1") + queue_name = f"queue{uuid4()}" + queue_url = sqs.create_queue(QueueName=queue_name)["QueueUrl"] + + message_txt = "test_message_txt" + exec_input = {"QueueUrl": queue_url, "Message": message_txt} + + expected_status = "RUNNING" + tmpl_name = "services/sqs_heartbeat" + + def _verify_result(client, execution, execution_arn): + + resp = sqs.receive_message(QueueUrl=queue_url) + if "Messages" in resp: + task_token = json.loads(resp["Messages"][0]["Body"])["TaskToken"] + + sfn.send_task_heartbeat(taskToken=task_token) + sfn.send_task_failure(taskToken=task_token) + return True + + return False + + verify_execution_result( + _verify_result, expected_status, tmpl_name, exec_input=json.dumps(exec_input) + ) + + +@mock_aws(config={"stepfunctions": {"execute_state_machine": True}}) +def test_state_machine_calling_sqs_with_task_success(): + if not settings.TEST_DECORATOR_MODE: + raise SkipTest("No point in testing this in ServerMode") + sqs = boto3.client("sqs", "us-east-1") + sfn = boto3.client("stepfunctions", "us-east-1") + queue_name = f"queue{uuid4()}" + queue_url = sqs.create_queue(QueueName=queue_name)["QueueUrl"] + + message_txt = "test_message_txt" + exec_input = {"QueueUrl": queue_url, "Message": message_txt} + + expected_status = "RUNNING" + tmpl_name = "services/sqs_heartbeat" + + def _verify_result(client, execution, execution_arn): + + resp = sqs.receive_message(QueueUrl=queue_url) + if "Messages" in resp: + task_token = json.loads(resp["Messages"][0]["Body"])["TaskToken"] + + sfn.send_task_success(taskToken=task_token, output="it's done") + return True + + return False + + verify_execution_result( + _verify_result, expected_status, tmpl_name, exec_input=json.dumps(exec_input) + ) diff --git a/tests/test_stepfunctions/test_stepfunctions.py b/tests/test_stepfunctions/test_stepfunctions.py index a1cf98358..203e6b1f4 100644 --- a/tests/test_stepfunctions/test_stepfunctions.py +++ b/tests/test_stepfunctions/test_stepfunctions.py @@ -657,7 +657,7 @@ def test_state_machine_describe_execution_with_no_input(): # assert description["ResponseMetadata"]["HTTPStatusCode"] == 200 assert description["executionArn"] == execution["executionArn"] - assert description["input"] == "{}" + assert description["input"] == '"{}"' assert re.match("[-0-9a-z]+", description["name"]) assert description["startDate"] == execution["startDate"] assert description["stateMachineArn"] == sm["stateMachineArn"] @@ -680,7 +680,7 @@ def test_state_machine_describe_execution_with_custom_input(): # assert description["ResponseMetadata"]["HTTPStatusCode"] == 200 assert description["executionArn"] == execution["executionArn"] - assert description["input"] == execution_input + assert json.loads(description["input"]) == execution_input assert re.match("[-a-z0-9]+", description["name"]) assert description["startDate"] == execution["startDate"] assert description["stateMachineArn"] == sm["stateMachineArn"]