# Copyright 2019 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module for parsing substitutions."""
import os
import re
from typing import Text
from ament_index_python.packages import get_package_share_directory
from lark import Lark
from lark import Token
from lark import Transformer
from .expose import instantiate_substitution
from ..substitutions import TextSubstitution
from ..utilities.type_utils import NormalizedValueType
from ..utilities.type_utils import StrSomeValueType
[docs]
def replace_escaped_characters(data: Text) -> Text:
"""Search escaped characters and replace them."""
return re.sub(r'\\(.)', r'\1', data)
[docs]
def get_grammar_path() -> str:
return os.path.join(
get_package_share_directory('launch'), 'frontend', 'grammar.lark')
_parser = None
[docs]
def parse_substitution(string_value):
global _parser
if not string_value:
# Grammar cannot deal with zero-width expressions.
return [TextSubstitution(text=string_value)]
if _parser is None:
with open(get_grammar_path(), 'r') as h:
_parser = Lark(h, start='template')
tree = _parser.parse(string_value)
transformer = ExtractSubstitution()
return transformer.transform(tree)
[docs]
def parse_if_substitutions(
value: StrSomeValueType
) -> NormalizedValueType:
"""
Parse substitutions in `value`, if there are any, and return a normalized value type.
If `value` is a `str`, substitutions will be interpolated in it.
If `value` is any other scalar type, it will be returned as-is.
If `value` is a list, the two rules above will be applied to each item.
When interpolating substitutions in a string, `TextSubstitution` instances are resolved
and the original `str` is left.
:raise: `ValueError` if the result cannot be parsed into a valid type.
"""
data_types = set()
def _parse_if(value):
if isinstance(value, str):
output = parse_substitution(value)
if len(output) == 1 and isinstance(output[0], TextSubstitution):
data_types.add(str)
return output[0].text
return output
data_types.add(type(value))
return value
if isinstance(value, list):
output = [_parse_if(x) for x in value]
else:
output = _parse_if(value)
if len(data_types) > 1:
raise ValueError('The result is a non-uniform list')
return output