@darabonba/python-generator 1.2.18 → 2.0.0
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.
- package/ChangeLog.md +0 -155
- package/lib/builtin.js +818 -0
- package/lib/generator.js +2704 -0
- package/lib/helper.js +422 -0
- package/package.json +6 -5
- package/src/lib/helper.js +11 -1
- package/src/resolver/base.js +3 -1
- package/src/resolver/client.js +7 -4
- package/src/resolver/model.js +5 -3
- package/tests/expected/alias/setup.py +79 -0
- package/tests/expected/alias/tea_python_tests/__init__.py +1 -0
- package/tests/expected/alias/tea_python_tests/client.py +35 -0
- package/tests/expected/annotation/tea_python_tests/__init__.py +1 -0
- package/tests/expected/annotation/tea_python_tests/client.py +93 -0
- package/tests/expected/annotation/tea_python_tests/models.py +37 -0
- package/tests/expected/api/tea_python_tests/__init__.py +1 -0
- package/tests/expected/api/tea_python_tests/client.py +106 -0
- package/tests/expected/builtin/tea_python_tests/client.py +685 -0
- package/tests/expected/comment/tea_python_tests/__init__.py +1 -0
- package/tests/expected/comment/tea_python_tests/client.py +288 -0
- package/tests/expected/comment/tea_python_tests/models.py +195 -0
- package/tests/expected/complex/tea_python_tests/__init__.py +1 -0
- package/tests/expected/complex/tea_python_tests/client.py +1168 -0
- package/tests/expected/complex/tea_python_tests/exceptions.py +39 -0
- package/tests/expected/complex/tea_python_tests/models.py +570 -0
- package/tests/expected/const/tea_python_tests/__init__.py +1 -0
- package/tests/expected/const/tea_python_tests/client.py +14 -0
- package/tests/expected/empty/setup.py +74 -0
- package/tests/expected/empty/tea_python_tests/__init__.py +1 -0
- package/tests/expected/empty/tea_python_tests/client.py +10 -0
- package/tests/expected/exec/tea_python_tests/__init__.py +1 -0
- package/tests/expected/exec/tea_python_tests/exec_client.py +21 -0
- package/tests/expected/function/tea_python_tests/__init__.py +1 -0
- package/tests/expected/function/tea_python_tests/client.py +64 -0
- package/tests/expected/import/setup.py +78 -0
- package/tests/expected/import/tea_python_tests/__init__.py +1 -0
- package/tests/expected/import/tea_python_tests/client.py +29 -0
- package/tests/expected/map/tea_python_tests/__init__.py +1 -0
- package/tests/expected/map/tea_python_tests/client.py +39 -0
- package/tests/expected/model/tea_python_tests/__init__.py +1 -0
- package/tests/expected/model/tea_python_tests/client.py +10 -0
- package/tests/expected/model/tea_python_tests/exceptions.py +28 -0
- package/tests/expected/model/tea_python_tests/models.py +780 -0
- package/tests/expected/multi/tea_python_tests/api.py +95 -0
- package/tests/expected/multi/tea_python_tests/client.py +40 -0
- package/tests/expected/multi/tea_python_tests/lib/util.py +19 -0
- package/tests/expected/multi/tea_python_tests/model/user.py +23 -0
- package/tests/expected/multi/tea_python_tests/model/user_exceptions.py +83 -0
- package/tests/expected/multi/tea_python_tests/model/user_models.py +145 -0
- package/tests/expected/python2/function/tea_python_tests/client.py +3 -1
- package/tests/expected/python2/model/tea_python_tests/models.py +57 -30
- package/tests/expected/python3/function/tea_python_tests/client.py +3 -1
- package/tests/expected/python3/model/tea_python_tests/models.py +57 -29
- package/tests/expected/statements/tea_python_tests/__init__.py +1 -0
- package/tests/expected/statements/tea_python_tests/client.py +86 -0
- package/tests/expected/super/tea_python_tests/__init__.py +1 -0
- package/tests/expected/super/tea_python_tests/client.py +16 -0
- package/tests/expected/typedef/setup.py +77 -0
- package/tests/expected/typedef/tea_python_tests/__init__.py +1 -0
- package/tests/expected/typedef/tea_python_tests/client.py +74 -0
- package/tests/expected/typedef/tea_python_tests/models.py +42 -0
- package/tests/fixtures/alias/Darafile +11 -0
- package/tests/fixtures/alias/libraries/Alias/Darafile +11 -0
- package/tests/fixtures/alias/libraries/Alias-Symbol/Darafile +11 -0
- package/tests/fixtures/builtin/Darafile +6 -0
- package/tests/fixtures/builtin/main.dara +333 -0
- package/tests/fixtures/complex/libraries/import.dara +18 -11
- package/tests/fixtures/complex/main.dara +451 -103
- package/tests/fixtures/function/main.dara +2 -0
- package/tests/fixtures/import/libraries/Darafile +1 -1
- package/tests/fixtures/import/pack/Darafile +3 -0
- package/tests/fixtures/map/libraries/Darafile +3 -0
- package/tests/fixtures/map/libraries/import.dara +4 -0
- package/tests/fixtures/map/main.dara +17 -2
- package/tests/fixtures/model/.libraries.json +3 -0
- package/tests/fixtures/model/Darafile +5 -2
- package/tests/fixtures/model/libraries/Darafile +20 -0
- package/tests/fixtures/model/libraries/import.dara +27 -0
- package/tests/fixtures/model/main.dara +57 -37
- package/tests/fixtures/multi/.libraries.json +3 -0
- package/tests/fixtures/multi/Darafile +12 -0
- package/tests/fixtures/multi/api.dara +20 -0
- package/tests/fixtures/multi/lib/util.dara +5 -0
- package/tests/fixtures/multi/libraries/darabonba_Util_0.2.11/Teafile +62 -0
- package/tests/fixtures/multi/libraries/darabonba_Util_0.2.11/main.tea +244 -0
- package/tests/fixtures/multi/main.dara +32 -0
- package/tests/fixtures/multi/model/user.dara +33 -0
- package/tests/{python3.tests.js → main.tests.js} +107 -65
- package/tests/output/alias/setup.py +79 -0
- package/tests/output/alias/tea_python_tests/client.py +35 -0
- package/tests/output/annotation/setup.py +77 -0
- package/tests/output/annotation/tea_python_tests/client.py +93 -0
- package/tests/output/annotation/tea_python_tests/models.py +37 -0
- package/tests/output/api/setup.py +77 -0
- package/tests/output/api/tea_python_tests/client.py +106 -0
- package/tests/output/builtin/setup.py +77 -0
- package/tests/output/builtin/tea_python_tests/client.py +685 -0
- package/tests/output/comment/setup.py +77 -0
- package/tests/output/comment/tea_python_tests/client.py +288 -0
- package/tests/output/comment/tea_python_tests/models.py +195 -0
- package/tests/output/complex/setup.py +77 -0
- package/tests/output/complex/tea_python_tests/client.py +1168 -0
- package/tests/output/complex/tea_python_tests/exceptions.py +39 -0
- package/tests/output/complex/tea_python_tests/models.py +570 -0
- package/tests/output/const/setup.py +77 -0
- package/tests/output/const/tea_python_tests/client.py +14 -0
- package/tests/output/empty/setup.py +77 -0
- package/tests/output/empty/tea_python_tests/client.py +10 -0
- package/tests/output/exec/setup.py +77 -0
- package/tests/output/exec/tea_python_tests/exec_client.py +21 -0
- package/tests/output/function/setup.py +77 -0
- package/tests/output/function/tea_python_tests/client.py +64 -0
- package/tests/output/import/setup.py +78 -0
- package/tests/output/import/tea_python_tests/client.py +29 -0
- package/tests/output/map/setup.py +77 -0
- package/tests/output/map/tea_python_tests/client.py +39 -0
- package/tests/output/model/setup.py +77 -0
- package/tests/output/model/tea_python_tests/client.py +10 -0
- package/tests/output/model/tea_python_tests/exceptions.py +28 -0
- package/tests/output/model/tea_python_tests/models.py +780 -0
- package/tests/output/multi/setup.py +77 -0
- package/tests/output/multi/tea_python_tests/api.py +95 -0
- package/tests/output/multi/tea_python_tests/client.py +40 -0
- package/tests/output/multi/tea_python_tests/lib/util.py +19 -0
- package/tests/output/multi/tea_python_tests/model/user.py +23 -0
- package/tests/output/multi/tea_python_tests/model/user_exceptions.py +83 -0
- package/tests/output/multi/tea_python_tests/model/user_models.py +145 -0
- package/tests/output/statements/setup.py +77 -0
- package/tests/output/statements/tea_python_tests/client.py +86 -0
- package/tests/output/super/setup.py +77 -0
- package/tests/output/super/tea_python_tests/client.py +16 -0
- package/tests/output/typedef/setup.py +78 -0
- package/tests/output/typedef/tea_python_tests/client.py +74 -0
- package/tests/output/typedef/tea_python_tests/models.py +42 -0
- package/tests/common.tests.js +0 -244
- package/tests/lib.tests.js +0 -269
- package/tests/python2.tests.js +0 -283
- package/tests/resolver.tests.js +0 -434
package/lib/generator.js
ADDED
|
@@ -0,0 +1,2704 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const assert = require('assert');
|
|
4
|
+
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
|
|
8
|
+
const DSL = require('@darabonba/parser');
|
|
9
|
+
const {
|
|
10
|
+
_name, _vid, _string, _upperFirst, _type, _escape,
|
|
11
|
+
_subModelName, _camelCase, _snakeCase, _getImport,
|
|
12
|
+
_isBinaryOp, _adaptedQuotes, CORE, REQUEST, RESPONSE
|
|
13
|
+
} = require('./helper');
|
|
14
|
+
const getBuiltin = require('./builtin');
|
|
15
|
+
const { Tag } = require('@darabonba/parser/lib/tag');
|
|
16
|
+
const Annotation = require('@darabonba/annotation-parser');
|
|
17
|
+
|
|
18
|
+
function avoidReserveName(name) {
|
|
19
|
+
const reserves = [
|
|
20
|
+
'function'
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
if (reserves.indexOf(name) !== -1) {
|
|
24
|
+
return `_${name}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return name;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class Visitor {
|
|
31
|
+
|
|
32
|
+
static get supportGenerateTest() {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
constructor(option = {}) {
|
|
37
|
+
this.config = Object.assign({
|
|
38
|
+
outputDir: '',
|
|
39
|
+
indent: ' ',
|
|
40
|
+
clientName: option.python.clientName || 'Client',
|
|
41
|
+
className: option.className || 'Client',
|
|
42
|
+
}, option);
|
|
43
|
+
assert.ok(this.config.outputDir, '`option.outputDir` should not empty');
|
|
44
|
+
assert.ok(this.config.package, `Darafile -> python -> package should not empty, please add python option into Darafile.
|
|
45
|
+
example:
|
|
46
|
+
"pthon": {
|
|
47
|
+
"package": "darabonba.core",
|
|
48
|
+
"className": "Client"
|
|
49
|
+
}`);
|
|
50
|
+
|
|
51
|
+
this.typedef = this.config.typedef || {};
|
|
52
|
+
this.imports = [];
|
|
53
|
+
this.outputDir = this.config.outputDir;
|
|
54
|
+
this.setupPath = path.join(this.outputDir, 'setup.py');
|
|
55
|
+
this.modelPath = path.join(this.outputDir, this.config.package, 'models.py');
|
|
56
|
+
this.exceptionPath = path.join(this.outputDir, this.config.package, 'exceptions.py');
|
|
57
|
+
this.config.clientPath = path.join(this.outputDir, this.config.package, `${_snakeCase(this.config.clientName)}.py`);
|
|
58
|
+
this.classNamespace = new Map();
|
|
59
|
+
// 新增:用于存储已使用的类型
|
|
60
|
+
this.isAsyncFunction = false; // 新增:用于标记是否为异步函数
|
|
61
|
+
this.isStaticFunction = true; // 新增:用于标记是否为非静态函数
|
|
62
|
+
this.clientName = new Map(); // 新增:用于存储importName
|
|
63
|
+
// this.moduleDir = this.config.modelDirName || 'Models'; // 新增,用于存储models文件
|
|
64
|
+
|
|
65
|
+
this.output = '';
|
|
66
|
+
if (!fs.existsSync(this.outputDir)) {
|
|
67
|
+
fs.mkdirSync(this.outputDir, {
|
|
68
|
+
recursive: true
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!this.outputDir) {
|
|
73
|
+
throw new Error('`option.outputDir` should not empty');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (!fs.existsSync(this.outputDir)) {
|
|
77
|
+
fs.mkdirSync(this.outputDir, {
|
|
78
|
+
recursive: true
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
this.package = {};
|
|
82
|
+
this.initSetupPy();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
initSetupPy() {
|
|
86
|
+
// 初始化包信息
|
|
87
|
+
this.package.name = this.package.name || this.config.package;
|
|
88
|
+
this.package.version = this.package.version || '1.0.0';
|
|
89
|
+
this.package.description = this.package.description || '';
|
|
90
|
+
this.package.author = this.package.author || 'Alibaba';
|
|
91
|
+
this.package.author_email = this.package.author_email || 'sdk-team@alibabacloud.com';
|
|
92
|
+
this.package.url = this.package.url || 'https://github.com/';
|
|
93
|
+
this.package.license = this.package.license || 'Apache License 2.0';
|
|
94
|
+
this.package.requires = this.package.requires || [];
|
|
95
|
+
|
|
96
|
+
// 收集依赖信息
|
|
97
|
+
if (!this.package.dependencies) {
|
|
98
|
+
this.package.dependencies = {};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
Object.keys(this.typedef).forEach(type => {
|
|
102
|
+
if (this.typedef[type].package) {
|
|
103
|
+
let [pkgName, version] = this.typedef[type].package.split(':');
|
|
104
|
+
if (!this.package.dependencies[pkgName]) {
|
|
105
|
+
this.package.dependencies[pkgName] = version;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// 创建 setup.py 内容
|
|
111
|
+
const setupPyContent = `
|
|
112
|
+
# -*- coding: utf-8 -*-
|
|
113
|
+
"""
|
|
114
|
+
Licensed to the Apache Software Foundation (ASF) under one
|
|
115
|
+
or more contributor license agreements. See the NOTICE file
|
|
116
|
+
distributed with this work for additional information
|
|
117
|
+
regarding copyright ownership. The ASF licenses this file
|
|
118
|
+
to you under the Apache License, Version 2.0 (the
|
|
119
|
+
"License"); you may not use this file except in compliance
|
|
120
|
+
with the License. You may obtain a copy of the License at
|
|
121
|
+
|
|
122
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
123
|
+
|
|
124
|
+
Unless required by applicable law or agreed to in writing,
|
|
125
|
+
software distributed under the License is distributed on an
|
|
126
|
+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
127
|
+
KIND, either express or implied. See the License for the
|
|
128
|
+
specific language governing permissions and limitations
|
|
129
|
+
under the License.
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
import os
|
|
133
|
+
from setuptools import setup, find_packages
|
|
134
|
+
|
|
135
|
+
"""
|
|
136
|
+
setup module for tea_python_tests.
|
|
137
|
+
|
|
138
|
+
Created on *
|
|
139
|
+
|
|
140
|
+
@author: Alibaba
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
PACKAGE = "${this.package.name}"
|
|
144
|
+
NAME = "${this.package.name}"
|
|
145
|
+
DESCRIPTION = "${this.package.description}"
|
|
146
|
+
AUTHOR = "${this.package.author}"
|
|
147
|
+
AUTHOR_EMAIL = "${this.package.author_email}"
|
|
148
|
+
URL = "${this.package.url}"
|
|
149
|
+
VERSION = __import__(PACKAGE).__version__
|
|
150
|
+
REQUIRES = [
|
|
151
|
+
"darabonba-core>=1.0.0, <2.0.0",
|
|
152
|
+
${Object.keys(this.package.dependencies).map(pkg => {
|
|
153
|
+
if(this.package.dependencies[pkg].includes('rc')) {
|
|
154
|
+
return ` "${pkg}==${this.package.dependencies[pkg]}"`;
|
|
155
|
+
}
|
|
156
|
+
return ` "${pkg}>=${this.package.dependencies[pkg]}, <${+this.package.dependencies[pkg].split('.')[0] + 1}.0.0"`;
|
|
157
|
+
}).join(',\n')}
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
LONG_DESCRIPTION = ''
|
|
161
|
+
if os.path.exists('./README.md'):
|
|
162
|
+
with open("README.md", encoding='utf-8') as fp:
|
|
163
|
+
LONG_DESCRIPTION = fp.read()
|
|
164
|
+
|
|
165
|
+
setup(
|
|
166
|
+
name=NAME,
|
|
167
|
+
version=VERSION,
|
|
168
|
+
description=DESCRIPTION,
|
|
169
|
+
long_description=LONG_DESCRIPTION,
|
|
170
|
+
long_description_content_type='text/markdown',
|
|
171
|
+
author=AUTHOR,
|
|
172
|
+
author_email=AUTHOR_EMAIL,
|
|
173
|
+
license="Apache License 2.0",
|
|
174
|
+
url=URL,
|
|
175
|
+
keywords=["tea","python","tests"],
|
|
176
|
+
packages=find_packages(exclude=["tests*"]),
|
|
177
|
+
include_package_data=True,
|
|
178
|
+
platforms="any",
|
|
179
|
+
install_requires=REQUIRES,
|
|
180
|
+
python_requires=">=3.6",
|
|
181
|
+
classifiers=(
|
|
182
|
+
"Development Status :: 4 - Beta",
|
|
183
|
+
"Intended Audience :: Developers",
|
|
184
|
+
"License :: OSI Approved :: Apache Software License",
|
|
185
|
+
"Programming Language :: Python",
|
|
186
|
+
"Programming Language :: Python :: 3",
|
|
187
|
+
"Programming Language :: Python :: 3.6",
|
|
188
|
+
"Programming Language :: Python :: 3.7",
|
|
189
|
+
"Programming Language :: Python :: 3.8",
|
|
190
|
+
"Programming Language :: Python :: 3.9",
|
|
191
|
+
"Topic :: Software Development"
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
`.trim();
|
|
195
|
+
|
|
196
|
+
// 将内容写入 setup.py 文件
|
|
197
|
+
const setupPath = path.join(this.outputDir, 'setup.py');
|
|
198
|
+
fs.writeFileSync(setupPath, setupPyContent);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
saveInnerModule(ast) {
|
|
205
|
+
const keys = ast.innerModule.keys();
|
|
206
|
+
let data = keys.next();
|
|
207
|
+
while (!data.done) {
|
|
208
|
+
const aliasId = data.value;
|
|
209
|
+
const moduleAst = ast.innerDep.get(aliasId);
|
|
210
|
+
this.ast = ast;
|
|
211
|
+
// this.modelPath = path.join(this.outputDir, this.config.package, 'models.py');
|
|
212
|
+
// this.exceptionPath = path.join(this.outputDir, this.config.package, 'exceptions.py');
|
|
213
|
+
const filepath = ast.innerModule.get(aliasId);
|
|
214
|
+
this.className = this.getInnerClient(aliasId);
|
|
215
|
+
this.modelPath = filepath.replace('.py', '_models.py');
|
|
216
|
+
this.exceptionPath = filepath.replace('.py', '_exceptions.py');
|
|
217
|
+
this.visitModule(moduleAst, filepath, false, 0);
|
|
218
|
+
data = keys.next();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
save(filepath) {
|
|
223
|
+
let targetPath = filepath;
|
|
224
|
+
if(path.resolve(filepath).startsWith(path.resolve(this.outputDir))) {
|
|
225
|
+
const baseDir = path.join(this.outputDir, path.sep);
|
|
226
|
+
filepath = filepath.replace(baseDir, '');
|
|
227
|
+
}
|
|
228
|
+
targetPath = path.join(this.outputDir, filepath);
|
|
229
|
+
fs.mkdirSync(path.dirname(targetPath), {
|
|
230
|
+
recursive: true
|
|
231
|
+
});
|
|
232
|
+
this.emitImports();
|
|
233
|
+
fs.writeFileSync(targetPath, this.output);
|
|
234
|
+
this.initSetupPy();
|
|
235
|
+
this.output = '';
|
|
236
|
+
this.imports = [];
|
|
237
|
+
this.usedClass = new Map();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
emit(str, level) {
|
|
241
|
+
this.output += ' '.repeat(level * 2) + str;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
visit(ast, level = 0) {
|
|
245
|
+
this.visitModule(ast, this.config.clientPath, level);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
overwrite(ast, filepath) {
|
|
249
|
+
if(!ast.moduleBody.nodes || !ast.moduleBody.nodes.length) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const beginNotes = DSL.note.getNotes(this.notes, 0, ast.moduleBody.nodes[0].tokenRange[0]);
|
|
253
|
+
const overwirte = beginNotes.find(note => note.note.lexeme === '@overwrite');
|
|
254
|
+
let targetPath = filepath;
|
|
255
|
+
if(path.resolve(filepath).startsWith(path.resolve(this.outputDir))) {
|
|
256
|
+
const baseDir = path.join(this.outputDir, path.sep);
|
|
257
|
+
filepath = filepath.replace(baseDir, '');
|
|
258
|
+
}
|
|
259
|
+
targetPath = path.join(this.outputDir, filepath);
|
|
260
|
+
if(overwirte && overwirte.arg.value === false && fs.existsSync(targetPath)) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
visitModule(ast, filepath, level) {
|
|
267
|
+
assert.equal(ast.type, 'module');
|
|
268
|
+
this.ast = ast;
|
|
269
|
+
this.predefined = ast.models;
|
|
270
|
+
this.usedExternException = ast.usedExternException;
|
|
271
|
+
this.usedExternModel = ast.usedExternModel;
|
|
272
|
+
this.parentModule = ast.extends;
|
|
273
|
+
this.comments = ast.comments;
|
|
274
|
+
this.notes = ast.notes;
|
|
275
|
+
this.builtin = getBuiltin(this);
|
|
276
|
+
ast.innerModule = new Map();
|
|
277
|
+
this.packageInfo = {};
|
|
278
|
+
this.usedTypes = [];
|
|
279
|
+
this.imports = [];
|
|
280
|
+
if(this.overwrite(ast, filepath) === false) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if(!this.className) {
|
|
285
|
+
let clientName = this.config.clientName.replace(/(?:^|_)([a-z])/g, (_, c) => (c ? c.toUpperCase() : ''));
|
|
286
|
+
this.className = clientName;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
this.eachImport(ast.imports, ast.usedExternModel, ast.innerModule, filepath, level);
|
|
291
|
+
|
|
292
|
+
const subModels = Object.keys(this.predefined).filter((key) => {
|
|
293
|
+
return !key.startsWith('$') && this.predefined[key].type === 'model' && key.indexOf('.') !== -1;
|
|
294
|
+
}).map((key) => {
|
|
295
|
+
return this.predefined[key];
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
for (let i = 0; i < subModels.length; i++) {
|
|
299
|
+
// sub model
|
|
300
|
+
// TODO: 生成model class之前需要判断属性是否为自定义类型,如果属性是自定义类型,需要先定义自定义类型
|
|
301
|
+
this.eachSubModel(subModels[i], level);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const models = ast.moduleBody.nodes.filter((item) => {
|
|
305
|
+
return item.type === 'model';
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
this.modelBefore(ast, level);
|
|
309
|
+
for (let i = 0; i < models.length; i++) {
|
|
310
|
+
this.eachModel(models[i], level);
|
|
311
|
+
}
|
|
312
|
+
if (models.length > 0) {
|
|
313
|
+
// 存一笔 models
|
|
314
|
+
|
|
315
|
+
this.save(this.modelPath);
|
|
316
|
+
this.usedTypes = [];
|
|
317
|
+
this.imports = [];
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const exceptions = ast.moduleBody.nodes.filter((item) => {
|
|
321
|
+
return item.type === 'exception';
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
if (exceptions.length > 0) {
|
|
326
|
+
this.exceptionsBody = true;
|
|
327
|
+
for (let i = 0; i < exceptions.length; i++) {
|
|
328
|
+
this.eachException(exceptions[i], level);
|
|
329
|
+
}
|
|
330
|
+
this.exceptionsBody = false;
|
|
331
|
+
this.save(this.exceptionPath);
|
|
332
|
+
this.usedTypes = [];
|
|
333
|
+
this.imports = [];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
this.moduleBefore(ast, level);
|
|
338
|
+
|
|
339
|
+
this.visitAnnotation(ast.annotation, level);
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
// models definition
|
|
344
|
+
this.apiBefore(level);
|
|
345
|
+
// TODO: 这个types里有type对应的类型,在这块加上一个非基础类型筛选,然后根据类型引入对应的模块
|
|
346
|
+
const types = ast.moduleBody.nodes.filter((item) => {
|
|
347
|
+
return item.type === 'type';
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
const inits = ast.moduleBody.nodes.filter((item) => {
|
|
351
|
+
return item.type === 'init';
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
const [init] = inits;
|
|
355
|
+
if (init) {
|
|
356
|
+
this.visitInit(init, types, level);
|
|
357
|
+
} else {
|
|
358
|
+
// 没有 init 的时候,也要处理 types
|
|
359
|
+
this.emit('\n');
|
|
360
|
+
types.forEach((type) => {
|
|
361
|
+
let comments = DSL.comment.getFrontComments(this.comments, type.tokenRange[0]);
|
|
362
|
+
this.visitComments(comments, level + 2);
|
|
363
|
+
this.emit(`${_snakeCase(_vid(type.vid))}: `, level + 2);
|
|
364
|
+
this.visitType(type.value);
|
|
365
|
+
this.emit(' = None\n');
|
|
366
|
+
});
|
|
367
|
+
this.emit('\n');
|
|
368
|
+
this.emit(` def __init__(self):
|
|
369
|
+
pass\n`);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const apis = ast.moduleBody.nodes.filter((item) => {
|
|
373
|
+
return item.type === 'api';
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
for (let i = 0; i < apis.length; i++) {
|
|
377
|
+
// 每个API都需要 Tea.request import TeaRequest
|
|
378
|
+
// from Tea.core import TeaCore
|
|
379
|
+
// 但是不需要重复引入
|
|
380
|
+
this.imports.push({
|
|
381
|
+
className: `${CORE}Core`,
|
|
382
|
+
packageName: 'darabonba.core'
|
|
383
|
+
});
|
|
384
|
+
this.eachAPI(apis[i], level + 2);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// this.functionBefore();
|
|
388
|
+
const functions = ast.moduleBody.nodes.filter((item) => {
|
|
389
|
+
return item.type === 'function';
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
for (let i = 0; i < functions.length; i++) {
|
|
393
|
+
this.eachFunction(functions[i], level + 2);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (this.config.exec) {
|
|
397
|
+
this.emitExec();
|
|
398
|
+
}
|
|
399
|
+
// 最后处理import
|
|
400
|
+
this.save(filepath);
|
|
401
|
+
this.saveInnerModule(ast, filepath);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
emitExec() {
|
|
405
|
+
this.pushImports('sys');
|
|
406
|
+
this.emit(`\n\nif __name__ == '__main__':
|
|
407
|
+
${this.config.clientName.replace(/(?:^|_)([a-z])/g, (_, c) => (c ? c.toUpperCase() : ''))}.main(sys.argv[1:])\n`);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
visitComments(comments, level) {
|
|
411
|
+
comments.forEach(comment => {
|
|
412
|
+
// 移除注释标记“// ”
|
|
413
|
+
const uncommented = comment.value.slice(3).trim();
|
|
414
|
+
// TODO: 这个地方需要判断什么场景用三引号 什么时候用#
|
|
415
|
+
// 使用三引号包裹并缩进
|
|
416
|
+
// this.emit(`"""\n`,level);
|
|
417
|
+
// this.emit(`${uncommented}\n`, level);
|
|
418
|
+
// this.emit(`"""\n`, level);
|
|
419
|
+
this.emit(`# ${uncommented}\n`, level);
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
visitAnnotation(annotation, level) {
|
|
425
|
+
if (!annotation || !annotation.value) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
let comments = DSL.comment.getFrontComments(this.comments, annotation.index);
|
|
429
|
+
this.visitComments(comments, level);
|
|
430
|
+
var ast = Annotation.parse(annotation.value);
|
|
431
|
+
var description = ast.items.find((item) => {
|
|
432
|
+
return item.type === 'description';
|
|
433
|
+
});
|
|
434
|
+
var summary = ast.items.find((item) => {
|
|
435
|
+
return item.type === 'summary';
|
|
436
|
+
});
|
|
437
|
+
var _return = ast.items.find((item) => {
|
|
438
|
+
return item.type === 'return';
|
|
439
|
+
});
|
|
440
|
+
var deprecated = ast.items.find((item) => {
|
|
441
|
+
return item.type === 'deprecated';
|
|
442
|
+
});
|
|
443
|
+
var params = ast.items.filter((item) => {
|
|
444
|
+
return item.type === 'param';
|
|
445
|
+
}).map((item) => {
|
|
446
|
+
return {
|
|
447
|
+
name: item.name.id,
|
|
448
|
+
text: item.text.text.trimEnd()
|
|
449
|
+
};
|
|
450
|
+
});
|
|
451
|
+
var throws = ast.items.filter((item) => {
|
|
452
|
+
return item.type === 'throws';
|
|
453
|
+
}).map((item) => {
|
|
454
|
+
return item.text.text.trimEnd();
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
const descriptionText = description ? description.text.text.trimEnd() : '';
|
|
458
|
+
const summaryText = summary ? summary.text.text.trimEnd() : '';
|
|
459
|
+
const returnText = _return ? _return.text.text.trimEnd() : '';
|
|
460
|
+
let hasNextSection = false;
|
|
461
|
+
|
|
462
|
+
this.emit('"""\n', level);
|
|
463
|
+
if (summaryText !== '') {
|
|
464
|
+
summaryText.split('\n').forEach((line) => {
|
|
465
|
+
this.emit(` * ${line}\n`, level);
|
|
466
|
+
});
|
|
467
|
+
hasNextSection = true;
|
|
468
|
+
}
|
|
469
|
+
if (descriptionText !== '') {
|
|
470
|
+
if (hasNextSection) {
|
|
471
|
+
this.emit(' * \n', level);
|
|
472
|
+
}
|
|
473
|
+
this.emit(' * @remarks\n', level);
|
|
474
|
+
descriptionText.split('\n').forEach((line) => {
|
|
475
|
+
this.emit(` * ${line}\n`, level);
|
|
476
|
+
});
|
|
477
|
+
hasNextSection = true;
|
|
478
|
+
}
|
|
479
|
+
if (deprecated) {
|
|
480
|
+
if (hasNextSection) {
|
|
481
|
+
this.emit(' * \n', level);
|
|
482
|
+
}
|
|
483
|
+
const deprecatedText = deprecated.text.text.trimEnd();
|
|
484
|
+
this.emit(' * @deprecated', level);
|
|
485
|
+
deprecatedText.split('\n').forEach((line, index) => {
|
|
486
|
+
if (index === 0) {
|
|
487
|
+
this.emit(` ${line}\n`);
|
|
488
|
+
} else {
|
|
489
|
+
this.emit(` * ${line}\n`, level);
|
|
490
|
+
}
|
|
491
|
+
});
|
|
492
|
+
hasNextSection = true;
|
|
493
|
+
}
|
|
494
|
+
if (params.length > 0) {
|
|
495
|
+
if (hasNextSection) {
|
|
496
|
+
this.emit(' * \n', level);
|
|
497
|
+
}
|
|
498
|
+
params.forEach((item) => {
|
|
499
|
+
this.emit(` * @param ${item.name} - `, level);
|
|
500
|
+
const items = item.text.trimEnd().split('\n');
|
|
501
|
+
items.forEach((line, index) => {
|
|
502
|
+
if (index === 0) {
|
|
503
|
+
this.emit(`${line}\n`);
|
|
504
|
+
} else {
|
|
505
|
+
this.emit(` * ${line}\n`, level);
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
if (returnText !== '') {
|
|
511
|
+
this.emit(' * @returns', level);
|
|
512
|
+
const returns = returnText.split('\n');
|
|
513
|
+
returns.forEach((line, index) => {
|
|
514
|
+
if (index === 0) {
|
|
515
|
+
this.emit(` ${line}\n`);
|
|
516
|
+
} else {
|
|
517
|
+
this.emit(` * ${line}\n`, level);
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
if (throws.length > 0) {
|
|
522
|
+
this.emit(' * \n', level);
|
|
523
|
+
throws.forEach((item) => {
|
|
524
|
+
this.emit(' * @throws', level);
|
|
525
|
+
const items = item.trimEnd().split('\n');
|
|
526
|
+
items.forEach((line, index) => {
|
|
527
|
+
if (index === 0) {
|
|
528
|
+
this.emit(` ${line}\n`);
|
|
529
|
+
} else {
|
|
530
|
+
this.emit(` * ${line}\n`, level);
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
this.emit('"""', level);
|
|
536
|
+
this.emit('\n');
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
visitInit(ast, types, level) {
|
|
540
|
+
assert.equal(ast.type, 'init');
|
|
541
|
+
this.emit('\n');
|
|
542
|
+
types.forEach((item) => {
|
|
543
|
+
let comments = DSL.comment.getFrontComments(this.comments, item.tokenRange[0]);
|
|
544
|
+
this.visitComments(comments, level + 2);
|
|
545
|
+
this.emit(`${_snakeCase(_vid(item.vid))}: `, level + 2);
|
|
546
|
+
this.visitType(item.value);
|
|
547
|
+
this.emit(' = None\n', level);
|
|
548
|
+
});
|
|
549
|
+
if(ast.params.params.length !== 0) {
|
|
550
|
+
this.emit('\n');
|
|
551
|
+
this.emit('def __init__(\n', level + 2);
|
|
552
|
+
this.emit('self,\n', level + 4);
|
|
553
|
+
for (var i = 0; i < ast.params.params.length; i++) {
|
|
554
|
+
const node = ast.params.params[i];
|
|
555
|
+
assert.equal(node.type, 'param');
|
|
556
|
+
const name = _snakeCase(_name(node.paramName));
|
|
557
|
+
this.emit(`${avoidReserveName(name)}: `, level + 4);
|
|
558
|
+
this.visitType(node.paramType, level);
|
|
559
|
+
this.emit(',');
|
|
560
|
+
if (i !== ast.params.length - 1) {
|
|
561
|
+
this.emit('\n');
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
this.emit('):\n', level + 2);
|
|
565
|
+
} else {
|
|
566
|
+
this.emit('def __init__(self):\n', level + 2);
|
|
567
|
+
}
|
|
568
|
+
if (ast.initBody && ast.initBody.stmts.length !==0 ) {
|
|
569
|
+
this.visitStmts(ast.initBody, level + 4);
|
|
570
|
+
} else {
|
|
571
|
+
this.emit('pass\n', level + 4);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
eachImport(imports, usedModels, innerModule, filepath, level) {
|
|
576
|
+
this.moduleTypedef = {};
|
|
577
|
+
if (imports.length > 0) {
|
|
578
|
+
const lockPath = path.join(this.config.pkgDir, '.libraries.json');
|
|
579
|
+
const lock = fs.existsSync(lockPath) ? JSON.parse(fs.readFileSync(lockPath, 'utf8')) : {};
|
|
580
|
+
for (let i = 0; i < imports.length; i++) {
|
|
581
|
+
const item = imports[i];
|
|
582
|
+
let comments = DSL.comment.getFrontComments(this.comments, item.tokenRange[0]);
|
|
583
|
+
this.visitComments(comments, level);
|
|
584
|
+
const aliasId = item.lexeme;
|
|
585
|
+
const main = item.mainModule;
|
|
586
|
+
const inner = item.module;
|
|
587
|
+
const moduleDir = main ? this.config.libraries[main] : this.config.libraries[aliasId];
|
|
588
|
+
const innerPath = item.innerPath;
|
|
589
|
+
if (!moduleDir && innerPath) {
|
|
590
|
+
let pyPath = innerPath.replace(/(\.tea)$|(\.spec)$|(\.dara)$/gi, '') + '.py';
|
|
591
|
+
if (pyPath.startsWith('./') || pyPath.startsWith('../')) {
|
|
592
|
+
pyPath = pyPath.split('/').map(dir => _snakeCase(dir)).join(path.sep);
|
|
593
|
+
pyPath = path.join(path.dirname(filepath), `${pyPath}`);
|
|
594
|
+
} else if (pyPath.startsWith('/')) {
|
|
595
|
+
pyPath = pyPath.split('/').map(dir => _snakeCase(dir)).join(path.sep);
|
|
596
|
+
pyPath = `${pyPath}`;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const classNamespace = this.getClassNamespace(pyPath);
|
|
600
|
+
const className = this.getInnerClient(aliasId, pyPath);
|
|
601
|
+
const aliasName = this.getAliasName(className, aliasId);
|
|
602
|
+
const filename = _snakeCase(path.basename(pyPath, '.py'));
|
|
603
|
+
this.packageInfo[aliasId] = {
|
|
604
|
+
aliasName: aliasName || className,
|
|
605
|
+
clientName: className,
|
|
606
|
+
namemespace: classNamespace,
|
|
607
|
+
fileName: filename,
|
|
608
|
+
models: `${filename}_models`,
|
|
609
|
+
exceptions: `${filename}_exceptions`,
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
innerModule.set(aliasId, pyPath);
|
|
613
|
+
continue;
|
|
614
|
+
}
|
|
615
|
+
let targetPath = '';
|
|
616
|
+
if (moduleDir.startsWith('./') || moduleDir.startsWith('../')) {
|
|
617
|
+
targetPath = path.join( this.config.pkgDir, moduleDir);
|
|
618
|
+
} else if (moduleDir.startsWith('/')) {
|
|
619
|
+
targetPath = moduleDir;
|
|
620
|
+
} else {
|
|
621
|
+
targetPath = path.join(this.config.pkgDir, lock[moduleDir]);
|
|
622
|
+
}
|
|
623
|
+
const pkgPath = fs.existsSync(path.join(targetPath, 'Teafile')) ? path.join(targetPath, 'Teafile') : path.join(targetPath, 'Darafile');
|
|
624
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath));
|
|
625
|
+
// 这部分是import
|
|
626
|
+
const pyPkg = pkg.python;
|
|
627
|
+
if (!pyPkg) {
|
|
628
|
+
throw new Error(`The '${aliasId}' has no Python supported.`);
|
|
629
|
+
}
|
|
630
|
+
let className = _camelCase(pyPkg.clientName || 'client');
|
|
631
|
+
let classNamespace = pyPkg.package;
|
|
632
|
+
let models = 'models';
|
|
633
|
+
let exceptions = 'exceptions';
|
|
634
|
+
if(inner && pkg.exports[inner]) {
|
|
635
|
+
let pyPath = pkg.exports[inner];
|
|
636
|
+
const [ filename ] = pyPath.split(path.sep).slice(-1);
|
|
637
|
+
models = filename.replace(/(\.tea)$|(\.spec)$|(\.dara)$/gi, '') + '_models';
|
|
638
|
+
exceptions = filename.replace(/(\.tea)$|(\.spec)$|(\.dara)$/gi, '') + '_exceptions';
|
|
639
|
+
const arr = pyPath.split(path.sep).slice(1, -1);
|
|
640
|
+
arr.map(key => {
|
|
641
|
+
classNamespace += '.' + _snakeCase(key);
|
|
642
|
+
});
|
|
643
|
+
const exportClientName = pyPkg.exports && pyPkg.exports[inner];
|
|
644
|
+
className = _camelCase(exportClientName || 'Client');
|
|
645
|
+
}
|
|
646
|
+
const aliasName = this.getAliasName(className, aliasId);
|
|
647
|
+
this.packageInfo[aliasId] = {
|
|
648
|
+
aliasName: aliasName || className,
|
|
649
|
+
fileName: _snakeCase(className),
|
|
650
|
+
clientName: className,
|
|
651
|
+
namemespace: classNamespace,
|
|
652
|
+
models: models,
|
|
653
|
+
exceptions: exceptions,
|
|
654
|
+
};
|
|
655
|
+
// 这部分处理setup.py
|
|
656
|
+
if (pkg.releases && pkg.releases.python) {
|
|
657
|
+
const REQUIRE = pkg.releases.python ;
|
|
658
|
+
const [pkgName, version] = REQUIRE.split(':');
|
|
659
|
+
this.package.dependencies[pkgName] = `${version}`;
|
|
660
|
+
}
|
|
661
|
+
const typedef = pkg.python && pkg.python.typedef || {};
|
|
662
|
+
this.moduleTypedef[aliasId] = typedef;
|
|
663
|
+
Object.keys(typedef).forEach(type => {
|
|
664
|
+
if (typedef[type].package) {
|
|
665
|
+
let [pack, ver] = typedef[type].package.split(':');
|
|
666
|
+
if (!this.package.dependencies[pack]) {
|
|
667
|
+
this.package.dependencies[pack] = ver;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
this.emit('\n\n');
|
|
673
|
+
this.__externModule = usedModels;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
visitTypedef(type, module) {
|
|
678
|
+
if (module && module.idType === 'module') {
|
|
679
|
+
const aliasId = _name(module);
|
|
680
|
+
if (this.moduleTypedef[aliasId] && this.moduleTypedef[aliasId][type]) {
|
|
681
|
+
if (this.moduleTypedef[aliasId][type].import) {
|
|
682
|
+
this.imports.push({
|
|
683
|
+
packageName: this.moduleTypedef[aliasId][type].import,
|
|
684
|
+
className: this.moduleTypedef[aliasId][type].type,
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
return this.getTypedefType(this.moduleTypedef[aliasId][type].type);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if (type.idType === 'typedef' && this.typedef[type.lexeme]) {
|
|
693
|
+
if (this.typedef[type.lexeme]) {
|
|
694
|
+
if (this.typedef[type.lexeme].import) {
|
|
695
|
+
this.imports.push({
|
|
696
|
+
packageName: this.typedef[type.lexeme].import,
|
|
697
|
+
className: this.typedef[type.lexeme].type,
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
return this.getTypedefType(this.typedef[type.lexeme].type);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
getTypedefType(type) {
|
|
707
|
+
if(/\bDict\b/.test(type)) {
|
|
708
|
+
this.usedTypes.push('Dict');
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
if(/\bList\b/.test(type)) {
|
|
712
|
+
this.usedTypes.push('List');
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
if(/\bAny\b/.test(type)) {
|
|
716
|
+
this.usedTypes.push('Any');
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if(/\bBinaryIO\b/.test(type)) {
|
|
720
|
+
this.usedTypes.push('BinaryIO');
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
return type;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
visitParams(ast, level, instanceFunc) {
|
|
727
|
+
level += 2;
|
|
728
|
+
assert.equal(ast.type, 'params');
|
|
729
|
+
if (ast.params.length === 0) {
|
|
730
|
+
this.emit(`(${instanceFunc ? 'self' : ''})`);
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
this.emit('(\n');
|
|
734
|
+
if (instanceFunc){
|
|
735
|
+
this.emit('self,\n', level);
|
|
736
|
+
}
|
|
737
|
+
for (var i = 0; i < ast.params.length; i++) {
|
|
738
|
+
const node = ast.params[i];
|
|
739
|
+
assert.equal(node.type, 'param');
|
|
740
|
+
const name = _snakeCase(_name(node.paramName));
|
|
741
|
+
this.emit(`${avoidReserveName(name)}: `, level);
|
|
742
|
+
this.visitType(node.paramType, level);
|
|
743
|
+
this.emit(',');
|
|
744
|
+
if (i !== ast.params.length - 1) {
|
|
745
|
+
this.emit('\n');
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
this.emit('\n');
|
|
749
|
+
this.emit(')',level - 2);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
visitType(ast, level) {
|
|
753
|
+
if (ast.type === 'array') {
|
|
754
|
+
this.pushImports('array');
|
|
755
|
+
this.emit('List[');
|
|
756
|
+
this.visitType(ast.subType, level);
|
|
757
|
+
this.emit(']');
|
|
758
|
+
} else if (ast.type === 'moduleModel') {
|
|
759
|
+
const [moduleId, ...rest] = ast.path;
|
|
760
|
+
const modelName = _subModelName(rest.map((item) => item.lexeme).join('.'));
|
|
761
|
+
this.emit(this.getModelName(modelName, _name(moduleId)));
|
|
762
|
+
} else if (ast.type === 'subModel') {
|
|
763
|
+
const [moduleId, ...rest] = ast.path;
|
|
764
|
+
this.emit('main_models.');
|
|
765
|
+
this.emit(_subModelName([moduleId.lexeme, ...rest.map((item) => {
|
|
766
|
+
return item.lexeme;
|
|
767
|
+
})].join('.')));
|
|
768
|
+
} else if (ast.type === 'moduleTypedef') {
|
|
769
|
+
const [moduleId, ...rest] = ast.path;
|
|
770
|
+
const type = rest.map((item) => { return item.lexeme; }).join('.');
|
|
771
|
+
this.emit(this.visitTypedef(type, moduleId));
|
|
772
|
+
} else if (ast.type === 'typedef' || ast.idType === 'typedef') {
|
|
773
|
+
this.emit(this.visitTypedef(ast));
|
|
774
|
+
} else if (ast.type === 'map') {
|
|
775
|
+
// 记录使用了Dict
|
|
776
|
+
this.pushImports('map');
|
|
777
|
+
this.emit('Dict[');
|
|
778
|
+
this.visitType(ast.keyType, level);
|
|
779
|
+
this.emit(', ');
|
|
780
|
+
this.visitType(ast.valueType, level);
|
|
781
|
+
this.emit(']');
|
|
782
|
+
} else if (ast.type === 'model') {
|
|
783
|
+
this.emit(this.getModelName(_upperFirst(_name(ast)), ast.moduleName));
|
|
784
|
+
} else if (ast.idType === 'model') {
|
|
785
|
+
this.emit(this.getModelName(_upperFirst(_name(ast)), ast.moduleName));
|
|
786
|
+
} else if (ast.type === 'module') {
|
|
787
|
+
this.emit(this.getModelName('', _name(ast), 'module'));
|
|
788
|
+
} else if (ast.idType === 'module') {
|
|
789
|
+
this.emit(this.getModelName('', _name(ast), 'module'));
|
|
790
|
+
} else if (this.isIterator(ast)) {
|
|
791
|
+
this.visitType(ast.valueType);
|
|
792
|
+
} else if (ast.type === 'entry') {
|
|
793
|
+
this.emit('[str, ');
|
|
794
|
+
this.visitType(ast.valueType);
|
|
795
|
+
this.emit(']');
|
|
796
|
+
} else {
|
|
797
|
+
const typeName = _type(_name(ast));
|
|
798
|
+
this.pushImports(typeName);
|
|
799
|
+
this.emit(typeName);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
visitTypeWithNone(ast, level) {
|
|
804
|
+
this.visitType(ast, level);
|
|
805
|
+
this.emit(' = None');
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
visitReturnType(ast, level) {
|
|
810
|
+
this.emit(' -> ');
|
|
811
|
+
if(this.isIterator(ast.returnType)) {
|
|
812
|
+
if(this.isAsyncFunction) {
|
|
813
|
+
this.usedTypes.push('AsyncGenerator');
|
|
814
|
+
this.emit('AsyncGenerator[');
|
|
815
|
+
} else {
|
|
816
|
+
this.usedTypes.push('Generator');
|
|
817
|
+
this.emit('Generator[');
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
this.visitType(ast.returnType, level);
|
|
822
|
+
if (this.isIterator(ast.returnType)) {
|
|
823
|
+
this.emit(', None, None]');
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
visitAPIBody(ast, level) {
|
|
828
|
+
assert.equal(ast.type, 'apiBody');
|
|
829
|
+
this.pushImports(`${CORE}Request`);
|
|
830
|
+
this.emit(`${REQUEST} = ${CORE}Request()\n`, level);
|
|
831
|
+
this.visitStmts(ast.stmts, level);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
visitRuntimeBefore(ast, level) {
|
|
835
|
+
assert.equal(ast.type, 'object');
|
|
836
|
+
this.emit('_runtime = {\n', level + 2);
|
|
837
|
+
if(ast.fields.length !== 0){
|
|
838
|
+
ast.fields.forEach((field) => {
|
|
839
|
+
this.emit(`'${field.fieldName.lexeme}': `, level + 4);
|
|
840
|
+
this.visitExpr(field.expr);
|
|
841
|
+
this.emit(',\n');
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
this.emit('}\n', level +2);
|
|
845
|
+
this.emit('_last_request = None\n', level+2);
|
|
846
|
+
this.emit('_last_response = None\n', level+2);
|
|
847
|
+
this.emit('_retries_attempted = 0\n', level + 2);
|
|
848
|
+
this.emit(`_context = RetryPolicyContext(
|
|
849
|
+
retries_attempted= _retries_attempted
|
|
850
|
+
)\n`, level + 2);
|
|
851
|
+
this.emit(`while ${CORE}Core.should_retry(_runtime.get('retryOptions'), _context):\n`, level + 2);
|
|
852
|
+
this.emit('if _retries_attempted > 0:\n', level + 4);
|
|
853
|
+
this.emit(`_backoff_time = ${CORE}Core.get_backoff_time(_runtime.get('retryOptions'), _context)\n`, level + 6);
|
|
854
|
+
this.emit('if _backoff_time > 0:\n', level + 6);
|
|
855
|
+
this.emit(`${CORE}Core.sleep(_backoff_time)\n`, level + 8);
|
|
856
|
+
this.emit('_retries_attempted = _retries_attempted + 1\n', level + 4);
|
|
857
|
+
this.emit('try:\n', level + 4);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
visitStmt(ast, level) {
|
|
861
|
+
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
|
|
862
|
+
this.visitComments(comments, level);
|
|
863
|
+
if (ast.type === 'return') {
|
|
864
|
+
this.visitReturn(ast, level);
|
|
865
|
+
} else if (ast.type === 'yield') {
|
|
866
|
+
this.visitYield(ast, level);
|
|
867
|
+
} else if (ast.type === 'if') {
|
|
868
|
+
this.visitIf(ast, level);
|
|
869
|
+
} else if (ast.type === 'throw') {
|
|
870
|
+
this.visitThrow(ast, level);
|
|
871
|
+
} else if (ast.type === 'assign') {
|
|
872
|
+
this.visitAssign(ast, level);
|
|
873
|
+
} else if (ast.type === 'retry') {
|
|
874
|
+
this.visitRetry(ast, level);
|
|
875
|
+
} else if (ast.type === 'break') {
|
|
876
|
+
this.emit('break\n', level);
|
|
877
|
+
} else if (ast.type === 'declare') {
|
|
878
|
+
this.visitDeclare(ast, level);
|
|
879
|
+
} else if (ast.type === 'while') {
|
|
880
|
+
this.visitWhile(ast, level);
|
|
881
|
+
} else if (ast.type === 'for') {
|
|
882
|
+
this.visitFor(ast, level);
|
|
883
|
+
} else if (ast.type === 'try') {
|
|
884
|
+
this.visitTry(ast, level);
|
|
885
|
+
} else {
|
|
886
|
+
this.emit('', level);
|
|
887
|
+
this.visitExpr(ast, level);
|
|
888
|
+
this.emit('\n');
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
visitFieldType(value, level, modelName, fieldName) {
|
|
893
|
+
if (value.type === 'modelBody') {
|
|
894
|
+
if(this.exceptionsBody) {
|
|
895
|
+
this.emit('main_models.');
|
|
896
|
+
}
|
|
897
|
+
this.emit(`${_subModelName([modelName, fieldName].join('.'))}`);
|
|
898
|
+
} else if (value.type === 'array') {
|
|
899
|
+
this.visitType(value);
|
|
900
|
+
} else if (value.fieldType === 'array') {
|
|
901
|
+
this.pushImports('array');
|
|
902
|
+
this.emit('List[');
|
|
903
|
+
this.visitFieldType(value.fieldItemType, level, modelName, fieldName);
|
|
904
|
+
this.emit(']');
|
|
905
|
+
} else if (value.fieldType === 'map') {
|
|
906
|
+
this.pushImports('map');
|
|
907
|
+
this.emit('Dict[');
|
|
908
|
+
this.emit(`${_type(_name(value.keyType))}, `);
|
|
909
|
+
this.visitFieldType(value.valueType);
|
|
910
|
+
this.emit(']');
|
|
911
|
+
} else if (value.type === 'map') {
|
|
912
|
+
this.pushImports('map');
|
|
913
|
+
this.emit('Dict[');
|
|
914
|
+
this.emit(`${_type(_name(value.keyType))}, `);
|
|
915
|
+
this.visitFieldType(value.valueType);
|
|
916
|
+
this.emit(']');
|
|
917
|
+
} else if (value.tag === Tag.TYPE) {
|
|
918
|
+
const type = _type(value.lexeme);
|
|
919
|
+
this.pushImports(type);
|
|
920
|
+
this.emit(`${type}`);
|
|
921
|
+
} else if (value.tag === Tag.ID) {
|
|
922
|
+
this.visitType(value);
|
|
923
|
+
} else if (value.type === 'moduleModel') {
|
|
924
|
+
let type = 'model';
|
|
925
|
+
const [moduleId, ...models] = value.path;
|
|
926
|
+
const modelName = _subModelName(models.map((item) => item.lexeme).join('.'));
|
|
927
|
+
const externEx = this.usedExternException.get(_name(moduleId.lexeme));
|
|
928
|
+
if (externEx && externEx.has(modelName)) {
|
|
929
|
+
type = 'exception';
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
this.emit(this.getModelName(modelName, _name(moduleId)), type);
|
|
933
|
+
|
|
934
|
+
} else if (value.type === 'subModel') {
|
|
935
|
+
const [moduleId, ...rest] = value.path;
|
|
936
|
+
const modelName = _subModelName([moduleId.lexeme, ...rest.map((item) => {
|
|
937
|
+
return item.lexeme;
|
|
938
|
+
})].join('.'));
|
|
939
|
+
this.emit(this.getModelName(modelName));
|
|
940
|
+
} else if (typeof value.fieldType === 'string'){
|
|
941
|
+
const type = _type(value.fieldType);
|
|
942
|
+
this.pushImports(type);
|
|
943
|
+
this.emit(type);
|
|
944
|
+
} else if (value.fieldType.type === 'moduleModel') {
|
|
945
|
+
let type = 'model';
|
|
946
|
+
const [moduleId, ...models] = value.fieldType.path;
|
|
947
|
+
const modelName = _subModelName(models.map((item) => item.lexeme).join('.'));
|
|
948
|
+
const externEx = this.usedExternException.get(_name(moduleId.lexeme));
|
|
949
|
+
if (externEx && externEx.has(modelName)) {
|
|
950
|
+
type = 'exception';
|
|
951
|
+
}
|
|
952
|
+
this.emit(this.getModelName(modelName, _name(moduleId), type));
|
|
953
|
+
|
|
954
|
+
} else if (value.fieldType.type === 'moduleTypedef') {
|
|
955
|
+
const [moduleId, ...rest] = value.fieldType.path;
|
|
956
|
+
const type = rest.map((item) => { return item.lexeme; }).join('.');
|
|
957
|
+
this.emit(this.visitTypedef(type, moduleId));
|
|
958
|
+
} else if (value.fieldType.type === 'typedef' || value.fieldType.idType === 'typedef') {
|
|
959
|
+
this.emit(this.visitTypedef(value.fieldType));
|
|
960
|
+
} else if (value.fieldType.type === 'subModel') {
|
|
961
|
+
const [moduleId, ...rest] = value.fieldType.path;
|
|
962
|
+
const modelName = _subModelName([moduleId.lexeme, ...rest.map((item) => {
|
|
963
|
+
return item.lexeme;
|
|
964
|
+
})].join('.'));
|
|
965
|
+
this.emit(this.getModelName(modelName));
|
|
966
|
+
} else if (value.fieldType.type) {
|
|
967
|
+
const type = _type(value.fieldType.lexeme);
|
|
968
|
+
this.pushImports(type);
|
|
969
|
+
this.emit(`${type}`);
|
|
970
|
+
} else if (value.fieldType.idType === 'model') {
|
|
971
|
+
let type = 'model';
|
|
972
|
+
if (this.predefined[_name(type)] && this.predefined[_name(type)].isException) {
|
|
973
|
+
type = 'exception';
|
|
974
|
+
}
|
|
975
|
+
this.emit(this.getModelName(_name(value.fieldType), value.fieldType.moduleName, type));
|
|
976
|
+
} else if (value.fieldType.idType === 'module') {
|
|
977
|
+
this.emit(this.getModelName('', _type(_name(value.fieldType)), 'module'));
|
|
978
|
+
} else if (value.fieldType.idType === 'builtin_model') {
|
|
979
|
+
const type = _type(value.fieldType.lexeme);
|
|
980
|
+
this.pushImports(type);
|
|
981
|
+
this.emit(`${type}`);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
visitModelBody(ast, level, modelName) {
|
|
986
|
+
assert.equal(ast.type, 'modelBody');
|
|
987
|
+
this.visitFieldsInit(ast, level, modelName);
|
|
988
|
+
let node;
|
|
989
|
+
|
|
990
|
+
for (let i = 0; i < ast.nodes.length; i++) {
|
|
991
|
+
node = ast.nodes[i];
|
|
992
|
+
let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
|
|
993
|
+
this.visitComments(comments, level);
|
|
994
|
+
let param = _snakeCase(_escape(_name(node.fieldName)));
|
|
995
|
+
const description = this.getAttributes(node, 'description');
|
|
996
|
+
if (description) {
|
|
997
|
+
const descriptions = description.trimEnd().split('\n');
|
|
998
|
+
for (let j = 0; j < descriptions.length; j++) {
|
|
999
|
+
this.emit(`# ${descriptions[j]}\n`, level + 2);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
this.emit(`self.${param} = ${param}\n`, level + 2);
|
|
1003
|
+
}
|
|
1004
|
+
this.emit('\n');
|
|
1005
|
+
// validate
|
|
1006
|
+
this.emit('def validate(self):\n', level);
|
|
1007
|
+
if(ast.nodes.length > 0) {
|
|
1008
|
+
this.visitModelValidate(ast, level);
|
|
1009
|
+
} else {
|
|
1010
|
+
this.emit('pass\n', level + 2);
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
this.emit('\n');
|
|
1014
|
+
|
|
1015
|
+
// to_map
|
|
1016
|
+
this.visitToMap(ast, level);
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
// from_map
|
|
1020
|
+
this.visitFromMap(ast, modelName, level);
|
|
1021
|
+
|
|
1022
|
+
if (node) {
|
|
1023
|
+
//find the last node's back comment
|
|
1024
|
+
let comments = DSL.comment.getBetweenComments(this.comments, node.tokenRange[0], ast.tokenRange[1]);
|
|
1025
|
+
this.visitComments(comments, level);
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
if (ast.nodes.length === 0) {
|
|
1029
|
+
//empty block's comment
|
|
1030
|
+
let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]);
|
|
1031
|
+
this.visitComments(comments, level);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
visitModelValidate(ast, level) {
|
|
1037
|
+
let notPass = false;
|
|
1038
|
+
for (let i = 0; i < ast.nodes.length; i++) {
|
|
1039
|
+
const node = ast.nodes[i];
|
|
1040
|
+
const pattern = this.getAttributes(node, 'pattern') || '';
|
|
1041
|
+
const maxLength = this.getAttributes(node, 'maxLength') || 0;
|
|
1042
|
+
const minLength = this.getAttributes(node, 'minLength') || 0;
|
|
1043
|
+
const maximum = this.getAttributes(node, 'maximum') || 0;
|
|
1044
|
+
const minimum = this.getAttributes(node, 'minimum') || 0;
|
|
1045
|
+
let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
|
|
1046
|
+
this.visitComments(comments, level);
|
|
1047
|
+
let param = _snakeCase(_escape(_name(node.fieldName)));
|
|
1048
|
+
// 这里判断类中属性是否是必填
|
|
1049
|
+
if (node.required) {
|
|
1050
|
+
notPass = true;
|
|
1051
|
+
this.emit(`self.validate_required(self.${param}, '${param}')\n`, level + 2);
|
|
1052
|
+
}
|
|
1053
|
+
// 这里判断类中属性的结构
|
|
1054
|
+
if(node.fieldValue.fieldType === 'array' && node.fieldValue.fieldItemType.type !== 'map' && node.fieldValue.fieldItemType.lexeme !== 'string') {
|
|
1055
|
+
// 最底下是string的就不需要validate
|
|
1056
|
+
if(this.checkFieldItemTypeAllString(node.fieldValue)){
|
|
1057
|
+
continue;
|
|
1058
|
+
}
|
|
1059
|
+
notPass = true;
|
|
1060
|
+
this.emit(`if self.${param}:\n`, level + 2);
|
|
1061
|
+
this.emit(`for k in self.${param}:\n`, level + 4);
|
|
1062
|
+
let baseLevel = level + 6;
|
|
1063
|
+
// 二层数组
|
|
1064
|
+
if(node.fieldValue.fieldItemType && node.fieldValue.fieldItemType.fieldType === 'array' || node.fieldValue.fieldItemType.fieldType === 'string') {
|
|
1065
|
+
this.emit('for k1 in k:\n', baseLevel);
|
|
1066
|
+
this.emit('if k1:\n', baseLevel += 2);
|
|
1067
|
+
this.emit('k1.validate()\n', baseLevel += 2);
|
|
1068
|
+
} else {
|
|
1069
|
+
this.emit('if k:\n', baseLevel);
|
|
1070
|
+
this.emit('k.validate()\n', baseLevel + 2);
|
|
1071
|
+
}
|
|
1072
|
+
} else if(node.fieldValue.fieldType === 'map' && node.fieldValue.valueType.lexeme !== 'string') {
|
|
1073
|
+
// TODO: 这里为array的时候不做validate
|
|
1074
|
+
// $dara.Model.validateMap
|
|
1075
|
+
if(this.checkFieldItemTypeAllString(node.fieldValue)){
|
|
1076
|
+
continue;
|
|
1077
|
+
}
|
|
1078
|
+
notPass = true;
|
|
1079
|
+
this.emit(`if self.${param}:\n`, level + 2);
|
|
1080
|
+
this.emit(`for v in self.${param}.values():\n`, level + 4);
|
|
1081
|
+
let baseLevel = level + 6;
|
|
1082
|
+
// 二层map 或 array 特殊操作
|
|
1083
|
+
if(node.fieldValue.fieldItemType && node.fieldValue.fieldItemType.fieldType === 'array') {
|
|
1084
|
+
this.emit('for v1 in k:\n', baseLevel);
|
|
1085
|
+
this.emit('if v1:\n', baseLevel += 2);
|
|
1086
|
+
this.emit('v1.validate()\n', baseLevel += 2);
|
|
1087
|
+
} else if(node.fieldValue.valueType.type === 'array'){
|
|
1088
|
+
this.emit('for k1 in v:\n', baseLevel);
|
|
1089
|
+
this.emit('if k1:\n', baseLevel += 2);
|
|
1090
|
+
this.emit('k1.validate()\n', baseLevel += 2);
|
|
1091
|
+
} else {
|
|
1092
|
+
this.emit('if v:\n', baseLevel);
|
|
1093
|
+
this.emit('v.validate()\n', baseLevel + 2);
|
|
1094
|
+
}
|
|
1095
|
+
} else if(node.fieldValue.fieldType && node.fieldValue.fieldType.idType === 'model' || node.fieldValue.type === 'modelBody'){
|
|
1096
|
+
notPass = true;
|
|
1097
|
+
this.emit(`if self.${param}:\n`, level + 2);
|
|
1098
|
+
this.emit(`self.${param}.validate()\n`, level + 4);
|
|
1099
|
+
} else if(pattern !== ''){
|
|
1100
|
+
notPass = true;
|
|
1101
|
+
this.emit(`if self.${param} is not None:\n`, level + 2);
|
|
1102
|
+
this.emit(`self.validate_pattern(self.${param}, '${param}', '${pattern}')\n`, level + 4);
|
|
1103
|
+
} else if(maxLength > 0 && maxLength <= 2147483647){
|
|
1104
|
+
notPass = true;
|
|
1105
|
+
this.emit(`if self.${param} is not None:\n`, level + 2);
|
|
1106
|
+
this.emit(`self.validate_max_length(self.${param}, '${param}', ${maxLength})\n`, level + 4);
|
|
1107
|
+
} else if(minLength > 0 && minLength <= 2147483647){
|
|
1108
|
+
notPass = true;
|
|
1109
|
+
this.emit(`if self.${param} is not None:\n`, level + 2);
|
|
1110
|
+
this.emit(`self.validate_min_length(self.${param}, '${param}', ${minLength})\n`, level + 4);
|
|
1111
|
+
} else if(maximum > 0 && maximum <= Number.MAX_SAFE_INTEGER){
|
|
1112
|
+
notPass = true;
|
|
1113
|
+
this.emit(`if self.${param} is not None:\n`, level + 2);
|
|
1114
|
+
this.emit(`self.validate_maximum(self.${param}, '${param}', ${maximum})\n`, level + 4);
|
|
1115
|
+
} else if(minimum > 0 && minimum <= Number.MAX_SAFE_INTEGER){
|
|
1116
|
+
notPass = true;
|
|
1117
|
+
this.emit(`if self.${param} is not None:\n`, level + 2);
|
|
1118
|
+
this.emit(`self.validate_minimum(self.${param}, '${param}', ${minimum})\n`, level + 4);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
if(!notPass) {
|
|
1123
|
+
this.emit('pass\n', level + 2);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
visitToMapField(fieldValue, key, value, level) {
|
|
1128
|
+
const deep = Math.floor(level / 4);
|
|
1129
|
+
if (fieldValue.type === 'modelBody' || fieldValue.type === 'moduleModel' ||
|
|
1130
|
+
fieldValue.type === 'subModel' || fieldValue.idType === 'model' ||
|
|
1131
|
+
(fieldValue.fieldType && (fieldValue.fieldType.type === 'moduleModel' ||
|
|
1132
|
+
fieldValue.fieldType.idType === 'model' || fieldValue.fieldType.idType === 'builtin_model'))) {
|
|
1133
|
+
this.emit(`${key} = ${value}.to_map()`, level);
|
|
1134
|
+
if(deep > 1) {
|
|
1135
|
+
this.emit(` if ${value} else None\n`);
|
|
1136
|
+
}
|
|
1137
|
+
this.emit('\n');
|
|
1138
|
+
} else if (fieldValue.type === 'array' || fieldValue.fieldType === 'array') {
|
|
1139
|
+
this.emit(`l${deep} = 0\n`, level);
|
|
1140
|
+
this.emit(`${key} = []\n`, level);
|
|
1141
|
+
this.emit(`for k${deep} in ${value}:\n`, level);
|
|
1142
|
+
this.emit(`l${deep} += 1\n`, level + 2);
|
|
1143
|
+
this.visitToMapField(fieldValue.fieldItemType || fieldValue.subType, `${key}[l${deep}]`, `k${deep}`, level + 2);
|
|
1144
|
+
} else if (fieldValue.fieldType === 'map' || fieldValue.type === 'map') {
|
|
1145
|
+
this.emit(`${key} = {}\n`, level);
|
|
1146
|
+
this.emit(`for k${deep}, v${deep} in k.items():\n`, level);
|
|
1147
|
+
this.visitToMapField(fieldValue.valueType, `${key}[k${deep}]`, `v${deep}`, level + 2);
|
|
1148
|
+
} else {
|
|
1149
|
+
this.emit(`${key} = ${value}\n`, level);
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
visitToMap(ast, level) {
|
|
1155
|
+
this.emit('def to_map(self):\n', level);
|
|
1156
|
+
this.emit(` _map = super().to_map()
|
|
1157
|
+
if _map is not None:
|
|
1158
|
+
return _map
|
|
1159
|
+
|
|
1160
|
+
result = dict()\n`);
|
|
1161
|
+
for (let i = 0; i < ast.nodes.length; i++) {
|
|
1162
|
+
const node = ast.nodes[i];
|
|
1163
|
+
let realName = this.getRealName(node);
|
|
1164
|
+
let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
|
|
1165
|
+
this.visitComments(comments, level);
|
|
1166
|
+
let param = _snakeCase(_escape(_name(node.fieldName)));
|
|
1167
|
+
this.emit(`if self.${param} is not None:\n`, level + 2);
|
|
1168
|
+
if(!this.checkFieldHasModel(node.fieldValue)) {
|
|
1169
|
+
this.emit(`result['${realName}'] = self.${param}`, level + 4);
|
|
1170
|
+
} else {
|
|
1171
|
+
this.visitToMapField(node.fieldValue, `result['${realName}']`, `self.${param}`, level + 4);
|
|
1172
|
+
}
|
|
1173
|
+
this.emit('\n');
|
|
1174
|
+
}
|
|
1175
|
+
this.emit('return result\n', level + 2);
|
|
1176
|
+
this.emit('\n');
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
visitFromField(fieldValue, fieldName, key, value, level) {
|
|
1180
|
+
const deep = Math.floor(level / 4);
|
|
1181
|
+
if (fieldValue.type === 'modelBody') {
|
|
1182
|
+
const subModelName = _subModelName(fieldName);
|
|
1183
|
+
this.emit(`temp_model = ${subModelName}\n`, level);
|
|
1184
|
+
this.emit(`${key} = temp_model.from_map(${value})\n`, level);
|
|
1185
|
+
} else if (fieldValue.type === 'array' || fieldValue.fieldType === 'array') {
|
|
1186
|
+
this.emit(`l${deep} = 0\n`, level);
|
|
1187
|
+
this.emit(`${key} = []\n`, level);
|
|
1188
|
+
this.emit(`for k${deep} in ${value}:\n`, level);
|
|
1189
|
+
this.emit(`l${deep} += 1\n`, level + 2);
|
|
1190
|
+
this.visitFromField(fieldValue.fieldItemType || fieldValue.subType, fieldName, `${key}[l${deep}]`, `k${deep}`, level + 2);
|
|
1191
|
+
} else if (fieldValue.fieldType === 'map' || fieldValue.type === 'map') {
|
|
1192
|
+
this.emit(`${key} = {}\n`, level);
|
|
1193
|
+
this.emit(`for k${deep}, v${deep} in ${value}.items():\n`, level);
|
|
1194
|
+
this.visitFromField(fieldValue.valueType, fieldName, `${key}[k${deep}]`, `v${deep}`, level + 2);
|
|
1195
|
+
} else if (fieldValue.type === 'moduleModel' ||
|
|
1196
|
+
(fieldValue.fieldType && fieldValue.fieldType.type === 'moduleModel')) {
|
|
1197
|
+
const [moduleId, ...rest] = fieldValue.path || fieldValue.fieldType.path;
|
|
1198
|
+
const modelName = _subModelName(rest.map((item) => {
|
|
1199
|
+
return item.lexeme;
|
|
1200
|
+
}).join('.'));
|
|
1201
|
+
this.emit(`${key} = ${this.getModelName(modelName, _name(moduleId), 'module')}.from_map(${value})\n`, level);
|
|
1202
|
+
} else if (fieldValue.type === 'subModel') {
|
|
1203
|
+
const [moduleId, ...rest] = fieldValue.path;
|
|
1204
|
+
const subModelName = _subModelName([moduleId.lexeme, ...rest.map((item) => {
|
|
1205
|
+
return item.lexeme;
|
|
1206
|
+
})].join('.'));
|
|
1207
|
+
this.emit(`${key} = ${subModelName}.from_map(${value})\n`, level);
|
|
1208
|
+
} else if (fieldValue.idType === 'model') {
|
|
1209
|
+
const modelName = _type(_name(fieldValue));
|
|
1210
|
+
this.emit(`${key} = ${modelName}.from_map(${value})\n`, level);
|
|
1211
|
+
} else if (fieldValue.fieldType && fieldValue.fieldType.idType === 'model') {
|
|
1212
|
+
const modelName = _type(_name(fieldValue.fieldType));
|
|
1213
|
+
this.emit(`${key} = ${modelName}.from_map(${value})\n`, level);
|
|
1214
|
+
} else if (fieldValue.fieldType && fieldValue.fieldType.idType === 'builtin_model') {
|
|
1215
|
+
const typeName = _type(_name(fieldValue.fieldType));
|
|
1216
|
+
this.pushImports(typeName);
|
|
1217
|
+
this.emit(`${key} = ${typeName}.from_map(${value})\n`, level);
|
|
1218
|
+
} else {
|
|
1219
|
+
this.emit(`${key} = ${value}\n`, level);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
visitFromMap(ast, modelName, level) {
|
|
1224
|
+
//
|
|
1225
|
+
this.emit('def from_map(self, m: dict = None):\n', level);
|
|
1226
|
+
this.emit('m = m or dict()\n', level + 2);
|
|
1227
|
+
for (let i = 0; i < ast.nodes.length; i++) {
|
|
1228
|
+
const node = ast.nodes[i];
|
|
1229
|
+
let realName = this.getRealName(node);
|
|
1230
|
+
let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
|
|
1231
|
+
this.visitComments(comments, level);
|
|
1232
|
+
let param = _snakeCase(_escape(_name(node.fieldName)));
|
|
1233
|
+
this.emit(`if m.get('${realName}') is not None:\n`, level + 2);
|
|
1234
|
+
if(!this.checkFieldHasModel(node.fieldValue)) {
|
|
1235
|
+
this.emit(`self.${param} = m.get('${realName}')`, level + 4);
|
|
1236
|
+
} else {
|
|
1237
|
+
this.visitFromField(node.fieldValue, [modelName, param].join('.'), `self.${param}`, `m.get('${realName}')`, level + 4);
|
|
1238
|
+
}
|
|
1239
|
+
this.emit('\n');
|
|
1240
|
+
}
|
|
1241
|
+
this.emit('return self\n', level + 2);
|
|
1242
|
+
this.emit('\n');
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
getAttributes(ast, name){
|
|
1246
|
+
const attr = ast.attrs.find((item) => {
|
|
1247
|
+
return item.attrName.lexeme === name;
|
|
1248
|
+
});
|
|
1249
|
+
if(!attr) {
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
return attr.attrValue.string || attr.attrValue.lexeme || attr.attrValue.value;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
visitFieldValidate(value, level, name) {
|
|
1256
|
+
if (value.type === 'array' || value.fieldType === 'array') {
|
|
1257
|
+
this.emit(`if(Array.isArray(${name})) {\n`, level);
|
|
1258
|
+
this.emit(`$dara.Model.validateArray(${name})\n`, level + 1);
|
|
1259
|
+
this.emit('}\n', level);
|
|
1260
|
+
} else if (value.fieldType === 'map' || value.type === 'map') {
|
|
1261
|
+
this.emit(`if(${name}) {\n`, level);
|
|
1262
|
+
this.emit(`$dara.Model.validateMap(${name})\n`, level + 1);
|
|
1263
|
+
this.emit('}\n', level);
|
|
1264
|
+
} else if (value.type === 'moduleModel' || value.type === 'modelBody'
|
|
1265
|
+
|| value.type === 'subModel' || value.fieldType.type === 'moduleModel'
|
|
1266
|
+
|| value.fieldType.idType === 'model' || value.fieldType.idType === 'module') {
|
|
1267
|
+
this.emit(`if(${name} && typeof (${name} as any).validate === 'function') {\n`, level);
|
|
1268
|
+
this.emit(`(${name} as any).validate()\n`, level + 1);
|
|
1269
|
+
this.emit('}\n', level);
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
extendBaseErr(extendOn){
|
|
1274
|
+
if (!extendOn) {
|
|
1275
|
+
return true;
|
|
1276
|
+
}
|
|
1277
|
+
if(_name(extendOn) === '$Error') {
|
|
1278
|
+
return true;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
return false;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
visitExtendOn(extendOn, type = 'model') {
|
|
1285
|
+
if (!extendOn) {
|
|
1286
|
+
type === 'model' ? this.pushImports(`${CORE}Model`) : this.pushImports(`${CORE}Exception`);
|
|
1287
|
+
return type === 'model' ? this.emit(`(${CORE}Model)`) : this.emit(`(${CORE}Exception)`);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
switch(_name(extendOn)) {
|
|
1291
|
+
case '$Error':
|
|
1292
|
+
this.pushImports(`${CORE}Exception`);
|
|
1293
|
+
this.emit(`(${CORE}Exception)`);
|
|
1294
|
+
return;
|
|
1295
|
+
case '$ResponseError':
|
|
1296
|
+
this.pushImports('ResponseException');
|
|
1297
|
+
this.emit('(ResponseException)');
|
|
1298
|
+
return;
|
|
1299
|
+
case '$Model':
|
|
1300
|
+
this.pushImports(`${CORE}Model`);
|
|
1301
|
+
this.emit(`(${CORE}Model)`);
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
let needBaseException = false;
|
|
1306
|
+
|
|
1307
|
+
if (extendOn.type === 'moduleModel') {
|
|
1308
|
+
const [moduleId, ...rest] = extendOn.path;
|
|
1309
|
+
const moduleName = _name(moduleId);
|
|
1310
|
+
const modelName = _subModelName(rest.map((item) => {
|
|
1311
|
+
return item.lexeme;
|
|
1312
|
+
}).join('.'));
|
|
1313
|
+
|
|
1314
|
+
const externModel = this.usedExternModel.get(moduleName);
|
|
1315
|
+
if (externModel && externModel.has(modelName) && type === 'exception') {
|
|
1316
|
+
needBaseException = true;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
this.emit(`(${this.getModelName(modelName, moduleName, type)}`);
|
|
1320
|
+
} else if (extendOn.type === 'subModel') {
|
|
1321
|
+
const [moduleId, ...rest] = extendOn.path;
|
|
1322
|
+
if (type === 'exception') {
|
|
1323
|
+
needBaseException = true;
|
|
1324
|
+
const modelPkgName = path.basename(this.modelPath, '.py');
|
|
1325
|
+
this.imports.push({
|
|
1326
|
+
className: modelPkgName,
|
|
1327
|
+
});
|
|
1328
|
+
this.emit(`${modelPkgName}.`);
|
|
1329
|
+
}
|
|
1330
|
+
this.emit(`(${_subModelName([moduleId.lexeme, ...rest.map((item) => {
|
|
1331
|
+
return item.lexeme;
|
|
1332
|
+
})].join('.'))}`);
|
|
1333
|
+
} else {
|
|
1334
|
+
let modelName = _upperFirst(_name(extendOn));
|
|
1335
|
+
this.emit('(');
|
|
1336
|
+
if(extendOn.moduleName){
|
|
1337
|
+
this.getModelName(_upperFirst(_name(extendOn)), extendOn.moduleName, type);
|
|
1338
|
+
} else if (this.predefined[modelName] && this.predefined[modelName].isException && type === 'model') {
|
|
1339
|
+
const exPkgName = path.basename(this.exceptionPath, '.py');
|
|
1340
|
+
this.imports.push({
|
|
1341
|
+
className: exPkgName,
|
|
1342
|
+
});
|
|
1343
|
+
this.emit(`${exPkgName}.`);
|
|
1344
|
+
} else if (this.predefined[modelName] && !this.predefined[modelName].isException && type === 'exception') {
|
|
1345
|
+
needBaseException = true;
|
|
1346
|
+
const modelPkgName = path.basename(this.modelPath, '.py');
|
|
1347
|
+
this.imports.push({
|
|
1348
|
+
className: modelPkgName,
|
|
1349
|
+
});
|
|
1350
|
+
this.emit(`${modelPkgName}.`);
|
|
1351
|
+
}
|
|
1352
|
+
this.emit(`${modelName}`);
|
|
1353
|
+
if(type === 'exception' && !needBaseException) {
|
|
1354
|
+
this.emit('Exception');
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
if(needBaseException) {
|
|
1358
|
+
this.emit(`, ${CORE}Exception`);
|
|
1359
|
+
}
|
|
1360
|
+
this.emit(')');
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
dealExtendFileds(ast) {
|
|
1364
|
+
const fileds = [];
|
|
1365
|
+
for (let i = 0; i < ast.nodes.length; i++) {
|
|
1366
|
+
const node = ast.nodes[i];
|
|
1367
|
+
const fieldName = _name(node.fieldName);
|
|
1368
|
+
fileds.push(fieldName);
|
|
1369
|
+
}
|
|
1370
|
+
const extendFileds = [];
|
|
1371
|
+
for (let i = 0; i < ast.extendFileds.length; i++) {
|
|
1372
|
+
const node = ast.extendFileds[i];
|
|
1373
|
+
node.extend = true;
|
|
1374
|
+
const fieldName = _name(node.fieldName);
|
|
1375
|
+
if(fileds.includes(fieldName)) {
|
|
1376
|
+
continue;
|
|
1377
|
+
}
|
|
1378
|
+
extendFileds.push(node);
|
|
1379
|
+
|
|
1380
|
+
}
|
|
1381
|
+
return extendFileds.concat(ast.nodes);
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
visitModel(modelBody, modelName, extendOn, level) {
|
|
1385
|
+
// const modelDir = path.join(path.dirname(filepath), this.modelDir);
|
|
1386
|
+
this.emit(`class ${modelName}`, level);
|
|
1387
|
+
this.visitExtendOn(extendOn);
|
|
1388
|
+
this.emit(':\n');
|
|
1389
|
+
this.visitModelBody(modelBody, level + 2, modelName);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
eachModel(ast, level) {
|
|
1393
|
+
assert.equal(ast.type, 'model');
|
|
1394
|
+
const modelName = _upperFirst(_name(ast.modelName));
|
|
1395
|
+
this.visitAnnotation(ast.annotation, level);
|
|
1396
|
+
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
|
|
1397
|
+
this.visitComments(comments, level);
|
|
1398
|
+
this.visitModel(ast.modelBody, modelName, ast.extendOn, level);
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
visitFieldsInit(ast, level, modelName, type = 'model', baseErr = false){
|
|
1402
|
+
let node;
|
|
1403
|
+
this.emit(' def __init__(');
|
|
1404
|
+
const paramNodes = this.dealExtendFileds(ast);
|
|
1405
|
+
if (!paramNodes.length) {
|
|
1406
|
+
this.emit('self):\n');
|
|
1407
|
+
this.emit('pass', level + 2);
|
|
1408
|
+
return;
|
|
1409
|
+
}
|
|
1410
|
+
this.emit('\n');
|
|
1411
|
+
this.emit('self, \n', level + 2);
|
|
1412
|
+
for (let i = 0; i < paramNodes.length; i++) {
|
|
1413
|
+
node = paramNodes[i];
|
|
1414
|
+
if(!node.extend) {
|
|
1415
|
+
let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
|
|
1416
|
+
this.visitComments(comments, level);
|
|
1417
|
+
}
|
|
1418
|
+
let param = _snakeCase(_escape(_name(node.fieldName)));
|
|
1419
|
+
if(param === 'name' && type === 'exception') {
|
|
1420
|
+
continue;
|
|
1421
|
+
}
|
|
1422
|
+
this.emit(`${param}: `, level + 2);
|
|
1423
|
+
this.visitFieldType(node.fieldValue, level, modelName, _name(node.fieldName));
|
|
1424
|
+
this.emit(' = None,\n');
|
|
1425
|
+
}
|
|
1426
|
+
this.emit('):\n', level);
|
|
1427
|
+
|
|
1428
|
+
if(ast.extendFileds && ast.extendFileds.length > 0) {
|
|
1429
|
+
this.emit('super().__init__(', level + 2);
|
|
1430
|
+
if(baseErr) {
|
|
1431
|
+
this.emit('{\n');
|
|
1432
|
+
for (let i = 0; i < ast.extendFileds.length; i++) {
|
|
1433
|
+
node = ast.extendFileds[i];
|
|
1434
|
+
let value = _snakeCase(_escape(_name(node.fieldName)));
|
|
1435
|
+
let key = _escape(_name(node.fieldName));
|
|
1436
|
+
if(key === 'name' && type === 'exception') {
|
|
1437
|
+
continue;
|
|
1438
|
+
}
|
|
1439
|
+
this.emit(`'${key}': ${value},\n`, level + 4);
|
|
1440
|
+
}
|
|
1441
|
+
this.emit('})\n', level + 2);
|
|
1442
|
+
} else {
|
|
1443
|
+
this.emit('\n');
|
|
1444
|
+
for (let i = 0; i < ast.extendFileds.length; i++) {
|
|
1445
|
+
node = ast.extendFileds[i];
|
|
1446
|
+
let param = _snakeCase(_escape(_name(node.fieldName)));
|
|
1447
|
+
if(param === 'name' && type === 'exception') {
|
|
1448
|
+
continue;
|
|
1449
|
+
}
|
|
1450
|
+
this.emit(`${param} = ${param},\n`, level + 4);
|
|
1451
|
+
}
|
|
1452
|
+
this.emit(')\n', level + 2);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
visitEcxceptionBody(ast, extendOn, exceptionName, level) {
|
|
1458
|
+
assert.equal(ast.type, 'exceptionBody');
|
|
1459
|
+
this.visitFieldsInit(ast, level, exceptionName, 'exception', this.extendBaseErr(extendOn));
|
|
1460
|
+
let node;
|
|
1461
|
+
|
|
1462
|
+
this.emit(`self.name = '${exceptionName}Exception'\n`, level + 2);
|
|
1463
|
+
for (let i = 0; i < ast.nodes.length; i++) {
|
|
1464
|
+
node = ast.nodes[i];
|
|
1465
|
+
let comments = DSL.comment.getFrontComments(this.comments, node.tokenRange[0]);
|
|
1466
|
+
this.visitComments(comments, level);
|
|
1467
|
+
let param = _snakeCase(_escape(_name(node.fieldName)));
|
|
1468
|
+
if(param === 'name') {
|
|
1469
|
+
continue;
|
|
1470
|
+
}
|
|
1471
|
+
this.emit(`self.${param} = ${param}\n`, level + 2);
|
|
1472
|
+
}
|
|
1473
|
+
this.emit('\n');
|
|
1474
|
+
if (node) {
|
|
1475
|
+
//find the last node's back comment
|
|
1476
|
+
let comments = DSL.comment.getBetweenComments(this.comments, node.tokenRange[0], ast.tokenRange[1]);
|
|
1477
|
+
this.visitComments(comments, level);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
if (ast.nodes.length === 0) {
|
|
1481
|
+
//empty block's comment
|
|
1482
|
+
let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]);
|
|
1483
|
+
this.visitComments(comments, level);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
visitException(exceptionBody, exceptionName, extendOn, level) {
|
|
1488
|
+
this.emit(`class ${exceptionName}Exception`, level);
|
|
1489
|
+
this.visitExtendOn(extendOn, 'exception');
|
|
1490
|
+
this.emit(':\n');
|
|
1491
|
+
this.visitEcxceptionBody(exceptionBody, extendOn, exceptionName, level + 2);
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
eachException(ast, level) {
|
|
1495
|
+
assert.equal(ast.type, 'exception');
|
|
1496
|
+
const exceptionName = _upperFirst(_name(ast.exceptionName));
|
|
1497
|
+
this.visitAnnotation(ast.annotation, level);
|
|
1498
|
+
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
|
|
1499
|
+
this.visitComments(comments, level);
|
|
1500
|
+
this.visitException(ast.exceptionBody, exceptionName, ast.extendOn, level);
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
eachSubModel(ast, level) {
|
|
1504
|
+
assert.equal(ast.type, 'model');
|
|
1505
|
+
const modelName = _subModelName(_name(ast.modelName));
|
|
1506
|
+
this.visitModel(ast.modelBody, modelName, ast.extendOn, level);
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
visitObjectFieldValue(ast, level) {
|
|
1510
|
+
this.visitExpr(ast, level);
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
visitObjectField(ast, level, end) {
|
|
1514
|
+
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
|
|
1515
|
+
this.visitComments(comments, level);
|
|
1516
|
+
if (ast.type === 'objectField') {
|
|
1517
|
+
// TODO 这里粗暴处理的双引号,可以考虑优化
|
|
1518
|
+
var key = _escape(_name(ast.fieldName) || _string(ast.fieldName)).replace(/['"]/g, '');
|
|
1519
|
+
this.emit(`'${key}': `, level + 2);
|
|
1520
|
+
this.visitObjectFieldValue(ast.expr, level + 2);
|
|
1521
|
+
if (!end) {
|
|
1522
|
+
this.emit(',\n');
|
|
1523
|
+
} else {
|
|
1524
|
+
this.emit('\n');
|
|
1525
|
+
}
|
|
1526
|
+
} else if (ast.type !== 'expandField'){
|
|
1527
|
+
throw new Error('unimpelemented');
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
visitModelField(ast, level, end) {
|
|
1532
|
+
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
|
|
1533
|
+
this.visitComments(comments, level);
|
|
1534
|
+
if (ast.type === 'objectField') {
|
|
1535
|
+
// TODO 这里粗暴处理的双引号,可以考虑优化
|
|
1536
|
+
var key = _escape(_name(ast.fieldName) || _string(ast.fieldName)).replace(/['"]/g, '');
|
|
1537
|
+
this.emit(`${_snakeCase(key)} = `, level + 2);
|
|
1538
|
+
this.visitObjectFieldValue(ast.expr, level + 2);
|
|
1539
|
+
if (!end) {
|
|
1540
|
+
this.emit(',\n');
|
|
1541
|
+
} else {
|
|
1542
|
+
this.emit('\n');
|
|
1543
|
+
}
|
|
1544
|
+
} else if (ast.type !== 'expandField'){
|
|
1545
|
+
throw new Error('unimpelemented');
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
visitObject(ast, level) {
|
|
1550
|
+
assert.equal(ast.type, 'object');
|
|
1551
|
+
if (ast.fields.length === 0) {
|
|
1552
|
+
this.emit('{');
|
|
1553
|
+
let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]);
|
|
1554
|
+
if (comments.length > 0) {
|
|
1555
|
+
this.emit('\n');
|
|
1556
|
+
this.visitComments(comments, level + 2);
|
|
1557
|
+
this.emit('', level);
|
|
1558
|
+
}
|
|
1559
|
+
this.emit('}');
|
|
1560
|
+
} else {
|
|
1561
|
+
var expandFields = [];
|
|
1562
|
+
for (var i = 0; i < ast.fields.length; i++) {
|
|
1563
|
+
if (ast.fields[i].type !== 'expandField') {
|
|
1564
|
+
continue;
|
|
1565
|
+
}
|
|
1566
|
+
expandFields.push(ast.fields[i]);
|
|
1567
|
+
}
|
|
1568
|
+
if (expandFields.length !== 0){
|
|
1569
|
+
this.pushImports(`${CORE}Core`);
|
|
1570
|
+
this.emit(`${CORE}Core.merge({`);
|
|
1571
|
+
if(ast.fields.length !== expandFields.length) {
|
|
1572
|
+
this.emit('\n');
|
|
1573
|
+
}
|
|
1574
|
+
} else {
|
|
1575
|
+
this.emit('{\n');
|
|
1576
|
+
}
|
|
1577
|
+
for (i = 0; i < ast.fields.length; i++) {
|
|
1578
|
+
this.visitObjectField(ast.fields[i], level, i === ast.fields.length - 1);
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
if (expandFields.length !== 0) {
|
|
1582
|
+
if(ast.fields.length !== expandFields.length) {
|
|
1583
|
+
this.emit('', level);
|
|
1584
|
+
}
|
|
1585
|
+
this.emit('}, ');
|
|
1586
|
+
this.visitExpr(expandFields[0].expr);
|
|
1587
|
+
expandFields.slice(1).forEach((item) => {
|
|
1588
|
+
this.emit(', ');
|
|
1589
|
+
this.visitExpr(item.expr);
|
|
1590
|
+
});
|
|
1591
|
+
this.emit(')');
|
|
1592
|
+
} else {
|
|
1593
|
+
this.emit('}', level);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
let comments = DSL.comment.getBetweenComments(this.comments, ast.fields[i - 1].tokenRange[0], ast.tokenRange[1]);
|
|
1597
|
+
this.visitComments(comments, level + 1);
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
visitMethodCall(ast, level) {
|
|
1602
|
+
assert.equal(ast.left.type, 'method_call');
|
|
1603
|
+
const name = _name(ast.left.id);
|
|
1604
|
+
const functionName = _snakeCase(name);
|
|
1605
|
+
if (name.startsWith('$') && this.builtin[name]) {
|
|
1606
|
+
const method = name.replace('$', '');
|
|
1607
|
+
this.builtin[name][method](ast, level, ast.isAsync && this.isAsyncFunction);
|
|
1608
|
+
return;
|
|
1609
|
+
} else if(this.isStaticFunction === false && this.isAsyncFunction && ast.isAsync){
|
|
1610
|
+
this.emit(`await self.${functionName}_async`);
|
|
1611
|
+
} else if(this.isStaticFunction === false) {
|
|
1612
|
+
this.emit(`self.${functionName}`);
|
|
1613
|
+
} else if(ast.isAsync && this.isAsyncFunction) {
|
|
1614
|
+
this.emit(`await ${this.className}.${functionName}_async`);
|
|
1615
|
+
} else {
|
|
1616
|
+
const functionName = _snakeCase(name);
|
|
1617
|
+
this.emit(`${this.className}.${functionName}`);
|
|
1618
|
+
}
|
|
1619
|
+
this.visitArgs(ast.args, level);
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
|
|
1623
|
+
visitInstanceCall(ast, level) {
|
|
1624
|
+
assert.equal(ast.left.type, 'instance_call');
|
|
1625
|
+
const method = _name(ast.left.propertyPath[0]);
|
|
1626
|
+
const async = ast.isAsync && this.isAsyncFunction;
|
|
1627
|
+
if (async) {
|
|
1628
|
+
this.emit('await ');
|
|
1629
|
+
}
|
|
1630
|
+
if (ast.builtinModule && this.builtin[ast.builtinModule] && this.builtin[ast.builtinModule][method]) {
|
|
1631
|
+
this.builtin[ast.builtinModule][method](ast, level, async);
|
|
1632
|
+
} else {
|
|
1633
|
+
if (ast.left.id.tag === DSL.Tag.Tag.VID) {
|
|
1634
|
+
this.emit(`self.${_snakeCase(_vid(ast.left.id))}`);
|
|
1635
|
+
} else {
|
|
1636
|
+
const aliasId = _snakeCase(_name(ast.left.id));
|
|
1637
|
+
this.emit(aliasId);
|
|
1638
|
+
}
|
|
1639
|
+
this.emit(`.${(_snakeCase(method))}`);
|
|
1640
|
+
if(async) {
|
|
1641
|
+
this.emit('_async');
|
|
1642
|
+
}
|
|
1643
|
+
this.visitArgs(ast.args, level);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
visitStaticCall(ast, level) {
|
|
1648
|
+
assert.equal(ast.left.type, 'static_call');
|
|
1649
|
+
if (ast.left.id.type === 'builtin_module') {
|
|
1650
|
+
this.visitBuiltinStaticCall(ast, level);
|
|
1651
|
+
return;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
|
|
1655
|
+
const aliasId = _name(ast.left.id);
|
|
1656
|
+
let clientName = this.getModelName('', aliasId, 'module');
|
|
1657
|
+
|
|
1658
|
+
const functionName = _snakeCase(_name(ast.left.propertyPath[0]));
|
|
1659
|
+
|
|
1660
|
+
if (ast.isAsync && this.isAsyncFunction) {
|
|
1661
|
+
this.emit(`await ${clientName}.${functionName}_async`);
|
|
1662
|
+
} else {
|
|
1663
|
+
this.emit(`${clientName}.${functionName}`);
|
|
1664
|
+
}
|
|
1665
|
+
this.visitArgs(ast.args, level);
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
visitBuiltinStaticCall(ast, level) {
|
|
1669
|
+
const moduleName = _name(ast.left.id);
|
|
1670
|
+
|
|
1671
|
+
const builtiner = this.builtin[moduleName];
|
|
1672
|
+
if (!builtiner) {
|
|
1673
|
+
throw new Error('un-implemented');
|
|
1674
|
+
}
|
|
1675
|
+
const func = _name(ast.left.propertyPath[0]);
|
|
1676
|
+
builtiner[func](ast, level, ast.isAsync && this.isAsyncFunction);
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
visitCall(ast, level) {
|
|
1680
|
+
// TODO 这块目前都进了method_call 下面两个分支不知道有没有用
|
|
1681
|
+
assert.equal(ast.type, 'call');
|
|
1682
|
+
if (ast.left.type === 'method_call') {
|
|
1683
|
+
this.visitMethodCall(ast, level);
|
|
1684
|
+
} else if (ast.left.type === 'instance_call') {
|
|
1685
|
+
this.visitInstanceCall(ast, level);
|
|
1686
|
+
} else if (ast.left.type === 'static_call') {
|
|
1687
|
+
this.visitStaticCall(ast, level);
|
|
1688
|
+
} else {
|
|
1689
|
+
throw new Error('un-implemented');
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
visitConstruct(ast, level) {
|
|
1694
|
+
assert.equal(ast.type, 'construct');
|
|
1695
|
+
const aliasId = _name(ast.aliasId);
|
|
1696
|
+
|
|
1697
|
+
if(this.builtin[aliasId]) {
|
|
1698
|
+
const type = _type(aliasId);
|
|
1699
|
+
this.pushImports(type);
|
|
1700
|
+
this.emit(type);
|
|
1701
|
+
} else {
|
|
1702
|
+
this.emit(this.getModelName('', aliasId, 'module'));
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
this.visitArgs(ast.args, level);
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
|
|
1709
|
+
visitSuper(ast, level) {
|
|
1710
|
+
assert.equal(ast.type, 'super');
|
|
1711
|
+
this.emit('super().__init__');
|
|
1712
|
+
this.visitArgs(ast.args, level);
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
visitArgs(args, level) {
|
|
1716
|
+
this.emit('(');
|
|
1717
|
+
for (let i = 0; i < args.length; i++) {
|
|
1718
|
+
const expr = args[i];
|
|
1719
|
+
if (expr.needCast) {
|
|
1720
|
+
this.emit(`${CORE}Core.to_map(`);
|
|
1721
|
+
this.visitExpr(expr, level);
|
|
1722
|
+
this.emit(')');
|
|
1723
|
+
} else {
|
|
1724
|
+
this.visitExpr(expr, level);
|
|
1725
|
+
}
|
|
1726
|
+
if (i !== args.length - 1) {
|
|
1727
|
+
this.emit(', ');
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
this.emit(')');
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
visitPropertyAccess(ast, env = {}) {
|
|
1734
|
+
assert.ok(ast.type === 'property_access' || ast.type === 'property');
|
|
1735
|
+
var id = _snakeCase(_name(ast.id));
|
|
1736
|
+
if (ast.id.tag === Tag.VID) {
|
|
1737
|
+
id = `self.${_snakeCase(_vid(ast.id))}`;
|
|
1738
|
+
}
|
|
1739
|
+
var expr = avoidReserveName(id);
|
|
1740
|
+
const prefix = env.left ? '[' : '.get(';
|
|
1741
|
+
const suffix = env.left ? ']' : ')';
|
|
1742
|
+
var current = ast.id.inferred;
|
|
1743
|
+
|
|
1744
|
+
for (var i = 0; i < ast.propertyPath.length; i++) {
|
|
1745
|
+
var name = _name(ast.propertyPath[i]);
|
|
1746
|
+
if (current.type === 'model') {
|
|
1747
|
+
expr += `.${_snakeCase(name)}`;
|
|
1748
|
+
} else {
|
|
1749
|
+
expr += `${prefix}"${name}"${suffix}`;
|
|
1750
|
+
}
|
|
1751
|
+
current = ast.propertyPathTypes[i];
|
|
1752
|
+
}
|
|
1753
|
+
this.emit(expr);
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
visitExpr(ast, level, env) {
|
|
1757
|
+
if (ast.type === 'boolean') {
|
|
1758
|
+
this.emit(_upperFirst(`${ast.value}`));
|
|
1759
|
+
} else if (ast.type === 'null') {
|
|
1760
|
+
this.emit('None');
|
|
1761
|
+
} else if (ast.type === 'property_access') {
|
|
1762
|
+
this.visitPropertyAccess(ast, env);
|
|
1763
|
+
} else if (ast.type === 'string') {
|
|
1764
|
+
this.emit(`'${(_string(ast.value))}'`);
|
|
1765
|
+
} else if (ast.type === 'number') {
|
|
1766
|
+
this.emit(ast.value.value);
|
|
1767
|
+
} else if (ast.type === 'object') {
|
|
1768
|
+
this.visitObject(ast, level);
|
|
1769
|
+
} else if (ast.type === 'variable') {
|
|
1770
|
+
if(ast.inferred && ast.inferred.type === 'basic' && ast.inferred.name === 'class') {
|
|
1771
|
+
this.emit(this.getModelName('', _name(ast.id), 'module'));
|
|
1772
|
+
} else {
|
|
1773
|
+
this.emit(avoidReserveName(_snakeCase(_name(ast.id))));
|
|
1774
|
+
}
|
|
1775
|
+
} else if (ast.type === 'virtualVariable') {
|
|
1776
|
+
this.emit(`self.${_snakeCase(_vid(ast.vid))}`);
|
|
1777
|
+
} else if (ast.type === 'decrement') {
|
|
1778
|
+
this.visitExpr(ast.expr, level, { left: true });
|
|
1779
|
+
this.emit('-= 1');
|
|
1780
|
+
} else if (ast.type === 'increment') {
|
|
1781
|
+
this.visitExpr(ast.expr, level, { left: true });
|
|
1782
|
+
this.emit('+= 1');
|
|
1783
|
+
} else if (ast.type === 'template_string') {
|
|
1784
|
+
const tmp = this.output;
|
|
1785
|
+
this.output = '';
|
|
1786
|
+
for (var i = 0; i < ast.elements.length; i++) {
|
|
1787
|
+
var item = ast.elements[i];
|
|
1788
|
+
if (item.type === 'element') {
|
|
1789
|
+
this.emit((item.value.string).replace(/{/g, '{{').replace(/}/g, '}}'));
|
|
1790
|
+
} else if (item.type === 'expr') {
|
|
1791
|
+
this.emit('{');
|
|
1792
|
+
this.visitExpr(item.expr, level);
|
|
1793
|
+
this.emit('}');
|
|
1794
|
+
} else {
|
|
1795
|
+
throw new Error('unimpelemented');
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
const quote = _adaptedQuotes(this.output);
|
|
1799
|
+
this.output = tmp + `f${quote}${this.output}${quote}`;
|
|
1800
|
+
} else if (ast.type === 'call') {
|
|
1801
|
+
// 调用函数
|
|
1802
|
+
this.visitCall(ast, level);
|
|
1803
|
+
} else if (ast.type === 'construct') {
|
|
1804
|
+
this.visitConstruct(ast, level);
|
|
1805
|
+
} else if (ast.type === 'array') {
|
|
1806
|
+
this.visitArray(ast, level);
|
|
1807
|
+
} else if (ast.type === 'group') {
|
|
1808
|
+
this.emit('(');
|
|
1809
|
+
this.visitExpr(ast.expr, level, env);
|
|
1810
|
+
this.emit(')');
|
|
1811
|
+
} else if (_isBinaryOp(ast.type)) {
|
|
1812
|
+
this.visitExpr(ast.left, level, env);
|
|
1813
|
+
if (ast.type === 'or') {
|
|
1814
|
+
this.emit(' or ');
|
|
1815
|
+
} else if (ast.type === 'add') {
|
|
1816
|
+
this.emit(' + ');
|
|
1817
|
+
} else if (ast.type === 'subtract') {
|
|
1818
|
+
this.emit(' - ');
|
|
1819
|
+
} else if (ast.type === 'div') {
|
|
1820
|
+
this.emit(' / ');
|
|
1821
|
+
} else if (ast.type === 'multi') {
|
|
1822
|
+
this.emit(' * ');
|
|
1823
|
+
} else if (ast.type === 'and') {
|
|
1824
|
+
this.emit(' and ');
|
|
1825
|
+
// eslint-disable-next-line no-dupe-else-if
|
|
1826
|
+
} else if (ast.type === 'or') {
|
|
1827
|
+
this.emit(' or ');
|
|
1828
|
+
} else if (ast.type === 'lte') {
|
|
1829
|
+
this.emit(' <= ');
|
|
1830
|
+
} else if (ast.type === 'lt') {
|
|
1831
|
+
this.emit(' < ');
|
|
1832
|
+
} else if (ast.type === 'gte') {
|
|
1833
|
+
this.emit(' >= ');
|
|
1834
|
+
} else if (ast.type === 'gt') {
|
|
1835
|
+
this.emit(' > ');
|
|
1836
|
+
} else if (ast.type === 'neq') {
|
|
1837
|
+
this.emit(' != ');
|
|
1838
|
+
} else if (ast.type === 'eq') {
|
|
1839
|
+
this.emit(' == ');
|
|
1840
|
+
}
|
|
1841
|
+
this.visitExpr(ast.right, level, env);
|
|
1842
|
+
} else if (ast.type === 'not') {
|
|
1843
|
+
this.emit('not ',level);
|
|
1844
|
+
this.visitExpr(ast.expr, level, env);
|
|
1845
|
+
} else if (ast.type === 'construct_model') {
|
|
1846
|
+
// 生成实例的初始化赋值
|
|
1847
|
+
this.visitConstructModel(ast, level);
|
|
1848
|
+
} else if (ast.type === 'map_access') {
|
|
1849
|
+
this.visitMapAccess(ast, level, env);
|
|
1850
|
+
} else if (ast.type === 'array_access') {
|
|
1851
|
+
this.visitArrayAccess(ast);
|
|
1852
|
+
} else if (ast.type === 'super') {
|
|
1853
|
+
this.visitSuper(ast, level);
|
|
1854
|
+
} else {
|
|
1855
|
+
throw new Error('unimpelemented');
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
visitConstructModel(ast, level) {
|
|
1860
|
+
assert.equal(ast.type, 'construct_model');
|
|
1861
|
+
if (ast.aliasId.isModule) {
|
|
1862
|
+
// 这里做了粗糙改动 直接生成aliasId对应的models
|
|
1863
|
+
let type = 'model';
|
|
1864
|
+
let moduleName = _name(ast.aliasId);
|
|
1865
|
+
let modelName = _subModelName(ast.propertyPath.map((item) => {
|
|
1866
|
+
return item.lexeme;
|
|
1867
|
+
}).join('.'));
|
|
1868
|
+
const externEx = this.usedExternException.get(moduleName);
|
|
1869
|
+
if (externEx && externEx.has(modelName)) {
|
|
1870
|
+
type = 'exception';
|
|
1871
|
+
}
|
|
1872
|
+
this.emit(this.getModelName(modelName, moduleName, type));
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
if (ast.aliasId.isModel) {
|
|
1876
|
+
let type = 'model';
|
|
1877
|
+
let mainModelName = _name(ast.aliasId);
|
|
1878
|
+
mainModelName = _subModelName([mainModelName, ...ast.propertyPath.map((item) => {
|
|
1879
|
+
return item.lexeme;
|
|
1880
|
+
})].join('.'));
|
|
1881
|
+
|
|
1882
|
+
if(mainModelName.startsWith('$') && _type(mainModelName)) {
|
|
1883
|
+
mainModelName = _type(mainModelName);
|
|
1884
|
+
this.pushImports(mainModelName);
|
|
1885
|
+
this.emit(mainModelName);
|
|
1886
|
+
} else {
|
|
1887
|
+
if (this.predefined[mainModelName] && this.predefined[mainModelName].isException) {
|
|
1888
|
+
type = 'exception';
|
|
1889
|
+
}
|
|
1890
|
+
this.emit(this.getModelName(mainModelName, '', type));
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
this.emit('(');
|
|
1895
|
+
if (ast.object && ast.object.fields.length !== 0) {
|
|
1896
|
+
// 判断是否有初始化赋值
|
|
1897
|
+
// this.visitObject(ast.object, level);
|
|
1898
|
+
this.emit('\n');
|
|
1899
|
+
for (var i = 0; i < ast.object.fields.length; i++) {
|
|
1900
|
+
this.visitModelField(ast.object.fields[i], level, i === ast.object.fields.length - 1);
|
|
1901
|
+
}
|
|
1902
|
+
this.emit(')', level);
|
|
1903
|
+
} else{
|
|
1904
|
+
this.emit(')');
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
visitMapAccess(ast, level, env = {}) {
|
|
1910
|
+
assert.equal(ast.type, 'map_access');
|
|
1911
|
+
let expr;
|
|
1912
|
+
if (ast.id.tag === DSL.Tag.Tag.VID) {
|
|
1913
|
+
expr = `self.${_snakeCase(_vid(ast.id))}`;
|
|
1914
|
+
} else {
|
|
1915
|
+
expr = `${_snakeCase(_name(ast.id))}`;
|
|
1916
|
+
}
|
|
1917
|
+
const prefix = env.left ? '[' : '.get(';
|
|
1918
|
+
const suffix = env.left ? ']' : ')';
|
|
1919
|
+
if (ast.propertyPath && ast.propertyPath.length) {
|
|
1920
|
+
var current = ast.id.inferred;
|
|
1921
|
+
for (var i = 0; i < ast.propertyPath.length; i++) {
|
|
1922
|
+
var name = _name(ast.propertyPath[i]);
|
|
1923
|
+
if (current.type === 'model') {
|
|
1924
|
+
expr += `.${_snakeCase(name)}`;
|
|
1925
|
+
} else {
|
|
1926
|
+
expr += `${prefix}"${name}"${suffix}`;
|
|
1927
|
+
}
|
|
1928
|
+
current = ast.propertyPathTypes[i];
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
this.emit(`${expr}${prefix}`);
|
|
1932
|
+
this.visitExpr(ast.accessKey, level);
|
|
1933
|
+
this.emit(suffix);
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
visitArrayAccess(ast, level) {
|
|
1937
|
+
assert.equal(ast.type, 'array_access');
|
|
1938
|
+
let expr;
|
|
1939
|
+
if (ast.id.tag === DSL.Tag.Tag.VID) {
|
|
1940
|
+
// 这个判断很奇怪诶
|
|
1941
|
+
expr = `self.${_snakeCase(_vid(ast.id))}`;
|
|
1942
|
+
} else {
|
|
1943
|
+
expr = `${_snakeCase(_name(ast.id))}`;
|
|
1944
|
+
}
|
|
1945
|
+
if (ast.propertyPath && ast.propertyPath.length) {
|
|
1946
|
+
var current = ast.id.inferred;
|
|
1947
|
+
for (var i = 0; i < ast.propertyPath.length; i++) {
|
|
1948
|
+
var name = _name(ast.propertyPath[i]);
|
|
1949
|
+
if (current.type === 'model') {
|
|
1950
|
+
expr += `.${_snakeCase(name)}`;
|
|
1951
|
+
} else {
|
|
1952
|
+
expr += `["${name}"]`;
|
|
1953
|
+
}
|
|
1954
|
+
current = ast.propertyPathTypes[i];
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
this.emit(`${expr}[`, level);
|
|
1958
|
+
this.visitExpr(ast.accessKey, level);
|
|
1959
|
+
this.emit(']');
|
|
1960
|
+
}
|
|
1961
|
+
|
|
1962
|
+
visitArray(ast, level) {
|
|
1963
|
+
assert.equal(ast.type, 'array');
|
|
1964
|
+
let arrayComments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]);
|
|
1965
|
+
if (ast.items.length === 0) {
|
|
1966
|
+
this.emit('[ ');
|
|
1967
|
+
if (arrayComments.length > 0) {
|
|
1968
|
+
this.emit('\n');
|
|
1969
|
+
this.visitComments(arrayComments, level);
|
|
1970
|
+
this.emit('', level);
|
|
1971
|
+
}
|
|
1972
|
+
this.emit(']');
|
|
1973
|
+
return;
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
this.emit('[\n');
|
|
1977
|
+
let item;
|
|
1978
|
+
for (let i = 0; i < ast.items.length; i++) {
|
|
1979
|
+
item = ast.items[i];
|
|
1980
|
+
let comments = DSL.comment.getFrontComments(this.comments, item.tokenRange[0]);
|
|
1981
|
+
this.visitComments(comments, level);
|
|
1982
|
+
this.emit('', level +2);
|
|
1983
|
+
this.visitExpr(item, level + 2);
|
|
1984
|
+
if (i < ast.items.length - 1) {
|
|
1985
|
+
this.emit(',');
|
|
1986
|
+
}
|
|
1987
|
+
this.emit('\n');
|
|
1988
|
+
}
|
|
1989
|
+
if (item) {
|
|
1990
|
+
//find the last item's back comment
|
|
1991
|
+
let comments = DSL.comment.getBetweenComments(this.comments, item.tokenRange[0], ast.tokenRange[1]);
|
|
1992
|
+
this.visitComments(comments, level);
|
|
1993
|
+
}
|
|
1994
|
+
this.emit(']', level);
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
visitYield(ast, level) {
|
|
1998
|
+
assert.equal(ast.type, 'yield');
|
|
1999
|
+
this.emit('yield ', level);
|
|
2000
|
+
if (!ast.expr || ast.expr.type === 'null') {
|
|
2001
|
+
this.emit('\n');
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
this.emit(' ');
|
|
2005
|
+
|
|
2006
|
+
if (ast.needCast) {
|
|
2007
|
+
this.emit(`${CORE}Core.from_map(\n`);
|
|
2008
|
+
this.emit('', level + 2);
|
|
2009
|
+
this.visitType(ast.expectedType);
|
|
2010
|
+
this.emit('(),\n');
|
|
2011
|
+
this.emit('', level + 2);
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
this.visitExpr(ast.expr, level);
|
|
2015
|
+
|
|
2016
|
+
if (ast.needCast) {
|
|
2017
|
+
this.emit(')');
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
this.emit('\n');
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
visitReturn(ast, level) {
|
|
2024
|
+
assert.equal(ast.type, 'return');
|
|
2025
|
+
this.emit('return', level);
|
|
2026
|
+
if (!ast.expr || ast.expr.type === 'null') {
|
|
2027
|
+
this.emit('\n');
|
|
2028
|
+
return;
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
this.emit(' ');
|
|
2032
|
+
|
|
2033
|
+
if (ast.needCast) {
|
|
2034
|
+
this.emit(`${CORE}Core.from_map(\n`);
|
|
2035
|
+
this.emit('', level + 2);
|
|
2036
|
+
this.visitType(ast.expectedType);
|
|
2037
|
+
this.emit('(),\n');
|
|
2038
|
+
this.emit('', level + 2);
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
this.visitExpr(ast.expr, level);
|
|
2042
|
+
|
|
2043
|
+
if (ast.needCast) {
|
|
2044
|
+
this.emit('\n');
|
|
2045
|
+
this.emit(')', level);
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
this.emit('\n');
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
visitRetry(ast, level) {
|
|
2052
|
+
assert.equal(ast.type, 'retry');
|
|
2053
|
+
this.pushImports(`${CORE}Exception`);
|
|
2054
|
+
this.emit(`raise ${CORE}Exception(${REQUEST}, ${RESPONSE})\n`, level);
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
visitTry(ast, level) {
|
|
2058
|
+
assert.equal(ast.type, 'try');
|
|
2059
|
+
this.emit('try :\n', level);
|
|
2060
|
+
this.visitStmts(ast.tryBlock, level + 2);
|
|
2061
|
+
if (ast.catchBlocks && ast.catchBlocks.length > 0) {
|
|
2062
|
+
ast.catchBlocks.forEach(catchBlock => {
|
|
2063
|
+
if (!catchBlock.id) {
|
|
2064
|
+
return;
|
|
2065
|
+
}
|
|
2066
|
+
if (!catchBlock.id.type) {
|
|
2067
|
+
this.emit(`except Exception as ${_name(ast.catchId)} :\n`, level);
|
|
2068
|
+
} else {
|
|
2069
|
+
this.emit('except ', level);
|
|
2070
|
+
this.visitType(catchBlock.id.type);
|
|
2071
|
+
this.emit(` as ${_name(ast.catchId)} :\n`);
|
|
2072
|
+
}
|
|
2073
|
+
this.visitStmts(catchBlock.catchStmts, level + 2);
|
|
2074
|
+
});
|
|
2075
|
+
} else if (ast.catchBlock && ast.catchBlock.stmts.length > 0) {
|
|
2076
|
+
this.emit(`except Exception as ${_name(ast.catchId)} :\n`, level);
|
|
2077
|
+
this.visitStmts(ast.catchBlock, level + 2);
|
|
2078
|
+
}
|
|
2079
|
+
if (ast.finallyBlock && ast.finallyBlock.stmts.length > 0) {
|
|
2080
|
+
this.emit('finally:\n', level);
|
|
2081
|
+
this.visitStmts(ast.finallyBlock, level + 2);
|
|
2082
|
+
}
|
|
2083
|
+
this.emit('\n', level);
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
visitWhile(ast, level) {
|
|
2087
|
+
assert.equal(ast.type, 'while');
|
|
2088
|
+
this.emit('while ', level);
|
|
2089
|
+
this.visitExpr(ast.condition);
|
|
2090
|
+
this.emit(':\n');
|
|
2091
|
+
this.visitStmts(ast.stmts, level + 2);
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
visitFor(ast, level) {
|
|
2095
|
+
assert.equal(ast.type, 'for');
|
|
2096
|
+
// this.emit('\n');
|
|
2097
|
+
if (ast.list.inferred.type === 'asyncIterator' && this.isAsyncFunction) {
|
|
2098
|
+
this.emit('async for ', level);
|
|
2099
|
+
} else {
|
|
2100
|
+
this.emit('for ', level);
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
if (ast.list.inferred && ast.list.inferred.itemType
|
|
2104
|
+
&& ast.list.inferred.itemType.type === 'entry'){
|
|
2105
|
+
this.emit('k, v in ');
|
|
2106
|
+
this.visitExpr(ast.list, level);
|
|
2107
|
+
} else {
|
|
2108
|
+
this.emit(`${_snakeCase(_name(ast.id))} in `);
|
|
2109
|
+
this.visitExpr(ast.list, level);
|
|
2110
|
+
}
|
|
2111
|
+
this.emit(':\n');
|
|
2112
|
+
this.visitStmts(ast.stmts, level + 2);
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
visitIf(ast, level) {
|
|
2116
|
+
assert.equal(ast.type, 'if');
|
|
2117
|
+
this.emit('if ', level);
|
|
2118
|
+
this.visitExpr(ast.condition);
|
|
2119
|
+
this.emit(':\n');
|
|
2120
|
+
this.visitStmts(ast.stmts, level + 2);
|
|
2121
|
+
|
|
2122
|
+
if (ast.elseIfs) {
|
|
2123
|
+
for (let i = 0; i < ast.elseIfs.length; i++) {
|
|
2124
|
+
const branch = ast.elseIfs[i];
|
|
2125
|
+
this.emit('elif ',level);
|
|
2126
|
+
this.visitExpr(branch.condition);
|
|
2127
|
+
this.emit(':\n');
|
|
2128
|
+
this.visitStmts(branch.stmts, level + 2);
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
if (ast.elseStmts) {
|
|
2133
|
+
this.emit('else:\n', level);
|
|
2134
|
+
for (let i = 0; i < ast.elseStmts.stmts.length; i++) {
|
|
2135
|
+
this.visitStmt(ast.elseStmts.stmts[i], level + 2);
|
|
2136
|
+
}
|
|
2137
|
+
if (ast.elseStmts.stmts.length === 0) {
|
|
2138
|
+
const comments = DSL.comment.getBetweenComments(this.comments, ast.elseStmts.tokenRange[0], ast.elseStmts.tokenRange[1]);
|
|
2139
|
+
this.visitComments(comments, level + 1);
|
|
2140
|
+
this.emit('pass', level + 2);
|
|
2141
|
+
}
|
|
2142
|
+
this.emit('\n');
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
visitThrow(ast, level) {
|
|
2147
|
+
this.emit('raise ', level);
|
|
2148
|
+
if (ast.expr.type === 'construct_model') {
|
|
2149
|
+
this.visitConstructModel(ast.expr, level);
|
|
2150
|
+
this.emit('\n');
|
|
2151
|
+
} else {
|
|
2152
|
+
this.pushImports(`${CORE}Exception`);
|
|
2153
|
+
this.emit(`${CORE}Exception(`);
|
|
2154
|
+
this.visitObject(ast.expr, level);
|
|
2155
|
+
this.emit(')\n');
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
visitAssign(ast, level) {
|
|
2160
|
+
if (ast.left.type === 'property_assign' || ast.left.type === 'property') {
|
|
2161
|
+
this.emit('', level);
|
|
2162
|
+
this.visitPropertyAccess(ast.left, { left: true });
|
|
2163
|
+
} else if (ast.left.type === 'virtualVariable') { // vid
|
|
2164
|
+
this.emit(`self.${_snakeCase(_vid((ast.left.vid)))}`, level);
|
|
2165
|
+
} else if (ast.left.type === 'variable') {
|
|
2166
|
+
this.emit(`${_snakeCase(_name(ast.left.id))}`, level);
|
|
2167
|
+
} else if (ast.left.type === 'map_access') {
|
|
2168
|
+
// 声明时不能用get去赋值
|
|
2169
|
+
this.emit('', level);
|
|
2170
|
+
this.visitMapAccess(ast.left, level, { left: true });
|
|
2171
|
+
} else if (ast.left.type === 'array_access') {
|
|
2172
|
+
this.emit('', level);
|
|
2173
|
+
this.visitArrayAccess(ast.left, level);
|
|
2174
|
+
} else {
|
|
2175
|
+
throw new Error('unimpelemented');
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
this.emit(' = ');
|
|
2179
|
+
// if (ast.expr.needToReadable) {
|
|
2180
|
+
// this.emit(`${CORE}Core.to_readable_stream(`);
|
|
2181
|
+
// }
|
|
2182
|
+
this.visitExpr(ast.expr, level);
|
|
2183
|
+
// if (ast.expr.needToReadable) {
|
|
2184
|
+
// this.emit(')');
|
|
2185
|
+
// }
|
|
2186
|
+
this.emit('\n');
|
|
2187
|
+
}
|
|
2188
|
+
|
|
2189
|
+
// 实例初始化 new的地方
|
|
2190
|
+
visitDeclare(ast, level) {
|
|
2191
|
+
var id = _snakeCase(_name(ast.id));
|
|
2192
|
+
this.emit(`${id}`, level);
|
|
2193
|
+
if(id === 'new_full_str'){
|
|
2194
|
+
this.emit('');
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
if (ast.expr.type === 'null') {
|
|
2198
|
+
this.emit(' = None\n');
|
|
2199
|
+
return;
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
this.emit(' = ');
|
|
2203
|
+
this.visitExpr(ast.expr, level);
|
|
2204
|
+
this.emit('\n');
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
visitStmts(ast, level) {
|
|
2208
|
+
assert.equal(ast.type, 'stmts');
|
|
2209
|
+
let node;
|
|
2210
|
+
for (var i = 0; i < ast.stmts.length; i++) {
|
|
2211
|
+
node = ast.stmts[i];
|
|
2212
|
+
this.visitStmt(node, level);
|
|
2213
|
+
}
|
|
2214
|
+
if (node) {
|
|
2215
|
+
//find the last node's back comment
|
|
2216
|
+
let comments = DSL.comment.getBackComments(this.comments, node.tokenRange[1]);
|
|
2217
|
+
this.visitComments(comments, level);
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
if (ast.stmts.length === 0) {
|
|
2221
|
+
//empty block's comment
|
|
2222
|
+
let comments = DSL.comment.getBetweenComments(this.comments, ast.tokenRange[0], ast.tokenRange[1]);
|
|
2223
|
+
this.visitComments(comments, level);
|
|
2224
|
+
this.emit('pass\n',level);
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
visitReturnBody(ast, level) {
|
|
2229
|
+
assert.equal(ast.type, 'returnBody');
|
|
2230
|
+
this.visitStmts(ast.stmts, level);
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
visitDefaultReturnBody(level) {
|
|
2234
|
+
this.emit('\n');
|
|
2235
|
+
this.emit('return {}\n', level);
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
visitFunctionBody(ast, level) {
|
|
2239
|
+
assert.equal(ast.type, 'functionBody');
|
|
2240
|
+
this.visitStmts(ast.stmts, level);
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
isIterator(returnType) {
|
|
2244
|
+
if (returnType.type === 'iterator' || returnType.type === 'asyncIterator') {
|
|
2245
|
+
return true;
|
|
2246
|
+
}
|
|
2247
|
+
return false;
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
eachFunction(ast, level) {
|
|
2251
|
+
this.emit('\n');
|
|
2252
|
+
// level += 1;
|
|
2253
|
+
// TODO: 注释部分,暂时移除
|
|
2254
|
+
// this.visitAnnotation(ast.annotation, level);
|
|
2255
|
+
// let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
|
|
2256
|
+
// this.visitComments(comments, level);
|
|
2257
|
+
const functionName = _snakeCase(_name(ast.functionName));
|
|
2258
|
+
|
|
2259
|
+
if (ast.isStatic) {
|
|
2260
|
+
this.emit('@staticmethod\n', level);
|
|
2261
|
+
} else {
|
|
2262
|
+
this.isStaticFunction = false;
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2265
|
+
this.emit('', level);
|
|
2266
|
+
|
|
2267
|
+
this.emit('def ');
|
|
2268
|
+
|
|
2269
|
+
this.emit(`${functionName}`);
|
|
2270
|
+
|
|
2271
|
+
// 入参
|
|
2272
|
+
if (ast.isStatic) {
|
|
2273
|
+
this.visitParams(ast.params, level);
|
|
2274
|
+
} else {
|
|
2275
|
+
this.visitParams(ast.params, level, true);
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
// 返回值类型
|
|
2279
|
+
this.visitReturnType(ast);
|
|
2280
|
+
this.emit(':\n');
|
|
2281
|
+
let secondLevel = level + 2;
|
|
2282
|
+
if (ast.functionBody) {
|
|
2283
|
+
// 这里是函数体
|
|
2284
|
+
this.visitFunctionBody(ast.functionBody, secondLevel);
|
|
2285
|
+
} else {
|
|
2286
|
+
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
|
|
2287
|
+
this.visitComments(comments, secondLevel);
|
|
2288
|
+
this.emit('raise Exception(\'Un-implemented\')\n', secondLevel);
|
|
2289
|
+
}
|
|
2290
|
+
// generate async function
|
|
2291
|
+
if (ast.isAsync) {
|
|
2292
|
+
this.isAsyncFunction = true;
|
|
2293
|
+
this.emit('\n');
|
|
2294
|
+
if (ast.isStatic) {
|
|
2295
|
+
this.emit('@staticmethod\n', level);
|
|
2296
|
+
} else {
|
|
2297
|
+
this.isStaticFunction = false;
|
|
2298
|
+
}
|
|
2299
|
+
this.emit('', level);
|
|
2300
|
+
this.emit('async def ');
|
|
2301
|
+
this.emit(`${functionName}_async`);
|
|
2302
|
+
// 入参
|
|
2303
|
+
if (ast.isStatic) {
|
|
2304
|
+
this.visitParams(ast.params, level);
|
|
2305
|
+
} else {
|
|
2306
|
+
this.visitParams(ast.params, level, true);
|
|
2307
|
+
}
|
|
2308
|
+
// 返回值类型
|
|
2309
|
+
this.visitReturnType(ast);
|
|
2310
|
+
this.emit(':\n');
|
|
2311
|
+
if (ast.functionBody) {
|
|
2312
|
+
// 这里是函数体
|
|
2313
|
+
this.visitFunctionBody(ast.functionBody, secondLevel);
|
|
2314
|
+
} else {
|
|
2315
|
+
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
|
|
2316
|
+
this.visitComments(comments, level+2);
|
|
2317
|
+
this.emit('raise Exception(\'Un-implemented\')\n', level + 2);
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
this.isAsyncFunction = false;
|
|
2321
|
+
this.isStaticFunction = true;
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
eachAPI(ast, level) {
|
|
2325
|
+
this.emit('\n');
|
|
2326
|
+
// if (ast.annotation) {
|
|
2327
|
+
// this.emit(`${_anno(ast.annotation.value)}\n`, level);
|
|
2328
|
+
// }
|
|
2329
|
+
|
|
2330
|
+
this.visitAnnotation(ast.annotation, level);
|
|
2331
|
+
let comments = DSL.comment.getFrontComments(this.comments, ast.tokenRange[0]);
|
|
2332
|
+
this.visitComments(comments, level);
|
|
2333
|
+
// set api name to _snakeCase
|
|
2334
|
+
const apiName = _snakeCase(_name(ast.apiName));
|
|
2335
|
+
this.isStaticFunction = false;
|
|
2336
|
+
this.emit(`def ${apiName}`, level);
|
|
2337
|
+
this.visitParams(ast.params, level, true);
|
|
2338
|
+
this.visitReturnType(ast);
|
|
2339
|
+
this.emit(':\n');
|
|
2340
|
+
let secondLevel = level + 2;
|
|
2341
|
+
this.pushImports(`${CORE}Core`);
|
|
2342
|
+
if (ast.runtimeBody) {
|
|
2343
|
+
this.pushImports('UnretryableException');
|
|
2344
|
+
this.pushImports('RetryPolicyContext');
|
|
2345
|
+
this.visitRuntimeBefore(ast.runtimeBody, level);
|
|
2346
|
+
secondLevel += 4;
|
|
2347
|
+
}
|
|
2348
|
+
if (ast.apiBody) {
|
|
2349
|
+
this.visitAPIBody(ast.apiBody, secondLevel);
|
|
2350
|
+
}
|
|
2351
|
+
this.emit(`_last_request = ${REQUEST}\n`, secondLevel);
|
|
2352
|
+
this.emit(`${RESPONSE} = ${CORE}Core.do_action(${REQUEST}`, secondLevel);
|
|
2353
|
+
if (ast.runtimeBody) {
|
|
2354
|
+
this.emit(', _runtime');
|
|
2355
|
+
}
|
|
2356
|
+
this.emit(')\n');
|
|
2357
|
+
if (ast.runtimeBody) {
|
|
2358
|
+
this.emit(`_last_response = ${RESPONSE}\n`, secondLevel);
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
|
|
2362
|
+
if (ast.returns) {
|
|
2363
|
+
this.visitReturnBody(ast.returns, secondLevel);
|
|
2364
|
+
} else {
|
|
2365
|
+
this.visitDefaultReturnBody(secondLevel);
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
if (ast.runtimeBody) {
|
|
2369
|
+
this.visitRuntimeAfter(ast.runtimeBody, level + 1);
|
|
2370
|
+
}
|
|
2371
|
+
// generate async function
|
|
2372
|
+
this.emit('\n');
|
|
2373
|
+
this.isAsyncFunction = true;
|
|
2374
|
+
this.emit(`async def ${apiName}_async`, level);
|
|
2375
|
+
this.visitParams(ast.params, level, true);
|
|
2376
|
+
this.visitReturnType(ast);
|
|
2377
|
+
this.emit(':\n');
|
|
2378
|
+
// api level
|
|
2379
|
+
if (ast.runtimeBody) {
|
|
2380
|
+
this.visitRuntimeBefore(ast.runtimeBody, level);
|
|
2381
|
+
}
|
|
2382
|
+
// temp level
|
|
2383
|
+
this.visitAPIBody(ast.apiBody, secondLevel);
|
|
2384
|
+
this.emit(`_last_request = ${REQUEST}\n`, secondLevel);
|
|
2385
|
+
this.emit(`${RESPONSE} = await ${CORE}Core.async_do_action(${REQUEST}`, secondLevel);
|
|
2386
|
+
if (ast.runtimeBody) {
|
|
2387
|
+
this.emit(', _runtime');
|
|
2388
|
+
}
|
|
2389
|
+
this.emit(')\n');
|
|
2390
|
+
if (ast.runtimeBody) {
|
|
2391
|
+
this.emit(`_last_response = ${RESPONSE}\n`, secondLevel);
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
if (ast.returns) {
|
|
2395
|
+
this.visitReturnBody(ast.returns, secondLevel);
|
|
2396
|
+
} else {
|
|
2397
|
+
this.visitDefaultReturnBody(secondLevel);
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
if (ast.runtimeBody) {
|
|
2401
|
+
this.visitRuntimeAfter(ast.runtimeBody, level + 1);
|
|
2402
|
+
}
|
|
2403
|
+
this.isStaticFunction = true;
|
|
2404
|
+
this.isAsyncFunction = false;
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
visitRuntimeAfter(ast, level) {
|
|
2408
|
+
this.emit(` except Exception as e:
|
|
2409
|
+
_context = RetryPolicyContext(
|
|
2410
|
+
retries_attempted= _retries_attempted,
|
|
2411
|
+
http_request = _last_request,
|
|
2412
|
+
http_response = _last_response,
|
|
2413
|
+
exception = e
|
|
2414
|
+
)
|
|
2415
|
+
continue
|
|
2416
|
+
raise UnretryableException(_context)\n`);
|
|
2417
|
+
}
|
|
2418
|
+
|
|
2419
|
+
emitImports() {
|
|
2420
|
+
let tempOutput = ''; // 定义一个临时变量来存放输出内容
|
|
2421
|
+
|
|
2422
|
+
if (this.config.editable !== true) {
|
|
2423
|
+
tempOutput += '# -*- coding: utf-8 -*-\n';
|
|
2424
|
+
tempOutput += '# This file is auto-generated, don\'t edit it. Thanks.\n';
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
tempOutput += 'from __future__ import annotations\n';
|
|
2428
|
+
|
|
2429
|
+
const imports = [];
|
|
2430
|
+
this.imports.forEach(ele => {
|
|
2431
|
+
let header = '';
|
|
2432
|
+
if(ele.packageName) {
|
|
2433
|
+
header += `from ${ele.packageName} `;
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
if(ele.className) {
|
|
2437
|
+
header += `import ${ele.className} `;
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2440
|
+
if(ele.aliasName) {
|
|
2441
|
+
header += `as ${ele.aliasName} `;
|
|
2442
|
+
}
|
|
2443
|
+
imports.push(header);
|
|
2444
|
+
});
|
|
2445
|
+
|
|
2446
|
+
tempOutput += [...new Set(imports)].join('\n') + '\n';
|
|
2447
|
+
|
|
2448
|
+
if (this.usedTypes.length > 0) {
|
|
2449
|
+
tempOutput += 'from typing import '
|
|
2450
|
+
+ [...new Set(this.usedTypes)].join(', ');
|
|
2451
|
+
tempOutput += '\n';
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2454
|
+
|
|
2455
|
+
// 将临时输出插入到 this.output 的开头
|
|
2456
|
+
this.output = tempOutput + '\n\n' + this.output;
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
modelBefore(ast, level) {
|
|
2460
|
+
let beginToken = 0;
|
|
2461
|
+
if(ast.imports.length > 0) {
|
|
2462
|
+
const lastIndex = ast.imports.length - 1;
|
|
2463
|
+
beginToken = ast.imports[lastIndex].tokenRange[0];
|
|
2464
|
+
}
|
|
2465
|
+
let endToken = 0;
|
|
2466
|
+
if(ast.moduleBody.nodes.length > 0) {
|
|
2467
|
+
endToken = ast.moduleBody.nodes[0].tokenRange[0];
|
|
2468
|
+
}
|
|
2469
|
+
const beginNotes = DSL.note.getNotes(this.notes, beginToken, endToken);
|
|
2470
|
+
const part = beginNotes.find(note => note.note.lexeme === '@pythonModel');
|
|
2471
|
+
if(part && part.arg.value) {
|
|
2472
|
+
this.emit(_string(part.arg.value));
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
moduleBefore(ast, level) {
|
|
2477
|
+
let beginToken = 0;
|
|
2478
|
+
if(ast.imports.length > 0) {
|
|
2479
|
+
const lastIndex = ast.imports.length - 1;
|
|
2480
|
+
beginToken = ast.imports[lastIndex].tokenRange[0];
|
|
2481
|
+
}
|
|
2482
|
+
let endToken = 0;
|
|
2483
|
+
if(ast.moduleBody.nodes.length > 0) {
|
|
2484
|
+
endToken = ast.moduleBody.nodes[0].tokenRange[0];
|
|
2485
|
+
}
|
|
2486
|
+
const beginNotes = DSL.note.getNotes(this.notes, beginToken, endToken);
|
|
2487
|
+
const part = beginNotes.find(note => note.note.lexeme === '@python');
|
|
2488
|
+
if(part && part.arg.value) {
|
|
2489
|
+
this.emit(_string(part.arg.value));
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2493
|
+
apiBefore(level) {
|
|
2494
|
+
|
|
2495
|
+
this.emit(`class ${this.className}`, level);
|
|
2496
|
+
if (this.parentModule) {
|
|
2497
|
+
const aliasId = _name(this.parentModule);
|
|
2498
|
+
let clientName = this.getModelName('', aliasId, 'module');
|
|
2499
|
+
this.emit(`(${clientName})`);
|
|
2500
|
+
}
|
|
2501
|
+
this.emit(':');
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
checkFieldHasModel(fieldValue) {
|
|
2505
|
+
if (fieldValue.type === 'modelBody') {
|
|
2506
|
+
return true;
|
|
2507
|
+
} else if (fieldValue.type === 'array' || fieldValue.fieldType === 'array') {
|
|
2508
|
+
return this.checkFieldHasModel(fieldValue.fieldItemType || fieldValue.subType);
|
|
2509
|
+
} else if (fieldValue.fieldType === 'map' || fieldValue.type === 'map') {
|
|
2510
|
+
return this.checkFieldHasModel(fieldValue.valueType);
|
|
2511
|
+
} else if (fieldValue.type === 'moduleModel' ||
|
|
2512
|
+
(fieldValue.fieldType && fieldValue.fieldType.type === 'moduleModel')) {
|
|
2513
|
+
return true;
|
|
2514
|
+
} else if (fieldValue.type === 'subModel') {
|
|
2515
|
+
return true;
|
|
2516
|
+
} else if (fieldValue.idType === 'model') {
|
|
2517
|
+
return true;
|
|
2518
|
+
} else if (fieldValue.fieldType && fieldValue.fieldType.idType === 'model') {
|
|
2519
|
+
return true;
|
|
2520
|
+
} else if (fieldValue.fieldType && fieldValue.fieldType.idType === 'builtin_model') {
|
|
2521
|
+
return true;
|
|
2522
|
+
}
|
|
2523
|
+
return false;
|
|
2524
|
+
}
|
|
2525
|
+
|
|
2526
|
+
checkFieldItemTypeAllString(obj) {
|
|
2527
|
+
// 基本检查,确保传入的是对象且存在 fieldItemType 属性
|
|
2528
|
+
if (obj && obj.fieldItemType) {
|
|
2529
|
+
// 如果 fieldItemType 是字符串且等于 'string'
|
|
2530
|
+
if (obj.fieldItemType.lexeme === 'string') {
|
|
2531
|
+
return true;
|
|
2532
|
+
} else if (obj.fieldItemType.fieldType === 'array') {
|
|
2533
|
+
// 如果 fieldItemType 仍然是数组
|
|
2534
|
+
return this.checkFieldItemTypeAllString(obj.fieldItemType);
|
|
2535
|
+
} else if (obj.fieldItemType.valueType && obj.fieldItemType.valueType.lexeme === 'any'){
|
|
2536
|
+
return true;
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
if (obj && obj.fieldType ==='map'){
|
|
2540
|
+
return this.checkFieldItemTypeAllString(obj.valueType);
|
|
2541
|
+
}
|
|
2542
|
+
if (obj && obj.subType){
|
|
2543
|
+
if (obj.subType.type === 'map'){
|
|
2544
|
+
return this.checkFieldItemTypeAllString(obj.subType);
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
if (obj && obj.valueType) {
|
|
2548
|
+
if (obj.valueType.lexeme === 'string') {
|
|
2549
|
+
return true;
|
|
2550
|
+
}
|
|
2551
|
+
}
|
|
2552
|
+
return false;
|
|
2553
|
+
}
|
|
2554
|
+
|
|
2555
|
+
getClassNamespace(pyPath) {
|
|
2556
|
+
if(path.resolve(pyPath).startsWith(path.resolve(this.outputDir))) {
|
|
2557
|
+
const baseDir = path.join(this.outputDir, path.sep, this.config.package);
|
|
2558
|
+
pyPath = pyPath.replace(baseDir, '');
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
const arr = pyPath.replace('.py', '').split(path.sep).slice(0, -1);
|
|
2562
|
+
|
|
2563
|
+
|
|
2564
|
+
let className = this.config.package;
|
|
2565
|
+
arr.map(key => {
|
|
2566
|
+
if(!key) {
|
|
2567
|
+
return;
|
|
2568
|
+
}
|
|
2569
|
+
className += '.' + key;
|
|
2570
|
+
});
|
|
2571
|
+
|
|
2572
|
+
return className;
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
getAliasName(name, aliasId) {
|
|
2576
|
+
let aliasName = '';
|
|
2577
|
+
if (!this.clientName.has(name) && name !== this.className) {
|
|
2578
|
+
this.clientName.set(name, aliasId);
|
|
2579
|
+
return aliasName;
|
|
2580
|
+
}
|
|
2581
|
+
if (aliasId) {
|
|
2582
|
+
aliasName = aliasId + name;
|
|
2583
|
+
}
|
|
2584
|
+
if (aliasName && !this.clientName.has(aliasName)) {
|
|
2585
|
+
this.clientName.set(aliasName, aliasId);
|
|
2586
|
+
return aliasName.replace(/-/g, '');
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
getRealName(node) {
|
|
2591
|
+
const nameAttr = node.attrs.find((item) => {
|
|
2592
|
+
return item.attrName.lexeme === 'name';
|
|
2593
|
+
});
|
|
2594
|
+
return nameAttr ?_string(nameAttr.attrValue) : _name(node.fieldName);
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
getModelName(name, moduleName, type = 'model'){
|
|
2598
|
+
if(type === 'model' && !moduleName) {
|
|
2599
|
+
const aliasName = 'main_models';
|
|
2600
|
+
this.imports.push({
|
|
2601
|
+
aliasName,
|
|
2602
|
+
packageName: this.config.package,
|
|
2603
|
+
className: 'models',
|
|
2604
|
+
});
|
|
2605
|
+
return `${aliasName}.${name}`;
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
if(type === 'model' && moduleName) {
|
|
2609
|
+
const { namemespace, models } = this.packageInfo[moduleName];
|
|
2610
|
+
const aliasName = `${_snakeCase(moduleName.replace(/-/g, ''))}_models`;
|
|
2611
|
+
this.imports.push({
|
|
2612
|
+
aliasName,
|
|
2613
|
+
packageName: namemespace,
|
|
2614
|
+
className: models || 'models',
|
|
2615
|
+
});
|
|
2616
|
+
return `${aliasName}.${name}`;
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
if(type === 'exception' && !moduleName) {
|
|
2620
|
+
const aliasName = 'main_exceptions';
|
|
2621
|
+
this.imports.push({
|
|
2622
|
+
aliasName,
|
|
2623
|
+
packageName: this.config.package,
|
|
2624
|
+
className: 'exceptions',
|
|
2625
|
+
});
|
|
2626
|
+
return `${aliasName}.${name}Exception`;
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2629
|
+
if(type === 'exception' && moduleName) {
|
|
2630
|
+
const { namemespace, exceptions } = this.packageInfo[moduleName];
|
|
2631
|
+
const aliasName = `${_snakeCase(moduleName.replace(/-/g, ''))}_exceptions`;
|
|
2632
|
+
this.imports.push({
|
|
2633
|
+
aliasName,
|
|
2634
|
+
packageName: namemespace,
|
|
2635
|
+
className: exceptions || 'exceptions',
|
|
2636
|
+
});
|
|
2637
|
+
return `${aliasName}.${name}Exception`;
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
if(type === 'module') {
|
|
2641
|
+
const {
|
|
2642
|
+
aliasName,
|
|
2643
|
+
clientName,
|
|
2644
|
+
fileName,
|
|
2645
|
+
namemespace,
|
|
2646
|
+
} = this.packageInfo[moduleName];
|
|
2647
|
+
|
|
2648
|
+
this.imports.push({
|
|
2649
|
+
aliasName: clientName === aliasName ? '' : aliasName,
|
|
2650
|
+
packageName: `${namemespace}.${fileName}`,
|
|
2651
|
+
className: clientName,
|
|
2652
|
+
});
|
|
2653
|
+
return aliasName;
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
name = _type(name);
|
|
2657
|
+
this.pushImports(name);
|
|
2658
|
+
return name;
|
|
2659
|
+
}
|
|
2660
|
+
|
|
2661
|
+
getInnerClient(aliasId) {
|
|
2662
|
+
const moduleAst = this.ast.innerDep.get(aliasId);
|
|
2663
|
+
const beginNotes = DSL.note.getNotes(moduleAst.notes, 0, moduleAst.moduleBody.nodes[0].tokenRange[0]);
|
|
2664
|
+
const clientNote = beginNotes.find(note => note.note.lexeme === '@clientName');
|
|
2665
|
+
if(clientNote) {
|
|
2666
|
+
return _string(clientNote.arg.value);
|
|
2667
|
+
}
|
|
2668
|
+
return 'Client';
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
pushImports(type) {
|
|
2672
|
+
const pkg = _getImport(type);
|
|
2673
|
+
if(pkg) {
|
|
2674
|
+
this.imports.push(pkg);
|
|
2675
|
+
return;
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2678
|
+
if(type === 'sys') {
|
|
2679
|
+
this.imports.push({
|
|
2680
|
+
className: 'sys',
|
|
2681
|
+
});
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
if(type === 'Any' ) {
|
|
2685
|
+
this.usedTypes.push('Any');
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2688
|
+
if(type === 'array') {
|
|
2689
|
+
this.usedTypes.push('List');
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
if(type === 'map') {
|
|
2693
|
+
this.usedTypes.push('Dict');
|
|
2694
|
+
}
|
|
2695
|
+
|
|
2696
|
+
if(type === 'BinaryIO') {
|
|
2697
|
+
this.usedTypes.push('BinaryIO');
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
module.exports = Visitor;
|