예제 #1
0
    def visit_placeholder_node(
        self, node: nodes.PlaceholderNode
    ) -> Optional[nodes.Node]:
        """
        Optimizations:
            - If placeholder is defined in bound context, and placeholder key has a single value, replaces the
                placeholder by a LiteralNode having that value.
            - If placeholder is defined in bound context and placeholder key has multiple values, replaces the
                placeholder by an AnyNode of LiteralNodes corresponding to the context values.
        Args:
            node (nodes.PlaceholderNode): The placeholder to replace.

        Returns:
            The replaced node.
        """
        if not self._ctx:
            return node

        # Not the most elegant solution, could be improved
        # Have to manually call the visit literal method since new nodes will never be visited as tree is traversed
        # depth-first
        try:
            values = self._ctx.get(node.key)
        except KeyError:
            return node

        if len(values) == 1:
            if values[0] is None:
                return None
            return self.visit_literal_node(nodes.LiteralNode(values[0]))

        return nodes.AnyNode(
            [self.visit_literal_node(nodes.LiteralNode(val)) for val in values]
        )
예제 #2
0
def test_optimizer_visit_entity_node_does_nothing_without_macro() -> None:
    o = Optimizer({}, {})
    entity_1 = nodes.EntityNode(
        "some_entity", [nodes.LiteralNode("a"),
                        nodes.LiteralNode("b")])
    entity_2 = nodes.EntityNode(
        "some_entity", [nodes.LiteralNode("a"),
                        nodes.LiteralNode("b")])

    assert entity_2 == o.visit_entity_node(entity_1)
예제 #3
0
def test_grammar_node_generate():
    grammar = nodes.Grammar(
        {
            "some_entity":
            nodes.EntityNode(
                "some_entity",
                [nodes.LiteralNode("a"),
                 nodes.PlaceholderNode("a")])
        },
        {},
    )

    assert grammar.generate("some_entity", {"a": "sdf"}) == "a sdf"
예제 #4
0
def test_optional_node_generate():
    expected_value = "a"
    node = nodes.OptionalNode(nodes.LiteralNode(expected_value))

    for i in range(1000):
        with mock.patch.object(
                node.expression,
                "generate",
                return_value=node.expression.generate()) as mock_gen:
            val = node.generate()
            if val == "":
                mock_gen.assert_not_called()
            else:
                assert expected_value == val
예제 #5
0
def test_optimizer_visit_entity_node_with_macro() -> None:
    parameters = [nodes.ParameterNode("a"), nodes.ParameterNode("b")]

    o = Optimizer(
        {},
        {"macro_a": nodes.MacroNode("macro_a", parameters, parameters[::-1])})

    entity_1 = nodes.EntityNode(
        "some_entity",
        [nodes.LiteralNode("a"),
         nodes.LiteralNode("b")],
        macro=nodes.MacroReferenceNode("macro_a"),
    )

    expected_entity = nodes.EntityNode(
        "some_entity",
        [
            nodes.ParameterNode("b", nodes.LiteralNode("b")),
            nodes.ParameterNode("a", nodes.LiteralNode("a")),
        ],
    )

    assert expected_entity == o.visit_entity_node(entity_1)
예제 #6
0
파일: parser.py 프로젝트: dalloriam/txtgen
    def expression(self) -> Expression:
        if self._accept(TokenType.Literal):
            assert self.current_token is not None
            return nodes.LiteralNode(value=self.current_token.value)

        if self._accept(TokenType.Placeholder):
            assert self.current_token is not None
            return nodes.PlaceholderNode(key=self.current_token.value)

        if self._accept(TokenType.Symbol):
            assert self.current_token is not None
            return nodes.ReferenceNode(key=self.current_token.value)

        if self._accept(TokenType.BracketOpen):
            optional_expr = self.expression()
            self._expect(TokenType.BracketClose)
            return nodes.OptionalNode(optional_expr)

        self._expect(TokenType.ParenOpen)
        if self._accept(TokenType.Function):
            assert self.current_token is not None
            fn_type = self.current_token.value

            if fn_type == Function.If:
                condition = self.condition()
                return condition

            if fn_type == Function.Repeat:
                repeat = self.repeat()
                return repeat

            children = []

            while not self._accept(TokenType.ParenClose):
                children.append(self.expression())

            if fn_type == Function.Any:
                return nodes.AnyNode(children)

        children = []
        while not self._accept(TokenType.ParenClose):
            children.append(self.expression())

        return nodes.ListNode(children)
예제 #7
0
from txtgen.parser import Expression, DescentParser
from txtgen import nodes

from typing import Optional

import pytest


@pytest.mark.parametrize(
    "text,expected_expression",
    [
        ('"hello world"', nodes.LiteralNode(value="hello world")),
        ("$hello.world", nodes.PlaceholderNode(key="hello.world")),
        ("hello_world", nodes.ReferenceNode(key="hello_world")),
        ("[hello_world]", nodes.OptionalNode(nodes.ReferenceNode("hello_world"))),
        (
            "(a b c)",
            nodes.ListNode(
                [
                    nodes.ReferenceNode("a"),
                    nodes.ReferenceNode("b"),
                    nodes.ReferenceNode("c"),
                ]
            ),
        ),
        (
            "(any a b)",
            nodes.AnyNode([nodes.ReferenceNode("a"), nodes.ReferenceNode("b")]),
        ),
        (
            "(if $a=$b a)",
예제 #8
0
def test_literal_node_generate():
    for val in ["asdf", "hello", "world", "hey_there", "1234", ","]:
        n = nodes.LiteralNode(val)
        assert n.generate() == val
예제 #9
0
from txtgen import nodes
from txtgen.constants import PUNCTUATION
from txtgen.context import Context

from typing import Optional, Set

from unittest import mock

import pytest


@pytest.mark.parametrize(
    "input_node,expected_output",
    [
        (
            nodes.LiteralNode("hello"),
            nodes.ListNode(
                [nodes.LiteralNode(" "),
                 nodes.LiteralNode("hello")]),
        ),
        *[(nodes.LiteralNode(x), nodes.LiteralNode(x)) for x in PUNCTUATION],
    ],
)
def test_sub_punctuation(input_node: nodes.LiteralNode,
                         expected_output: nodes.Node) -> None:
    assert nodes.sub_punctuation(input_node) == expected_output


@pytest.mark.parametrize(
    "input_node,input_ctx,expected_node",
    [
예제 #10
0
from txtgen import nodes
from txtgen.context import Context
from txtgen.optimizer import Optimizer

from typing import Dict, Optional

import pytest


@pytest.mark.parametrize(
    "node,expected",
    [
        (nodes.AnyNode([nodes.LiteralNode("a")]), nodes.LiteralNode("a")),
        (
            nodes.AnyNode([nodes.LiteralNode("a"),
                           nodes.LiteralNode("b")]),
            nodes.AnyNode([nodes.LiteralNode("a"),
                           nodes.LiteralNode("b")]),
        ),
    ],
)
def test_optimizer_visit_any_node(node: nodes.Node,
                                  expected: nodes.Node) -> None:
    o = Optimizer({}, {})
    assert expected == o.visit_any_node(node)


@pytest.mark.parametrize(
    "node,ctx,expected",
    [
        (