Exemple #1
0
def convert_classdef(config: ParserConfig, children: Sequence[Any]) -> Any:
    classdef, name, *arglist, colon, suite = children

    # First, parse out the comments and empty lines before the statement.
    leading_lines = parse_empty_lines(config, classdef.whitespace_before)

    # Compute common whitespace and nodes
    whitespace_after_class = parse_simple_whitespace(config,
                                                     classdef.whitespace_after)
    namenode = Name(name.string)
    whitespace_after_name = parse_simple_whitespace(config,
                                                    name.whitespace_after)

    # Now, construct the classdef node itself
    if not arglist:
        # No arglist, so no arguments to this class
        return ClassDef(
            leading_lines=leading_lines,
            lines_after_decorators=(),
            whitespace_after_class=whitespace_after_class,
            name=namenode,
            whitespace_after_name=whitespace_after_name,
            body=suite,
        )
    else:
        # Unwrap arglist partial, because its valid to not have any
        lpar, *args, rpar = arglist
        args = args[0].args if args else []

        bases: List[Arg] = []
        keywords: List[Arg] = []

        current_arg = bases
        for arg in args:
            if arg.star == "**" or arg.keyword is not None:
                current_arg = keywords
            # Some quick validation
            if current_arg is keywords and (arg.star == "*" or
                                            (arg.star == ""
                                             and arg.keyword is None)):
                raise PartialParserSyntaxError(
                    "Positional argument follows keyword argument.")
            current_arg.append(arg)

        return ClassDef(
            leading_lines=leading_lines,
            lines_after_decorators=(),
            whitespace_after_class=whitespace_after_class,
            name=namenode,
            whitespace_after_name=whitespace_after_name,
            lpar=LeftParen(whitespace_after=parse_parenthesizable_whitespace(
                config, lpar.whitespace_after)),
            bases=bases,
            keywords=keywords,
            rpar=RightParen(whitespace_before=parse_parenthesizable_whitespace(
                config, rpar.whitespace_before)),
            whitespace_before_colon=parse_simple_whitespace(
                config, colon.whitespace_before),
            body=suite,
        )
Exemple #2
0
def convert_except_clause(config: ParserConfig, children: Sequence[Any]) -> Any:
    if len(children) == 1:
        (except_token,) = children
        whitespace_after_except = SimpleWhitespace("")
        test = None
        name = None
    elif len(children) == 2:
        (except_token, test_node) = children
        whitespace_after_except = parse_simple_whitespace(
            config, except_token.whitespace_after
        )
        test = test_node.value
        name = None
    else:
        (except_token, test_node, as_token, name_token) = children
        whitespace_after_except = parse_simple_whitespace(
            config, except_token.whitespace_after
        )
        test = test_node.value
        name = AsName(
            whitespace_before_as=parse_simple_whitespace(
                config, as_token.whitespace_before
            ),
            whitespace_after_as=parse_simple_whitespace(
                config, as_token.whitespace_after
            ),
            name=Name(name_token.string),
        )

    return ExceptClausePartial(
        leading_lines=parse_empty_lines(config, except_token.whitespace_before),
        whitespace_after_except=whitespace_after_except,
        type=test,
        name=name,
    )
Exemple #3
0
def convert_dotted_name(config: ParserConfig, children: Sequence[Any]) -> Any:
    left, *rest = children
    node = Name(left.string)

    for dot, right in grouper(rest, 2):
        node = Attribute(
            value=node,
            dot=Dot(
                whitespace_before=parse_parenthesizable_whitespace(
                    config, dot.whitespace_before),
                whitespace_after=parse_parenthesizable_whitespace(
                    config, dot.whitespace_after),
            ),
            attr=Name(right.string),
        )

    return node
Exemple #4
0
def convert_import_as_name(config: ParserConfig,
                           children: Sequence[Any]) -> Any:
    if len(children) == 1:
        (dotted_name, ) = children
        return ImportAlias(name=Name(dotted_name.string), asname=None)
    else:
        dotted_name, astoken, name = children
        return ImportAlias(
            name=Name(dotted_name.string),
            asname=AsName(
                whitespace_before_as=parse_simple_whitespace(
                    config, astoken.whitespace_before),
                whitespace_after_as=parse_simple_whitespace(
                    config, astoken.whitespace_after),
                name=Name(name.string),
            ),
        )
Exemple #5
0
def _construct_nameitems(config: ParserConfig,
                         names: Sequence[Any]) -> List[NameItem]:
    nameitems: List[NameItem] = []
    for name, maybe_comma in grouper(names, 2):
        if maybe_comma is None:
            nameitems.append(NameItem(Name(name.string)))
        else:
            nameitems.append(
                NameItem(
                    Name(name.string),
                    comma=Comma(
                        whitespace_before=parse_simple_whitespace(
                            config, maybe_comma.whitespace_before),
                        whitespace_after=parse_simple_whitespace(
                            config, maybe_comma.whitespace_after),
                    ),
                ))
    return nameitems
Exemple #6
0
def convert_fpdef(config: ParserConfig, children: Sequence[Any]) -> Any:
    if len(children) == 1:
        # This is just a parameter
        (child, ) = children
        namenode = Name(child.string)
        annotation = None
    else:
        # This is a parameter with a type hint
        name, colon, typehint = children
        namenode = Name(name.string)
        annotation = Annotation(
            whitespace_before_indicator=parse_parenthesizable_whitespace(
                config, colon.whitespace_before),
            whitespace_after_indicator=parse_parenthesizable_whitespace(
                config, colon.whitespace_after),
            annotation=typehint.value,
        )

    return Param(star="", name=namenode, annotation=annotation, default=None)
Exemple #7
0
def convert_funcdef(config: ParserConfig, children: Sequence[Any]) -> Any:
    defnode, namenode, param_partial, *annotation, colon, suite = children

    # If the trailing paremeter doesn't have a comma, then it owns the trailing
    # whitespace before the rpar. Otherwise, the comma owns it (and will have
    # already parsed it). We don't check/update ParamStar because if it exists
    # then we are guaranteed have at least one kwonly_param.
    parameters = param_partial.params
    if parameters.star_kwarg is not None:
        if parameters.star_kwarg.comma == MaybeSentinel.DEFAULT:
            parameters = parameters.with_changes(
                star_kwarg=parameters.star_kwarg.with_changes(
                    whitespace_after_param=param_partial.rpar.whitespace_before
                ))
    elif parameters.kwonly_params:
        if parameters.kwonly_params[-1].comma == MaybeSentinel.DEFAULT:
            parameters = parameters.with_changes(kwonly_params=(
                *parameters.kwonly_params[:-1],
                parameters.kwonly_params[-1].with_changes(
                    whitespace_after_param=param_partial.rpar.whitespace_before
                ),
            ))
    elif isinstance(parameters.star_arg, Param):
        if parameters.star_arg.comma == MaybeSentinel.DEFAULT:
            parameters = parameters.with_changes(
                star_arg=parameters.star_arg.with_changes(
                    whitespace_after_param=param_partial.rpar.whitespace_before
                ))
    elif parameters.params:
        if parameters.params[-1].comma == MaybeSentinel.DEFAULT:
            parameters = parameters.with_changes(params=(
                *parameters.params[:-1],
                parameters.params[-1].with_changes(
                    whitespace_after_param=param_partial.rpar.whitespace_before
                ),
            ))

    return WithLeadingWhitespace(
        FunctionDef(
            whitespace_after_def=parse_simple_whitespace(
                config, defnode.whitespace_after),
            name=Name(namenode.string),
            whitespace_after_name=parse_simple_whitespace(
                config, namenode.whitespace_after),
            whitespace_before_params=param_partial.lpar.whitespace_after,
            params=parameters,
            returns=None if not annotation else annotation[0],
            whitespace_before_colon=parse_simple_whitespace(
                config, colon.whitespace_before),
            body=suite,
        ),
        defnode.whitespace_before,
    )
Exemple #8
0
def convert_trailer_attribute(
        config: ParserConfig,
        children: typing.Sequence[typing.Any]) -> typing.Any:
    dot, name = children
    return AttributePartial(
        dot=Dot(
            whitespace_before=parse_parenthesizable_whitespace(
                config, dot.whitespace_before),
            whitespace_after=parse_parenthesizable_whitespace(
                config, dot.whitespace_after),
        ),
        attr=Name(name.string),
    )
Exemple #9
0
def convert_atom_basic(
    config: ParserConfig, children: typing.Sequence[typing.Any]
) -> typing.Any:
    (child,) = children
    if child.type.name == "NAME":
        # This also handles 'None', 'True', and 'False' directly, but we
        # keep it in the grammar to be more correct.
        return WithLeadingWhitespace(Name(child.string), child.whitespace_before)
    elif child.type.name == "NUMBER":
        # We must determine what type of number it is since we split node
        # types up this way.
        if re.fullmatch(INTNUMBER_RE, child.string):
            return WithLeadingWhitespace(Integer(child.string), child.whitespace_before)
        elif re.fullmatch(FLOATNUMBER_RE, child.string):
            return WithLeadingWhitespace(Float(child.string), child.whitespace_before)
        elif re.fullmatch(IMAGNUMBER_RE, child.string):
            return WithLeadingWhitespace(
                Imaginary(child.string), child.whitespace_before
            )
        else:
            raise Exception("Unparseable number {child.string}")
    else:
        raise Exception(f"Logic error, unexpected token {child.type.name}")