xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/codeop.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Workerr"""Utilities to compile possibly incomplete Python source code.
2*cda5da8dSAndroid Build Coastguard Worker
3*cda5da8dSAndroid Build Coastguard WorkerThis module provides two interfaces, broadly similar to the builtin
4*cda5da8dSAndroid Build Coastguard Workerfunction compile(), which take program text, a filename and a 'mode'
5*cda5da8dSAndroid Build Coastguard Workerand:
6*cda5da8dSAndroid Build Coastguard Worker
7*cda5da8dSAndroid Build Coastguard Worker- Return code object if the command is complete and valid
8*cda5da8dSAndroid Build Coastguard Worker- Return None if the command is incomplete
9*cda5da8dSAndroid Build Coastguard Worker- Raise SyntaxError, ValueError or OverflowError if the command is a
10*cda5da8dSAndroid Build Coastguard Worker  syntax error (OverflowError and ValueError can be produced by
11*cda5da8dSAndroid Build Coastguard Worker  malformed literals).
12*cda5da8dSAndroid Build Coastguard Worker
13*cda5da8dSAndroid Build Coastguard WorkerThe two interfaces are:
14*cda5da8dSAndroid Build Coastguard Worker
15*cda5da8dSAndroid Build Coastguard Workercompile_command(source, filename, symbol):
16*cda5da8dSAndroid Build Coastguard Worker
17*cda5da8dSAndroid Build Coastguard Worker    Compiles a single command in the manner described above.
18*cda5da8dSAndroid Build Coastguard Worker
19*cda5da8dSAndroid Build Coastguard WorkerCommandCompiler():
20*cda5da8dSAndroid Build Coastguard Worker
21*cda5da8dSAndroid Build Coastguard Worker    Instances of this class have __call__ methods identical in
22*cda5da8dSAndroid Build Coastguard Worker    signature to compile_command; the difference is that if the
23*cda5da8dSAndroid Build Coastguard Worker    instance compiles program text containing a __future__ statement,
24*cda5da8dSAndroid Build Coastguard Worker    the instance 'remembers' and compiles all subsequent program texts
25*cda5da8dSAndroid Build Coastguard Worker    with the statement in force.
26*cda5da8dSAndroid Build Coastguard Worker
27*cda5da8dSAndroid Build Coastguard WorkerThe module also provides another class:
28*cda5da8dSAndroid Build Coastguard Worker
29*cda5da8dSAndroid Build Coastguard WorkerCompile():
30*cda5da8dSAndroid Build Coastguard Worker
31*cda5da8dSAndroid Build Coastguard Worker    Instances of this class act like the built-in function compile,
32*cda5da8dSAndroid Build Coastguard Worker    but with 'memory' in the sense described above.
33*cda5da8dSAndroid Build Coastguard Worker"""
34*cda5da8dSAndroid Build Coastguard Worker
35*cda5da8dSAndroid Build Coastguard Workerimport __future__
36*cda5da8dSAndroid Build Coastguard Workerimport warnings
37*cda5da8dSAndroid Build Coastguard Worker
38*cda5da8dSAndroid Build Coastguard Worker_features = [getattr(__future__, fname)
39*cda5da8dSAndroid Build Coastguard Worker             for fname in __future__.all_feature_names]
40*cda5da8dSAndroid Build Coastguard Worker
41*cda5da8dSAndroid Build Coastguard Worker__all__ = ["compile_command", "Compile", "CommandCompiler"]
42*cda5da8dSAndroid Build Coastguard Worker
43*cda5da8dSAndroid Build Coastguard Worker# The following flags match the values from Include/cpython/compile.h
44*cda5da8dSAndroid Build Coastguard Worker# Caveat emptor: These flags are undocumented on purpose and depending
45*cda5da8dSAndroid Build Coastguard Worker# on their effect outside the standard library is **unsupported**.
46*cda5da8dSAndroid Build Coastguard WorkerPyCF_DONT_IMPLY_DEDENT = 0x200
47*cda5da8dSAndroid Build Coastguard WorkerPyCF_ALLOW_INCOMPLETE_INPUT = 0x4000
48*cda5da8dSAndroid Build Coastguard Worker
49*cda5da8dSAndroid Build Coastguard Workerdef _maybe_compile(compiler, source, filename, symbol):
50*cda5da8dSAndroid Build Coastguard Worker    # Check for source consisting of only blank lines and comments.
51*cda5da8dSAndroid Build Coastguard Worker    for line in source.split("\n"):
52*cda5da8dSAndroid Build Coastguard Worker        line = line.strip()
53*cda5da8dSAndroid Build Coastguard Worker        if line and line[0] != '#':
54*cda5da8dSAndroid Build Coastguard Worker            break               # Leave it alone.
55*cda5da8dSAndroid Build Coastguard Worker    else:
56*cda5da8dSAndroid Build Coastguard Worker        if symbol != "eval":
57*cda5da8dSAndroid Build Coastguard Worker            source = "pass"     # Replace it with a 'pass' statement
58*cda5da8dSAndroid Build Coastguard Worker
59*cda5da8dSAndroid Build Coastguard Worker    # Disable compiler warnings when checking for incomplete input.
60*cda5da8dSAndroid Build Coastguard Worker    with warnings.catch_warnings():
61*cda5da8dSAndroid Build Coastguard Worker        warnings.simplefilter("ignore", (SyntaxWarning, DeprecationWarning))
62*cda5da8dSAndroid Build Coastguard Worker        try:
63*cda5da8dSAndroid Build Coastguard Worker            compiler(source, filename, symbol)
64*cda5da8dSAndroid Build Coastguard Worker        except SyntaxError:  # Let other compile() errors propagate.
65*cda5da8dSAndroid Build Coastguard Worker            try:
66*cda5da8dSAndroid Build Coastguard Worker                compiler(source + "\n", filename, symbol)
67*cda5da8dSAndroid Build Coastguard Worker                return None
68*cda5da8dSAndroid Build Coastguard Worker            except SyntaxError as e:
69*cda5da8dSAndroid Build Coastguard Worker                if "incomplete input" in str(e):
70*cda5da8dSAndroid Build Coastguard Worker                    return None
71*cda5da8dSAndroid Build Coastguard Worker                # fallthrough
72*cda5da8dSAndroid Build Coastguard Worker
73*cda5da8dSAndroid Build Coastguard Worker    return compiler(source, filename, symbol)
74*cda5da8dSAndroid Build Coastguard Worker
75*cda5da8dSAndroid Build Coastguard Worker
76*cda5da8dSAndroid Build Coastguard Workerdef _is_syntax_error(err1, err2):
77*cda5da8dSAndroid Build Coastguard Worker    rep1 = repr(err1)
78*cda5da8dSAndroid Build Coastguard Worker    rep2 = repr(err2)
79*cda5da8dSAndroid Build Coastguard Worker    if "was never closed" in rep1 and "was never closed" in rep2:
80*cda5da8dSAndroid Build Coastguard Worker        return False
81*cda5da8dSAndroid Build Coastguard Worker    if rep1 == rep2:
82*cda5da8dSAndroid Build Coastguard Worker        return True
83*cda5da8dSAndroid Build Coastguard Worker    return False
84*cda5da8dSAndroid Build Coastguard Worker
85*cda5da8dSAndroid Build Coastguard Workerdef _compile(source, filename, symbol):
86*cda5da8dSAndroid Build Coastguard Worker    return compile(source, filename, symbol, PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT)
87*cda5da8dSAndroid Build Coastguard Worker
88*cda5da8dSAndroid Build Coastguard Workerdef compile_command(source, filename="<input>", symbol="single"):
89*cda5da8dSAndroid Build Coastguard Worker    r"""Compile a command and determine whether it is incomplete.
90*cda5da8dSAndroid Build Coastguard Worker
91*cda5da8dSAndroid Build Coastguard Worker    Arguments:
92*cda5da8dSAndroid Build Coastguard Worker
93*cda5da8dSAndroid Build Coastguard Worker    source -- the source string; may contain \n characters
94*cda5da8dSAndroid Build Coastguard Worker    filename -- optional filename from which source was read; default
95*cda5da8dSAndroid Build Coastguard Worker                "<input>"
96*cda5da8dSAndroid Build Coastguard Worker    symbol -- optional grammar start symbol; "single" (default), "exec"
97*cda5da8dSAndroid Build Coastguard Worker              or "eval"
98*cda5da8dSAndroid Build Coastguard Worker
99*cda5da8dSAndroid Build Coastguard Worker    Return value / exceptions raised:
100*cda5da8dSAndroid Build Coastguard Worker
101*cda5da8dSAndroid Build Coastguard Worker    - Return a code object if the command is complete and valid
102*cda5da8dSAndroid Build Coastguard Worker    - Return None if the command is incomplete
103*cda5da8dSAndroid Build Coastguard Worker    - Raise SyntaxError, ValueError or OverflowError if the command is a
104*cda5da8dSAndroid Build Coastguard Worker      syntax error (OverflowError and ValueError can be produced by
105*cda5da8dSAndroid Build Coastguard Worker      malformed literals).
106*cda5da8dSAndroid Build Coastguard Worker    """
107*cda5da8dSAndroid Build Coastguard Worker    return _maybe_compile(_compile, source, filename, symbol)
108*cda5da8dSAndroid Build Coastguard Worker
109*cda5da8dSAndroid Build Coastguard Workerclass Compile:
110*cda5da8dSAndroid Build Coastguard Worker    """Instances of this class behave much like the built-in compile
111*cda5da8dSAndroid Build Coastguard Worker    function, but if one is used to compile text containing a future
112*cda5da8dSAndroid Build Coastguard Worker    statement, it "remembers" and compiles all subsequent program texts
113*cda5da8dSAndroid Build Coastguard Worker    with the statement in force."""
114*cda5da8dSAndroid Build Coastguard Worker    def __init__(self):
115*cda5da8dSAndroid Build Coastguard Worker        self.flags = PyCF_DONT_IMPLY_DEDENT | PyCF_ALLOW_INCOMPLETE_INPUT
116*cda5da8dSAndroid Build Coastguard Worker
117*cda5da8dSAndroid Build Coastguard Worker    def __call__(self, source, filename, symbol):
118*cda5da8dSAndroid Build Coastguard Worker        codeob = compile(source, filename, symbol, self.flags, True)
119*cda5da8dSAndroid Build Coastguard Worker        for feature in _features:
120*cda5da8dSAndroid Build Coastguard Worker            if codeob.co_flags & feature.compiler_flag:
121*cda5da8dSAndroid Build Coastguard Worker                self.flags |= feature.compiler_flag
122*cda5da8dSAndroid Build Coastguard Worker        return codeob
123*cda5da8dSAndroid Build Coastguard Worker
124*cda5da8dSAndroid Build Coastguard Workerclass CommandCompiler:
125*cda5da8dSAndroid Build Coastguard Worker    """Instances of this class have __call__ methods identical in
126*cda5da8dSAndroid Build Coastguard Worker    signature to compile_command; the difference is that if the
127*cda5da8dSAndroid Build Coastguard Worker    instance compiles program text containing a __future__ statement,
128*cda5da8dSAndroid Build Coastguard Worker    the instance 'remembers' and compiles all subsequent program texts
129*cda5da8dSAndroid Build Coastguard Worker    with the statement in force."""
130*cda5da8dSAndroid Build Coastguard Worker
131*cda5da8dSAndroid Build Coastguard Worker    def __init__(self,):
132*cda5da8dSAndroid Build Coastguard Worker        self.compiler = Compile()
133*cda5da8dSAndroid Build Coastguard Worker
134*cda5da8dSAndroid Build Coastguard Worker    def __call__(self, source, filename="<input>", symbol="single"):
135*cda5da8dSAndroid Build Coastguard Worker        r"""Compile a command and determine whether it is incomplete.
136*cda5da8dSAndroid Build Coastguard Worker
137*cda5da8dSAndroid Build Coastguard Worker        Arguments:
138*cda5da8dSAndroid Build Coastguard Worker
139*cda5da8dSAndroid Build Coastguard Worker        source -- the source string; may contain \n characters
140*cda5da8dSAndroid Build Coastguard Worker        filename -- optional filename from which source was read;
141*cda5da8dSAndroid Build Coastguard Worker                    default "<input>"
142*cda5da8dSAndroid Build Coastguard Worker        symbol -- optional grammar start symbol; "single" (default) or
143*cda5da8dSAndroid Build Coastguard Worker                  "eval"
144*cda5da8dSAndroid Build Coastguard Worker
145*cda5da8dSAndroid Build Coastguard Worker        Return value / exceptions raised:
146*cda5da8dSAndroid Build Coastguard Worker
147*cda5da8dSAndroid Build Coastguard Worker        - Return a code object if the command is complete and valid
148*cda5da8dSAndroid Build Coastguard Worker        - Return None if the command is incomplete
149*cda5da8dSAndroid Build Coastguard Worker        - Raise SyntaxError, ValueError or OverflowError if the command is a
150*cda5da8dSAndroid Build Coastguard Worker          syntax error (OverflowError and ValueError can be produced by
151*cda5da8dSAndroid Build Coastguard Worker          malformed literals).
152*cda5da8dSAndroid Build Coastguard Worker        """
153*cda5da8dSAndroid Build Coastguard Worker        return _maybe_compile(self.compiler, source, filename, symbol)
154