"""Lookup expression parser."""
from typing import List, Tuple
from text_lint.config import (
LOOKUP_SENTINEL,
LOOKUP_SEPERATOR,
LOOKUP_STATIC_VALUE_MARKER,
)
from text_lint.exceptions.lookups import LookupSyntaxInvalid
from text_lint.exceptions.schema import (
LookupExpressionInvalid,
LookupExpressionInvalidDuplicatePositional,
LookupExpressionInvalidSequence,
)
from text_lint.operations.lookups import lookup_registry
from text_lint.operations.lookups.bases.lookup_base import AliasLookupParams
from text_lint.operations.lookups.parsers.lookups import parse_lookup
[Doku]
class ParsedLookup:
"""A parsed lookup operation with its parameters."""
[Doku]
def __init__(
self,
name: str,
params: "AliasLookupParams",
) -> None:
"""Instantiate ParsedLookup instances.
:param name: The name of the lookup operation.
:param params: A list of parameters for this lookup operation.
"""
self.name = name
self.params = params
LOOKUPS_SENTINEL_VALUE = [ParsedLookup(name=LOOKUP_SENTINEL, params=[])]
[Doku]
def parse_lookup_expression(value: str) -> Tuple[str, List["ParsedLookup"]]:
"""Extract the save ids, lookups and parameters from a lookup expression.
:param value: The lookup expression to parse.
:returns: A tuple of the data source and lookup operation instances.
:raises: LookupExpressionInvalid, LookupExpressionInvalidSequence,
LookupExpressionInvalidDuplicatePositional
"""
if value.startswith(LOOKUP_STATIC_VALUE_MARKER):
return value, LOOKUPS_SENTINEL_VALUE
split_value = value.split(LOOKUP_SEPERATOR)
segments = split_value[1:]
source = split_value[0]
lookups: List["ParsedLookup"] = []
if not segments:
return source, LOOKUPS_SENTINEL_VALUE
current_segment = ""
found_non_positional_lookup = False
while segments:
if current_segment:
current_segment += LOOKUP_SEPERATOR
current_segment += segments.pop(0)
try:
name, params = parse_lookup(current_segment)
if name in lookup_registry:
registry_reference = lookup_registry[name]
if not registry_reference.is_positional:
found_non_positional_lookup = True
else:
if found_non_positional_lookup:
raise LookupExpressionInvalidSequence(value)
if name in [previously_added.name for previously_added in lookups]:
raise LookupExpressionInvalidDuplicatePositional(name)
lookups.append(ParsedLookup(name=name, params=params))
current_segment = ""
except LookupSyntaxInvalid:
pass
if (value and not lookups) or current_segment:
raise LookupExpressionInvalid(value)
return source, lookups