py2ecma 0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- py2ecma/__init__.py +10 -0
- py2ecma/__main__.py +146 -0
- py2ecma/arguments.py +152 -0
- py2ecma/codegenerator/__init__.py +0 -0
- py2ecma/codegenerator/enums.py +19 -0
- py2ecma/codegenerator/nameconverter.py +10 -0
- py2ecma/codegenerator/nintermediate/__init__.py +18 -0
- py2ecma/codegenerator/nintermediate/asyncs.py +32 -0
- py2ecma/codegenerator/nintermediate/classes.py +303 -0
- py2ecma/codegenerator/nintermediate/comprehensions.py +72 -0
- py2ecma/codegenerator/nintermediate/controlflow.py +135 -0
- py2ecma/codegenerator/nintermediate/expressions.py +320 -0
- py2ecma/codegenerator/nintermediate/functions.py +187 -0
- py2ecma/codegenerator/nintermediate/imports.py +51 -0
- py2ecma/codegenerator/nintermediate/literals.py +133 -0
- py2ecma/codegenerator/nintermediate/module.py +113 -0
- py2ecma/codegenerator/nintermediate/node.py +29 -0
- py2ecma/codegenerator/nintermediate/statements.py +104 -0
- py2ecma/codegenerator/nintermediate/subscripting.py +56 -0
- py2ecma/codegenerator/nintermediate/variables.py +24 -0
- py2ecma/codegenerator/optimizer.py +121 -0
- py2ecma/codegenerator/parser.py +642 -0
- py2ecma/codegenerator/specialcases.py +12 -0
- py2ecma/codegenerator/traversers.py +91 -0
- py2ecma/conf.py +48 -0
- py2ecma/dependency/__init__.py +0 -0
- py2ecma/dependency/excludes.py +6 -0
- py2ecma/dependency/getdeps.py +83 -0
- py2ecma/dependency/sortedset.py +60 -0
- py2ecma/dependency/spec.py +57 -0
- py2ecma/filesystem.py +121 -0
- py2ecma/get_logger.py +64 -0
- py2ecma/javascript/base.js +1 -0
- py2ecma/javascript/builtins.js +339 -0
- py2ecma/javascript/classes.js +162 -0
- py2ecma/javascript/comprehensions.js +53 -0
- py2ecma/javascript/dict.js +131 -0
- py2ecma/javascript/exceptions.js +58 -0
- py2ecma/javascript/list.js +199 -0
- py2ecma/javascript/set.js +214 -0
- py2ecma/javascript/strings.js +60 -0
- py2ecma/lexer/__init__.py +0 -0
- py2ecma/lexer/syntaxtree.py +6 -0
- py2ecma/linker/__init__.py +0 -0
- py2ecma/linker/jsloader.py +66 -0
- py2ecma/linker/packager.py +91 -0
- py2ecma/main.py +45 -0
- py2ecma/minimizer/__init__.py +3 -0
- py2ecma/minimizer/closure.py +51 -0
- py2ecma/modules/__init__.py +0 -0
- py2ecma/modules/codecs.py +965 -0
- py2ecma/modules/collections.py +1462 -0
- py2ecma/modules/copy.py +52 -0
- py2ecma/modules/dataclasses.py +1337 -0
- py2ecma/modules/datetime.py +1953 -0
- py2ecma/modules/enum.py +945 -0
- py2ecma/modules/functools.py +912 -0
- py2ecma/modules/json.py +94 -0
- py2ecma/modules/keyword.py +101 -0
- py2ecma/modules/math.py +170 -0
- py2ecma/modules/operator.py +575 -0
- py2ecma/modules/re.py +415 -0
- py2ecma/modules/re_/__init__.py +838 -0
- py2ecma/modules/re_/translate.py +348 -0
- py2ecma/modules/sre_compile.py +0 -0
- py2ecma/modules/sre_constants.py +259 -0
- py2ecma/modules/sre_parse.py +1073 -0
- py2ecma/modules/stubs.py +1 -0
- py2ecma/modules/sys.py +0 -0
- py2ecma/modules/time.py +539 -0
- py2ecma/modules/types.py +279 -0
- py2ecma/progress.py +103 -0
- py2ecma/py.typed +0 -0
- py2ecma/transpiler.py +184 -0
- py2ecma/watcher/__init__.py +0 -0
- py2ecma/watcher/autocompile.py +42 -0
- py2ecma-0.0.2.dist-info/METADATA +26 -0
- py2ecma-0.0.2.dist-info/RECORD +80 -0
- py2ecma-0.0.2.dist-info/WHEEL +4 -0
- py2ecma-0.0.2.dist-info/licenses/LICENSE-2.0.txt +202 -0
py2ecma/__init__.py
ADDED
py2ecma/__main__.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# WRAP_STDERR=true
|
|
3
|
+
import argparse
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
from py2ecma.conf import TranspilerConfig
|
|
7
|
+
from py2ecma.transpiler import Transpiler
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main():
|
|
11
|
+
parser = argparse.ArgumentParser()
|
|
12
|
+
|
|
13
|
+
# Positional arguments; required
|
|
14
|
+
parser.add_argument(
|
|
15
|
+
"input",
|
|
16
|
+
metavar="input.py",
|
|
17
|
+
help="main .py file to transpile. The transpiler"
|
|
18
|
+
" will translate every import recursively from this"
|
|
19
|
+
" entry point.",
|
|
20
|
+
)
|
|
21
|
+
# Options
|
|
22
|
+
parser.add_argument(
|
|
23
|
+
"-o",
|
|
24
|
+
"--output",
|
|
25
|
+
dest="output_file",
|
|
26
|
+
default="./bundle.js",
|
|
27
|
+
metavar="output.js",
|
|
28
|
+
help="output javascript file. The intermediate output"
|
|
29
|
+
" will be bundled together into this file.",
|
|
30
|
+
)
|
|
31
|
+
parser.add_argument(
|
|
32
|
+
"-b",
|
|
33
|
+
"--build-dir",
|
|
34
|
+
dest="build_dir",
|
|
35
|
+
default="./.build/",
|
|
36
|
+
help="build directive, all intermediate output from"
|
|
37
|
+
" transpiled files will end up here. While abiding to"
|
|
38
|
+
" the directory stucture. Will default to .build in"
|
|
39
|
+
" the current directory.",
|
|
40
|
+
metavar="dir",
|
|
41
|
+
)
|
|
42
|
+
parser.add_argument(
|
|
43
|
+
"-c",
|
|
44
|
+
"--clean",
|
|
45
|
+
action="store_true",
|
|
46
|
+
dest="clean",
|
|
47
|
+
default=False,
|
|
48
|
+
help="clean the build directory before transpiling."
|
|
49
|
+
" This will trigger a complete compile of all"
|
|
50
|
+
" source files",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"-d",
|
|
54
|
+
"--dont-follow-imports",
|
|
55
|
+
action="store_false",
|
|
56
|
+
dest="recursive",
|
|
57
|
+
default=True,
|
|
58
|
+
help="don't follow imports in the python input file."
|
|
59
|
+
" Only transpile single file.",
|
|
60
|
+
)
|
|
61
|
+
parser.add_argument(
|
|
62
|
+
"-e",
|
|
63
|
+
"--externs",
|
|
64
|
+
required=False,
|
|
65
|
+
nargs="+",
|
|
66
|
+
dest="externs",
|
|
67
|
+
default=list(),
|
|
68
|
+
help="Extern files for the closure compiler, can be a list of files",
|
|
69
|
+
)
|
|
70
|
+
parser.add_argument(
|
|
71
|
+
"-m",
|
|
72
|
+
"--minimize",
|
|
73
|
+
action="store_true",
|
|
74
|
+
dest="minimize",
|
|
75
|
+
default=False,
|
|
76
|
+
help="minimize the output file.",
|
|
77
|
+
)
|
|
78
|
+
parser.add_argument(
|
|
79
|
+
"-p",
|
|
80
|
+
"--disable-progressbar",
|
|
81
|
+
action="store_true",
|
|
82
|
+
dest="disable_progressbar",
|
|
83
|
+
default=False,
|
|
84
|
+
help="Disable progressbar.",
|
|
85
|
+
)
|
|
86
|
+
parser.add_argument(
|
|
87
|
+
"-q",
|
|
88
|
+
"--quiet",
|
|
89
|
+
action="store_true",
|
|
90
|
+
dest="quiet",
|
|
91
|
+
default=False,
|
|
92
|
+
help="don't print status messages to stdout.",
|
|
93
|
+
)
|
|
94
|
+
parser.add_argument(
|
|
95
|
+
"-v",
|
|
96
|
+
"--verbose",
|
|
97
|
+
action="store_true",
|
|
98
|
+
dest="verbose",
|
|
99
|
+
default=False,
|
|
100
|
+
help="set the logging level to info.",
|
|
101
|
+
)
|
|
102
|
+
parser.add_argument(
|
|
103
|
+
"-vv",
|
|
104
|
+
"--very_verbose",
|
|
105
|
+
action="store_true",
|
|
106
|
+
dest="very_verbose",
|
|
107
|
+
default=False,
|
|
108
|
+
help="set the logging level to debug.",
|
|
109
|
+
)
|
|
110
|
+
parser.add_argument(
|
|
111
|
+
"-w",
|
|
112
|
+
"--watch",
|
|
113
|
+
action="store_true",
|
|
114
|
+
dest="watch",
|
|
115
|
+
default=False,
|
|
116
|
+
help="watch the input file and depedencies for changes" " and recompile.",
|
|
117
|
+
)
|
|
118
|
+
parser.add_argument(
|
|
119
|
+
"-r",
|
|
120
|
+
"--raw",
|
|
121
|
+
action="store_true",
|
|
122
|
+
dest="raw",
|
|
123
|
+
default=False,
|
|
124
|
+
help="Output the compiled js to console without" " runtime environment",
|
|
125
|
+
)
|
|
126
|
+
parser.add_argument(
|
|
127
|
+
"-t",
|
|
128
|
+
"--type-check",
|
|
129
|
+
action="store_true",
|
|
130
|
+
dest="type_check",
|
|
131
|
+
default=False,
|
|
132
|
+
help="enable python3.x typechecking with mypy.",
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
args = parser.parse_args()
|
|
136
|
+
transpiler_config = TranspilerConfig(args)
|
|
137
|
+
transpiler = Transpiler(transpiler_config)
|
|
138
|
+
try:
|
|
139
|
+
transpiler.transpile()
|
|
140
|
+
except:
|
|
141
|
+
return 1
|
|
142
|
+
return 0
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
main()
|
py2ecma/arguments.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
|
|
3
|
+
PROGRAM_HANDLE = "py2ecma"
|
|
4
|
+
|
|
5
|
+
DESCRIPTION = ""
|
|
6
|
+
|
|
7
|
+
EPILOG = """
|
|
8
|
+
Notes:
|
|
9
|
+
~~~~~~
|
|
10
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
|
|
11
|
+
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
|
|
12
|
+
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
|
13
|
+
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore
|
|
14
|
+
eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt
|
|
15
|
+
in culpa qui officia deserunt mollit anim id est laborum.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def arg_parser() -> argparse.ArgumentParser:
|
|
20
|
+
"""Function to implement argparse parameters
|
|
21
|
+
|
|
22
|
+
NOTE: If this function gets out of hand, length wise, consider moving it to
|
|
23
|
+
its own file(e.g. arg_parse.py)
|
|
24
|
+
"""
|
|
25
|
+
parser = argparse.ArgumentParser(
|
|
26
|
+
prog=PROGRAM_HANDLE,
|
|
27
|
+
description=DESCRIPTION,
|
|
28
|
+
epilog=EPILOG,
|
|
29
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
30
|
+
)
|
|
31
|
+
parser.add_argument(
|
|
32
|
+
"input",
|
|
33
|
+
metavar="input.py",
|
|
34
|
+
help="main .py file to transpile. The transpiler"
|
|
35
|
+
" will translate every import recursively from this"
|
|
36
|
+
" entry point.",
|
|
37
|
+
)
|
|
38
|
+
# Options
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"-o",
|
|
41
|
+
"--output",
|
|
42
|
+
dest="output_file",
|
|
43
|
+
default="./bundle.js",
|
|
44
|
+
metavar="output.js",
|
|
45
|
+
help="output javascript file. The intermediate output"
|
|
46
|
+
" will be bundled together into this file.",
|
|
47
|
+
)
|
|
48
|
+
parser.add_argument(
|
|
49
|
+
"-b",
|
|
50
|
+
"--build-dir",
|
|
51
|
+
dest="build_dir",
|
|
52
|
+
default="./.build/",
|
|
53
|
+
help="build directive, all intermediate output from"
|
|
54
|
+
" transpiled files will end up here. While abiding to"
|
|
55
|
+
" the directory stucture. Will default to .build in"
|
|
56
|
+
" the current directory.",
|
|
57
|
+
metavar="dir",
|
|
58
|
+
)
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"-c",
|
|
61
|
+
"--clean",
|
|
62
|
+
action="store_true",
|
|
63
|
+
dest="clean",
|
|
64
|
+
default=False,
|
|
65
|
+
help="clean the build directory before transpiling."
|
|
66
|
+
" This will trigger a complete compile of all"
|
|
67
|
+
" source files",
|
|
68
|
+
)
|
|
69
|
+
parser.add_argument(
|
|
70
|
+
"-d",
|
|
71
|
+
"--dont-follow-imports",
|
|
72
|
+
action="store_false",
|
|
73
|
+
dest="recursive",
|
|
74
|
+
default=True,
|
|
75
|
+
help="don't follow imports in the python input file."
|
|
76
|
+
" Only transpile single file.",
|
|
77
|
+
)
|
|
78
|
+
parser.add_argument(
|
|
79
|
+
"-e",
|
|
80
|
+
"--externs",
|
|
81
|
+
required=False,
|
|
82
|
+
nargs="+",
|
|
83
|
+
dest="externs",
|
|
84
|
+
default=list(),
|
|
85
|
+
help="Extern files for the closure compiler, can be a list of files",
|
|
86
|
+
)
|
|
87
|
+
parser.add_argument(
|
|
88
|
+
"-m",
|
|
89
|
+
"--minimize",
|
|
90
|
+
action="store_true",
|
|
91
|
+
dest="minimize",
|
|
92
|
+
default=False,
|
|
93
|
+
help="minimize the output file.",
|
|
94
|
+
)
|
|
95
|
+
parser.add_argument(
|
|
96
|
+
"-p",
|
|
97
|
+
"--disable-progressbar",
|
|
98
|
+
action="store_true",
|
|
99
|
+
dest="disable_progressbar",
|
|
100
|
+
default=False,
|
|
101
|
+
help="Disable progressbar.",
|
|
102
|
+
)
|
|
103
|
+
parser.add_argument(
|
|
104
|
+
"-q",
|
|
105
|
+
"--quiet",
|
|
106
|
+
action="store_true",
|
|
107
|
+
dest="quiet",
|
|
108
|
+
default=False,
|
|
109
|
+
help="don't print status messages to stdout.",
|
|
110
|
+
)
|
|
111
|
+
parser.add_argument(
|
|
112
|
+
"-v",
|
|
113
|
+
"--verbose",
|
|
114
|
+
action="store_true",
|
|
115
|
+
dest="verbose",
|
|
116
|
+
default=False,
|
|
117
|
+
help="set the logging level to info.",
|
|
118
|
+
)
|
|
119
|
+
parser.add_argument(
|
|
120
|
+
"-vv",
|
|
121
|
+
"--very_verbose",
|
|
122
|
+
action="store_true",
|
|
123
|
+
dest="very_verbose",
|
|
124
|
+
default=False,
|
|
125
|
+
help="set the logging level to debug.",
|
|
126
|
+
)
|
|
127
|
+
parser.add_argument(
|
|
128
|
+
"-w",
|
|
129
|
+
"--watch",
|
|
130
|
+
action="store_true",
|
|
131
|
+
dest="watch",
|
|
132
|
+
default=False,
|
|
133
|
+
help="watch the input file and depedencies for changes" " and recompile.",
|
|
134
|
+
)
|
|
135
|
+
parser.add_argument(
|
|
136
|
+
"-r",
|
|
137
|
+
"--raw",
|
|
138
|
+
action="store_true",
|
|
139
|
+
dest="raw",
|
|
140
|
+
default=False,
|
|
141
|
+
help="Output the compiled js to console without" " runtime environment",
|
|
142
|
+
)
|
|
143
|
+
parser.add_argument(
|
|
144
|
+
"-t",
|
|
145
|
+
"--type-check",
|
|
146
|
+
action="store_true",
|
|
147
|
+
dest="type_check",
|
|
148
|
+
default=False,
|
|
149
|
+
help="enable python3.x typechecking with mypy.",
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
return parser
|
|
File without changes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CTX(Enum):
|
|
6
|
+
LOAD = 1
|
|
7
|
+
STORE = 2
|
|
8
|
+
DELETE = 3
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def from_ast(ctx):
|
|
12
|
+
if isinstance(ctx, ast.Load):
|
|
13
|
+
return CTX.LOAD
|
|
14
|
+
elif isinstance(ctx, ast.Store):
|
|
15
|
+
return CTX.STORE
|
|
16
|
+
elif isinstance(ctx, ast.Del):
|
|
17
|
+
return CTX.DELETE
|
|
18
|
+
else:
|
|
19
|
+
raise ValueError(f"Unknown context type {type(ctx)}")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from typing import Iterable
|
|
2
|
+
|
|
3
|
+
from py2ecma.get_logger import logger
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def code_generation(intermediate) -> str:
|
|
7
|
+
def flatten(container):
|
|
8
|
+
for i in container:
|
|
9
|
+
if not isinstance(i, str) and isinstance(i, (list, tuple, Iterable)):
|
|
10
|
+
for j in flatten(i):
|
|
11
|
+
yield j
|
|
12
|
+
elif i is None:
|
|
13
|
+
pass
|
|
14
|
+
logger.warning(f"Trying to flatten a None value")
|
|
15
|
+
else:
|
|
16
|
+
yield i
|
|
17
|
+
|
|
18
|
+
return "".join(flatten(intermediate))
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
from .node import Node
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class AsyncFunctionDef(Node):
|
|
9
|
+
name: str
|
|
10
|
+
decorator_list: List[Node]
|
|
11
|
+
args: Node
|
|
12
|
+
body: List[Node]
|
|
13
|
+
var: str
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class Await(Node):
|
|
18
|
+
value: Node
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class AsyncFor(Node):
|
|
23
|
+
target: Node
|
|
24
|
+
iter: Node
|
|
25
|
+
body: List[Node]
|
|
26
|
+
orelse: List[Node]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class AsyncWith(Node):
|
|
31
|
+
items: List[Node]
|
|
32
|
+
body: List[Node]
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
from copy import deepcopy as copy
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import List
|
|
4
|
+
|
|
5
|
+
from .functions import FunctionDef
|
|
6
|
+
from .node import Node
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class ClassDef(Node):
|
|
11
|
+
name: str
|
|
12
|
+
bases: List[Node]
|
|
13
|
+
keywords: List[Node]
|
|
14
|
+
body: List[Node]
|
|
15
|
+
constructors: List[Node]
|
|
16
|
+
decorator_list: List[Node]
|
|
17
|
+
init: List[Node]
|
|
18
|
+
assignments: List[str]
|
|
19
|
+
is_proxy: bool
|
|
20
|
+
|
|
21
|
+
def inheritance(self):
|
|
22
|
+
if len(self.bases) > 0:
|
|
23
|
+
yield self.bases[-1]
|
|
24
|
+
else:
|
|
25
|
+
yield "BaseClass"
|
|
26
|
+
|
|
27
|
+
def multiple_inheritance(self):
|
|
28
|
+
if len(self.bases) > 1:
|
|
29
|
+
for b in self.bases[::-1][1:]:
|
|
30
|
+
yield f"_cls_extend({self.name}.prototype, "
|
|
31
|
+
yield b
|
|
32
|
+
yield ".prototype);\n"
|
|
33
|
+
else:
|
|
34
|
+
yield ""
|
|
35
|
+
|
|
36
|
+
def constructor_body(self):
|
|
37
|
+
assigns = copy(self.assignments)
|
|
38
|
+
yield "constructor(...args) {\n"
|
|
39
|
+
yield "super(...args);\n"
|
|
40
|
+
for t in assigns:
|
|
41
|
+
yield t.body()
|
|
42
|
+
yield self.binds()
|
|
43
|
+
yield self.constructor_kwargs()
|
|
44
|
+
yield self.binds_static()
|
|
45
|
+
if len(self.constructors) > 0:
|
|
46
|
+
for x in self.constructors:
|
|
47
|
+
yield x.body
|
|
48
|
+
yield "}\n"
|
|
49
|
+
|
|
50
|
+
def constructor_kwargs(self):
|
|
51
|
+
methods = [method for method in self.body if isinstance(method, Method)]
|
|
52
|
+
simple_methods = filter(
|
|
53
|
+
lambda m: not (m.is_staticmethod or m.is_classmethod or m.is_property),
|
|
54
|
+
methods,
|
|
55
|
+
)
|
|
56
|
+
for method in simple_methods:
|
|
57
|
+
yield f"this.{method.name}"
|
|
58
|
+
yield method.kwargs("this")
|
|
59
|
+
|
|
60
|
+
def special_methods_kwargs(self):
|
|
61
|
+
"""Special methods referes to classmethods & static methods"""
|
|
62
|
+
methods = [method for method in self.body if isinstance(method, Method)]
|
|
63
|
+
simple_methods = list(
|
|
64
|
+
filter(lambda m: (m.is_staticmethod or m.is_classmethod), methods)
|
|
65
|
+
)
|
|
66
|
+
for method in simple_methods:
|
|
67
|
+
yield f"{self.name}.{method.name}"
|
|
68
|
+
yield method.kwargs(self.name)
|
|
69
|
+
|
|
70
|
+
def kwargs(self):
|
|
71
|
+
if len(self.init) > 0:
|
|
72
|
+
yield [init.static_kwarg() for init in self.init]
|
|
73
|
+
|
|
74
|
+
def call(self):
|
|
75
|
+
if len(self.init) > 0:
|
|
76
|
+
yield [init.static_call(self.name) for init in self.init]
|
|
77
|
+
|
|
78
|
+
def binds(self):
|
|
79
|
+
methods = [method for method in self.body if isinstance(method, Method)]
|
|
80
|
+
simples = [
|
|
81
|
+
m.name
|
|
82
|
+
for m in methods
|
|
83
|
+
if not (m.is_property or m.is_staticmethod or m.is_classmethod)
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
for m in simples:
|
|
87
|
+
yield f"this.{m} = this.{m}.bind(this);\n"
|
|
88
|
+
|
|
89
|
+
def binds_static(self):
|
|
90
|
+
methods = [method for method in self.body if isinstance(method, Method)]
|
|
91
|
+
statics = [
|
|
92
|
+
method.name
|
|
93
|
+
for method in methods
|
|
94
|
+
if method.is_staticmethod or method.is_classmethod
|
|
95
|
+
]
|
|
96
|
+
for m in statics:
|
|
97
|
+
yield f"this.{m} = this.constructor.{m}.bind(this);\n"
|
|
98
|
+
yield f"this.{m}.kwargs = this.constructor.{m}.kwargs.bind(this);\n"
|
|
99
|
+
simples = [
|
|
100
|
+
m.name
|
|
101
|
+
for m in methods
|
|
102
|
+
if not (m.is_property or m.is_staticmethod or m.is_classmethod)
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
for m in simples:
|
|
106
|
+
yield f"this.{m}.kwargs = this.{m}.kwargs.bind(this);\n"
|
|
107
|
+
|
|
108
|
+
def proxy(self):
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
def code(self):
|
|
112
|
+
yield f"class {'py_' if self.is_proxy else ''}{ self.name } extends "
|
|
113
|
+
yield self.inheritance()
|
|
114
|
+
yield " {\n"
|
|
115
|
+
yield self.constructor_body()
|
|
116
|
+
yield self.kwargs()
|
|
117
|
+
yield self.call()
|
|
118
|
+
yield [
|
|
119
|
+
b
|
|
120
|
+
for b in self.body
|
|
121
|
+
if not (isinstance(b, Method) and b.name == "constructor")
|
|
122
|
+
]
|
|
123
|
+
yield "}\n"
|
|
124
|
+
if self.is_proxy:
|
|
125
|
+
yield f"const {self.name} = proxyClass(py_{self.name});\n"
|
|
126
|
+
yield self.assignments
|
|
127
|
+
yield self.special_methods_kwargs()
|
|
128
|
+
yield self.multiple_inheritance()
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@dataclass
|
|
132
|
+
class Method(Node):
|
|
133
|
+
name: str
|
|
134
|
+
clsname: str
|
|
135
|
+
decorators: List[Node]
|
|
136
|
+
args: Node
|
|
137
|
+
body: List[Node]
|
|
138
|
+
var: str
|
|
139
|
+
is_generator: bool
|
|
140
|
+
is_staticmethod: bool
|
|
141
|
+
is_property: bool
|
|
142
|
+
is_classmethod: bool
|
|
143
|
+
|
|
144
|
+
def code(self):
|
|
145
|
+
yield "static " if self.is_staticmethod or self.is_classmethod else ""
|
|
146
|
+
yield "get " if self.is_property else ""
|
|
147
|
+
yield "* " if self.is_generator else ""
|
|
148
|
+
yield f"{ self.name } ("
|
|
149
|
+
yield FunctionDef.arg_string_generator(
|
|
150
|
+
self.arg[1 if self.is_classmethod else 0 :],
|
|
151
|
+
self.args.defaults,
|
|
152
|
+
self.args.vararg,
|
|
153
|
+
self.args.kwarg,
|
|
154
|
+
)
|
|
155
|
+
yield ") {\n"
|
|
156
|
+
if self.is_classmethod:
|
|
157
|
+
yield f"var {self.arg[0]} = this;\n"
|
|
158
|
+
yield "return (("
|
|
159
|
+
yield FunctionDef.arg_string_generator(
|
|
160
|
+
self.arg, self.args.defaults, self.args.vararg, self.args.kwarg
|
|
161
|
+
)
|
|
162
|
+
yield ") => {\n"
|
|
163
|
+
yield self.var
|
|
164
|
+
yield self.body
|
|
165
|
+
if self.is_classmethod:
|
|
166
|
+
yield "})(this, "
|
|
167
|
+
yield self.join(
|
|
168
|
+
", ",
|
|
169
|
+
self.arg[1:] # Skip first argument it will be self
|
|
170
|
+
+ ([self.args.kwarg] if self.args.kwarg else [])
|
|
171
|
+
+ ([f"...{self.args.vararg}"] if self.args.vararg else []),
|
|
172
|
+
)
|
|
173
|
+
yield ");\n"
|
|
174
|
+
yield "}\n"
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def arg(self):
|
|
178
|
+
offset = 0 if self.is_staticmethod or self.is_classmethod else 1
|
|
179
|
+
return self.args.args[offset:]
|
|
180
|
+
|
|
181
|
+
def kwargs(self, callee):
|
|
182
|
+
varg = [f"...{self.args.vararg}"] if self.args.vararg is not None else []
|
|
183
|
+
|
|
184
|
+
yield f".kwargs = (__kwargs__, ...__args__) => {{\n"
|
|
185
|
+
yield FunctionDef.kwargs_body(
|
|
186
|
+
name="",
|
|
187
|
+
call=f"{self.clsname}.call",
|
|
188
|
+
args=self.arg[1 if self.is_classmethod else 0 :],
|
|
189
|
+
defaults=self.args.defaults,
|
|
190
|
+
varg=self.args.vararg,
|
|
191
|
+
kwarg=self.args.kwarg,
|
|
192
|
+
)
|
|
193
|
+
yield f"return {callee}.{self.name}.call(this, "
|
|
194
|
+
yield ", ".join(self.arg[1 if self.is_classmethod else 0 :] + ["__kwargs__"])
|
|
195
|
+
yield [", "] * len(varg) + varg
|
|
196
|
+
yield ");\n};\n"
|
|
197
|
+
|
|
198
|
+
def static_kwarg(self):
|
|
199
|
+
varg = [f"...{self.args.vararg}"] if self.args.vararg is not None else []
|
|
200
|
+
|
|
201
|
+
yield "static kwargs(__kwargs__, ...__args__) {\n"
|
|
202
|
+
|
|
203
|
+
yield FunctionDef.kwargs_body(
|
|
204
|
+
name="",
|
|
205
|
+
call=f"{self.clsname}.call",
|
|
206
|
+
args=self.arg,
|
|
207
|
+
defaults=self.args.defaults,
|
|
208
|
+
varg=self.args.vararg,
|
|
209
|
+
kwarg=self.args.kwarg,
|
|
210
|
+
)
|
|
211
|
+
yield f"return this.__new__("
|
|
212
|
+
yield ", ".join(self.arg + ["dict(__kwargs__)"])
|
|
213
|
+
yield [", "] * len(varg) + varg
|
|
214
|
+
yield ");\n};\n"
|
|
215
|
+
|
|
216
|
+
def static_call(self, name):
|
|
217
|
+
if bool(self.args.vararg) and bool(self.args.kwarg):
|
|
218
|
+
args = self.args.args
|
|
219
|
+
namedargs = ", ".join(args[1:]) + ", " if len(args) > 1 else ""
|
|
220
|
+
yield f"static call(self, {namedargs} ...arg) {{"
|
|
221
|
+
yield f"const cls_ = this.__new__({namedargs} dict(), ...arg);\n"
|
|
222
|
+
yield f"return cls_ }};\n"
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
@dataclass
|
|
226
|
+
class ClassAssign(Node):
|
|
227
|
+
cls: str
|
|
228
|
+
targets: List[Node]
|
|
229
|
+
value: Node
|
|
230
|
+
|
|
231
|
+
def code(self):
|
|
232
|
+
for t in self.targets:
|
|
233
|
+
yield f'__attribute__({self.cls}, "'
|
|
234
|
+
yield t
|
|
235
|
+
yield '", '
|
|
236
|
+
yield self.value
|
|
237
|
+
yield ");\n"
|
|
238
|
+
|
|
239
|
+
def body(self):
|
|
240
|
+
for t in self.targets:
|
|
241
|
+
yield '__attribute__(this, "'
|
|
242
|
+
yield t
|
|
243
|
+
yield '", '
|
|
244
|
+
yield self.cls
|
|
245
|
+
yield "."
|
|
246
|
+
yield t
|
|
247
|
+
yield ");\n"
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@dataclass
|
|
251
|
+
class Super(Node):
|
|
252
|
+
func: Node
|
|
253
|
+
args: List[Node]
|
|
254
|
+
|
|
255
|
+
def code(self):
|
|
256
|
+
if bool(self.args):
|
|
257
|
+
yield "__super__("
|
|
258
|
+
yield self.join(", ", self.args)
|
|
259
|
+
yield ")"
|
|
260
|
+
else:
|
|
261
|
+
yield "super"
|
|
262
|
+
|
|
263
|
+
@classmethod
|
|
264
|
+
def from_node(cls, node, file_):
|
|
265
|
+
return cls(
|
|
266
|
+
file_,
|
|
267
|
+
node.func,
|
|
268
|
+
node.args,
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
@dataclass
|
|
273
|
+
class MethodFunc(FunctionDef):
|
|
274
|
+
name: str
|
|
275
|
+
decorators: List[Node]
|
|
276
|
+
args: Node
|
|
277
|
+
body: List[Node]
|
|
278
|
+
var: str
|
|
279
|
+
is_generator: bool
|
|
280
|
+
|
|
281
|
+
def code(self):
|
|
282
|
+
args = self.get_parameters()
|
|
283
|
+
gen = "*" if self.is_generator else ""
|
|
284
|
+
yield f"let {self.name} = {gen}("
|
|
285
|
+
yield args
|
|
286
|
+
yield ") => {\n"
|
|
287
|
+
yield self.var
|
|
288
|
+
yield self.body
|
|
289
|
+
yield "}\n"
|
|
290
|
+
yield (
|
|
291
|
+
self.kwarg_method(
|
|
292
|
+
self.name,
|
|
293
|
+
self.name,
|
|
294
|
+
self.args.args,
|
|
295
|
+
self.args.defaults,
|
|
296
|
+
self.args.vararg,
|
|
297
|
+
self.args.kwarg,
|
|
298
|
+
)
|
|
299
|
+
if len(self.args.args) + len(self.args.defaults)
|
|
300
|
+
or self.args.vararg
|
|
301
|
+
or self.args.kwarg
|
|
302
|
+
else ""
|
|
303
|
+
)
|