Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
ast.py203 linesDownload Raw Back to mako
1# mako/ast.py2# Copyright 2006-2024 the Mako authors and contributors <see AUTHORS file>3#4# This module is part of Mako and is released under5# the MIT License: http://www.opensource.org/licenses/mit-license.php6 7"""utilities for analyzing expressions and blocks of Python8code, as well as generating Python from AST nodes"""9 10import re11 12from mako import exceptions13from mako import pyparser14 15 16class PythonCode:17 18    """represents information about a string containing Python code"""19 20    def __init__(self, code, **exception_kwargs):21        self.code = code22 23        # represents all identifiers which are assigned to at some point in24        # the code25        self.declared_identifiers = set()26 27        # represents all identifiers which are referenced before their28        # assignment, if any29        self.undeclared_identifiers = set()30 31        # note that an identifier can be in both the undeclared and declared32        # lists.33 34        # using AST to parse instead of using code.co_varnames,35        # code.co_names has several advantages:36        # - we can locate an identifier as "undeclared" even if37        # its declared later in the same block of code38        # - AST is less likely to break with version changes39        # (for example, the behavior of co_names changed a little bit40        # in python version 2.5)41        if isinstance(code, str):42            expr = pyparser.parse(code.lstrip(), "exec", **exception_kwargs)43        else:44            expr = code45 46        f = pyparser.FindIdentifiers(self, **exception_kwargs)47        f.visit(expr)48 49 50class ArgumentList:51 52    """parses a fragment of code as a comma-separated list of expressions"""53 54    def __init__(self, code, **exception_kwargs):55        self.codeargs = []56        self.args = []57        self.declared_identifiers = set()58        self.undeclared_identifiers = set()59        if isinstance(code, str):60            if re.match(r"\S", code) and not re.match(r",\s*$", code):61                # if theres text and no trailing comma, insure its parsed62                # as a tuple by adding a trailing comma63                code += ","64            expr = pyparser.parse(code, "exec", **exception_kwargs)65        else:66            expr = code67 68        f = pyparser.FindTuple(self, PythonCode, **exception_kwargs)69        f.visit(expr)70 71 72class PythonFragment(PythonCode):73 74    """extends PythonCode to provide identifier lookups in partial control75    statements76 77    e.g.::78 79        for x in 5:80        elif y==9:81        except (MyException, e):82 83    """84 85    def __init__(self, code, **exception_kwargs):86        m = re.match(r"^(\w+)(?:\s+(.*?))?:\s*(#|$)", code.strip(), re.S)87        if not m:88            raise exceptions.CompileException(89                "Fragment '%s' is not a partial control statement" % code,90                **exception_kwargs,91            )92        if m.group(3):93            code = code[: m.start(3)]94        (keyword, expr) = m.group(1, 2)95        if keyword in ["for", "if", "while"]:96            code = code + "pass"97        elif keyword == "try":98            code = code + "pass\nexcept:pass"99        elif keyword in ["elif", "else"]:100            code = "if False:pass\n" + code + "pass"101        elif keyword == "except":102            code = "try:pass\n" + code + "pass"103        elif keyword == "with":104            code = code + "pass"105        else:106            raise exceptions.CompileException(107                "Unsupported control keyword: '%s'" % keyword,108                **exception_kwargs,109            )110        super().__init__(code, **exception_kwargs)111 112 113class FunctionDecl:114 115    """function declaration"""116 117    def __init__(self, code, allow_kwargs=True, **exception_kwargs):118        self.code = code119        expr = pyparser.parse(code, "exec", **exception_kwargs)120 121        f = pyparser.ParseFunc(self, **exception_kwargs)122        f.visit(expr)123        if not hasattr(self, "funcname"):124            raise exceptions.CompileException(125                "Code '%s' is not a function declaration" % code,126                **exception_kwargs,127            )128        if not allow_kwargs and self.kwargs:129            raise exceptions.CompileException(130                "'**%s' keyword argument not allowed here"131                % self.kwargnames[-1],132                **exception_kwargs,133            )134 135    def get_argument_expressions(self, as_call=False):136        """Return the argument declarations of this FunctionDecl as a printable137        list.138 139        By default the return value is appropriate for writing in a ``def``;140        set `as_call` to true to build arguments to be passed to the function141        instead (assuming locals with the same names as the arguments exist).142        """143 144        namedecls = []145 146        # Build in reverse order, since defaults and slurpy args come last147        argnames = self.argnames[::-1]148        kwargnames = self.kwargnames[::-1]149        defaults = self.defaults[::-1]150        kwdefaults = self.kwdefaults[::-1]151 152        # Named arguments153        if self.kwargs:154            namedecls.append("**" + kwargnames.pop(0))155 156        for name in kwargnames:157            # Keyword-only arguments must always be used by name, so even if158            # this is a call, print out `foo=foo`159            if as_call:160                namedecls.append("%s=%s" % (name, name))161            elif kwdefaults:162                default = kwdefaults.pop(0)163                if default is None:164                    # The AST always gives kwargs a default, since you can do165                    # `def foo(*, a=1, b, c=3)`166                    namedecls.append(name)167                else:168                    namedecls.append(169                        "%s=%s"170                        % (name, pyparser.ExpressionGenerator(default).value())171                    )172            else:173                namedecls.append(name)174 175        # Positional arguments176        if self.varargs:177            namedecls.append("*" + argnames.pop(0))178 179        for name in argnames:180            if as_call or not defaults:181                namedecls.append(name)182            else:183                default = defaults.pop(0)184                namedecls.append(185                    "%s=%s"186                    % (name, pyparser.ExpressionGenerator(default).value())187                )188 189        namedecls.reverse()190        return namedecls191 192    @property193    def allargnames(self):194        return tuple(self.argnames) + tuple(self.kwargnames)195 196 197class FunctionArgs(FunctionDecl):198 199    """the argument portion of a function declaration"""200 201    def __init__(self, code, **kwargs):202        super().__init__("def ANON(%s):pass" % code, **kwargs)203 
codekingpro/portable-devtools · Team Ai