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.
Files changed (80) hide show
  1. py2ecma/__init__.py +10 -0
  2. py2ecma/__main__.py +146 -0
  3. py2ecma/arguments.py +152 -0
  4. py2ecma/codegenerator/__init__.py +0 -0
  5. py2ecma/codegenerator/enums.py +19 -0
  6. py2ecma/codegenerator/nameconverter.py +10 -0
  7. py2ecma/codegenerator/nintermediate/__init__.py +18 -0
  8. py2ecma/codegenerator/nintermediate/asyncs.py +32 -0
  9. py2ecma/codegenerator/nintermediate/classes.py +303 -0
  10. py2ecma/codegenerator/nintermediate/comprehensions.py +72 -0
  11. py2ecma/codegenerator/nintermediate/controlflow.py +135 -0
  12. py2ecma/codegenerator/nintermediate/expressions.py +320 -0
  13. py2ecma/codegenerator/nintermediate/functions.py +187 -0
  14. py2ecma/codegenerator/nintermediate/imports.py +51 -0
  15. py2ecma/codegenerator/nintermediate/literals.py +133 -0
  16. py2ecma/codegenerator/nintermediate/module.py +113 -0
  17. py2ecma/codegenerator/nintermediate/node.py +29 -0
  18. py2ecma/codegenerator/nintermediate/statements.py +104 -0
  19. py2ecma/codegenerator/nintermediate/subscripting.py +56 -0
  20. py2ecma/codegenerator/nintermediate/variables.py +24 -0
  21. py2ecma/codegenerator/optimizer.py +121 -0
  22. py2ecma/codegenerator/parser.py +642 -0
  23. py2ecma/codegenerator/specialcases.py +12 -0
  24. py2ecma/codegenerator/traversers.py +91 -0
  25. py2ecma/conf.py +48 -0
  26. py2ecma/dependency/__init__.py +0 -0
  27. py2ecma/dependency/excludes.py +6 -0
  28. py2ecma/dependency/getdeps.py +83 -0
  29. py2ecma/dependency/sortedset.py +60 -0
  30. py2ecma/dependency/spec.py +57 -0
  31. py2ecma/filesystem.py +121 -0
  32. py2ecma/get_logger.py +64 -0
  33. py2ecma/javascript/base.js +1 -0
  34. py2ecma/javascript/builtins.js +339 -0
  35. py2ecma/javascript/classes.js +162 -0
  36. py2ecma/javascript/comprehensions.js +53 -0
  37. py2ecma/javascript/dict.js +131 -0
  38. py2ecma/javascript/exceptions.js +58 -0
  39. py2ecma/javascript/list.js +199 -0
  40. py2ecma/javascript/set.js +214 -0
  41. py2ecma/javascript/strings.js +60 -0
  42. py2ecma/lexer/__init__.py +0 -0
  43. py2ecma/lexer/syntaxtree.py +6 -0
  44. py2ecma/linker/__init__.py +0 -0
  45. py2ecma/linker/jsloader.py +66 -0
  46. py2ecma/linker/packager.py +91 -0
  47. py2ecma/main.py +45 -0
  48. py2ecma/minimizer/__init__.py +3 -0
  49. py2ecma/minimizer/closure.py +51 -0
  50. py2ecma/modules/__init__.py +0 -0
  51. py2ecma/modules/codecs.py +965 -0
  52. py2ecma/modules/collections.py +1462 -0
  53. py2ecma/modules/copy.py +52 -0
  54. py2ecma/modules/dataclasses.py +1337 -0
  55. py2ecma/modules/datetime.py +1953 -0
  56. py2ecma/modules/enum.py +945 -0
  57. py2ecma/modules/functools.py +912 -0
  58. py2ecma/modules/json.py +94 -0
  59. py2ecma/modules/keyword.py +101 -0
  60. py2ecma/modules/math.py +170 -0
  61. py2ecma/modules/operator.py +575 -0
  62. py2ecma/modules/re.py +415 -0
  63. py2ecma/modules/re_/__init__.py +838 -0
  64. py2ecma/modules/re_/translate.py +348 -0
  65. py2ecma/modules/sre_compile.py +0 -0
  66. py2ecma/modules/sre_constants.py +259 -0
  67. py2ecma/modules/sre_parse.py +1073 -0
  68. py2ecma/modules/stubs.py +1 -0
  69. py2ecma/modules/sys.py +0 -0
  70. py2ecma/modules/time.py +539 -0
  71. py2ecma/modules/types.py +279 -0
  72. py2ecma/progress.py +103 -0
  73. py2ecma/py.typed +0 -0
  74. py2ecma/transpiler.py +184 -0
  75. py2ecma/watcher/__init__.py +0 -0
  76. py2ecma/watcher/autocompile.py +42 -0
  77. py2ecma-0.0.2.dist-info/METADATA +26 -0
  78. py2ecma-0.0.2.dist-info/RECORD +80 -0
  79. py2ecma-0.0.2.dist-info/WHEEL +4 -0
  80. py2ecma-0.0.2.dist-info/licenses/LICENSE-2.0.txt +202 -0
py2ecma/__init__.py ADDED
@@ -0,0 +1,10 @@
1
+ def loadjs(js, filepath):
2
+ pass
3
+
4
+
5
+ def js(js: str):
6
+ pass
7
+
8
+
9
+ def boundmethod(func):
10
+ return func
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,10 @@
1
+ CONVERT = {
2
+ "self": "this",
3
+ "split": "_split",
4
+ "switch": "_switch",
5
+ "TypeError": "_TypeError",
6
+ }
7
+
8
+
9
+ def converter(name: str) -> str:
10
+ return CONVERT.get(name, name)
@@ -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
+ )