Пример #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
Пример #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)
    )
Пример #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)
    )
Пример #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())
Пример #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)
Пример #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))
Пример #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)
Пример #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)
Пример #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
    )
Пример #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)
Пример #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
Пример #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
Пример #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
Пример #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):
Пример #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
Пример #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
Пример #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
Пример #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: