Ejemplo n.º 1
0
def make_element_parser(config, content, jinja):
    container_element = make_container_element_parser(
        config,
        content=content,
        jinja=jinja,
    )

    self_closing_element_opening_tag = make_opening_tag_parser(
        config,
        tag_name_parser=P.string_from(*SELF_CLOSING_ELEMENTS),
        allow_slash=True,
        jinja=jinja,
    )

    self_closing_element = (
        locate(P.seq(
            self_closing_element_opening_tag.skip(whitespace),
            P.success(None),  # No content
            P.success(None),  # No closing tag
        ))
        .combine(_combine_element)
    )

    style = make_raw_text_element_parser(config, 'style', jinja=jinja)
    script = make_raw_text_element_parser(config, 'script', jinja=jinja)

    return style | script | self_closing_element | container_element
Ejemplo n.º 2
0
def make_opening_tag_parser(config,
                            jinja,
                            tag_name_parser=None,
                            allow_slash=False):
    attributes = make_attributes_parser(config, jinja)

    if not tag_name_parser:
        tag_name_parser = tag_name | jinja

    if allow_slash:
        slash = (
            locate(
                P.string('/')
                .skip(whitespace)
            )
            .combine(_combine_slash)
            .optional()
        )
    else:
        slash = P.success(None)

    return (
        locate(P.seq(
            P.string('<'),
            tag_name_parser,
            attributes.skip(whitespace),
            slash,
            P.string('>'),
        ))
        .combine(_combine_opening_tag)
    )
Ejemplo n.º 3
0
def make_jinja_element_parser(name_parsers, content):
    """
    `name_parsers` must be a list of tag name parsers. For example,
    `name_parsers` can be defined as follow in order to parse `if` statements:

        name_parsers = [P.string(n) for n in ['if', 'elif', 'else', 'endif']]
    """

    if len(name_parsers) == 1:
        tag = make_jinja_tag_parser(name_parsers[0])
        part = locate(P.seq(
            tag, P.success(None),
        )).combine(_combine_jinja_element_part)
        parts = [part]
        end_tag_parser = None
    else:
        part_names = name_parsers[:-1]
        first_part = make_jinja_element_part_parser(
            part_names[0], content=content)
        next_parts = [
            make_jinja_element_part_parser(name, content=content).many()
            for name in part_names[1:]
        ]
        parts = [first_part] + next_parts
        end_tag_parser = make_jinja_tag_parser(name_parsers[-1])

    content = [P.seq(*parts)]
    if end_tag_parser:
        content.append(end_tag_parser)

    return (
        locate(P.seq(*content))
        .combine(_combine_jinja_element)
    )
Ejemplo n.º 4
0
def space(
    p_space=char.space,
    p_line_comment=parsy.fail('line-comment'),
    p_block_comment=parsy.fail('block-comment')
):
    """
    Produces a parser that consumes white space in general. It's expected
    that you create such a parser once and pass it to other functions in this
    package as needed (when you see `p_space_consumer` in documentation,
    usually it means that something like `space()` is expected there).

    Args:
        p_space_chars: is used to parse blocks of space characters.
            You can use 'char.space' for this purpose, or your own parser
            (if you don't want to automatically consume newlines, for example).
            Make sure the parser does not succeed on empty input though.
        p_line_comment: is used to parse line comments. You can use
            'megaparsy.skip_line_comment` if you don't need anything special.
        p_block_comment: is used to parse block (multi-line) comments. You can
            use `megaparsy.skip_block_comment` or `skip_block_comment_nested`
            if you don't need anything special.

    If you don't want to match a kind of comment, simply pass `parsy.fail()`
    and `space` will just move on or finish depending on whether there is more
    white space for it to consume.
    """
    return parsy.success('')\
        .skip(p_space.optional())\
        .skip(p_line_comment.optional())\
        .skip(p_block_comment.optional())
Ejemplo n.º 5
0
    def type_sequence_parser() -> Generator:
        name = parsers.token('NAME')
        individual_type_variable = (
            # FIXME: Keep track of individual type variables
            parsers.token('BACKTICK') >> name >> parsy.success(None))
        lpar = parsers.token('LPAR')
        rpar = parsers.token('RPAR')
        nested_stack_effect = lpar >> parsers['stack-effect-type'] << rpar
        type = parsers['type'] | individual_type_variable | nested_stack_effect

        # TODO: Allow type-only items
        item = parsy.seq(
            name, (parsers.token('COLON') >>
                   type).optional()).map(_TypeSequenceIndividualTypeNode)
        items = item.many()

        seq_var = parsers.token('STAR') >> name
        seq_var_parsed, i = yield parsy.seq(seq_var.optional(), items)
        seq_var_value = None

        if seq_var_parsed is None and i:
            location = i[0].location
        elif seq_var_parsed is not None:
            location = seq_var_parsed.start
            seq_var_value = seq_var_parsed.value
        else:
            location = None

        return TypeSequenceNode(location, seq_var_value, i)
Ejemplo n.º 6
0
def make_jinja_element_parser(name_parsers, content):
    if len(name_parsers) == 1:
        tag = make_jinja_tag_parser(name_parsers[0])
        part = locate(P.seq(
            tag,
            P.success(None),
        )).combine(_combine_jinja_element_part)
        parts = [part]
        end_tag_parser = None
    else:
        part_names = name_parsers[:-1]
        first_part = make_jinja_element_part_parser(part_names[0],
                                                    content=content)
        next_parts = [
            make_jinja_element_part_parser(name, content=content).many()
            for name in part_names[1:]
        ]
        parts = [first_part] + next_parts
        end_tag_parser = make_jinja_tag_parser(name_parsers[-1])

    content = [P.seq(*parts)]
    if end_tag_parser:
        content.append(end_tag_parser)

    return (locate(P.seq(*content)).combine(_combine_jinja_element))
Ejemplo n.º 7
0
def multiplicative():
    prod = yield additive
    while True:
        op = yield multiplicative_op | success(None)
        if not op:
            return prod
        operand = yield additive
        prod = BinOp(prod, op, operand)
Ejemplo n.º 8
0
def additive():
    sum = yield simple
    while True:
        op = yield additive_op | success(None)
        if not op:
            return sum
        operand = yield simple
        sum = BinOp(sum, op, operand)
Ejemplo n.º 9
0
def make_element_parser(config, content, jinja):
    container_element = make_container_element_parser(
        config, content=content, jinja=jinja
    )

    void_element_opening_tag = make_opening_tag_parser(
        config,
        tag_name_parser=P.string_from(*VOID_ELEMENTS),
        allow_slash=True,
        jinja=jinja,
    )

    void_element = locate(
        P.seq(
            void_element_opening_tag.skip(whitespace),
            P.success(None),  # No content
            P.success(None),  # No closing tag
        )
    ).combine(_combine_element)

    svg_self_closing_tag = make_opening_tag_parser(
        config,
        tag_name_parser=P.string_from(*SVG_SELF_CLOSING_ELEMENTS),
        mandate_slash=True,
        jinja=jinja,
    )

    svg_self_closing_element = locate(
        P.seq(
            svg_self_closing_tag.skip(whitespace),
            P.success(None),  # No content
            P.success(None),  # No closing tag
        )
    ).combine(_combine_element)

    style = make_raw_text_element_parser(config, "style", jinja=jinja)
    script = make_raw_text_element_parser(config, "script", jinja=jinja)

    return (
        style
        | script
        | void_element
        | svg_self_closing_element
        | container_element
    )
Ejemplo n.º 10
0
def binop():
    left = yield simple
    # print('left', left)
    while True:
        op = yield all_op | success(None)
        #   print('binop', op)
        if not op:
            return left

        right = yield simple
        # print('right', right)
        left = BinOp(left, op, right)
Ejemplo n.º 11
0
 def multiplicative():
     res = yield simple
     op = match_item('*') | match_item('/')
     while True:
         operation = yield op | success('')
         if not operation:
             break
         operand = yield simple
         if operation == '*':
             res *= operand
         elif operation == '/':
             res /= operand
     return res
Ejemplo n.º 12
0
 def additive():
     res = yield multiplicative
     sign = match_item('+') | match_item('-')
     while True:
         operation = yield sign | success('')
         if not operation:
             break
         operand = yield multiplicative
         if operation == '+':
             res += operand
         elif operation == '-':
             res -= operand
     return res
Ejemplo n.º 13
0
def expr_add():
    op = (string("+").result(
        lambda first: lambda rest: lambda env: first(env) + rest(env))
          | string("-").result(
              lambda first: lambda rest: lambda env: first(env) - rest(env)))
    this = lambda _: lambda rest: rest
    ms = yield (success([this]) + expr_mul.times(1)).times(1) + \
               (whitespace.optional() >> op.times(1) + expr_mul.times(1)).many()

    value = None
    for op, item in ms:
        value = op(value)(item)

    return value
Ejemplo n.º 14
0
    Create parsers for Jinja variables and regular Jinja tags.

    `name` should be a parser to parse the tag name.
    """
    end = whitespace.then(P.string('-').optional()).skip(P.string(mr + '}'))
    return locate(P.seq(
        P.string('{' + ml).then(P.string('+').optional()),
        P.string('-').optional().skip(whitespace),
        name.skip(whitespace),
        until(end).concat(),
        end
    )).combine(_combine_jinja_tag_like)


jinja_variable = make_jinja_tag_like_parser(
    P.success(None), '{', '}'
).combine(_combine_jinja_variable)


jinja_comment = (
    locate(
        P.string('{#')
        .skip(whitespace)
        .then(until(whitespace + P.string('#}')).concat())
        .skip(whitespace + P.string('#}'))
    )
    .combine(_combine_jinja_comment)
)


def make_jinja_tag_parser(name_parser):
Ejemplo n.º 15
0
    `name` should be a parser to parse the tag name.
    """
    end = whitespace.then(P.string("-").optional()).skip(P.string(mr + "}"))
    return locate(
        P.seq(
            P.string("{" + ml).then(P.string("+").optional()),
            P.string("-").optional().skip(whitespace),
            name.skip(whitespace),
            until(end).concat(),
            end,
        )
    ).combine(_combine_jinja_tag_like)


jinja_variable = make_jinja_tag_like_parser(P.success(None), "{", "}").combine(
    _combine_jinja_variable
)


jinja_comment = locate(
    P.string("{#")
    .skip(whitespace)
    .then(until(whitespace + P.string("#}")).concat())
    .skip(whitespace + P.string("#}"))
).combine(_combine_jinja_comment)


def make_jinja_tag_parser(name_parser):
    return make_jinja_tag_like_parser(name_parser, "%", "%").combine(
        _combine_jinja_tag
Ejemplo n.º 16
0
 def number():
     sign = yield match_item('+') | match_item('-') | success('+')
     value = yield test_item(lambda x: isinstance(x, (int, float)),
                             'number')
     return value if sign == '+' else -value
Ejemplo n.º 17
0
    `name` should be a parser to parse the tag name.
    """
    end = whitespace.then(P.string("-").optional()).skip(P.string(mr + "}"))
    return locate(
        P.seq(
            P.string("{" + ml).then(P.string("+").optional()),
            P.string("-").optional().skip(whitespace),
            name.skip(whitespace),
            until(end).concat(),
            end,
        )).combine(_combine_jinja_tag_like)


jinja_variable = make_jinja_tag_like_parser(
    P.success(None), "{", "}").combine(_combine_jinja_variable)

jinja_comment = locate(
    P.string("{#").skip(whitespace).then(
        until(whitespace + P.string("#}")).concat()).skip(
            whitespace + P.string("#}"))).combine(_combine_jinja_comment)


def make_jinja_tag_parser(name_parser):
    return make_jinja_tag_like_parser(name_parser, "%",
                                      "%").combine(_combine_jinja_tag)


def _combine_jinja_element(locations, content):
    parts = list(flatten(content[0]))
    closing_tag = content[1] if len(content) == 2 else None
Ejemplo n.º 18
0
        operand = yield simple
        sum = BinOp(sum, op, operand)


@generate
def multiplicative():
    prod = yield additive
    while True:
        op = yield multiplicative_op | success(None)
        if not op:
            return prod
        operand = yield additive
        prod = BinOp(prod, op, operand)


sign_op = plus | minus | success("+")


@generate
def number():
    sign = yield sign_op
    num = yield int_ | float_
    return num if sign == "+" else -num


simple = (lparen >> multiplicative << rparen) | number

expr = whitespace >> multiplicative

s = 0
with puzzle_input(18, example, False) as f: