1# (C) Copyright 2020 by Rocky Bernstein
2#
3#  This program is free software; you can redistribute it and/or
4#  modify it under the terms of the GNU General Public License
5#  as published by the Free Software Foundation; either version 2
6#  of the License, or (at your option) any later version.
7#
8#  This program is distributed in the hope that it will be useful,
9#  but WITHOUT ANY WARRANTY; without even the implied warranty of
10#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11#  GNU General Public License for more details.
12#
13#  You should have received a copy of the GNU General Public License
14#  along with this program; if not, write to the Free Software
15#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16
17from xdis.version_info import PYTHON_VERSION
18from xdis.codetype.code30 import Code3, Code3FieldTypes
19import types
20from copy import deepcopy
21
22# Note: order is the positional order. It is important to match this
23# with the 3.8 order.
24Code38FieldNames = """
25        co_argcount
26        co_posonlyargcount
27        co_kwonlyargcount
28        co_nlocals
29        co_stacksize
30        co_flags
31        co_code
32        co_consts
33        co_names
34        co_varnames
35        co_filename
36        co_name
37        co_firstlineno
38        co_lnotab
39        co_freevars
40        co_cellvars
41"""
42
43Code38FieldTypes = deepcopy(Code3FieldTypes)
44Code38FieldTypes.update({
45    "co_posonlyargcount": int,
46})
47
48
49
50class Code38(Code3):
51    """Class for a Python 3.8+ code object used when a Python interpreter less than 3.8 is
52    working on Python3 bytecode. It also functions as an object that can be used
53    to build or write a Python3 code object, since we allow mutable structures.
54
55    When done mutating, call method to_native().
56
57    For convenience in generating code objects, fields like
58    `co_consts`, co_names which are (immutable) tuples in the end-result can be stored
59    instead as (mutable) lists. Likewise the line number table `co_lnotab`
60    can be stored as a simple list of offset, line_number tuples.
61    """
62
63    def __init__(
64        self,
65        co_argcount,
66        co_posonlyargcount,
67        co_kwonlyargcount,
68        co_nlocals,
69        co_stacksize,
70        co_flags,
71        co_code,
72        co_consts,
73        co_names,
74        co_varnames,
75        co_filename,
76        co_name,
77        co_firstlineno,
78        co_lnotab,
79        co_freevars,
80        co_cellvars,
81    ):
82        super(Code38, self).__init__(
83            co_argcount,
84            co_kwonlyargcount,
85            co_nlocals,
86            co_stacksize,
87            co_flags,
88            co_code,
89            co_consts,
90            co_names,
91            co_varnames,
92            co_filename,
93            co_name,
94            co_firstlineno,
95            co_lnotab,
96            co_freevars,
97            co_cellvars,
98        )
99        self.co_posonlyargcount = co_posonlyargcount
100        self.fieldtypes = Code38FieldTypes
101        if type(self) == Code38:
102            self.check()
103
104    def to_native(self):
105        if not (PYTHON_VERSION >= 3.8):
106            raise TypeError(
107                "Python Interpreter needs to be in 3.8 or greater; is %s"
108                % PYTHON_VERSION
109            )
110
111        code = deepcopy(self)
112        code.freeze()
113        try:
114            code.check()
115        except AssertionError as e:
116            raise TypeError(e)
117
118        return types.CodeType(
119            code.co_argcount,
120            code.co_posonlyargcount,
121            code.co_kwonlyargcount,
122            code.co_nlocals,
123            code.co_stacksize,
124            code.co_flags,
125            code.co_code,
126            code.co_consts,
127            code.co_names,
128            code.co_varnames,
129            code.co_filename,
130            code.co_name,
131            code.co_firstlineno,
132            code.co_lnotab,
133            code.co_freevars,
134            code.co_cellvars,
135        )
136