nadesiko3 3.7.21 → 3.7.22
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/batch/command.txt +370 -334
- package/batch/jsplugin2text.nako3 +1 -1
- package/batch/pickup_command.nako3 +12 -0
- package/core/command/snako.mts +5 -1
- package/core/deno/snako.ts +5 -1
- package/core/package-lock.json +382 -21
- package/core/package.json +4 -4
- package/core/src/nako3.mts +178 -614
- package/core/src/nako_basic_plugins.mts +39 -0
- package/core/src/nako_core_version.mts +2 -2
- package/core/src/nako_csv.mts +0 -1
- package/core/src/nako_event.mts +49 -0
- package/core/src/nako_gen.mts +291 -202
- package/core/src/nako_indent_inline.mts +2 -2
- package/core/src/nako_lex_rules.mts +1 -1
- package/core/src/nako_parser3.mts +106 -165
- package/core/src/nako_parser_async.mts +97 -0
- package/core/src/nako_parser_base.mts +4 -55
- package/core/src/nako_parser_message.mts +105 -0
- package/core/src/nako_parser_operator.mts +93 -0
- package/core/src/nako_plugin_manager.mts +260 -0
- package/core/src/nako_require.mts +292 -0
- package/core/src/nako_runner.mts +191 -0
- package/core/src/nako_tokenizer.mts +221 -0
- package/core/src/plugin_csv.mts +1 -1
- package/core/src/plugin_system.mts +34 -3259
- package/core/src/plugin_system_array.mts +699 -0
- package/core/src/plugin_system_datetime.mts +368 -0
- package/core/src/plugin_system_debug.mts +403 -0
- package/core/src/plugin_system_dict.mts +85 -0
- package/core/src/plugin_system_json.mts +73 -0
- package/core/src/plugin_system_math.mts +383 -0
- package/core/src/plugin_system_regexp.mts +120 -0
- package/core/src/plugin_system_stdio.mts +86 -0
- package/core/src/plugin_system_string.mts +666 -0
- package/core/src/plugin_system_timer.mts +152 -0
- package/core/src/plugin_system_types.mts +151 -0
- package/core/src/plugin_system_url.mts +193 -0
- package/core/src/plugin_toml.mts +3 -3
- package/core/test/fixtures/README.md +39 -0
- package/core/test/fixtures/make_parser_ast_golden.mjs +31 -0
- package/core/test/fixtures/parser_ast_golden.json +8027 -0
- package/core/test/fixtures/parser_corpus.mjs +120 -0
- package/core/test/indent_test.mjs +6 -0
- package/core/test/nako_basic_plugins_test.mjs +44 -0
- package/core/test/nako_event_test.mjs +85 -0
- package/core/test/nako_gen_perf_test.mjs +178 -0
- package/core/test/nako_parser_async_test.mjs +112 -0
- package/core/test/nako_parser_test.mjs +160 -0
- package/core/test/nako_plugin_manager_test.mjs +185 -0
- package/core/test/nako_require_test.mjs +153 -0
- package/core/test/nako_runner_test.mjs +114 -0
- package/core/test/nako_tokenizer_test.mjs +115 -0
- package/core/test/plugin_system_debug_test.mjs +141 -0
- package/core/test/plugin_system_split_test.mjs +179 -0
- package/core/test/plugin_system_test.mjs +6 -0
- package/core/tsconfig.json +0 -1
- package/package.json +17 -21
- package/release/_hash.txt +36 -36
- package/release/_script-tags.txt +16 -16
- package/release/command.json +1 -1
- package/release/command.json.js +1 -1
- package/release/command_cnako3.json +1 -1
- package/release/command_list.json +1 -1
- package/release/edit_main.js +6 -6
- package/release/edit_main.js.map +3 -3
- package/release/editor.js +6 -6
- package/release/plugin_keigo.js.map +3 -3
- package/release/plugin_markup.js +46 -46
- package/release/plugin_markup.js.map +3 -3
- package/release/plugin_weykturtle3d.js +1 -1
- package/release/plugin_weykturtle3d.js.map +3 -3
- package/release/version.js +2 -2
- package/release/version_main.js +2 -2
- package/release/version_main.js.map +1 -1
- package/release/wnako3.js +186 -213
- package/release/wnako3.js.map +4 -4
- package/release/wnako3webworker.js +172 -199
- package/release/wnako3webworker.js.map +4 -4
- package/src/cnako3mod.mjs +7 -2
- package/src/cnako3mod.mts +7 -2
- package/src/nako_version.mjs +2 -2
- package/src/nako_version.mts +2 -2
- package/src/plugin_browser_ajax.mjs +4 -4
- package/src/plugin_browser_ajax.mts +4 -4
- package/src/plugin_browser_audio.mjs +10 -10
- package/src/plugin_browser_audio.mts +10 -10
- package/src/plugin_browser_camera.mjs +4 -4
- package/src/plugin_browser_camera.mts +4 -4
- package/src/plugin_browser_canvas.mjs +2 -2
- package/src/plugin_browser_canvas.mts +2 -2
- package/src/plugin_browser_crypto.mjs +3 -3
- package/src/plugin_browser_crypto.mts +3 -3
- package/src/plugin_browser_dom_event.mjs +1 -1
- package/src/plugin_browser_dom_event.mts +1 -1
- package/src/plugin_browser_geolocation.mjs +1 -1
- package/src/plugin_browser_geolocation.mts +1 -1
- package/src/plugin_browser_hotkey.mjs +1 -1
- package/src/plugin_browser_hotkey.mts +1 -1
- package/src/plugin_browser_html.mjs +1 -1
- package/src/plugin_browser_html.mts +1 -1
- package/src/plugin_browser_location.mjs +1 -1
- package/src/plugin_browser_location.mts +1 -1
- package/src/plugin_browser_speech.mjs +1 -1
- package/src/plugin_browser_speech.mts +1 -1
- package/src/plugin_browser_storage.mjs +2 -2
- package/src/plugin_browser_storage.mts +2 -2
- package/src/plugin_httpserver.mjs +3 -3
- package/src/plugin_httpserver.mts +3 -3
- package/src/plugin_keigo.mjs +2 -2
- package/src/plugin_keigo.mts +2 -2
- package/src/plugin_node.mjs +48 -48
- package/src/plugin_node.mts +53 -53
- package/src/plugin_weykturtle3d.mjs +56 -56
- package/src/plugin_weykturtle3d.mts +56 -56
- package/src/wnako3.mjs +1 -1
- package/src/wnako3.mts +1 -1
- package/src/wnako3_editor.mjs +5 -5
- package/src/wnako3_editor.mts +5 -5
- package/src/wnako3mod.mjs +2 -2
- package/src/wnako3mod.mts +2 -2
- package/core/src/nako3.mjs +0 -1021
- package/core/src/nako_ast.mjs +0 -4
- package/core/src/nako_colors.mjs +0 -77
- package/core/src/nako_core_version.mjs +0 -8
- package/core/src/nako_csv.mjs +0 -193
- package/core/src/nako_errors.mjs +0 -166
- package/core/src/nako_from_dncl.mjs +0 -285
- package/core/src/nako_from_dncl2.mjs +0 -347
- package/core/src/nako_gen.mjs +0 -2500
- package/core/src/nako_global.mjs +0 -138
- package/core/src/nako_indent.mjs +0 -442
- package/core/src/nako_indent_chars.mjs +0 -29
- package/core/src/nako_indent_inline.mjs +0 -361
- package/core/src/nako_josi_list.mjs +0 -47
- package/core/src/nako_lex_rules.mjs +0 -319
- package/core/src/nako_lexer.mjs +0 -794
- package/core/src/nako_logger.mjs +0 -221
- package/core/src/nako_parser3.mjs +0 -3250
- package/core/src/nako_parser_base.mjs +0 -403
- package/core/src/nako_parser_const.mjs +0 -37
- package/core/src/nako_prepare.mjs +0 -329
- package/core/src/nako_reserved_words.mjs +0 -42
- package/core/src/nako_source_mapping.mjs +0 -207
- package/core/src/nako_test.mjs +0 -37
- package/core/src/nako_token.mjs +0 -1
- package/core/src/nako_tools.mjs +0 -53
- package/core/src/nako_types.mjs +0 -14
- package/core/src/plugin_api.mjs +0 -4
- package/core/src/plugin_csv.mjs +0 -97
- package/core/src/plugin_math.mjs +0 -352
- package/core/src/plugin_promise.mjs +0 -102
- package/core/src/plugin_system.mjs +0 -3810
- package/core/src/plugin_test.mjs +0 -52
- package/core/src/plugin_toml.mjs +0 -39
package/core/src/nako_gen.mjs
DELETED
|
@@ -1,2500 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* パーサーが生成した中間オブジェクトを実際のJavaScriptのコードに変換する。
|
|
3
|
-
* なお速度優先で忠実にJavaScriptのコードを生成する。
|
|
4
|
-
*/
|
|
5
|
-
import { NakoSyntaxError } from './nako_errors.mjs';
|
|
6
|
-
// なでしこで定義した関数の開始コードと終了コード
|
|
7
|
-
const topOfFunction = '(function(){\n';
|
|
8
|
-
const endOfFunction = '})';
|
|
9
|
-
const topOfFunctionAsync = '(async function(){\n';
|
|
10
|
-
/** コード生成オプション */
|
|
11
|
-
export class NakoGenOptions {
|
|
12
|
-
constructor(isTest = false, importFiles = [], codeStandalone = '', convEnv = '') {
|
|
13
|
-
this.isTest = isTest;
|
|
14
|
-
this.codeStandalone = codeStandalone;
|
|
15
|
-
this.codeEnv = convEnv;
|
|
16
|
-
this.importFiles = ['plugin_system.mjs', 'plugin_math.mjs', 'plugin_csv.mjs', 'plugin_promise.mjs', 'plugin_test.mjs'];
|
|
17
|
-
for (const fname of importFiles) {
|
|
18
|
-
this.importFiles.push(fname);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* 構文木からJSのコードを生成するクラス
|
|
24
|
-
*/
|
|
25
|
-
export class NakoGen {
|
|
26
|
-
/** constructor
|
|
27
|
-
* @param com コンパイラのインスタンス
|
|
28
|
-
*/
|
|
29
|
-
constructor(com) {
|
|
30
|
-
/**
|
|
31
|
-
* 出力するJavaScriptコードのヘッダー部分で定義する必要のある関数。fnはjsのコード。
|
|
32
|
-
* プラグイン関数は含まれない。
|
|
33
|
-
*/
|
|
34
|
-
this.nakoFuncList = new Map(com.getNakoFuncList());
|
|
35
|
-
/**
|
|
36
|
-
* なでしこで定義したテストの一覧
|
|
37
|
-
*/
|
|
38
|
-
this.nakoTestFuncs = new Map();
|
|
39
|
-
/**
|
|
40
|
-
* プログラム内で参照された関数のリスト。プラグインの命令を含む。
|
|
41
|
-
* JavaScript単体で実行するとき、このリストにある関数の定義をJavaScriptコードの先頭に付け足す。
|
|
42
|
-
*/
|
|
43
|
-
this.usedFuncSet = new Set();
|
|
44
|
-
/**
|
|
45
|
-
* ループ時の一時変数が被らないようにIDで管理
|
|
46
|
-
*/
|
|
47
|
-
this.loopId = 1;
|
|
48
|
-
/**
|
|
49
|
-
* 非同関数を何回使ったか
|
|
50
|
-
*/
|
|
51
|
-
this.numAsyncFn = 0;
|
|
52
|
-
/**
|
|
53
|
-
* 関数定義の際、関数の中でasyncFn=trueの関数を呼び出したかどうかを調べる @see convDefFuncCommon
|
|
54
|
-
*/
|
|
55
|
-
this.usedAsyncFn = false;
|
|
56
|
-
/** 変換中の処理が、ループの中かどうかを判定する */
|
|
57
|
-
this.flagLoop = false;
|
|
58
|
-
this.__self = com;
|
|
59
|
-
/** コードジェネレータの種類 */
|
|
60
|
-
this.genMode = 'sync';
|
|
61
|
-
/** 行番号とファイル名が分かるときは `l123:main.nako3`、行番号だけ分かるときは `l123`、そうでなければ任意の文字列。 */
|
|
62
|
-
this.lastLineNo = null;
|
|
63
|
-
/** スタック */
|
|
64
|
-
this.varslistSet = this.setVarslistSet(com.__varslist);
|
|
65
|
-
/** スタックトップ */
|
|
66
|
-
this.varsSet = { isFunction: false, names: new Set(), readonly: new Set() };
|
|
67
|
-
this.varslistSet[2] = this.varsSet;
|
|
68
|
-
this.functionContextStack = [];
|
|
69
|
-
// 現在定義中の関数名
|
|
70
|
-
this.defFuncName = '';
|
|
71
|
-
// 1以上のとき高速化する。
|
|
72
|
-
// 実行速度優先ブロック内で1増える。
|
|
73
|
-
this.speedMode = {
|
|
74
|
-
lineNumbers: 0, // 行番号を出力しない
|
|
75
|
-
implicitTypeCasting: 0, // 数値加算でparseFloatを出力しない
|
|
76
|
-
invalidSore: 0, // 「それ」を用いない
|
|
77
|
-
forcePure: 0 // 全てのシステム命令をpureとして扱う。命令からローカル変数への参照が出来なくなる。
|
|
78
|
-
};
|
|
79
|
-
// 1以上のとき測定をinjectする。
|
|
80
|
-
// パフォーマンスモニタのブロック内で1増える。
|
|
81
|
-
this.performanceMonitor = {
|
|
82
|
-
userFunction: 0, // 呼び出されたユーザ関数
|
|
83
|
-
systemFunction: 0, // システム関数(呼び出しコードを含む)
|
|
84
|
-
systemFunctionBody: 0, // システム関数(呼び出しコードを除く)
|
|
85
|
-
mumeiId: 0
|
|
86
|
-
};
|
|
87
|
-
/**
|
|
88
|
-
* 未定義の変数の警告を行う
|
|
89
|
-
*/
|
|
90
|
-
this.constPools = [];
|
|
91
|
-
this.constPoolsTemplate = [];
|
|
92
|
-
// undefinedの警告制御 (「厳しくチェック」でオンになる)
|
|
93
|
-
this.warnUndefinedVar = false;
|
|
94
|
-
this.warnUndefinedReturnUserFunc = false;
|
|
95
|
-
this.warnUndefinedCallingUserFunc = false;
|
|
96
|
-
this.warnUndefinedCallingSystemFunc = false;
|
|
97
|
-
this.warnUndefinedCalledUserFuncArgs = false;
|
|
98
|
-
this.debugOption = com.debugOption;
|
|
99
|
-
}
|
|
100
|
-
static isValidIdentifier(name) {
|
|
101
|
-
// TODO: いらなそうな部分は削る
|
|
102
|
-
// https://stackoverflow.com/a/9337047
|
|
103
|
-
// eslint-disable-next-line no-misleading-character-class
|
|
104
|
-
return /^(?!(?:do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)$)[$A-Z_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc][$A-Z_a-z\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc0-9\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19b0-\u19c0\u19c8\u19c9\u19d0-\u19d9\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1dc0-\u1de6\u1dfc-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f]*$/.test(name);
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* com.__varslistを元に、this.varslistSetを設定
|
|
108
|
-
*/
|
|
109
|
-
setVarslistSet(varslist) {
|
|
110
|
-
const vlist = [];
|
|
111
|
-
// 変数名の一覧をVarsSetに格納 (0: システム変数, 1: グローバル変数, 2: ローカル変数) 0と1のみ移す
|
|
112
|
-
for (let i = 0; i <= 1; i++) {
|
|
113
|
-
const scope = varslist[i];
|
|
114
|
-
const names = new Set(scope.keys());
|
|
115
|
-
names.delete('meta'); // remove 'meta' from names
|
|
116
|
-
vlist[i] = { isFunction: false, names, readonly: new Set() };
|
|
117
|
-
}
|
|
118
|
-
return vlist;
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* 改行を埋め込む
|
|
122
|
-
*/
|
|
123
|
-
convLineno(node, forceUpdate = false, incLine = 0) {
|
|
124
|
-
// スピードモードでは行番号を埋め込まない
|
|
125
|
-
if (this.speedMode.lineNumbers > 0) {
|
|
126
|
-
return '';
|
|
127
|
-
}
|
|
128
|
-
const lineNo = node.line + incLine;
|
|
129
|
-
let lineNoStr;
|
|
130
|
-
if (typeof node.line !== 'number') {
|
|
131
|
-
lineNoStr = 'unknown';
|
|
132
|
-
}
|
|
133
|
-
else if (typeof node.file !== 'string') {
|
|
134
|
-
lineNoStr = `l${lineNo}`;
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
lineNoStr = `l${lineNo}:${node.file}`;
|
|
138
|
-
}
|
|
139
|
-
// 強制的に行番号をアップデートするか
|
|
140
|
-
if (!forceUpdate) {
|
|
141
|
-
if (lineNoStr === this.lastLineNo) {
|
|
142
|
-
return '';
|
|
143
|
-
}
|
|
144
|
-
this.lastLineNo = lineNoStr;
|
|
145
|
-
}
|
|
146
|
-
// 実行行のデータ
|
|
147
|
-
const lineDataJSON = JSON.stringify(lineNoStr);
|
|
148
|
-
// デバッグ実行か
|
|
149
|
-
let debugCode = '';
|
|
150
|
-
if (this.debugOption.useDebug) {
|
|
151
|
-
// messageAction
|
|
152
|
-
if (this.debugOption.messageAction) {
|
|
153
|
-
debugCode += `window.postMessage({action:'${this.debugOption.messageAction}',` +
|
|
154
|
-
`line: ${lineDataJSON}});`;
|
|
155
|
-
}
|
|
156
|
-
// waitTime
|
|
157
|
-
if (lineNo >= 1) {
|
|
158
|
-
if (this.debugOption.waitTime > 0) {
|
|
159
|
-
debugCode += `await __v0.get('秒待')(${this.debugOption.waitTime},__self);`;
|
|
160
|
-
}
|
|
161
|
-
// breakpoints
|
|
162
|
-
this.numAsyncFn += 1;
|
|
163
|
-
this.usedAsyncFn = true;
|
|
164
|
-
debugCode += `await __v0.get('__DEBUG_BP_WAIT')(${lineNo}, __self);`;
|
|
165
|
-
}
|
|
166
|
-
// end
|
|
167
|
-
debugCode += 'if (__v0.get(\'__forceClose\')) { return -1 };';
|
|
168
|
-
}
|
|
169
|
-
// 例: __v0.set('__line', 'l1:main.nako3')
|
|
170
|
-
// return `__v0.set('__line', ${lineDataJSON});` + debugCode
|
|
171
|
-
return `__line(${lineDataJSON});` + debugCode;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* ローカル変数の取得用JavaScriptコードを生成する。
|
|
175
|
-
* @param {string} name
|
|
176
|
-
*/
|
|
177
|
-
varname_get(name) {
|
|
178
|
-
if (this.varslistSet.length === 3) {
|
|
179
|
-
// グローバル
|
|
180
|
-
return `__self.__varslist[${2}].get(${JSON.stringify(name)})`;
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
// ローカル
|
|
184
|
-
return `__self.__vars.get(${JSON.stringify(name)})`;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* ローカル変数の設定用JavaScriptコードを生成する。
|
|
189
|
-
* @param {string} name
|
|
190
|
-
* @param {string} jsvalue
|
|
191
|
-
*/
|
|
192
|
-
varname_set(name, jsvalue) {
|
|
193
|
-
if (this.varslistSet.length === 3) {
|
|
194
|
-
return `__self.__varslist[2].set(${JSON.stringify(name)}, (${jsvalue}))`;
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
return `__self.__vars.set(${JSON.stringify(name)}, (${jsvalue}))`;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* ローカル変数の設定用JavaScriptコードを生成する。
|
|
202
|
-
* @param {string} name
|
|
203
|
-
* @param {string} jsvalue
|
|
204
|
-
*/
|
|
205
|
-
varname_set_sys(name, jsvalue) {
|
|
206
|
-
return `__self.__setSysVar(${JSON.stringify(name)}, (${jsvalue}))`;
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* @param {string} name
|
|
210
|
-
* @returns {string}
|
|
211
|
-
*/
|
|
212
|
-
static getFuncName(name) {
|
|
213
|
-
if (name.indexOf('__') >= 0) { // スコープがある場合
|
|
214
|
-
const a = name.split('__');
|
|
215
|
-
const scope = a[0];
|
|
216
|
-
const name3 = NakoGen.getFuncName(a[1]);
|
|
217
|
-
return `${scope}__${name3}`;
|
|
218
|
-
}
|
|
219
|
-
let name2 = name.replace(/[ぁ-ん]+$/, '');
|
|
220
|
-
if (name2 === '') {
|
|
221
|
-
name2 = name;
|
|
222
|
-
}
|
|
223
|
-
return name2;
|
|
224
|
-
}
|
|
225
|
-
/** @param {Ast} node */
|
|
226
|
-
static convPrint(node) {
|
|
227
|
-
return `__print(${node});`;
|
|
228
|
-
}
|
|
229
|
-
/** @param {AstStrValue} node */
|
|
230
|
-
convRequire(node) {
|
|
231
|
-
const moduleName = node.value;
|
|
232
|
-
return this.convLineno(node, false) +
|
|
233
|
-
`__module['${moduleName}'] = require('${moduleName}');\n`;
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* プログラムの実行に必要な関数定義を書き出す(グローバル領域)
|
|
237
|
-
* convGenの結果を利用するため、convGenの後に呼び出すこと。
|
|
238
|
-
* @param com
|
|
239
|
-
* @param opt
|
|
240
|
-
*/
|
|
241
|
-
getDefFuncCode(com, opt) {
|
|
242
|
-
let code = '';
|
|
243
|
-
// よく使う変数のショートカット
|
|
244
|
-
// jsInit の部分に設定するコード
|
|
245
|
-
code += `const nakoVersion = { version: ${JSON.stringify(com.version)} }\n`;
|
|
246
|
-
code += 'const __self = self;\n';
|
|
247
|
-
code += '__self.__self = __self;\n';
|
|
248
|
-
code += 'const __varslist = __self.__varslist;\n';
|
|
249
|
-
code += 'const __module = __self.__module;\n';
|
|
250
|
-
code += 'const __v0 = __self.__v0 = __self.__varslist[0];\n';
|
|
251
|
-
code += 'const __v1 = __self.__v1 = __self.__varslist[1];\n';
|
|
252
|
-
code += 'const __vars = __self.__vars = __self.__varslist[2];\n';
|
|
253
|
-
code += 'const __nako_make_closure = (local, parent) => ({\n' +
|
|
254
|
-
' has: (key) => local.has(key) || (parent !== null && parent.has(key)),\n' +
|
|
255
|
-
' get: (key) => local.has(key) ? local.get(key) : (parent !== null ? parent.get(key) : undefined),\n' +
|
|
256
|
-
' set: (key, value) => { if (local.has(key) || parent === null || !parent.has(key)) { local.set(key, value); } else { parent.set(key, value); } return value; }\n' +
|
|
257
|
-
'});\n';
|
|
258
|
-
code += `const __modList = __self.__modList = ${JSON.stringify(com.getModList())}\n`;
|
|
259
|
-
code += 'const __line = (lineno) => { __self.__v0.set(\'__line\', lineno); }\n';
|
|
260
|
-
code += '__v0.set(\'__line\', \'l0:__getDefFuncCode\');\n';
|
|
261
|
-
code += '__v0.set(\'__forceClose\', false);\n';
|
|
262
|
-
code += `__v0.set('__useDebug', ${String(this.debugOption.useDebug)});\n`;
|
|
263
|
-
// 定数を埋め込む
|
|
264
|
-
code += '__self.constPools = ' + JSON.stringify(this.constPools) + ';\n';
|
|
265
|
-
code += '__self.constPoolsTemplate = ' + JSON.stringify(this.constPoolsTemplate) + ';\n';
|
|
266
|
-
//
|
|
267
|
-
code += '__self.__propAccessor = [];\n';
|
|
268
|
-
// なでしこの関数定義を行う
|
|
269
|
-
let nakoFuncCode = '';
|
|
270
|
-
this.nakoFuncList.forEach((value, key) => {
|
|
271
|
-
const f = trim(cleanGeneratedCode(String(value.fn), 1));
|
|
272
|
-
const isAsync = value.asyncFn ? 'true' : 'false';
|
|
273
|
-
nakoFuncCode += '' +
|
|
274
|
-
`//[DEF_FUNC name='${key}' asyncFn=${isAsync}]\n` +
|
|
275
|
-
`__self.__varslist[1].set("${key}", ${f});\n` +
|
|
276
|
-
`//[/DEF_FUNC name='${key}']\n`;
|
|
277
|
-
});
|
|
278
|
-
if (nakoFuncCode !== '') {
|
|
279
|
-
code += '__v0.set(\'__line\', \'関数の定義\');\n' + nakoFuncCode;
|
|
280
|
-
}
|
|
281
|
-
// テストの定義を行う
|
|
282
|
-
if (opt.isTest) {
|
|
283
|
-
let testCode = 'const __tests = [];\n';
|
|
284
|
-
this.nakoTestFuncs.forEach((value) => {
|
|
285
|
-
const f = value.fn;
|
|
286
|
-
testCode += `${String(f)};\n`;
|
|
287
|
-
});
|
|
288
|
-
if (testCode !== '') {
|
|
289
|
-
code += '__v0.set(\'__line\', \'テストの定義\');\n';
|
|
290
|
-
code += testCode + '\n';
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return code;
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* プラグイン・オブジェクトを追加
|
|
297
|
-
* @param po プラグイン・オブジェクト
|
|
298
|
-
*/
|
|
299
|
-
addPlugin(po) {
|
|
300
|
-
return this.__self.addPlugin(po);
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* プラグイン・オブジェクトを追加(ブラウザ向け)
|
|
304
|
-
* @param name オブジェクト名
|
|
305
|
-
* @param po 関数リスト
|
|
306
|
-
*/
|
|
307
|
-
addPluginObject(name, po) {
|
|
308
|
-
this.__self.addPluginObject(name, po);
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* プラグイン・ファイルを追加(Node.js向け)
|
|
312
|
-
* @param objName オブジェクト名
|
|
313
|
-
* @param path ファイルパス
|
|
314
|
-
* @param po 登録するオブジェクト
|
|
315
|
-
*/
|
|
316
|
-
addPluginFile(objName, path, po) {
|
|
317
|
-
this.__self.addPluginFile(objName, path, po);
|
|
318
|
-
}
|
|
319
|
-
/**
|
|
320
|
-
* 関数を追加する
|
|
321
|
-
* @param key 関数名
|
|
322
|
-
* @param josi 助詞
|
|
323
|
-
* @param fn 関数
|
|
324
|
-
*/
|
|
325
|
-
addFunc(key, josi, fn) {
|
|
326
|
-
this.__self.addFunc(key, josi, fn);
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* プラグイン関数を参照する
|
|
330
|
-
* @param key プラグイン関数の関数名
|
|
331
|
-
* @returns プラグイン・オブジェクト
|
|
332
|
-
*/
|
|
333
|
-
getFunc(key) {
|
|
334
|
-
return this.__self.getFunc(key);
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* 関数を先に登録してしまう
|
|
338
|
-
*/
|
|
339
|
-
registerFunction(ast) {
|
|
340
|
-
if (ast.type !== 'block') {
|
|
341
|
-
throw NakoSyntaxError.fromNode('構文解析に失敗しています。構文は必ずblockが先頭になります', ast);
|
|
342
|
-
}
|
|
343
|
-
/** 関数一覧 */
|
|
344
|
-
const funcList = [];
|
|
345
|
-
// なでしこ関数を定義して this.nako_func[name] に定義する
|
|
346
|
-
const registFunc = (t) => {
|
|
347
|
-
// (t.type == 'def_func') はチェック済み
|
|
348
|
-
if (!t.name) {
|
|
349
|
-
throw new Error('[System Error] 関数の定義で関数名が指定されていません');
|
|
350
|
-
}
|
|
351
|
-
const name = t.name;
|
|
352
|
-
this.usedFuncSet.add(name);
|
|
353
|
-
this.__self.__varslist[1].set(name, () => { }); // 事前に適当な値を設定
|
|
354
|
-
this.varslistSet[1].names.add(name); // global
|
|
355
|
-
const meta = t.meta;
|
|
356
|
-
if (!meta) {
|
|
357
|
-
throw new Error('[System Error] 関数の定義で関数名のメタ情報が指定されていません');
|
|
358
|
-
}
|
|
359
|
-
this.nakoFuncList.set(name, {
|
|
360
|
-
josi: meta.josi,
|
|
361
|
-
fn: () => { },
|
|
362
|
-
type: 'func',
|
|
363
|
-
asyncFn: !!t.asyncFn,
|
|
364
|
-
isExport: t.isExport
|
|
365
|
-
});
|
|
366
|
-
funcList.push({ name, node: t });
|
|
367
|
-
};
|
|
368
|
-
const registFuncs = (ast) => {
|
|
369
|
-
// blocksプロパティを持っているか?
|
|
370
|
-
if (ast.blocks) {
|
|
371
|
-
// 各ブロックをくまなく巡回チェック
|
|
372
|
-
for (const t of ast.blocks) {
|
|
373
|
-
if (t.type === 'def_func') { // 関数定義
|
|
374
|
-
registFunc(t);
|
|
375
|
-
}
|
|
376
|
-
else {
|
|
377
|
-
registFuncs(t);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
};
|
|
382
|
-
// 関数の登録
|
|
383
|
-
registFuncs(ast);
|
|
384
|
-
// __self.__varslistの変更を反映
|
|
385
|
-
const initialNames = new Set();
|
|
386
|
-
if (this.speedMode.invalidSore === 0) {
|
|
387
|
-
initialNames.add('それ');
|
|
388
|
-
}
|
|
389
|
-
this.varsSet = { isFunction: false, names: initialNames, readonly: new Set() };
|
|
390
|
-
this.varslistSet = this.setVarslistSet(this.__self.__varslist);
|
|
391
|
-
this.varslistSet[2] = this.varsSet;
|
|
392
|
-
}
|
|
393
|
-
/**
|
|
394
|
-
* @param node
|
|
395
|
-
* @param opt
|
|
396
|
-
*/
|
|
397
|
-
convGen(node, opt) {
|
|
398
|
-
const result = this.convLineno(node, false) + this._convGen(node, true);
|
|
399
|
-
if (opt.isTest) {
|
|
400
|
-
return '';
|
|
401
|
-
}
|
|
402
|
-
else {
|
|
403
|
-
return result;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
/**
|
|
407
|
-
* @param {Ast} node
|
|
408
|
-
* @param {boolean} isExpression
|
|
409
|
-
*/
|
|
410
|
-
_convGen(node, isExpression) {
|
|
411
|
-
if (!node) {
|
|
412
|
-
return '';
|
|
413
|
-
}
|
|
414
|
-
let code = '';
|
|
415
|
-
if (node instanceof Array) {
|
|
416
|
-
for (let i = 0; i < node.length; i++) {
|
|
417
|
-
const n = node[i];
|
|
418
|
-
code += this._convGen(n, isExpression);
|
|
419
|
-
}
|
|
420
|
-
return code;
|
|
421
|
-
}
|
|
422
|
-
if (node === null) {
|
|
423
|
-
return 'null';
|
|
424
|
-
}
|
|
425
|
-
if (node === undefined) {
|
|
426
|
-
return 'undefined';
|
|
427
|
-
}
|
|
428
|
-
if (typeof (node) !== 'object') {
|
|
429
|
-
return '' + String(node);
|
|
430
|
-
}
|
|
431
|
-
// switch
|
|
432
|
-
switch (node.type) {
|
|
433
|
-
case 'nop':
|
|
434
|
-
break;
|
|
435
|
-
case 'block':
|
|
436
|
-
code += this.convBlock(node);
|
|
437
|
-
break;
|
|
438
|
-
case 'comment':
|
|
439
|
-
case 'eol':
|
|
440
|
-
code += this.convComment(node);
|
|
441
|
-
break;
|
|
442
|
-
case 'run_mode':
|
|
443
|
-
code += this.convRunMode(node);
|
|
444
|
-
break;
|
|
445
|
-
case 'break':
|
|
446
|
-
code += this.convCheckLoop(node, 'break');
|
|
447
|
-
break;
|
|
448
|
-
case 'continue':
|
|
449
|
-
code += this.convCheckLoop(node, 'continue');
|
|
450
|
-
break;
|
|
451
|
-
case 'end':
|
|
452
|
-
code += '__v0.get(\'終\')(__self);';
|
|
453
|
-
break;
|
|
454
|
-
case 'number':
|
|
455
|
-
code += node.value;
|
|
456
|
-
break;
|
|
457
|
-
case 'bigint':
|
|
458
|
-
code += node.value;
|
|
459
|
-
break;
|
|
460
|
-
case 'string':
|
|
461
|
-
code += this.convString(node);
|
|
462
|
-
break;
|
|
463
|
-
case 'def_local_var':
|
|
464
|
-
code += this.convDefLocalVar(node);
|
|
465
|
-
break;
|
|
466
|
-
case 'def_local_varlist':
|
|
467
|
-
code += this.convDefLocalVarlist(node);
|
|
468
|
-
break;
|
|
469
|
-
case 'let':
|
|
470
|
-
code += this.convLet(node);
|
|
471
|
-
break;
|
|
472
|
-
case 'let_prop':
|
|
473
|
-
code += this.convLetProp(node);
|
|
474
|
-
break;
|
|
475
|
-
case 'ref_prop':
|
|
476
|
-
code += this.convRefProp(node);
|
|
477
|
-
break;
|
|
478
|
-
case 'inc':
|
|
479
|
-
code += this.convInc(node);
|
|
480
|
-
break;
|
|
481
|
-
case 'word':
|
|
482
|
-
case 'variable':
|
|
483
|
-
code += this.convGetVar(node);
|
|
484
|
-
break;
|
|
485
|
-
case 'op':
|
|
486
|
-
case 'calc':
|
|
487
|
-
code += this.convOp(node);
|
|
488
|
-
break;
|
|
489
|
-
case 'renbun':
|
|
490
|
-
code += this.convRenbun(node);
|
|
491
|
-
break;
|
|
492
|
-
case 'not':
|
|
493
|
-
code += '((' + this._convGen(node.blocks[0], true) + ')?false:true)';
|
|
494
|
-
break;
|
|
495
|
-
case 'func':
|
|
496
|
-
case 'func_pointer':
|
|
497
|
-
case 'calc_func':
|
|
498
|
-
code += this.convCallFunc(node, isExpression);
|
|
499
|
-
break;
|
|
500
|
-
case 'call_value':
|
|
501
|
-
code += this.convCallValue(node, isExpression);
|
|
502
|
-
break;
|
|
503
|
-
case 'if':
|
|
504
|
-
code += this.convIf(node);
|
|
505
|
-
break;
|
|
506
|
-
case 'for':
|
|
507
|
-
code += this.convFor(node);
|
|
508
|
-
break;
|
|
509
|
-
case 'foreach': // 反復
|
|
510
|
-
code += this.convForeach(node);
|
|
511
|
-
break;
|
|
512
|
-
case 'repeat_times': // 回
|
|
513
|
-
code += this.convRepeatTimes(node);
|
|
514
|
-
break;
|
|
515
|
-
case 'speed_mode':
|
|
516
|
-
code += this.convSpeedMode(node, isExpression);
|
|
517
|
-
break;
|
|
518
|
-
case 'performance_monitor':
|
|
519
|
-
code += this.convPerformanceMonitor(node, isExpression);
|
|
520
|
-
break;
|
|
521
|
-
case 'while':
|
|
522
|
-
code += this.convWhile(node);
|
|
523
|
-
break;
|
|
524
|
-
case 'atohantei':
|
|
525
|
-
code += this.convAtohantei(node);
|
|
526
|
-
break;
|
|
527
|
-
case 'switch':
|
|
528
|
-
code += this.convSwitch(node);
|
|
529
|
-
break;
|
|
530
|
-
case 'let_array':
|
|
531
|
-
code += this.convLetArray(node);
|
|
532
|
-
break;
|
|
533
|
-
case 'ref_array':
|
|
534
|
-
code += this.convRefArray(node);
|
|
535
|
-
break;
|
|
536
|
-
case 'ref_array_value':
|
|
537
|
-
code += this.convRefArrayValue(node);
|
|
538
|
-
break;
|
|
539
|
-
case 'json_array':
|
|
540
|
-
code += this.convJsonArray(node);
|
|
541
|
-
break;
|
|
542
|
-
case 'json_obj':
|
|
543
|
-
code += this.convJsonObj(node);
|
|
544
|
-
break;
|
|
545
|
-
case 'bool':
|
|
546
|
-
code += (node.value) ? 'true' : 'false';
|
|
547
|
-
break;
|
|
548
|
-
case 'null':
|
|
549
|
-
code += 'null';
|
|
550
|
-
break;
|
|
551
|
-
case 'def_test':
|
|
552
|
-
code += this.convDefTest(node);
|
|
553
|
-
break;
|
|
554
|
-
case 'def_func':
|
|
555
|
-
code += this.convDefFunc(node);
|
|
556
|
-
break;
|
|
557
|
-
case 'func_obj':
|
|
558
|
-
code += this.convFuncObj(node);
|
|
559
|
-
break;
|
|
560
|
-
case 'return':
|
|
561
|
-
code += this.convReturn(node);
|
|
562
|
-
break;
|
|
563
|
-
case 'try_except':
|
|
564
|
-
code += this.convTryExcept(node);
|
|
565
|
-
break;
|
|
566
|
-
case 'require':
|
|
567
|
-
code += this.convRequire(node);
|
|
568
|
-
break;
|
|
569
|
-
default:
|
|
570
|
-
throw new Error('System Error: unknown_type=' + node.type);
|
|
571
|
-
}
|
|
572
|
-
return code;
|
|
573
|
-
}
|
|
574
|
-
/** 変数を検索 */
|
|
575
|
-
findVar(name, jsvalue = null) {
|
|
576
|
-
// __vars ? (ローカル変数)
|
|
577
|
-
if (this.varslistSet.length > 3 && this.varsSet.names.has(name)) {
|
|
578
|
-
return {
|
|
579
|
-
i: this.varslistSet.length - 1,
|
|
580
|
-
name,
|
|
581
|
-
isTop: true,
|
|
582
|
-
js: this.varname_get(name),
|
|
583
|
-
js_set: this.varname_set(name, String(jsvalue))
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
// 外側の無名関数のローカル変数をクロージャとして参照する #2268
|
|
587
|
-
const currentFunc = this.functionContextStack[this.functionContextStack.length - 1];
|
|
588
|
-
if (this.varslistSet.length > 4 && currentFunc?.isAnonymous) {
|
|
589
|
-
const currentIndex = this.varslistSet.length - 1;
|
|
590
|
-
for (let i = currentIndex - 1; i >= 3; i--) {
|
|
591
|
-
if (this.varslistSet[i].names.has(name)) {
|
|
592
|
-
for (const context of this.functionContextStack) {
|
|
593
|
-
if (context.isAnonymous && context.varsIndex > i) {
|
|
594
|
-
context.usesClosure = true;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
const nameJson = JSON.stringify(name);
|
|
598
|
-
return {
|
|
599
|
-
i,
|
|
600
|
-
name,
|
|
601
|
-
isTop: false,
|
|
602
|
-
js: `__nako_closure.get(${nameJson})`,
|
|
603
|
-
js_set: `__nako_closure.set(${nameJson}, ${jsvalue ?? 'undefined'})`
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
// __varslist ?
|
|
609
|
-
for (let i = 2; i >= 0; i--) {
|
|
610
|
-
if (this.varslistSet[i].names.has(name)) {
|
|
611
|
-
// ユーザーの定義したグローバル変数 (__varslist[2]) は、変数展開されている(そのままの名前で定義されている)可能性がある。
|
|
612
|
-
// それ以外の変数は、必ず__varslistに入っている。
|
|
613
|
-
return {
|
|
614
|
-
i,
|
|
615
|
-
name,
|
|
616
|
-
isTop: false,
|
|
617
|
-
js: `__self.__varslist[${i}].get(${JSON.stringify(name)})`,
|
|
618
|
-
js_set: `__self.__varslist[${i}].set(${JSON.stringify(name)}, ${jsvalue ?? 'undefined'})`
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
return null;
|
|
623
|
-
}
|
|
624
|
-
/**
|
|
625
|
-
* 定義済みの変数の参照
|
|
626
|
-
* @param {string} name
|
|
627
|
-
* @param {Ast} position
|
|
628
|
-
*/
|
|
629
|
-
genVar(name, position) {
|
|
630
|
-
const res = this.findVar(name);
|
|
631
|
-
const lno = position.line;
|
|
632
|
-
if (res === null) {
|
|
633
|
-
// 定義されていない名前の参照は変数の定義とみなす。
|
|
634
|
-
// 多くの場合はundefined値を持つ変数であり分かりづらいバグを引き起こすが、
|
|
635
|
-
// 「ナデシコする」などの命令の中で定義された変数の参照の場合があるため警告に留める。
|
|
636
|
-
// ただし、自動的に定義される変数『引数』『それ』などは例外 #952
|
|
637
|
-
if (name === '引数' || name === 'それ' || name === '対象' || name === '対象キー') {
|
|
638
|
-
// デフォルト定義されている変数名
|
|
639
|
-
}
|
|
640
|
-
else {
|
|
641
|
-
if (this.warnUndefinedVar) {
|
|
642
|
-
// main__は省略して表示するように。 #1223
|
|
643
|
-
const dispName = name.replace(/^main__(.+)$/, '$1');
|
|
644
|
-
this.__self.getLogger().warn(`変数『${dispName}』は定義されていません。`, position);
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
this.varsSet.names.add(name);
|
|
648
|
-
return this.varname_get(name);
|
|
649
|
-
}
|
|
650
|
-
const i = res.i;
|
|
651
|
-
// システム関数・変数の場合
|
|
652
|
-
if (i === 0) {
|
|
653
|
-
const pv = this.__self.getNakoFunc(name);
|
|
654
|
-
if (!pv) {
|
|
655
|
-
return `${res.js}/*[link_error]l${lno}:${position.file ?? 'unknown'}*/`;
|
|
656
|
-
}
|
|
657
|
-
if (pv.type === 'const' || pv.type === 'var') {
|
|
658
|
-
return res.js;
|
|
659
|
-
}
|
|
660
|
-
if (pv.type === 'func') {
|
|
661
|
-
if (!pv.josi || pv.josi.length === 0) {
|
|
662
|
-
return `(${res.js}())`;
|
|
663
|
-
}
|
|
664
|
-
throw NakoSyntaxError.fromNode(`『${name}』が複文で使われました。単文で記述してください。(v1非互換)`, position);
|
|
665
|
-
}
|
|
666
|
-
throw NakoSyntaxError.fromNode(`『${name}』は関数であり参照できません。`, position);
|
|
667
|
-
}
|
|
668
|
-
return res.js;
|
|
669
|
-
}
|
|
670
|
-
convGetVar(node) {
|
|
671
|
-
// 変数名を得る
|
|
672
|
-
const name = node.value;
|
|
673
|
-
// 変数を取得するコードを生成
|
|
674
|
-
return this.genVar(name, node);
|
|
675
|
-
}
|
|
676
|
-
convBlock(node) {
|
|
677
|
-
let code = '';
|
|
678
|
-
for (const block of node.blocks) {
|
|
679
|
-
code += this._convGen(block, false);
|
|
680
|
-
}
|
|
681
|
-
return code;
|
|
682
|
-
}
|
|
683
|
-
convComment(node) {
|
|
684
|
-
let commentSrc = String(node.comment);
|
|
685
|
-
// コメントの改行や空行を無効化
|
|
686
|
-
commentSrc = commentSrc.replace(/\n/g, '¶');
|
|
687
|
-
commentSrc = commentSrc.replace(/\*\//g, '*/');
|
|
688
|
-
commentSrc = commentSrc.replace(/(^\s+|\s+$)/g, '');
|
|
689
|
-
// コメントの行番号を得る
|
|
690
|
-
const lineNo = this.convLineno(node, false);
|
|
691
|
-
if (commentSrc === '' && lineNo === '') {
|
|
692
|
-
return ';';
|
|
693
|
-
}
|
|
694
|
-
if (commentSrc === '') {
|
|
695
|
-
return ';' + lineNo + '\n';
|
|
696
|
-
}
|
|
697
|
-
return ';' + lineNo + '//' + commentSrc + '\n';
|
|
698
|
-
}
|
|
699
|
-
convRunMode(node) {
|
|
700
|
-
const mode = node.value;
|
|
701
|
-
let isStrict = false;
|
|
702
|
-
if (mode === '厳しくチェック') {
|
|
703
|
-
// 厳しくチェックモードの場合、変数の未定義チェックを行う
|
|
704
|
-
isStrict = true;
|
|
705
|
-
}
|
|
706
|
-
this.warnUndefinedVar = isStrict;
|
|
707
|
-
this.warnUndefinedReturnUserFunc = isStrict;
|
|
708
|
-
this.warnUndefinedCallingUserFunc = isStrict;
|
|
709
|
-
this.warnUndefinedCallingSystemFunc = isStrict;
|
|
710
|
-
this.warnUndefinedCalledUserFuncArgs = isStrict;
|
|
711
|
-
return `/* 実行モード: ${mode} */`;
|
|
712
|
-
}
|
|
713
|
-
convReturn(node) {
|
|
714
|
-
// 関数の中であれば利用可能
|
|
715
|
-
if (this.varsSet.names.has('!関数')) {
|
|
716
|
-
throw NakoSyntaxError.fromNode('『戻る』がありますが、関数定義内のみで使用可能です。', node);
|
|
717
|
-
}
|
|
718
|
-
const astValue = node.blocks[0];
|
|
719
|
-
const lno = this.convLineno(node, false);
|
|
720
|
-
// 戻り値のコードを得る
|
|
721
|
-
let value = '';
|
|
722
|
-
if (astValue.type !== 'nop') {
|
|
723
|
-
value = this._convGen(astValue, true);
|
|
724
|
-
}
|
|
725
|
-
else if (this.speedMode.invalidSore === 0) {
|
|
726
|
-
value = this.varname_get('それ');
|
|
727
|
-
}
|
|
728
|
-
// 戻り値のない関数の場合
|
|
729
|
-
if (value === '') {
|
|
730
|
-
return lno + 'return;';
|
|
731
|
-
}
|
|
732
|
-
// 戻り値がundefindかをチェックするかどうか
|
|
733
|
-
if (!this.warnUndefinedReturnUserFunc) {
|
|
734
|
-
return lno + `return ${value};`;
|
|
735
|
-
}
|
|
736
|
-
else {
|
|
737
|
-
const funcName = (this.defFuncName) ? this.defFuncName : '無名関数';
|
|
738
|
-
const poolIndex = this.addConstPool(`ユーザ関数『${funcName}』からundefinedが返されています`, [], node.file, node.line);
|
|
739
|
-
return lno + `return (__self.chk(${value}, ${poolIndex}));`;
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
getConstPoolsTemplateId(msg) {
|
|
743
|
-
let id = this.constPoolsTemplate.indexOf(msg);
|
|
744
|
-
if (id < 0) {
|
|
745
|
-
id = this.constPoolsTemplate.length;
|
|
746
|
-
this.constPoolsTemplate[id] = msg;
|
|
747
|
-
}
|
|
748
|
-
return id;
|
|
749
|
-
}
|
|
750
|
-
addConstPool(msg, args, file, line) {
|
|
751
|
-
// file
|
|
752
|
-
file = String(file);
|
|
753
|
-
const fileNo = this.getConstPoolsTemplateId(file);
|
|
754
|
-
// msg
|
|
755
|
-
const msgNo = this.getConstPoolsTemplateId(msg);
|
|
756
|
-
// args
|
|
757
|
-
const args2 = [];
|
|
758
|
-
for (const arg of args) {
|
|
759
|
-
const argStr = '' + String(arg);
|
|
760
|
-
const argNo = this.getConstPoolsTemplateId(argStr);
|
|
761
|
-
args2.push(argNo);
|
|
762
|
-
}
|
|
763
|
-
const poolIndex = this.constPools.length;
|
|
764
|
-
this.constPools.push([msgNo, args2, fileNo, line]);
|
|
765
|
-
return poolIndex;
|
|
766
|
-
}
|
|
767
|
-
convCheckLoop(node, cmd) {
|
|
768
|
-
// ループの中であれば利用可能
|
|
769
|
-
if (!this.flagLoop) {
|
|
770
|
-
const cmdj = (cmd === 'continue') ? '続ける' : '抜ける';
|
|
771
|
-
throw NakoSyntaxError.fromNode(`『${cmdj}』文がありますが、それは繰り返しの中で利用してください。`, node);
|
|
772
|
-
}
|
|
773
|
-
return this.convLineno(node) + cmd + ';';
|
|
774
|
-
}
|
|
775
|
-
convDefFuncCommon(node, name) {
|
|
776
|
-
// 定義中の関数名を記録
|
|
777
|
-
this.defFuncName = name;
|
|
778
|
-
// 変数をJS変数に展開するかどうか (TODO)
|
|
779
|
-
const isExtractJS = false;
|
|
780
|
-
// パフォーマンスモニタ:ユーザ関数のinjectの定義
|
|
781
|
-
let performanceMonitorInjectAtStart = '';
|
|
782
|
-
let performanceMonitorInjectAtEnd = '';
|
|
783
|
-
if (this.performanceMonitor.userFunction !== 0) {
|
|
784
|
-
let key = name;
|
|
785
|
-
if (!key) {
|
|
786
|
-
if (typeof this.performanceMonitor.mumeiId === 'undefined') {
|
|
787
|
-
this.performanceMonitor.mumeiId = 0;
|
|
788
|
-
}
|
|
789
|
-
this.performanceMonitor.mumeiId++;
|
|
790
|
-
key = `anous_${this.performanceMonitor.mumeiId}`;
|
|
791
|
-
}
|
|
792
|
-
performanceMonitorInjectAtStart = 'const performanceMonitorEnd = (function (key, type) {\n' +
|
|
793
|
-
'const uf_start = performance.now() * 1000;\n' +
|
|
794
|
-
'return function () {\n' +
|
|
795
|
-
'const el_time = performance.now() * 1000 - uf_start;\n' +
|
|
796
|
-
'if (!__self.__performance_monitor) {\n' +
|
|
797
|
-
'__self.__performance_monitor={};\n' +
|
|
798
|
-
'__self.__performance_monitor[key] = { called:1, totel_usec: el_time, min_usec: el_time, max_usec: el_time, type: type };\n' +
|
|
799
|
-
'} else if (!__self.__performance_monitor[key]) {\n' +
|
|
800
|
-
'__self.__performance_monitor[key] = { called:1, totel_usec: el_time, min_usec: el_time, max_usec: el_time, type: type };\n' +
|
|
801
|
-
'} else {\n' +
|
|
802
|
-
'__self.__performance_monitor[key].called++;\n' +
|
|
803
|
-
'__self.__performance_monitor[key].totel_usec+=el_time;\n' +
|
|
804
|
-
'if(__self.__performance_monitor[key].min_usec>el_time){__self.__performance_monitor[key].min_usec=el_time;}\n' +
|
|
805
|
-
'if(__self.__performance_monitor[key].max_usec<el_time){__self.__performance_monitor[key].max_usec=el_time;}\n' +
|
|
806
|
-
`}};})('${key}', 'user');` +
|
|
807
|
-
'try {\n';
|
|
808
|
-
performanceMonitorInjectAtEnd = '} finally { performanceMonitorEnd(); }\n';
|
|
809
|
-
}
|
|
810
|
-
let variableDeclarations = '';
|
|
811
|
-
const indent = ' ';
|
|
812
|
-
let pushStack = '';
|
|
813
|
-
let popStack = '';
|
|
814
|
-
const initialNames = new Set();
|
|
815
|
-
if (this.speedMode.invalidSore === 0) {
|
|
816
|
-
initialNames.add('それ');
|
|
817
|
-
}
|
|
818
|
-
this.varsSet = { isFunction: true, names: initialNames, readonly: new Set() };
|
|
819
|
-
// ローカル変数をPUSHする
|
|
820
|
-
this.varslistSet.push(this.varsSet);
|
|
821
|
-
const funcContext = {
|
|
822
|
-
isAnonymous: name === '',
|
|
823
|
-
varsIndex: this.varslistSet.length - 1,
|
|
824
|
-
usesClosure: false
|
|
825
|
-
};
|
|
826
|
-
this.functionContextStack.push(funcContext);
|
|
827
|
-
// JSの引数と引数をバインド
|
|
828
|
-
if (isExtractJS) {
|
|
829
|
-
variableDeclarations += indent + 'var 引数 = arguments;\n';
|
|
830
|
-
}
|
|
831
|
-
else {
|
|
832
|
-
variableDeclarations += indent + '__self.__vars.set(\'引数\', arguments);\n';
|
|
833
|
-
}
|
|
834
|
-
// ローカル変数を生成 (再帰関数呼び出しで引数の値が壊れる問題があるので修正 #1663 / タイミングによって壊れるので修理 #1758)
|
|
835
|
-
// 暫定変数__localVarsに現在のローカル変数の値をPUSHし、変数を抜ける時にPOPする)
|
|
836
|
-
// 関数として宣言しているが、JS関数となでしこ関数では変数管理の方法が異なるため、完全なローカル変数としては使えない
|
|
837
|
-
// 必ず、pushStack/popStack する必要がある
|
|
838
|
-
pushStack += '\n// PUSH STACK\n';
|
|
839
|
-
pushStack += 'const __localvars = __self.__vars;\n';
|
|
840
|
-
pushStack += '__self.__vars = new Map();\n';
|
|
841
|
-
pushStack += 'try {\n';
|
|
842
|
-
popStack += '} finally {\n';
|
|
843
|
-
popStack += indent + '// POP STACK\n';
|
|
844
|
-
popStack += indent + 'self.__vars = __localvars;\n';
|
|
845
|
-
popStack += '}\n';
|
|
846
|
-
// 宣言済みの名前を保存
|
|
847
|
-
const varsDeclared = Array.from(this.varsSet.names.values());
|
|
848
|
-
let code = '';
|
|
849
|
-
// 引数をローカル変数に設定
|
|
850
|
-
const meta = node.meta;
|
|
851
|
-
if (!meta) {
|
|
852
|
-
throw new Error('[System Error] 関数の定義でメタ情報が指定されていません');
|
|
853
|
-
}
|
|
854
|
-
if (!meta.varnames) {
|
|
855
|
-
meta.varnames = [];
|
|
856
|
-
}
|
|
857
|
-
for (let i = 0; i < meta.varnames.length; i++) {
|
|
858
|
-
const word = meta.varnames[i];
|
|
859
|
-
if (word === '引数') {
|
|
860
|
-
continue;
|
|
861
|
-
}
|
|
862
|
-
if (!this.warnUndefinedCalledUserFuncArgs) {
|
|
863
|
-
code += indent + this.varname_set(word, `arguments[${i}]`) + ';\n';
|
|
864
|
-
}
|
|
865
|
-
else {
|
|
866
|
-
// check undefined
|
|
867
|
-
let errMsg = `匿名関数の引数『${word}』にundefinedが渡されました`;
|
|
868
|
-
if (name) {
|
|
869
|
-
errMsg = `ユーザ関数『${name}』の引数『${word}』にundefinedが渡されました`;
|
|
870
|
-
}
|
|
871
|
-
const warnJS = `__self.logger.warn('${errMsg}', {line: ${node.line}, file: ${JSON.stringify(node.file)}});`;
|
|
872
|
-
const checkFunc = `((a) => { if (a === undefined) { ${warnJS} }; return a; })`;
|
|
873
|
-
const callCheckFunc = `${checkFunc}(arguments[${i}])`;
|
|
874
|
-
code += indent + this.varname_set(word, callCheckFunc) + ';\n';
|
|
875
|
-
}
|
|
876
|
-
this.varsSet.names.add(word);
|
|
877
|
-
}
|
|
878
|
-
// 関数定義は、グローバル領域で。
|
|
879
|
-
if (name) {
|
|
880
|
-
this.usedFuncSet.add(name);
|
|
881
|
-
this.varslistSet[1].names.add(name);
|
|
882
|
-
if (this.nakoFuncList.get(name) === undefined) {
|
|
883
|
-
if (!node.meta) {
|
|
884
|
-
throw new Error('[System Error] 関数の定義でメタ情報が指定されていません');
|
|
885
|
-
}
|
|
886
|
-
// 既に generate で作成済みのはず(念のため)
|
|
887
|
-
this.nakoFuncList.set(name, {
|
|
888
|
-
josi: node.meta.josi,
|
|
889
|
-
fn: () => { },
|
|
890
|
-
type: 'func',
|
|
891
|
-
asyncFn: false,
|
|
892
|
-
isExport: null
|
|
893
|
-
});
|
|
894
|
-
this.__self.getLogger().warn(`generateで未定義の状態の関数『${name}』が動的に登録されています。`);
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
// ブロックを解析
|
|
898
|
-
const oldUsedAsyncFn = this.usedAsyncFn;
|
|
899
|
-
this.usedAsyncFn = false;
|
|
900
|
-
if (this.debugOption.useDebug) {
|
|
901
|
-
this.usedAsyncFn = true;
|
|
902
|
-
}
|
|
903
|
-
const block = this._convGen(node.blocks[0], false);
|
|
904
|
-
code += block.split('\n').map((line) => ' ' + line).join('\n') + '\n';
|
|
905
|
-
// 関数の最後に、変数「それ」をreturnするようにする
|
|
906
|
-
if (this.speedMode.invalidSore === 0) {
|
|
907
|
-
code += ` return (${this.varname_get('それ')});\n`;
|
|
908
|
-
}
|
|
909
|
-
// パフォーマンスモニタ:ユーザ関数のinject
|
|
910
|
-
code += performanceMonitorInjectAtEnd;
|
|
911
|
-
// 名前のある関数で非同期関数であれば、関数にasyncを付与する
|
|
912
|
-
if (name && this.usedAsyncFn) {
|
|
913
|
-
const f = this.nakoFuncList.get(name);
|
|
914
|
-
if (f) {
|
|
915
|
-
f.asyncFn = true;
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
// 関数の末尾に、ローカル変数をPOP
|
|
919
|
-
// 関数内で定義されたローカル変数の宣言
|
|
920
|
-
if (isExtractJS) {
|
|
921
|
-
for (const name of Array.from(this.varsSet.names.values())) {
|
|
922
|
-
if (!varsDeclared.includes(name)) {
|
|
923
|
-
if (NakoGen.isValidIdentifier(name)) {
|
|
924
|
-
variableDeclarations += ` var ${name};\n`;
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
if (this.speedMode.invalidSore === 0) {
|
|
929
|
-
if (NakoGen.isValidIdentifier('それ')) {
|
|
930
|
-
variableDeclarations += ' var それ = \'\';\n';
|
|
931
|
-
}
|
|
932
|
-
else {
|
|
933
|
-
variableDeclarations += ` ${this.varname_get('それ')} = '';`;
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
// usedAsyncFnの値に応じて関数定義の方法を変更
|
|
938
|
-
const tof = (this.usedAsyncFn) ? topOfFunctionAsync : topOfFunction;
|
|
939
|
-
// 関数コード全体を構築
|
|
940
|
-
const lineInfo = ' ' + this.convLineno(node, true, 1) + '\n';
|
|
941
|
-
code = tof + performanceMonitorInjectAtStart + pushStack + variableDeclarations + lineInfo + code + popStack;
|
|
942
|
-
code += endOfFunction;
|
|
943
|
-
if (funcContext.isAnonymous && funcContext.usesClosure) {
|
|
944
|
-
const parentClosure = `(typeof __nako_closure === 'undefined' ? null : __nako_closure)`;
|
|
945
|
-
code = `(function(__nako_closure) {\n return ${code}\n})(__nako_make_closure(__self.__vars, ${parentClosure}))`;
|
|
946
|
-
}
|
|
947
|
-
// 名前があれば、関数を登録する
|
|
948
|
-
if (name) {
|
|
949
|
-
const nameFuncValue = this.nakoFuncList.get(name);
|
|
950
|
-
if (nameFuncValue) {
|
|
951
|
-
nameFuncValue.fn = code;
|
|
952
|
-
nameFuncValue.asyncFn = this.usedAsyncFn;
|
|
953
|
-
meta.asyncFn = this.usedAsyncFn;
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
this.usedAsyncFn = oldUsedAsyncFn; // 以前の値を戻す
|
|
957
|
-
this.varslistSet.pop();
|
|
958
|
-
this.functionContextStack.pop();
|
|
959
|
-
this.varsSet = this.varslistSet[this.varslistSet.length - 1];
|
|
960
|
-
if (name) {
|
|
961
|
-
this.__self.__varslist[1].set(name, code);
|
|
962
|
-
}
|
|
963
|
-
this.defFuncName = ''; // 関数名をクリア
|
|
964
|
-
return code;
|
|
965
|
-
}
|
|
966
|
-
convDefTest(node) {
|
|
967
|
-
const name = node.name;
|
|
968
|
-
let code = `__tests.push({ name: '${name}', f: () => {\n`;
|
|
969
|
-
// ブロックを解析
|
|
970
|
-
const block = this._convGen(node.blocks[0], false);
|
|
971
|
-
code += ` ${block}\n` +
|
|
972
|
-
'}});';
|
|
973
|
-
if (!node.meta) {
|
|
974
|
-
throw new Error('[System Error] テストのメタ情報が指定されていません');
|
|
975
|
-
}
|
|
976
|
-
this.nakoTestFuncs.set(name, {
|
|
977
|
-
josi: node.meta.josi,
|
|
978
|
-
fn: code,
|
|
979
|
-
type: 'test_func'
|
|
980
|
-
});
|
|
981
|
-
// ★この時点ではテストコードを生成しない★
|
|
982
|
-
// プログラム冒頭でコード生成時にテストの定義を行う
|
|
983
|
-
return '';
|
|
984
|
-
}
|
|
985
|
-
convDefFunc(node) {
|
|
986
|
-
// ※ [関数定義のメモ]
|
|
987
|
-
// ※ 関数の定義はプログラムの冒頭に移される。
|
|
988
|
-
// ※ そのため、生成されたコードはここでは返さない
|
|
989
|
-
// ※ registerFunction を参照
|
|
990
|
-
if (!node.name) {
|
|
991
|
-
return '';
|
|
992
|
-
}
|
|
993
|
-
const name = NakoGen.getFuncName(node.name);
|
|
994
|
-
this.convDefFuncCommon(node, name);
|
|
995
|
-
return '';
|
|
996
|
-
}
|
|
997
|
-
convFuncObj(node) {
|
|
998
|
-
return '/*convFuncObj*/' + this.convDefFuncCommon(node, '');
|
|
999
|
-
}
|
|
1000
|
-
convJsonObj(node) {
|
|
1001
|
-
const resultArray = [];
|
|
1002
|
-
const list = node.blocks;
|
|
1003
|
-
for (let i = 0; i < list.length / 2; i++) {
|
|
1004
|
-
const idx = i * 2;
|
|
1005
|
-
const key = list[idx + 0];
|
|
1006
|
-
const val = list[idx + 1];
|
|
1007
|
-
const keyStr = this._convGen(key, true);
|
|
1008
|
-
const valStr = this._convGen(val, true);
|
|
1009
|
-
resultArray.push(`${keyStr}: ${valStr}`);
|
|
1010
|
-
}
|
|
1011
|
-
return '{' + resultArray.join(', ') + '}';
|
|
1012
|
-
}
|
|
1013
|
-
convJsonArray(node) {
|
|
1014
|
-
const list = node.blocks;
|
|
1015
|
-
const codelist = list.map((e) => {
|
|
1016
|
-
return this._convGen(e, true);
|
|
1017
|
-
});
|
|
1018
|
-
return '[' + codelist.join(',') + ']';
|
|
1019
|
-
}
|
|
1020
|
-
convRefArray(node) {
|
|
1021
|
-
let code = '';
|
|
1022
|
-
code = this._convGen(node.name, true);
|
|
1023
|
-
const list = node.index;
|
|
1024
|
-
if (!list) {
|
|
1025
|
-
return code;
|
|
1026
|
-
}
|
|
1027
|
-
for (let i = 0; i < list.length; i++) {
|
|
1028
|
-
const idx = this._convGen(list[i], true);
|
|
1029
|
-
code += '[' + idx + ']';
|
|
1030
|
-
}
|
|
1031
|
-
return code;
|
|
1032
|
-
}
|
|
1033
|
-
convRefArrayValue(node) {
|
|
1034
|
-
let code = '';
|
|
1035
|
-
const op = node.name ? String(node.name) : '???';
|
|
1036
|
-
const val = node.index ? node.index.shift() : undefined;
|
|
1037
|
-
if (!val) {
|
|
1038
|
-
return '/*[WARNING] convRefArrayOperator::InvalidValue */';
|
|
1039
|
-
}
|
|
1040
|
-
code = this._convGen(val, true);
|
|
1041
|
-
const list = node.index;
|
|
1042
|
-
if (!list) {
|
|
1043
|
-
return code;
|
|
1044
|
-
}
|
|
1045
|
-
if (op === '@' || op === '[') {
|
|
1046
|
-
for (let i = 0; i < list.length; i++) {
|
|
1047
|
-
const idx = this._convGen(list[i], true);
|
|
1048
|
-
code += '[' + idx + ']';
|
|
1049
|
-
}
|
|
1050
|
-
return code;
|
|
1051
|
-
}
|
|
1052
|
-
if (op === '$') {
|
|
1053
|
-
return this.convRefProp_genCode(code, list);
|
|
1054
|
-
}
|
|
1055
|
-
// operator not found
|
|
1056
|
-
const op2 = op.replace('*/', '*/');
|
|
1057
|
-
return `/* [WARNING] convRefArrayOperator::UnknownOperator [${op2}] */` + code;
|
|
1058
|
-
}
|
|
1059
|
-
convLetArray(node) {
|
|
1060
|
-
const id = this.loopId++;
|
|
1061
|
-
const valueNode = node.blocks[0];
|
|
1062
|
-
const indexNodes = node.blocks.slice(1);
|
|
1063
|
-
const name = this.genVar(node.name, node);
|
|
1064
|
-
let codeInit = '';
|
|
1065
|
-
let code = name;
|
|
1066
|
-
let codeArray = '';
|
|
1067
|
-
// codeInit?
|
|
1068
|
-
if (node.checkInit) { // DNCLのための初期化処理 ... DNCLでは配列の初期化なしでいきなり配列を使う試験問題があるため
|
|
1069
|
-
const arrayDefCode = '[0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0]';
|
|
1070
|
-
// [name]の内容は[__self.__varslist[2].get("a__A")]のようなものになっているはず
|
|
1071
|
-
if (node.name) {
|
|
1072
|
-
const word = node.name;
|
|
1073
|
-
const tmpVar = `$nako_tmp_a${id}`;
|
|
1074
|
-
const initArrayCode = this.varname_set(word, arrayDefCode);
|
|
1075
|
-
codeInit += `\n/*配列初期化*/if (!(${name} instanceof Array)) { ${initArrayCode} };\n`;
|
|
1076
|
-
codeInit += `${tmpVar} = ${name};\n`;
|
|
1077
|
-
for (let i = 0; i < indexNodes.length - 1; i++) {
|
|
1078
|
-
const idx = this._convGen(indexNodes[i], true);
|
|
1079
|
-
codeArray += `[${idx}]`;
|
|
1080
|
-
codeInit += `\n/*配列初期化${i}*/if (!(${tmpVar}${codeArray} instanceof Array)) { ${tmpVar}${codeArray} = ${arrayDefCode}; };`;
|
|
1081
|
-
}
|
|
1082
|
-
codeInit += '\n';
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
// array
|
|
1086
|
-
for (let i = 0; i < indexNodes.length; i++) {
|
|
1087
|
-
const idx = this._convGen(indexNodes[i], true);
|
|
1088
|
-
code += '[' + idx + ']';
|
|
1089
|
-
}
|
|
1090
|
-
// value
|
|
1091
|
-
let value = null;
|
|
1092
|
-
if (this.speedMode.invalidSore === 0) {
|
|
1093
|
-
value = this.varname_get('それ');
|
|
1094
|
-
}
|
|
1095
|
-
if (valueNode.type !== 'nop') {
|
|
1096
|
-
value = this._convGen(valueNode, true);
|
|
1097
|
-
}
|
|
1098
|
-
if (value === null) {
|
|
1099
|
-
throw NakoSyntaxError.fromNode('代入する先の変数名がありません。', node);
|
|
1100
|
-
}
|
|
1101
|
-
code += ' = ' + value + ';\n';
|
|
1102
|
-
// generate code
|
|
1103
|
-
const src = this.convLineno(node, false) + codeInit + code;
|
|
1104
|
-
return src;
|
|
1105
|
-
}
|
|
1106
|
-
convGenLoop(node) {
|
|
1107
|
-
const tmpflag = this.flagLoop;
|
|
1108
|
-
this.flagLoop = true;
|
|
1109
|
-
try {
|
|
1110
|
-
return this._convGen(node, false);
|
|
1111
|
-
}
|
|
1112
|
-
finally {
|
|
1113
|
-
this.flagLoop = tmpflag;
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
convFor(node) {
|
|
1117
|
-
const astFrom = node.blocks[0];
|
|
1118
|
-
const astTo = node.blocks[1];
|
|
1119
|
-
const astInc = node.blocks[2];
|
|
1120
|
-
const astBlock = node.blocks[3];
|
|
1121
|
-
// forのIDを取得
|
|
1122
|
-
const idLoop = this.loopId++;
|
|
1123
|
-
const varI = `$nako_i${idLoop}`;
|
|
1124
|
-
// ループ変数について
|
|
1125
|
-
let loopVarSetter = '';
|
|
1126
|
-
if (node.word !== '') { // ループ変数を使う時
|
|
1127
|
-
const varName = node.word;
|
|
1128
|
-
this.varsSet.names.add(varName);
|
|
1129
|
-
loopVarSetter = this.varname_set(varName, varI);
|
|
1130
|
-
}
|
|
1131
|
-
// ループ条件を変数に入れる用
|
|
1132
|
-
const varFrom = `$nako_from${idLoop}`;
|
|
1133
|
-
const varTo = `$nako_to${idLoop}`;
|
|
1134
|
-
const varTemp = `$nako_temp${idLoop}`;
|
|
1135
|
-
let sorePrefex = '';
|
|
1136
|
-
if (this.speedMode.invalidSore === 0) {
|
|
1137
|
-
sorePrefex = this.varname_set('それ', varI);
|
|
1138
|
-
}
|
|
1139
|
-
// ループ条件を確認
|
|
1140
|
-
let kara = '0';
|
|
1141
|
-
let made = '0';
|
|
1142
|
-
let temp = '0';
|
|
1143
|
-
if (astTo && astTo.type === 'func' && astTo.name === '範囲') {
|
|
1144
|
-
temp = this._convGen(astTo, true);
|
|
1145
|
-
kara = `${varTemp}['先頭'] || 0`;
|
|
1146
|
-
made = `${varTemp}['末尾'] || 0`;
|
|
1147
|
-
}
|
|
1148
|
-
else {
|
|
1149
|
-
kara = this._convGen(astFrom, true);
|
|
1150
|
-
made = this._convGen(astTo, true);
|
|
1151
|
-
}
|
|
1152
|
-
const flagDown = node.flagDown;
|
|
1153
|
-
const flagUp = node.flagUp;
|
|
1154
|
-
let inc = '1';
|
|
1155
|
-
if (astInc.type !== 'nop') {
|
|
1156
|
-
inc = this._convGen(astInc, true);
|
|
1157
|
-
}
|
|
1158
|
-
// ループ内のブロック内容を得る
|
|
1159
|
-
const block = this.convGenLoop(astBlock);
|
|
1160
|
-
const code = this.convLineno(node, false) + '\n' +
|
|
1161
|
-
`/*[convFor id=${idLoop}]*/\n` +
|
|
1162
|
-
`const ${varTemp} = ${temp};\n` +
|
|
1163
|
-
`const ${varFrom} = ${kara};\n` +
|
|
1164
|
-
`const ${varTo} = ${made};\n` +
|
|
1165
|
-
`if (${varFrom} < ${varTo}) { // up\n` +
|
|
1166
|
-
` if (${String(flagUp)}) {` +
|
|
1167
|
-
` for (let ${varI} = ${varFrom}; ${varI} <= ${varTo}; ${varI}+= ${inc}) {\n` +
|
|
1168
|
-
` ${sorePrefex};${loopVarSetter}\n` +
|
|
1169
|
-
' // for block begin\n' +
|
|
1170
|
-
` ${block}\n` +
|
|
1171
|
-
' // for block end\n' +
|
|
1172
|
-
' };\n' +
|
|
1173
|
-
' };\n' +
|
|
1174
|
-
`} else if (${varFrom} > ${varTo}) { // down\n` +
|
|
1175
|
-
` if (${String(flagDown)}) {` +
|
|
1176
|
-
` for (let ${varI} = ${varFrom}; ${varI} >= ${varTo}; ${varI}-= ${inc}) {\n` +
|
|
1177
|
-
` ${sorePrefex};${loopVarSetter}\n` +
|
|
1178
|
-
' // for block begin\n' +
|
|
1179
|
-
` ${block}\n` +
|
|
1180
|
-
' // for block end\n' +
|
|
1181
|
-
' }\n' +
|
|
1182
|
-
' };\n' +
|
|
1183
|
-
'} else { // from == to\n' +
|
|
1184
|
-
` for (let ${varI} = ${varFrom}; ${varI} <= ${varTo}; ${varI}+= 1) {\n` +
|
|
1185
|
-
` ${sorePrefex};${loopVarSetter}\n` +
|
|
1186
|
-
' // for block begin\n' +
|
|
1187
|
-
` ${block}\n` +
|
|
1188
|
-
' // for block end\n' +
|
|
1189
|
-
' };\n' +
|
|
1190
|
-
'};\n' +
|
|
1191
|
-
`//[/convFor id=${idLoop}]\n`;
|
|
1192
|
-
return code;
|
|
1193
|
-
}
|
|
1194
|
-
convForeach(node) {
|
|
1195
|
-
const exprAst = node.blocks[0];
|
|
1196
|
-
const blockAst = node.blocks[1];
|
|
1197
|
-
// foreachのIDを取得
|
|
1198
|
-
const id = this.loopId++;
|
|
1199
|
-
const loopKeyVar = `$nako_i${id}`;
|
|
1200
|
-
const loopValueVar = `$nako_foreach_value${id}`;
|
|
1201
|
-
const loopDataVar = `$nako_foreach_data${id}`;
|
|
1202
|
-
const taisyouTemp = `$nako_taisyou_temp${id}`;
|
|
1203
|
-
const taisyouKeyTemp = `$nako_taisyou_key_temp${id}`;
|
|
1204
|
-
const soreTemp = `$nako_foreach_sore_temp${id}`;
|
|
1205
|
-
// 「対象」「対象キー」を取得 --- blockより早く変数を定義する必要がある
|
|
1206
|
-
let taisyoPrefex = this.varname_set_sys('対象', loopValueVar);
|
|
1207
|
-
if (node.word !== '') { // 対象変数がある場合、対象は設定されない
|
|
1208
|
-
const valueVar = node.word;
|
|
1209
|
-
this.varsSet.names.add(valueVar);
|
|
1210
|
-
taisyoPrefex = this.varname_set(valueVar, loopValueVar);
|
|
1211
|
-
}
|
|
1212
|
-
const keyVar = '対象キー';
|
|
1213
|
-
const keySetter = this.varname_set_sys(keyVar, loopKeyVar);
|
|
1214
|
-
// 「それ」(対象のエイリアス)の設定
|
|
1215
|
-
let sorePrefex = '';
|
|
1216
|
-
let soreRecover = '';
|
|
1217
|
-
let soreBackup = '';
|
|
1218
|
-
if (this.speedMode.invalidSore === 0) {
|
|
1219
|
-
sorePrefex = this.varname_set('それ', loopValueVar);
|
|
1220
|
-
soreRecover = this.varname_set('それ', soreTemp);
|
|
1221
|
-
soreBackup = `let ${soreTemp} = ` + this.varname_get('それ') + ';';
|
|
1222
|
-
}
|
|
1223
|
-
// 反復するデータを取得
|
|
1224
|
-
let targetData = '';
|
|
1225
|
-
if (exprAst.type === 'nop') {
|
|
1226
|
-
if (this.speedMode.invalidSore === 0) {
|
|
1227
|
-
targetData = this.varname_get('それ');
|
|
1228
|
-
}
|
|
1229
|
-
else {
|
|
1230
|
-
throw NakoSyntaxError.fromNode('『反復』の対象がありません。', node);
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
else {
|
|
1234
|
-
targetData = this._convGen(exprAst, true);
|
|
1235
|
-
}
|
|
1236
|
-
// 反復するブロックを取得
|
|
1237
|
-
const block = trim(cleanGeneratedCode(this.convGenLoop(blockAst), 1));
|
|
1238
|
-
// コードを生成
|
|
1239
|
-
const code = this.convLineno(node, false) + '\n' +
|
|
1240
|
-
`// [convForeach id=${id}]\n` +
|
|
1241
|
-
`const ${taisyouTemp} = __self.__getSysVar('対象'); ${soreBackup}; ` +
|
|
1242
|
-
`const ${taisyouKeyTemp} = __self.__getSysVar('対象キー');\n` +
|
|
1243
|
-
`let ${loopDataVar} = ${targetData};\n` +
|
|
1244
|
-
'// foreach Map?\n' +
|
|
1245
|
-
`if (${loopDataVar} instanceof Map) { // Objectに強制変換\n` +
|
|
1246
|
-
` let tmp = {}; for (let tmpKey of ${loopDataVar}.keys()) { tmp[tmpKey] = ${loopDataVar}.get(tmpKey); }; \n` +
|
|
1247
|
-
` ${loopDataVar} = tmp;\n` +
|
|
1248
|
-
'}\n' +
|
|
1249
|
-
`for (let ${loopKeyVar} in ${loopDataVar}) {\n` +
|
|
1250
|
-
` if (!${loopDataVar}.hasOwnProperty(${loopKeyVar})) { continue }\n` +
|
|
1251
|
-
' // 対象キーの設定\n' +
|
|
1252
|
-
` ${keySetter}\n` +
|
|
1253
|
-
' // 対象の設定\n' +
|
|
1254
|
-
` let ${loopValueVar} = $nako_foreach_data${id}[${loopKeyVar}]\n` +
|
|
1255
|
-
` ${sorePrefex};\n` +
|
|
1256
|
-
` ${taisyoPrefex};\n` +
|
|
1257
|
-
' // [convForeach::block]\n' +
|
|
1258
|
-
` ${block}\n` +
|
|
1259
|
-
' // [/convForeach::block]\n' +
|
|
1260
|
-
'}\n' +
|
|
1261
|
-
`__self.__setSysVar('対象', ${taisyouTemp});${soreRecover};` +
|
|
1262
|
-
`__self.__setSysVar('対象キー', ${taisyouKeyTemp});` +
|
|
1263
|
-
`// [/convForeach id=${id}]\n`;
|
|
1264
|
-
return code;
|
|
1265
|
-
}
|
|
1266
|
-
convRepeatTimes(node) {
|
|
1267
|
-
// ループのIDを取得
|
|
1268
|
-
const id = this.loopId++;
|
|
1269
|
-
const varI = `$nako_i${id}`;
|
|
1270
|
-
const varCount = `$nako_times_data${id}`;
|
|
1271
|
-
const varKaisuTemp = `$nako_kaisu_temp${id}`;
|
|
1272
|
-
const codeCount = this._convGen(node.blocks[0], true);
|
|
1273
|
-
// ブロックを得る
|
|
1274
|
-
const block = trim(cleanGeneratedCode(this.convGenLoop(node.blocks[1]), 1));
|
|
1275
|
-
// それ
|
|
1276
|
-
let sorePrefex = '';
|
|
1277
|
-
let soreRecover = '';
|
|
1278
|
-
if (this.speedMode.invalidSore === 0) {
|
|
1279
|
-
sorePrefex = this.varname_set('それ', varI);
|
|
1280
|
-
soreRecover = this.varname_set('それ', varKaisuTemp);
|
|
1281
|
-
}
|
|
1282
|
-
// 回数
|
|
1283
|
-
sorePrefex += `;__self.__setSysVar('回数', ${varI});`;
|
|
1284
|
-
soreRecover += `;__self.__setSysVar('回数', ${varKaisuTemp});`;
|
|
1285
|
-
const code = this.convLineno(node, false) + '\n' +
|
|
1286
|
-
`// [convRepeatTimes id=${id}] // 『n回』構文\n` +
|
|
1287
|
-
`let ${varKaisuTemp} = __self.__getSysVar('回数')\n` +
|
|
1288
|
-
`let ${varCount} = ${codeCount};\n` +
|
|
1289
|
-
`for (let ${varI} = 1; ${varI} <= ${varCount}; ${varI}++) {\n` +
|
|
1290
|
-
` ${sorePrefex}\n` +
|
|
1291
|
-
` ${block}\n` +
|
|
1292
|
-
'}\n' +
|
|
1293
|
-
`${soreRecover}\n` +
|
|
1294
|
-
`// [/convRepeatTimes id=${id}]\n`;
|
|
1295
|
-
return code;
|
|
1296
|
-
}
|
|
1297
|
-
/**
|
|
1298
|
-
* @param {Ast} node
|
|
1299
|
-
* @param {boolean} isExpression
|
|
1300
|
-
*/
|
|
1301
|
-
convSpeedMode(node, isExpression) {
|
|
1302
|
-
if (!node.options) {
|
|
1303
|
-
return '';
|
|
1304
|
-
}
|
|
1305
|
-
const prev = { ...this.speedMode };
|
|
1306
|
-
if (node.options['行番号無し']) {
|
|
1307
|
-
this.speedMode.lineNumbers++;
|
|
1308
|
-
}
|
|
1309
|
-
if (node.options['暗黙の型変換無し']) {
|
|
1310
|
-
this.speedMode.implicitTypeCasting++;
|
|
1311
|
-
}
|
|
1312
|
-
if (node.options['強制ピュア']) {
|
|
1313
|
-
this.speedMode.forcePure++;
|
|
1314
|
-
}
|
|
1315
|
-
if (node.options['それ無効']) {
|
|
1316
|
-
this.speedMode.invalidSore++;
|
|
1317
|
-
}
|
|
1318
|
-
try {
|
|
1319
|
-
return this._convGen(node.blocks[0], isExpression);
|
|
1320
|
-
}
|
|
1321
|
-
finally {
|
|
1322
|
-
this.speedMode = prev;
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
/**
|
|
1326
|
-
* @param {Ast} node
|
|
1327
|
-
* @param {boolean} isExpression
|
|
1328
|
-
*/
|
|
1329
|
-
convPerformanceMonitor(node, isExpression) {
|
|
1330
|
-
const prev = { ...this.performanceMonitor };
|
|
1331
|
-
if (!node.options) {
|
|
1332
|
-
return '';
|
|
1333
|
-
}
|
|
1334
|
-
if (node.options['ユーザ関数']) {
|
|
1335
|
-
this.performanceMonitor.userFunction++;
|
|
1336
|
-
}
|
|
1337
|
-
if (node.options['システム関数本体']) {
|
|
1338
|
-
this.performanceMonitor.systemFunctionBody++;
|
|
1339
|
-
}
|
|
1340
|
-
if (node.options['システム関数']) {
|
|
1341
|
-
this.performanceMonitor.systemFunction++;
|
|
1342
|
-
}
|
|
1343
|
-
try {
|
|
1344
|
-
return this._convGen(node.blocks[0], isExpression);
|
|
1345
|
-
}
|
|
1346
|
-
finally {
|
|
1347
|
-
this.performanceMonitor = prev;
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
convWhile(node) {
|
|
1351
|
-
const exprAst = node.blocks[0];
|
|
1352
|
-
const blockAst = node.blocks[1];
|
|
1353
|
-
const cond = this._convGen(exprAst, true);
|
|
1354
|
-
const block = trim(cleanGeneratedCode(this.convGenLoop(blockAst), 1));
|
|
1355
|
-
const code = '// [convWhile]\n' +
|
|
1356
|
-
this.convLineno(node, false) + '\n' +
|
|
1357
|
-
`while (${cond})` + '{\n' +
|
|
1358
|
-
` ${block}` + '\n' +
|
|
1359
|
-
'}\n' +
|
|
1360
|
-
'// [convWhile]\n';
|
|
1361
|
-
return code;
|
|
1362
|
-
}
|
|
1363
|
-
convAtohantei(node) {
|
|
1364
|
-
const id = this.loopId++;
|
|
1365
|
-
const varId = `$nako_i${id}`;
|
|
1366
|
-
const cond = this._convGen(node.blocks[0], true);
|
|
1367
|
-
const block = this.convGenLoop(node.blocks[1]);
|
|
1368
|
-
const code = 'while (true) {\n' +
|
|
1369
|
-
` ${block}\n` +
|
|
1370
|
-
` let ${varId} = ${cond};\n` +
|
|
1371
|
-
` if (${varId}) { continue } else { break }\n` +
|
|
1372
|
-
'}\n\n';
|
|
1373
|
-
return this.convLineno(node, false) + code;
|
|
1374
|
-
}
|
|
1375
|
-
convSwitch(node) {
|
|
1376
|
-
const expr = this._convGen(node.blocks[0], true);
|
|
1377
|
-
const defaultStr = this._convGen(node.blocks[1], false);
|
|
1378
|
-
let body = '';
|
|
1379
|
-
for (let i = 0; i < node.case_count; i++) {
|
|
1380
|
-
const caseIndex = i * 2 + 2;
|
|
1381
|
-
const condStr = this._convGen(node.blocks[caseIndex + 0], true);
|
|
1382
|
-
const blockStr = this.convGenLoop(node.blocks[caseIndex + 1]);
|
|
1383
|
-
body += ` case ${condStr}:\n`;
|
|
1384
|
-
body += ` ${blockStr}\n` +
|
|
1385
|
-
' break\n';
|
|
1386
|
-
}
|
|
1387
|
-
const code = '// [switch]\n' +
|
|
1388
|
-
`switch (${expr})` + '{\n' +
|
|
1389
|
-
`${body}` + '\n' +
|
|
1390
|
-
' default:\n' +
|
|
1391
|
-
` ${defaultStr}\n` +
|
|
1392
|
-
'}\n' +
|
|
1393
|
-
'// [/switch]\n';
|
|
1394
|
-
return this.convLineno(node, false) + code;
|
|
1395
|
-
}
|
|
1396
|
-
convIf(node) {
|
|
1397
|
-
const exprAst = node.blocks[0];
|
|
1398
|
-
const trueAst = node.blocks[1];
|
|
1399
|
-
const falseAst = node.blocks[2];
|
|
1400
|
-
// 条件
|
|
1401
|
-
const expr = this._convGen(exprAst, true);
|
|
1402
|
-
// TRUEブロック
|
|
1403
|
-
const trueBlock = trim(cleanGeneratedCode(this._convGen(trueAst, false), 1));
|
|
1404
|
-
// FALSEブロック
|
|
1405
|
-
const falseBlock = trim(cleanGeneratedCode(this._convGen(falseAst, false), 1));
|
|
1406
|
-
let code = '// [convIf]\n' +
|
|
1407
|
-
this.convLineno(node, false) + '\n' +
|
|
1408
|
-
`if (${expr}) {\n` +
|
|
1409
|
-
` ${trueBlock}\n` +
|
|
1410
|
-
'}';
|
|
1411
|
-
if (trim(falseBlock) !== '') {
|
|
1412
|
-
code +=
|
|
1413
|
-
' else {\n' +
|
|
1414
|
-
` ${falseBlock}\n` +
|
|
1415
|
-
'}\n';
|
|
1416
|
-
}
|
|
1417
|
-
code += '\n// [/convIf]\n';
|
|
1418
|
-
return code;
|
|
1419
|
-
}
|
|
1420
|
-
convFuncGetArgsCalcType(_funcName, _func, node) {
|
|
1421
|
-
const args = [];
|
|
1422
|
-
const opts = {};
|
|
1423
|
-
const nodeArgs = (node.blocks) ? node.blocks : [];
|
|
1424
|
-
for (let i = 0; i < nodeArgs.length; i++) {
|
|
1425
|
-
const arg = nodeArgs[i];
|
|
1426
|
-
if (i === 0 && arg === null && this.speedMode.invalidSore === 0) {
|
|
1427
|
-
args.push(this.varname_get('それ'));
|
|
1428
|
-
opts.sore = true;
|
|
1429
|
-
}
|
|
1430
|
-
else {
|
|
1431
|
-
let argCode = this._convGen(arg, true);
|
|
1432
|
-
if (argCode === '') {
|
|
1433
|
-
argCode = 'undefined';
|
|
1434
|
-
}
|
|
1435
|
-
if (typeof argCode !== 'string') {
|
|
1436
|
-
argCode = 'undefined';
|
|
1437
|
-
}
|
|
1438
|
-
args.push(`/*arg${i}*/${argCode}`);
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
return [args, opts];
|
|
1442
|
-
}
|
|
1443
|
-
getPluginList() {
|
|
1444
|
-
const r = [];
|
|
1445
|
-
for (const name in this.__self.__module) {
|
|
1446
|
-
r.push(name);
|
|
1447
|
-
}
|
|
1448
|
-
return r;
|
|
1449
|
-
}
|
|
1450
|
-
/**
|
|
1451
|
-
* 関数の呼び出し
|
|
1452
|
-
* @param {Ast} node
|
|
1453
|
-
* @param {boolean} isExpression
|
|
1454
|
-
* @returns string コード
|
|
1455
|
-
*/
|
|
1456
|
-
convCallFunc(node, isExpression) {
|
|
1457
|
-
const funcName = NakoGen.getFuncName(node.name);
|
|
1458
|
-
const res = this.findVar(funcName);
|
|
1459
|
-
if (res === null) {
|
|
1460
|
-
throw NakoSyntaxError.fromNode(`関数『${funcName}』が見当たりません。有効プラグイン=[` + this.getPluginList().join(', ') + ']', node);
|
|
1461
|
-
}
|
|
1462
|
-
// どの関数を呼び出すのか関数を特定する
|
|
1463
|
-
let func;
|
|
1464
|
-
if (res.i === 0) { // plugin function
|
|
1465
|
-
func = this.__self.getFunc(funcName);
|
|
1466
|
-
if (!func) {
|
|
1467
|
-
throw new Error(`[System Error] 関数「${funcName}」NakoCompiler.nakoFuncList の不整合があります。`);
|
|
1468
|
-
}
|
|
1469
|
-
if (func.type !== 'func') {
|
|
1470
|
-
throw NakoSyntaxError.fromNode(`『${funcName}』は関数ではありません。`, node);
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
else {
|
|
1474
|
-
func = this.nakoFuncList.get(funcName);
|
|
1475
|
-
// 無名関数の可能性
|
|
1476
|
-
if (func === undefined) {
|
|
1477
|
-
func = { return_none: false, asyncFn: !!node.asyncFn };
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
// 関数の参照渡しか?
|
|
1481
|
-
if (node.type === 'func_pointer') {
|
|
1482
|
-
return res.js;
|
|
1483
|
-
}
|
|
1484
|
-
// 関数の参照渡しでない場合
|
|
1485
|
-
// 関数定義より助詞を一つずつ調べる
|
|
1486
|
-
const argsInfo = this.convFuncGetArgsCalcType(funcName, func, node);
|
|
1487
|
-
const args = argsInfo[0];
|
|
1488
|
-
const argsOpts = argsInfo[1];
|
|
1489
|
-
// function
|
|
1490
|
-
this.usedFuncSet.add(funcName);
|
|
1491
|
-
if (funcName === '名前空間設定') {
|
|
1492
|
-
return `\n// --- 名前空間(${args[0]}) ---\n__self.__varslist[0].get('名前空間設定')(${args[0]}, __self);__self.__modName=${args[0]};\n`;
|
|
1493
|
-
}
|
|
1494
|
-
else if (funcName === 'プラグイン名設定') {
|
|
1495
|
-
return `\n__self.__varslist[0].get('プラグイン名設定')(${args[0]}, __self);\n`;
|
|
1496
|
-
}
|
|
1497
|
-
// 関数呼び出しで、引数の末尾にthisを追加する-システム情報を参照するため
|
|
1498
|
-
args.push('__self');
|
|
1499
|
-
let funcDef = 'function';
|
|
1500
|
-
let funcBegin = '';
|
|
1501
|
-
let funcEnd = '';
|
|
1502
|
-
// setter?
|
|
1503
|
-
if (node.setter) {
|
|
1504
|
-
funcBegin += ';__self.isSetter = true;\n';
|
|
1505
|
-
funcEnd += ';__self.isSetter = false;\n';
|
|
1506
|
-
}
|
|
1507
|
-
// 関数内 (__varslist.length > 3) からプラグイン関数 (res.i === 0) を呼び出すとき、 そのプラグイン関数がpureでなければ
|
|
1508
|
-
// 呼び出しの直前に全てのローカル変数をthis.__localsに入れる。
|
|
1509
|
-
if (res.i === 0 && this.varslistSet.length > 3 && func.pure !== true && this.speedMode.forcePure === 0) { // undefinedはfalseとみなす
|
|
1510
|
-
// 展開されたローカル変数の列挙
|
|
1511
|
-
const localVars = [];
|
|
1512
|
-
for (const name of Array.from(this.varsSet.names.values())) {
|
|
1513
|
-
if (NakoGen.isValidIdentifier(name)) {
|
|
1514
|
-
localVars.push({ str: JSON.stringify(name), js: this.varname_get(name) });
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
// --- 実行前 ---
|
|
1518
|
-
// 全ての展開されていないローカル変数を __self.__locals にコピーする
|
|
1519
|
-
funcBegin += '__self.__locals = __vars;\n';
|
|
1520
|
-
// 全ての展開されたローカル変数を __self.__locals に保存する
|
|
1521
|
-
if (localVars.length > 0) {
|
|
1522
|
-
funcBegin += '/* 全ての展開されたローカル変数を __self.__locals に保存 */\n';
|
|
1523
|
-
for (const v of localVars) {
|
|
1524
|
-
funcBegin += `__self.__locals.set(${v.str}, ${v.js});\n`;
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1527
|
-
// --- 実行後 ---
|
|
1528
|
-
// 全ての展開されたローカル変数を __self.__locals から受け取る
|
|
1529
|
-
// 「それ」は関数の実行結果を受け取るために使うためスキップ。
|
|
1530
|
-
if (localVars.length > 0) {
|
|
1531
|
-
funcEnd += '/* 全ての展開されたローカル変数を __self.__locals から受け取る */\n';
|
|
1532
|
-
for (const v of localVars) {
|
|
1533
|
-
if (v.js !== 'それ') {
|
|
1534
|
-
funcEnd += `__self.__varslist[2].set(${v.str}, __self.__locals[${v.str}]);\n`;
|
|
1535
|
-
}
|
|
1536
|
-
}
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
|
-
// 変数「それ」が補完されていることをヒントとして出力
|
|
1540
|
-
if (argsOpts.sore) {
|
|
1541
|
-
funcBegin += '/*[sore]*/';
|
|
1542
|
-
}
|
|
1543
|
-
const indent = (text, n) => {
|
|
1544
|
-
let result = '';
|
|
1545
|
-
for (const line of text.split('\n')) {
|
|
1546
|
-
if (line !== '') {
|
|
1547
|
-
result += ' '.repeat(n) + line + '\n';
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
return result;
|
|
1551
|
-
};
|
|
1552
|
-
// 引数チェックの例外 #1260
|
|
1553
|
-
const noCheckFuncs = { 'TYPEOF': true, '変数型確認': true };
|
|
1554
|
-
// 関数呼び出しコードの構築
|
|
1555
|
-
let argsCode;
|
|
1556
|
-
if ((!this.warnUndefinedCallingUserFunc && res.i !== 0) || (!this.warnUndefinedCallingSystemFunc && res.i === 0)) {
|
|
1557
|
-
argsCode = args.join(',');
|
|
1558
|
-
}
|
|
1559
|
-
else {
|
|
1560
|
-
const argsA = [];
|
|
1561
|
-
args.forEach((arg) => {
|
|
1562
|
-
if (arg === '__self' || noCheckFuncs[funcName] === true) { // #1260
|
|
1563
|
-
argsA.push(`${arg}`);
|
|
1564
|
-
}
|
|
1565
|
-
else {
|
|
1566
|
-
// 引数のundefinedチェックのコードを入れる
|
|
1567
|
-
const msg = (res.i === 0) ? '命令『$0』の引数にundefinedを渡しています。' : 'ユーザ命令『$0』の引数にundefinedを渡しています。';
|
|
1568
|
-
const poolIndex = this.addConstPool(msg, [funcName], node.file, node.line);
|
|
1569
|
-
// argが空になる対策 #1315
|
|
1570
|
-
const argStr = (arg === '') ? '""' : arg;
|
|
1571
|
-
argsA.push(`(__self.chk(${argStr}, ${poolIndex}))`);
|
|
1572
|
-
}
|
|
1573
|
-
});
|
|
1574
|
-
argsCode = argsA.join(', ');
|
|
1575
|
-
}
|
|
1576
|
-
let funcCall = `${res.js}(${argsCode})`;
|
|
1577
|
-
if (func.asyncFn) {
|
|
1578
|
-
funcDef = `async ${funcDef}`;
|
|
1579
|
-
funcCall = `await ${funcCall}`;
|
|
1580
|
-
this.numAsyncFn++;
|
|
1581
|
-
this.usedAsyncFn = true;
|
|
1582
|
-
// 非同期関数の呼び出し前に __self.__vars を待避しておく必要がある (#1758)
|
|
1583
|
-
const varI = `$nako_i${this.loopId}`;
|
|
1584
|
-
this.loopId++;
|
|
1585
|
-
funcBegin += `const __local_async${varI} = __self.__vars;\n`;
|
|
1586
|
-
funcEnd += `__self.__vars = __local_async${varI};\n`;
|
|
1587
|
-
}
|
|
1588
|
-
if (res.i === 0 && this.performanceMonitor.systemFunctionBody !== 0) {
|
|
1589
|
-
let key = funcName;
|
|
1590
|
-
if (!key) {
|
|
1591
|
-
if (typeof this.performanceMonitor.mumeiId === 'undefined') {
|
|
1592
|
-
this.performanceMonitor.mumeiId = 0;
|
|
1593
|
-
}
|
|
1594
|
-
this.performanceMonitor.mumeiId++;
|
|
1595
|
-
key = `anous_${this.performanceMonitor.mumeiId}`;
|
|
1596
|
-
}
|
|
1597
|
-
funcCall = `(${funcDef} (key, type) {\n` +
|
|
1598
|
-
'const sbf_start = performance.now() * 1000;\n' +
|
|
1599
|
-
'try {\n' +
|
|
1600
|
-
'return ' + funcCall + ';\n' +
|
|
1601
|
-
'} finally {\n' +
|
|
1602
|
-
'const sbl_time = performance.now() * 1000 - sbf_start;\n' +
|
|
1603
|
-
'if (!__self.__performance_monitor) {\n' +
|
|
1604
|
-
'__self.__performance_monitor={};\n' +
|
|
1605
|
-
'__self.__performance_monitor[key] = { called:1, totel_usec: sbl_time, min_usec: sbl_time, max_usec: sbl_time, type: type };\n' +
|
|
1606
|
-
'} else if (!__self.__performance_monitor[key]) {\n' +
|
|
1607
|
-
'__self.__performance_monitor[key] = { called:1, totel_usec: sbl_time, min_usec: sbl_time, max_usec: sbl_time, type: type };\n' +
|
|
1608
|
-
'} else {\n' +
|
|
1609
|
-
'__self.__performance_monitor[key].called++;\n' +
|
|
1610
|
-
'__self.__performance_monitor[key].totel_usec+=sbl_time;\n' +
|
|
1611
|
-
'if(__self.__performance_monitor[key].min_usec>sbl_time){__self.__performance_monitor[key].min_usec=sbl_time;}\n' +
|
|
1612
|
-
'if(__self.__performance_monitor[key].max_usec<sbl_time){__self.__performance_monitor[key].max_usec=sbl_time;}\n' +
|
|
1613
|
-
`}}})('${funcName}_body', 'sysbody')\n`;
|
|
1614
|
-
}
|
|
1615
|
-
let code = '';
|
|
1616
|
-
if (func.return_none) {
|
|
1617
|
-
// ------------------------------------
|
|
1618
|
-
// 戻り値のない関数の場合
|
|
1619
|
-
// ------------------------------------
|
|
1620
|
-
if (funcEnd === '') {
|
|
1621
|
-
code = `/*VOID関数呼出*/${funcBegin}${funcCall}\n`;
|
|
1622
|
-
}
|
|
1623
|
-
else {
|
|
1624
|
-
code = `/*VOID関数呼出(前後処理付)*/${funcBegin}try {\n${indent(funcCall, 1)};\n} finally {\n${indent(funcEnd, 1)}}\n`;
|
|
1625
|
-
}
|
|
1626
|
-
// 行番号を追加
|
|
1627
|
-
code = this.convLineno(node, false) + code;
|
|
1628
|
-
}
|
|
1629
|
-
else {
|
|
1630
|
-
// ------------------------------------
|
|
1631
|
-
// 戻り値のある関数の場合
|
|
1632
|
-
// ------------------------------------
|
|
1633
|
-
let sorePrefex = '';
|
|
1634
|
-
let sorePostfix = '';
|
|
1635
|
-
if (this.speedMode.invalidSore === 0) {
|
|
1636
|
-
// 関数の戻り値を記録
|
|
1637
|
-
sorePrefex = '__self.__setSore(';
|
|
1638
|
-
sorePostfix = ')';
|
|
1639
|
-
}
|
|
1640
|
-
if (funcBegin === '' && funcEnd === '') {
|
|
1641
|
-
code = `${sorePrefex}${funcCall}${sorePostfix}`;
|
|
1642
|
-
}
|
|
1643
|
-
else {
|
|
1644
|
-
if (funcEnd === '') {
|
|
1645
|
-
const funcBody = `${sorePrefex}${funcCall}${sorePostfix}`;
|
|
1646
|
-
const funcObj = `${funcDef}(){ return ${funcBody} }`;
|
|
1647
|
-
const funcCallThis = `(${funcObj}).call(this)`;
|
|
1648
|
-
code = `/* funcCallThis1 */${funcCallThis}`;
|
|
1649
|
-
}
|
|
1650
|
-
else { // つまり、pure=falseの場合
|
|
1651
|
-
const varI = `$nako_i${this.loopId}`;
|
|
1652
|
-
this.loopId++;
|
|
1653
|
-
code = `/* funcCallThis2 */(${funcDef}(){\n` +
|
|
1654
|
-
indent(funcBegin, 1) + '\n' +
|
|
1655
|
-
indent('try {', 1) + '\n' +
|
|
1656
|
-
indent(`let ${varI} = ${funcCall};`, 2) + '\n' +
|
|
1657
|
-
indent(`return ${varI};`, 2) + '\n' +
|
|
1658
|
-
indent('} finally {', 2) + '\n' +
|
|
1659
|
-
indent(funcEnd, 1) + '\n' +
|
|
1660
|
-
indent('}', 1) + '\n' +
|
|
1661
|
-
'}).call(this)';
|
|
1662
|
-
if (func.asyncFn) {
|
|
1663
|
-
code = `await (${code})`;
|
|
1664
|
-
}
|
|
1665
|
-
code = `${sorePrefex}${code}${sorePostfix}`;
|
|
1666
|
-
}
|
|
1667
|
-
}
|
|
1668
|
-
// ...して
|
|
1669
|
-
if (node.josi === 'して' || (node.josi === '' && !isExpression)) {
|
|
1670
|
-
code = this.convLineno(node, false) + code;
|
|
1671
|
-
code += ';\n';
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
if (res.i === 0 && this.performanceMonitor.systemFunction !== 0) {
|
|
1675
|
-
code = '(function (key, type) {\n' +
|
|
1676
|
-
'const sf_start = performance.now() * 1000;\n' +
|
|
1677
|
-
'try {\n' +
|
|
1678
|
-
'return ' + code + ';\n' +
|
|
1679
|
-
'} finally {\n' +
|
|
1680
|
-
'const sl_time = performance.now() * 1000 - sf_start;\n' +
|
|
1681
|
-
'if (!__self.__performance_monitor) {\n' +
|
|
1682
|
-
'__self.__performance_monitor={};\n' +
|
|
1683
|
-
'__self.__performance_monitor[key] = { called:1, totel_usec: sl_time, min_usec: sl_time, max_usec: sl_time, type: type };\n' +
|
|
1684
|
-
'} else if (!__self.__performance_monitor[key]) {\n' +
|
|
1685
|
-
'__self.__performance_monitor[key] = { called:1, totel_usec: sl_time, min_usec: sl_time, max_usec: sl_time, type: type };\n' +
|
|
1686
|
-
'} else {\n' +
|
|
1687
|
-
'__self.__performance_monitor[key].called++;\n' +
|
|
1688
|
-
'__self.__performance_monitor[key].totel_usec+=sl_time;\n' +
|
|
1689
|
-
'if(__self.__performance_monitor[key].min_usec>sl_time){__self.__performance_monitor[key].min_usec=sl_time;}\n' +
|
|
1690
|
-
'if(__self.__performance_monitor[key].max_usec<sl_time){__self.__performance_monitor[key].max_usec=sl_time;}\n' +
|
|
1691
|
-
`}}})('${funcName}_sys', 'system')\n`;
|
|
1692
|
-
}
|
|
1693
|
-
return code;
|
|
1694
|
-
}
|
|
1695
|
-
convCallValue(node, isExpression) {
|
|
1696
|
-
const callee = this._convGen(node.blocks[0], true);
|
|
1697
|
-
const args = node.blocks.slice(1).map((arg) => this._convGen(arg, true));
|
|
1698
|
-
args.push('__self');
|
|
1699
|
-
const funcCall = `${callee}(${args.join(',')})`;
|
|
1700
|
-
if (isExpression) {
|
|
1701
|
-
return funcCall;
|
|
1702
|
-
}
|
|
1703
|
-
const sorePrefex = (this.speedMode.invalidSore === 0) ? '__self.__setSore(' : '';
|
|
1704
|
-
const sorePostfix = (this.speedMode.invalidSore === 0) ? ')' : '';
|
|
1705
|
-
return this.convLineno(node, false) + `${sorePrefex}${funcCall}${sorePostfix};\n`;
|
|
1706
|
-
}
|
|
1707
|
-
convRenbun(node) {
|
|
1708
|
-
const right = this._convGen(node.blocks[1], true);
|
|
1709
|
-
const left = this._convGen(node.blocks[0], false);
|
|
1710
|
-
this.numAsyncFn++;
|
|
1711
|
-
this.usedAsyncFn = true;
|
|
1712
|
-
return `/*[連文]*/await (async function(){ ${left}; return ${right} }).call(this)/*[/連文]*/`;
|
|
1713
|
-
}
|
|
1714
|
-
convOp(node) {
|
|
1715
|
-
// トークン名からJS演算子への変換 - 単純な変換が可能なものをここで定義
|
|
1716
|
-
const OP_TBL = {
|
|
1717
|
-
'&': '+""+',
|
|
1718
|
-
eq: '==',
|
|
1719
|
-
noteq: '!=',
|
|
1720
|
-
'===': '===',
|
|
1721
|
-
'!==': '!==',
|
|
1722
|
-
gt: '>',
|
|
1723
|
-
lt: '<',
|
|
1724
|
-
gteq: '>=',
|
|
1725
|
-
lteq: '<=',
|
|
1726
|
-
and: '&&',
|
|
1727
|
-
or: '||',
|
|
1728
|
-
shift_l: '<<',
|
|
1729
|
-
shift_r: '>>',
|
|
1730
|
-
shift_r0: '>>>',
|
|
1731
|
-
'÷': '/'
|
|
1732
|
-
};
|
|
1733
|
-
let op = node.operator || ''; // 演算子
|
|
1734
|
-
let right = this._convGen(node.blocks[1], true);
|
|
1735
|
-
let left = this._convGen(node.blocks[0], true);
|
|
1736
|
-
if (op === '+' && this.speedMode.implicitTypeCasting === 0) {
|
|
1737
|
-
if (node.blocks[0] && (node.blocks[0]).type !== 'number' && (node.blocks[0]).type !== 'bigint') {
|
|
1738
|
-
left = `self.__parseFloatOrBigint(${left})`;
|
|
1739
|
-
}
|
|
1740
|
-
if (node.blocks[1] && (node.blocks[1]).type !== 'number' && (node.blocks[1]).type !== 'bigint') {
|
|
1741
|
-
right = `self.__parseFloatOrBigint(${right})`;
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
// 階乗
|
|
1745
|
-
if (op === '^' || op === '**') {
|
|
1746
|
-
return `((${left}) ** (${right}))`;
|
|
1747
|
-
}
|
|
1748
|
-
// 整数の割り算 #1152
|
|
1749
|
-
if (op === '÷÷') {
|
|
1750
|
-
return `(Math.floor(${left} / ${right}))`;
|
|
1751
|
-
}
|
|
1752
|
-
// 一般的なオペレータに変換
|
|
1753
|
-
if (OP_TBL[op]) {
|
|
1754
|
-
op = OP_TBL[op];
|
|
1755
|
-
}
|
|
1756
|
-
//
|
|
1757
|
-
return `(${left} ${op} ${right})`;
|
|
1758
|
-
}
|
|
1759
|
-
convInc(node) {
|
|
1760
|
-
// idを得る
|
|
1761
|
-
const id = this.loopId++;
|
|
1762
|
-
const valueVar = `$nako_v${id}`;
|
|
1763
|
-
// もし値が省略されていたら、変数「それ」に代入する
|
|
1764
|
-
let incValue = '1';
|
|
1765
|
-
if (this.speedMode.invalidSore === 0) {
|
|
1766
|
-
incValue = this.varname_get('それ');
|
|
1767
|
-
}
|
|
1768
|
-
const astValue = node.blocks[0];
|
|
1769
|
-
if (astValue.type !== 'nop') {
|
|
1770
|
-
incValue = this._convGen(astValue, true);
|
|
1771
|
-
}
|
|
1772
|
-
// 配列への代入か(core#86)
|
|
1773
|
-
let code = '';
|
|
1774
|
-
let varGetter = '';
|
|
1775
|
-
let varSetter = '';
|
|
1776
|
-
let varInitter = '';
|
|
1777
|
-
const nodeName = node.name;
|
|
1778
|
-
if (nodeName.type === 'ref_array') {
|
|
1779
|
-
varGetter = this.convRefArray(nodeName);
|
|
1780
|
-
varSetter = `${varGetter} = ${valueVar}`;
|
|
1781
|
-
varInitter = `${varGetter} = 0`;
|
|
1782
|
-
}
|
|
1783
|
-
else if (nodeName.type === 'ref_prop') {
|
|
1784
|
-
// プロパティアクセス(A$a)の場合 (#1793)
|
|
1785
|
-
const baseName = this._convGen(nodeName.name, true);
|
|
1786
|
-
const propList = nodeName.index;
|
|
1787
|
-
// __getProp/__setPropを持つオブジェクトにも対応するgetter/setter生成
|
|
1788
|
-
const buildPropGetter = (targetExpr, propKey) => `(()=>{const __nako_obj=${targetExpr};` +
|
|
1789
|
-
`return (__nako_obj!=null&&typeof __nako_obj.__getProp==='function')` +
|
|
1790
|
-
`?__nako_obj.__getProp(${propKey}, __self)` +
|
|
1791
|
-
`:__nako_obj[${propKey}]})()`;
|
|
1792
|
-
const buildPropSetter = (targetExpr, propKey, valueExpr) => `(()=>{const __nako_obj=${targetExpr};` +
|
|
1793
|
-
`return (__nako_obj!=null&&typeof __nako_obj.__setProp==='function')` +
|
|
1794
|
-
`?__nako_obj.__setProp(${propKey}, ${valueExpr}, __self)` +
|
|
1795
|
-
`:(__nako_obj[${propKey}]=${valueExpr})})()`;
|
|
1796
|
-
const propKeys = propList.map((prop) => JSON.stringify(prop.value));
|
|
1797
|
-
// getter: 全プロパティを順にたどる
|
|
1798
|
-
let currentExpr = baseName;
|
|
1799
|
-
for (const propKey of propKeys) {
|
|
1800
|
-
currentExpr = buildPropGetter(currentExpr, propKey);
|
|
1801
|
-
}
|
|
1802
|
-
varGetter = currentExpr;
|
|
1803
|
-
// setter/initter: 最後のプロパティだけsetterで、残りはgetterでたどる
|
|
1804
|
-
let parentExpr = baseName;
|
|
1805
|
-
for (const propKey of propKeys.slice(0, -1)) {
|
|
1806
|
-
parentExpr = buildPropGetter(parentExpr, propKey);
|
|
1807
|
-
}
|
|
1808
|
-
const lastPropKey = propKeys[propKeys.length - 1];
|
|
1809
|
-
varSetter = buildPropSetter(parentExpr, lastPropKey, valueVar);
|
|
1810
|
-
varInitter = buildPropSetter(parentExpr, lastPropKey, '0');
|
|
1811
|
-
}
|
|
1812
|
-
else {
|
|
1813
|
-
// 変数名
|
|
1814
|
-
const name = nodeName.value;
|
|
1815
|
-
let res = this.findVar(name, valueVar);
|
|
1816
|
-
if (res === null) {
|
|
1817
|
-
this.varsSet.names.add(name);
|
|
1818
|
-
res = this.findVar(name, valueVar);
|
|
1819
|
-
if (!res) {
|
|
1820
|
-
throw new Error('『増』または『減』で変数が見当たりません。');
|
|
1821
|
-
}
|
|
1822
|
-
}
|
|
1823
|
-
varGetter = res.js;
|
|
1824
|
-
varSetter = res.js_set;
|
|
1825
|
-
res = this.findVar(name, '0');
|
|
1826
|
-
if (res !== null) {
|
|
1827
|
-
varInitter = res.js_set;
|
|
1828
|
-
}
|
|
1829
|
-
}
|
|
1830
|
-
// 自動初期化するか
|
|
1831
|
-
code += '\n/*[convInc]*/\n';
|
|
1832
|
-
code += this.convLineno(node, false) + '\n';
|
|
1833
|
-
code += `let ${valueVar} = ${varGetter}\n`;
|
|
1834
|
-
code += `if (typeof ${valueVar} === 'undefined') { ${varInitter}; }\n`;
|
|
1835
|
-
code += `${valueVar} = Number(${varGetter}) + Number(${incValue});\n`;
|
|
1836
|
-
code += `${varSetter}\n`;
|
|
1837
|
-
code += '/*[/convInc]*/\n';
|
|
1838
|
-
return code;
|
|
1839
|
-
}
|
|
1840
|
-
convLet(node) {
|
|
1841
|
-
const astValue = node.blocks[0];
|
|
1842
|
-
// もし値が省略されていたら、変数「それ」に代入する
|
|
1843
|
-
let value = null;
|
|
1844
|
-
if (this.speedMode.invalidSore === 0) {
|
|
1845
|
-
value = this.varname_get('それ');
|
|
1846
|
-
}
|
|
1847
|
-
// 値のプログラムを生成
|
|
1848
|
-
if (astValue) {
|
|
1849
|
-
// 関数の戻り値がない場合はエラーを出す
|
|
1850
|
-
if (astValue.type === 'func' && astValue.name !== undefined) {
|
|
1851
|
-
const astFunc = astValue;
|
|
1852
|
-
const func = this.__self.getFunc(astFunc.name);
|
|
1853
|
-
if (func && func.return_none) {
|
|
1854
|
-
throw NakoSyntaxError.fromNode(`関数『${astValue.name}』は戻り値がないので結果を代入できません。`, node);
|
|
1855
|
-
}
|
|
1856
|
-
}
|
|
1857
|
-
value = this._convGen(astValue, true);
|
|
1858
|
-
}
|
|
1859
|
-
// 戻り値の検証
|
|
1860
|
-
if (value === null) {
|
|
1861
|
-
throw NakoSyntaxError.fromNode('代入する先の変数名がありません。', node);
|
|
1862
|
-
}
|
|
1863
|
-
// 変数名
|
|
1864
|
-
const name = node.name;
|
|
1865
|
-
const res = this.findVar(name, value);
|
|
1866
|
-
let code = '/*[convLet]*/';
|
|
1867
|
-
if (res === null) {
|
|
1868
|
-
this.varsSet.names.add(name);
|
|
1869
|
-
code = `${this.varname_set(name, value)};`;
|
|
1870
|
-
}
|
|
1871
|
-
else {
|
|
1872
|
-
// 定数ならエラーを出す
|
|
1873
|
-
if (this.varslistSet[res.i].readonly.has(name)) {
|
|
1874
|
-
throw NakoSyntaxError.fromNode(`定数『${name}』は既に定義済みなので、値を代入することはできません。`, node);
|
|
1875
|
-
}
|
|
1876
|
-
code = `${res.js_set};`;
|
|
1877
|
-
}
|
|
1878
|
-
return ';' + this.convLineno(node, false) + code + '\n';
|
|
1879
|
-
}
|
|
1880
|
-
// プロパティへの代入式 (#1793)
|
|
1881
|
-
convLetProp(node) {
|
|
1882
|
-
if (!node.index || node.index.length === 0) {
|
|
1883
|
-
throw NakoSyntaxError.fromNode('代入する先のプロパティ名がありません。', node);
|
|
1884
|
-
}
|
|
1885
|
-
if (!node.blocks || node.blocks.length === 0) {
|
|
1886
|
-
throw NakoSyntaxError.fromNode('代入する値がありません。', node);
|
|
1887
|
-
}
|
|
1888
|
-
const propList = node.index;
|
|
1889
|
-
const propTopAst = propList.pop();
|
|
1890
|
-
if (propTopAst === undefined) {
|
|
1891
|
-
throw NakoSyntaxError.fromNode('代入する先のプロパティ名がありません。', node);
|
|
1892
|
-
}
|
|
1893
|
-
const propTop = (typeof propTopAst.value === 'string') ? propTopAst.value : '';
|
|
1894
|
-
const astValue = node.blocks[0];
|
|
1895
|
-
let value = null;
|
|
1896
|
-
// 値のプログラムを生成
|
|
1897
|
-
if (astValue) {
|
|
1898
|
-
value = this._convGen(astValue, true);
|
|
1899
|
-
}
|
|
1900
|
-
else {
|
|
1901
|
-
throw NakoSyntaxError.fromNode('代入する値がありません。', node);
|
|
1902
|
-
}
|
|
1903
|
-
// 変数名
|
|
1904
|
-
const name = node.name;
|
|
1905
|
-
const res = this.findVar(name, value);
|
|
1906
|
-
let code = '/*[convLetProp]*/\n';
|
|
1907
|
-
// 変数が存在しないとき
|
|
1908
|
-
if (res === null) {
|
|
1909
|
-
throw NakoSyntaxError.fromNode(`変数『${name}』が見当たりません。`, node);
|
|
1910
|
-
}
|
|
1911
|
-
// 変数のプロパティ
|
|
1912
|
-
let nameJs = res.js;
|
|
1913
|
-
// 配列アクセス
|
|
1914
|
-
if (node.blocks.length >= 2) {
|
|
1915
|
-
for (let i = 1; i < node.blocks.length; i++) {
|
|
1916
|
-
const indexNode = node.blocks[i];
|
|
1917
|
-
const indexJs = this._convGen(indexNode, true);
|
|
1918
|
-
nameJs += `[${indexJs}]`;
|
|
1919
|
-
}
|
|
1920
|
-
}
|
|
1921
|
-
if (propList.length > 0) {
|
|
1922
|
-
for (const prop of propList) {
|
|
1923
|
-
if (typeof prop.value === 'string') {
|
|
1924
|
-
nameJs += `['${prop.value}']`;
|
|
1925
|
-
}
|
|
1926
|
-
else {
|
|
1927
|
-
throw NakoSyntaxError.fromNode(`変数『${nameJs}』以下のプロパティにアクセスできません。`, node);
|
|
1928
|
-
}
|
|
1929
|
-
}
|
|
1930
|
-
}
|
|
1931
|
-
// プロパティへの代入式を作る
|
|
1932
|
-
code += `if (typeof ${nameJs}.__setProp === 'function') { ${nameJs}.__setProp('${propTop}', ${value}, __self); } else { `;
|
|
1933
|
-
code += `__self.__checkPropAccessor('set', ${nameJs});`;
|
|
1934
|
-
code += `if (typeof ${nameJs}.__setProp === 'function') { ${nameJs}.__setProp('${propTop}', ${value}, __self); } else { `;
|
|
1935
|
-
code += `${nameJs}['${propTop}'] = ${value} }};`;
|
|
1936
|
-
return ';' + this.convLineno(node, false) + code + '\n';
|
|
1937
|
-
}
|
|
1938
|
-
// プロパティへの参照 (#1793)
|
|
1939
|
-
convRefProp(node) {
|
|
1940
|
-
const name = this._convGen(node.name, true);
|
|
1941
|
-
const list = node.index;
|
|
1942
|
-
if (!list || list.length <= 0) {
|
|
1943
|
-
throw NakoSyntaxError.fromNode('プロパティがありません。', node);
|
|
1944
|
-
}
|
|
1945
|
-
return this.convRefProp_genCode(name, list);
|
|
1946
|
-
}
|
|
1947
|
-
// プロパティへの参照のコード生成部分 (#1793)
|
|
1948
|
-
convRefProp_genCode(name, propList) {
|
|
1949
|
-
let code;
|
|
1950
|
-
if (propList.length <= 1) {
|
|
1951
|
-
const propKey = propList[0].value;
|
|
1952
|
-
const codeCall = `${name}.__getProp('${propKey}', __self)`;
|
|
1953
|
-
const codeProp = `${name}['${propKey}']`;
|
|
1954
|
-
const codeCheckAccessor = `__self.__checkPropAccessor('get', ${name});\n` +
|
|
1955
|
-
`if (typeof ${name}.__getProp === 'function') { return ${codeCall} }\n` +
|
|
1956
|
-
`return ${codeProp}\n`;
|
|
1957
|
-
const codeIf = `if (${name}.__getProp) { return ${codeCall} } else { ${codeCheckAccessor} }`;
|
|
1958
|
-
code = `( (()=>{ ${codeIf} })() )`;
|
|
1959
|
-
}
|
|
1960
|
-
else {
|
|
1961
|
-
const arrs = [];
|
|
1962
|
-
const keys = [];
|
|
1963
|
-
for (let i = 0; i < propList.length; i++) {
|
|
1964
|
-
const propKey = propList[i].value;
|
|
1965
|
-
keys.push(`['${propKey}']`);
|
|
1966
|
-
arrs.push(`'${propKey}'`);
|
|
1967
|
-
}
|
|
1968
|
-
const keyStr = keys.join('');
|
|
1969
|
-
const arrStr = '[' + arrs.join(',') + ']';
|
|
1970
|
-
const codeCall = `${name}.__getProp(${arrStr}, __self)`;
|
|
1971
|
-
const codeProp = `${name}${keyStr}`;
|
|
1972
|
-
const codeCheckAccessor = `__self.__checkPropAccessor('get', ${name});\n` +
|
|
1973
|
-
`if (${name}.__getProp) { return ${codeCall} }\n` +
|
|
1974
|
-
`return ${codeProp}\n`;
|
|
1975
|
-
const codeIf = `if (${name}.__getProp) { return ${codeCall} } else { ${codeCheckAccessor} }`;
|
|
1976
|
-
code = `( (()=>{ ${codeIf} })() )`;
|
|
1977
|
-
}
|
|
1978
|
-
return code;
|
|
1979
|
-
}
|
|
1980
|
-
convDefLocalVar(node) {
|
|
1981
|
-
const astValue = node.blocks[0];
|
|
1982
|
-
let value = '0';
|
|
1983
|
-
if (astValue.type !== 'nop') {
|
|
1984
|
-
value = this._convGen(astValue, true);
|
|
1985
|
-
}
|
|
1986
|
-
const name = node.name; // 変数名
|
|
1987
|
-
const vtype = node.vartype; // 変数 or 定数
|
|
1988
|
-
// 二重定義?
|
|
1989
|
-
if (this.varsSet.names.has(name)) {
|
|
1990
|
-
throw NakoSyntaxError.fromNode(`${vtype}『${name}』の二重定義はできません。`, node);
|
|
1991
|
-
}
|
|
1992
|
-
//
|
|
1993
|
-
this.varsSet.names.add(name);
|
|
1994
|
-
if (vtype === '定数') {
|
|
1995
|
-
this.varsSet.readonly.add(name);
|
|
1996
|
-
}
|
|
1997
|
-
const code = `/*${vtype}*/${this.varname_set(name, value)};\n`;
|
|
1998
|
-
return this.convLineno(node, false) + code;
|
|
1999
|
-
}
|
|
2000
|
-
// #563 複数変数への代入
|
|
2001
|
-
convDefLocalVarlist(node) {
|
|
2002
|
-
let code = '';
|
|
2003
|
-
const vtype = node.vartype; // 変数 or 定数
|
|
2004
|
-
// 初期値を取得
|
|
2005
|
-
let value = '0';
|
|
2006
|
-
if (node.blocks.length > 0) {
|
|
2007
|
-
const astValue = node.blocks[0];
|
|
2008
|
-
if (astValue.type !== 'nop') {
|
|
2009
|
-
value = this._convGen(astValue, true);
|
|
2010
|
-
}
|
|
2011
|
-
}
|
|
2012
|
-
// 代入する変数名を取得
|
|
2013
|
-
const id = this.loopId++;
|
|
2014
|
-
const varI = `$nako_i${id}`;
|
|
2015
|
-
code += `let ${varI} = ${value}\n`;
|
|
2016
|
-
code += `if (!(${varI} instanceof Array)) { ${varI}=[${varI}] }\n`;
|
|
2017
|
-
const names = (node.names) ? node.names : [];
|
|
2018
|
-
for (let i = 0; i < names.length; i++) {
|
|
2019
|
-
const nameObj = names[i];
|
|
2020
|
-
const name = nameObj.value;
|
|
2021
|
-
// 二重定義?
|
|
2022
|
-
if (this.varsSet.names.has(name)) {
|
|
2023
|
-
// 複数変数文では、二重定義も許容する #1027
|
|
2024
|
-
// throw NakoSyntaxError.fromNode(`${vtype}『${name}』の二重定義はできません。`, node)
|
|
2025
|
-
}
|
|
2026
|
-
this.varsSet.names.add(name);
|
|
2027
|
-
if (vtype === '定数') {
|
|
2028
|
-
this.varsSet.readonly.add(name);
|
|
2029
|
-
}
|
|
2030
|
-
code += this.varname_set(name, `${varI}[${i}]`) + ';\n';
|
|
2031
|
-
}
|
|
2032
|
-
return this.convLineno(node, false) +
|
|
2033
|
-
'/*[convDefLocalVarlist]*/\n' +
|
|
2034
|
-
code +
|
|
2035
|
-
'/*[/convDefLocalVarlist]*/\n';
|
|
2036
|
-
}
|
|
2037
|
-
convString(node) {
|
|
2038
|
-
let value = String(node.value);
|
|
2039
|
-
value = value.replace(/\\/g, '\\\\');
|
|
2040
|
-
value = value.replace(/"/g, '\\"');
|
|
2041
|
-
value = value.replace(/\r/g, '\\r');
|
|
2042
|
-
value = value.replace(/\n/g, '\\n');
|
|
2043
|
-
return '"' + value + '"';
|
|
2044
|
-
}
|
|
2045
|
-
convTryExcept(node) {
|
|
2046
|
-
const block = this._convGen(node.blocks[0], false);
|
|
2047
|
-
const errBlock = this._convGen(node.blocks[1], false);
|
|
2048
|
-
return this.convLineno(node, false) +
|
|
2049
|
-
`try {\n${block}\n} catch (e) {\n` +
|
|
2050
|
-
' __self.__setSysVar("エラーメッセージ", e.message);\n' +
|
|
2051
|
-
';\n' +
|
|
2052
|
-
`${errBlock}}\n`;
|
|
2053
|
-
}
|
|
2054
|
-
getUsedFuncSet() {
|
|
2055
|
-
return this.usedFuncSet;
|
|
2056
|
-
}
|
|
2057
|
-
getPluginInitCode() {
|
|
2058
|
-
// プラグインの初期化関数を実行する
|
|
2059
|
-
let code = '';
|
|
2060
|
-
let pluginCode = '';
|
|
2061
|
-
for (const name in this.__self.__module) {
|
|
2062
|
-
const initkey = `!${name}:初期化`;
|
|
2063
|
-
if (this.varslistSet[0].names.has(initkey)) {
|
|
2064
|
-
const initkeyDone = `!${name}:初期化済`;
|
|
2065
|
-
this.usedFuncSet.add(initkey);
|
|
2066
|
-
pluginCode += `if (!__v0.has('${initkeyDone}')) { __v0.get('${initkey}')(__self); __v0.set('${initkeyDone}', true) }\n`;
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
if (pluginCode !== '') {
|
|
2070
|
-
code += '__v0.set(\'__line\', \'l0:プラグインの初期化\');\n' + pluginCode;
|
|
2071
|
-
}
|
|
2072
|
-
return code;
|
|
2073
|
-
}
|
|
2074
|
-
}
|
|
2075
|
-
/** template of standalone js code */
|
|
2076
|
-
const STANDALONE_CODE = `
|
|
2077
|
-
// === generated by nadesiko3 v__version__(core:__coreVersion__) ===
|
|
2078
|
-
// -----------------------------------------------------------------
|
|
2079
|
-
// <nadesiko3standalone>
|
|
2080
|
-
// -----------------------------------------------------------------
|
|
2081
|
-
// --- import
|
|
2082
|
-
import path from 'path'
|
|
2083
|
-
import { NakoRuntimeError } from './nako3runtime/nako_errors.mjs'
|
|
2084
|
-
__codeImportFiles__
|
|
2085
|
-
// --- init global self
|
|
2086
|
-
const self = {
|
|
2087
|
-
newVariables: () => {
|
|
2088
|
-
const map = new Map()
|
|
2089
|
-
return map
|
|
2090
|
-
}
|
|
2091
|
-
}
|
|
2092
|
-
self.coreVersion = '__coreVersion__'
|
|
2093
|
-
self.version = '__version__'
|
|
2094
|
-
self.logger = {
|
|
2095
|
-
error: (message) => { console.error(message) },
|
|
2096
|
-
warn: (message) => { console.warn(message) },
|
|
2097
|
-
send: (level, message) => { console.log(message) },
|
|
2098
|
-
runtimeError: (message, lineInfo) => { console.error(message, lineInfo) }
|
|
2099
|
-
};
|
|
2100
|
-
self.__varslist = [self.newVariables(), self.newVariables(), self.newVariables()]
|
|
2101
|
-
self.__v0 = self.__varslist[0]
|
|
2102
|
-
self.initFuncList = []
|
|
2103
|
-
self.clearFuncList = []
|
|
2104
|
-
self.__propAccessor = []
|
|
2105
|
-
// --- jsInit ---
|
|
2106
|
-
__jsInit__
|
|
2107
|
-
// --- Copy module functions ---
|
|
2108
|
-
for (const mod of __importNames__) {
|
|
2109
|
-
for (const funcName in mod) {
|
|
2110
|
-
// プラグインの初期化とクリア関数を登録
|
|
2111
|
-
if (funcName === '初期化') {
|
|
2112
|
-
__self.initFuncList.push(mod[funcName].fn)
|
|
2113
|
-
continue
|
|
2114
|
-
}
|
|
2115
|
-
if (funcName === '!クリア') {
|
|
2116
|
-
__self.clearFuncList.push(mod[funcName].fn)
|
|
2117
|
-
continue
|
|
2118
|
-
}
|
|
2119
|
-
// 関数や定数を登録
|
|
2120
|
-
const f = mod[funcName]
|
|
2121
|
-
if (f.type === 'func') { // 関数
|
|
2122
|
-
__self.__varslist[0].set(funcName, f.fn)
|
|
2123
|
-
} else { // 定数
|
|
2124
|
-
__self.__varslist[0].set(funcName, f.value)
|
|
2125
|
-
}
|
|
2126
|
-
}
|
|
2127
|
-
}
|
|
2128
|
-
__self.__vars = __self.__varslist[2];
|
|
2129
|
-
__self.__module = {};
|
|
2130
|
-
__self.__locals = __self.newVariables();
|
|
2131
|
-
__self.__genMode = 'sync';
|
|
2132
|
-
// プラグインの初期化コードを実行
|
|
2133
|
-
__self.initFuncList.map(f => f(self))
|
|
2134
|
-
// standalone
|
|
2135
|
-
__self.__v0.set('__standalone', true)
|
|
2136
|
-
// -----------------------------------------------------------------
|
|
2137
|
-
try {
|
|
2138
|
-
try {
|
|
2139
|
-
// -----------------------------------------------------------------
|
|
2140
|
-
// <prepareMainCode>
|
|
2141
|
-
__codeStandalone__
|
|
2142
|
-
// </prepareMainCode>
|
|
2143
|
-
// -----------------------------------------------------------------
|
|
2144
|
-
// <mainCode>
|
|
2145
|
-
// -----------------------------------------------------------------
|
|
2146
|
-
__codeJS__
|
|
2147
|
-
// -----------------------------------------------------------------
|
|
2148
|
-
// </mainCode>
|
|
2149
|
-
// -----------------------------------------------------------------
|
|
2150
|
-
} catch (err) {
|
|
2151
|
-
__self.logger.error(err);
|
|
2152
|
-
throw err;
|
|
2153
|
-
}
|
|
2154
|
-
} finally {
|
|
2155
|
-
// standaloneCodeでは、即時プラグインのクリアコードを実行
|
|
2156
|
-
__self.clearFuncList.map(f => f(__self))
|
|
2157
|
-
}
|
|
2158
|
-
// -----------------------------------------------------------------
|
|
2159
|
-
// </nadesiko3standalone>
|
|
2160
|
-
// -----------------------------------------------------------------
|
|
2161
|
-
`;
|
|
2162
|
-
/**
|
|
2163
|
-
* @param com
|
|
2164
|
-
* @param ast
|
|
2165
|
-
* @param opt
|
|
2166
|
-
*/
|
|
2167
|
-
export function generateJS(com, ast, opt) {
|
|
2168
|
-
// NakoGenのインスタンスを作成
|
|
2169
|
-
const gen = new NakoGen(com);
|
|
2170
|
-
// ※ [関数定義に関するコード生成のヒント]
|
|
2171
|
-
// ※ 関数の名前だけを(1)で登録して、(2)で実際に関数のコードを生成する。
|
|
2172
|
-
// ※ ただし(2)では生成するだけなので、(3)でプログラム冒頭に関数定義のコードを記述する。
|
|
2173
|
-
// この順番を変えることはできない (グローバル変数が認識できなくなったり、関数定義のタイミングがずれる)
|
|
2174
|
-
// (1) ユーザー定義関数をシステムに登録する
|
|
2175
|
-
gen.registerFunction(ast);
|
|
2176
|
-
// (2) JSコードを生成する
|
|
2177
|
-
let js = trim(cleanGeneratedCode(gen.convGen(ast, opt), 1));
|
|
2178
|
-
// (3) JSコードを実行するための事前ヘッダ部分の生成
|
|
2179
|
-
const jsInit = gen.getDefFuncCode(com, opt);
|
|
2180
|
-
// ランダムな関数名を生成
|
|
2181
|
-
const funcID = String((new Date()).getTime()) + '_' + Math.floor(0xFFFFFFFF * Math.random()).toString();
|
|
2182
|
-
// テストの実行
|
|
2183
|
-
if (js && opt.isTest) {
|
|
2184
|
-
js += '\n__self._runTests(__tests);\n';
|
|
2185
|
-
}
|
|
2186
|
-
// async method
|
|
2187
|
-
if (gen.numAsyncFn > 0 || gen.debugOption.useDebug) {
|
|
2188
|
-
const asyncMain = '__eval_nako3async_' + funcID + '__';
|
|
2189
|
-
js = `
|
|
2190
|
-
// ------------------------------------------------------------------
|
|
2191
|
-
// <nadesiko3::gen::async id="${funcID}" times="${gen.numAsyncFn}">
|
|
2192
|
-
// ------------------------------------------------------------------
|
|
2193
|
-
async function ${asyncMain}(__self) {
|
|
2194
|
-
// --- code_begin ---
|
|
2195
|
-
${js}
|
|
2196
|
-
// --- code_end ---
|
|
2197
|
-
// __処理末尾__ // ← テストなどで必要なので消さない
|
|
2198
|
-
} // end of ${asyncMain}
|
|
2199
|
-
// ------------------------------------------------------------------
|
|
2200
|
-
// call ${asyncMain}
|
|
2201
|
-
(async () => {
|
|
2202
|
-
if (__self.__v0.get('__standalone')) {
|
|
2203
|
-
await ${asyncMain}(self);
|
|
2204
|
-
} else {
|
|
2205
|
-
${asyncMain}.call(self, self)
|
|
2206
|
-
.then(() => { /* __async_ok__ */ })
|
|
2207
|
-
.catch(err => {
|
|
2208
|
-
if (err.message === '__終わる__') { return }
|
|
2209
|
-
__self.numFailures++
|
|
2210
|
-
// send errors to logger
|
|
2211
|
-
let rterr = __self.logger.runtimeError(err, __self.__v0.get('__line'))
|
|
2212
|
-
__self.logger.error(rterr)
|
|
2213
|
-
})
|
|
2214
|
-
}
|
|
2215
|
-
})();
|
|
2216
|
-
// ------------------------------------------------------------------
|
|
2217
|
-
// </nadesiko3::gen::async id="${funcID}">
|
|
2218
|
-
// ------------------------------------------------------------------
|
|
2219
|
-
`;
|
|
2220
|
-
}
|
|
2221
|
-
else {
|
|
2222
|
-
const syncMain = '__eval_nako3sync_' + funcID + '__';
|
|
2223
|
-
js = `
|
|
2224
|
-
// ------------------------------------------------------------------
|
|
2225
|
-
// <nadesiko3::gen::syncMode>
|
|
2226
|
-
// ------------------------------------------------------------------
|
|
2227
|
-
function ${syncMain}(__self) {
|
|
2228
|
-
try {
|
|
2229
|
-
${js}
|
|
2230
|
-
// __処理末尾__ // ← テストなどで必要なので消さない
|
|
2231
|
-
} catch (err) {
|
|
2232
|
-
if (err.message === '__終わる__') { return }
|
|
2233
|
-
__self.numFailures++
|
|
2234
|
-
throw __self.logger.runtimeError(err, __self.__v0.get('__line'))
|
|
2235
|
-
}
|
|
2236
|
-
} // end of ${syncMain}
|
|
2237
|
-
${syncMain}(__self)
|
|
2238
|
-
// ------------------------------------------------------------------
|
|
2239
|
-
// </nadesiko3::gen::syncMode>
|
|
2240
|
-
// ------------------------------------------------------------------
|
|
2241
|
-
`;
|
|
2242
|
-
}
|
|
2243
|
-
// --- 生成したコードの簡単な整形 ---
|
|
2244
|
-
js = cleanGeneratedCode(js);
|
|
2245
|
-
// デバッグメッセージ
|
|
2246
|
-
let codeImportFiles = '';
|
|
2247
|
-
const importNames = [];
|
|
2248
|
-
for (const f of opt.importFiles) {
|
|
2249
|
-
if (f === 'nako_errors.mjs') {
|
|
2250
|
-
continue;
|
|
2251
|
-
}
|
|
2252
|
-
const ff = 'nako3runtime_' + f.replace(/\.(js|mjs)$/, '').replace(/[^a-zA-Z0-9_]/g, '_');
|
|
2253
|
-
importNames.push(ff);
|
|
2254
|
-
codeImportFiles += `import ${ff} from './nako3runtime/${f}'\n`;
|
|
2255
|
-
}
|
|
2256
|
-
// ---
|
|
2257
|
-
const initCode = gen.getPluginInitCode();
|
|
2258
|
-
const runtimeEnvCode = `
|
|
2259
|
-
// <runtimeEnvCode>
|
|
2260
|
-
const self = this
|
|
2261
|
-
${opt.codeEnv}
|
|
2262
|
-
${jsInit}
|
|
2263
|
-
${initCode}
|
|
2264
|
-
${js}
|
|
2265
|
-
// </runtimeEnvCode>
|
|
2266
|
-
`;
|
|
2267
|
-
com.getLogger().trace('--- generate::jsInit ---\n' + jsInit);
|
|
2268
|
-
com.getLogger().trace('--- generate::js ---\n' + js);
|
|
2269
|
-
return {
|
|
2270
|
-
// なでしこの実行環境ありの場合(thisが有効)
|
|
2271
|
-
runtimeEnv: runtimeEnvCode,
|
|
2272
|
-
// JavaScript単体で動かす場合
|
|
2273
|
-
standalone: replaceTemplateCode(STANDALONE_CODE, {
|
|
2274
|
-
codeImportFiles,
|
|
2275
|
-
'coreVersion': com.coreVersion,
|
|
2276
|
-
'version': com.version,
|
|
2277
|
-
'importNames': ('[' + importNames.join(', ') + ']'),
|
|
2278
|
-
'codeStandalone': opt.codeStandalone,
|
|
2279
|
-
'codeJS': js,
|
|
2280
|
-
jsInit
|
|
2281
|
-
}),
|
|
2282
|
-
// コード生成に使ったNakoGenのインスタンス
|
|
2283
|
-
gen
|
|
2284
|
-
};
|
|
2285
|
-
}
|
|
2286
|
-
// template
|
|
2287
|
-
function replaceTemplateCode(template, values) {
|
|
2288
|
-
for (const key in values) {
|
|
2289
|
-
const pat = `__${key}__`;
|
|
2290
|
-
const val = values[key];
|
|
2291
|
-
template = template.split(pat).join(val);
|
|
2292
|
-
}
|
|
2293
|
-
return template;
|
|
2294
|
-
}
|
|
2295
|
-
// clean generated code
|
|
2296
|
-
function cleanGeneratedCode(code, indent = 0) {
|
|
2297
|
-
// 1. 無意味な改行やセミコロンを削除
|
|
2298
|
-
// 2. 行頭の空白やセミコロンを削除
|
|
2299
|
-
// 3. indent分インデントを追加
|
|
2300
|
-
// ただし、文字列リテラル内の改行やセミコロンは削除しない (#2153)
|
|
2301
|
-
// 文字列リテラル外の連続セミコロンと連続改行を削除
|
|
2302
|
-
code = removeDuplicateChars(code);
|
|
2303
|
-
// indent分インデントを追加
|
|
2304
|
-
let spc = '';
|
|
2305
|
-
for (let i = 0; i < indent; i++) {
|
|
2306
|
-
spc += ' ';
|
|
2307
|
-
}
|
|
2308
|
-
// 行頭の";"を削除
|
|
2309
|
-
const result = [];
|
|
2310
|
-
const lines = code.split('\n');
|
|
2311
|
-
for (let i = 0; i < lines.length; i++) {
|
|
2312
|
-
let line = lines[i];
|
|
2313
|
-
line = line.replace(/^(\s*);/, '$1');
|
|
2314
|
-
if (trim(line) === '') {
|
|
2315
|
-
continue;
|
|
2316
|
-
}
|
|
2317
|
-
result.push(spc + line);
|
|
2318
|
-
}
|
|
2319
|
-
// 結果のコードを返す
|
|
2320
|
-
code = result.join('\n');
|
|
2321
|
-
return code;
|
|
2322
|
-
}
|
|
2323
|
-
/**
|
|
2324
|
-
* 文字列リテラル外の連続セミコロンと連続改行を1つに置換する
|
|
2325
|
-
* 文字列リテラル内のセミコロンと改行は保護する (#2153)
|
|
2326
|
-
* JavaScriptの文字列リテラル、正規表現、テンプレートリテラル、コメントを考慮
|
|
2327
|
-
*/
|
|
2328
|
-
function removeDuplicateChars(code) {
|
|
2329
|
-
const result = [];
|
|
2330
|
-
let i = 0;
|
|
2331
|
-
let inString = false;
|
|
2332
|
-
let inRegex = false;
|
|
2333
|
-
let inTemplate = false;
|
|
2334
|
-
let inLineComment = false;
|
|
2335
|
-
let inBlockComment = false;
|
|
2336
|
-
let stringDelimiter = '';
|
|
2337
|
-
let prevChar = '';
|
|
2338
|
-
let lastSemiPos = -2; // 最後のセミコロンの位置
|
|
2339
|
-
let lastNewlinePos = -2; // 最後の改行の位置
|
|
2340
|
-
/**
|
|
2341
|
-
* 直前のバックスラッシュの数をカウント
|
|
2342
|
-
* 偶数個なら次の文字はエスケープされていない
|
|
2343
|
-
*/
|
|
2344
|
-
const countBackslashes = (pos) => {
|
|
2345
|
-
let count = 0;
|
|
2346
|
-
let p = pos - 1;
|
|
2347
|
-
while (p >= 0 && code.charAt(p) === '\\') {
|
|
2348
|
-
count++;
|
|
2349
|
-
p--;
|
|
2350
|
-
}
|
|
2351
|
-
return count;
|
|
2352
|
-
};
|
|
2353
|
-
while (i < code.length) {
|
|
2354
|
-
const ch = code.charAt(i);
|
|
2355
|
-
const nextCh = i + 1 < code.length ? code.charAt(i + 1) : '';
|
|
2356
|
-
// 行コメントの処理
|
|
2357
|
-
if (inLineComment) {
|
|
2358
|
-
result.push(ch);
|
|
2359
|
-
if (ch === '\n') {
|
|
2360
|
-
inLineComment = false;
|
|
2361
|
-
}
|
|
2362
|
-
prevChar = ch;
|
|
2363
|
-
i++;
|
|
2364
|
-
continue;
|
|
2365
|
-
}
|
|
2366
|
-
// ブロックコメントの処理
|
|
2367
|
-
if (inBlockComment) {
|
|
2368
|
-
result.push(ch);
|
|
2369
|
-
if (ch === '*' && nextCh === '/') {
|
|
2370
|
-
result.push(nextCh);
|
|
2371
|
-
inBlockComment = false;
|
|
2372
|
-
i += 2;
|
|
2373
|
-
prevChar = '/';
|
|
2374
|
-
continue;
|
|
2375
|
-
}
|
|
2376
|
-
prevChar = ch;
|
|
2377
|
-
i++;
|
|
2378
|
-
continue;
|
|
2379
|
-
}
|
|
2380
|
-
// テンプレートリテラルの処理
|
|
2381
|
-
if (inTemplate) {
|
|
2382
|
-
result.push(ch);
|
|
2383
|
-
if (ch === '`') {
|
|
2384
|
-
const backslashCount = countBackslashes(i);
|
|
2385
|
-
if (backslashCount % 2 === 0) {
|
|
2386
|
-
// 偶数個のバックスラッシュ = エスケープされていない
|
|
2387
|
-
inTemplate = false;
|
|
2388
|
-
}
|
|
2389
|
-
}
|
|
2390
|
-
prevChar = ch;
|
|
2391
|
-
i++;
|
|
2392
|
-
continue;
|
|
2393
|
-
}
|
|
2394
|
-
// 正規表現の処理
|
|
2395
|
-
if (inRegex) {
|
|
2396
|
-
result.push(ch);
|
|
2397
|
-
if (ch === '/') {
|
|
2398
|
-
const backslashCount = countBackslashes(i);
|
|
2399
|
-
if (backslashCount % 2 === 0) {
|
|
2400
|
-
inRegex = false;
|
|
2401
|
-
}
|
|
2402
|
-
}
|
|
2403
|
-
prevChar = ch;
|
|
2404
|
-
i++;
|
|
2405
|
-
continue;
|
|
2406
|
-
}
|
|
2407
|
-
// 文字列リテラルの処理
|
|
2408
|
-
if (inString) {
|
|
2409
|
-
result.push(ch);
|
|
2410
|
-
if (ch === stringDelimiter) {
|
|
2411
|
-
const backslashCount = countBackslashes(i);
|
|
2412
|
-
if (backslashCount % 2 === 0) {
|
|
2413
|
-
// 偶数個のバックスラッシュ = エスケープされていない
|
|
2414
|
-
inString = false;
|
|
2415
|
-
stringDelimiter = '';
|
|
2416
|
-
}
|
|
2417
|
-
}
|
|
2418
|
-
prevChar = ch;
|
|
2419
|
-
i++;
|
|
2420
|
-
continue;
|
|
2421
|
-
}
|
|
2422
|
-
// コメント開始チェック
|
|
2423
|
-
if (ch === '/' && nextCh === '/') {
|
|
2424
|
-
result.push(ch);
|
|
2425
|
-
result.push(nextCh);
|
|
2426
|
-
inLineComment = true;
|
|
2427
|
-
i += 2;
|
|
2428
|
-
prevChar = '/';
|
|
2429
|
-
continue;
|
|
2430
|
-
}
|
|
2431
|
-
if (ch === '/' && nextCh === '*') {
|
|
2432
|
-
result.push(ch);
|
|
2433
|
-
result.push(nextCh);
|
|
2434
|
-
inBlockComment = true;
|
|
2435
|
-
i += 2;
|
|
2436
|
-
prevChar = '*';
|
|
2437
|
-
continue;
|
|
2438
|
-
}
|
|
2439
|
-
// 文字列・正規表現・テンプレートリテラルの開始チェック
|
|
2440
|
-
if (ch === '"' || ch === '\'') {
|
|
2441
|
-
inString = true;
|
|
2442
|
-
stringDelimiter = ch;
|
|
2443
|
-
result.push(ch);
|
|
2444
|
-
prevChar = ch;
|
|
2445
|
-
i++;
|
|
2446
|
-
continue;
|
|
2447
|
-
}
|
|
2448
|
-
if (ch === '`') {
|
|
2449
|
-
inTemplate = true;
|
|
2450
|
-
result.push(ch);
|
|
2451
|
-
prevChar = ch;
|
|
2452
|
-
i++;
|
|
2453
|
-
continue;
|
|
2454
|
-
}
|
|
2455
|
-
// 正規表現リテラルの開始チェック(簡易版)
|
|
2456
|
-
// / の前が演算子や ( や , や = などの場合は正規表現の可能性が高い
|
|
2457
|
-
if (ch === '/' && /[=([,;:!&|?+\-*%^~{]|\breturn\b|\bnew\b/.test(prevChar)) {
|
|
2458
|
-
inRegex = true;
|
|
2459
|
-
result.push(ch);
|
|
2460
|
-
prevChar = ch;
|
|
2461
|
-
i++;
|
|
2462
|
-
continue;
|
|
2463
|
-
}
|
|
2464
|
-
// 文字列外の連続セミコロンをスキップ
|
|
2465
|
-
if (ch === ';' && lastSemiPos === i - 1) {
|
|
2466
|
-
// 連続するセミコロンの2番目以降はスキップ
|
|
2467
|
-
lastSemiPos = i;
|
|
2468
|
-
i++;
|
|
2469
|
-
prevChar = ch;
|
|
2470
|
-
continue;
|
|
2471
|
-
}
|
|
2472
|
-
if (ch === ';') {
|
|
2473
|
-
lastSemiPos = i;
|
|
2474
|
-
}
|
|
2475
|
-
// 文字列外の連続改行をスキップ
|
|
2476
|
-
if (ch === '\n' && lastNewlinePos === i - 1) {
|
|
2477
|
-
// 連続する改行の2番目以降はスキップ
|
|
2478
|
-
lastNewlinePos = i;
|
|
2479
|
-
i++;
|
|
2480
|
-
prevChar = ch;
|
|
2481
|
-
continue;
|
|
2482
|
-
}
|
|
2483
|
-
if (ch === '\n') {
|
|
2484
|
-
lastNewlinePos = i;
|
|
2485
|
-
}
|
|
2486
|
-
result.push(ch);
|
|
2487
|
-
prevChar = ch;
|
|
2488
|
-
i++;
|
|
2489
|
-
}
|
|
2490
|
-
return result.join('');
|
|
2491
|
-
}
|
|
2492
|
-
/**
|
|
2493
|
-
* 前後の空白を削除する
|
|
2494
|
-
* @param str 対象文字列
|
|
2495
|
-
* @returns トリムした文字列
|
|
2496
|
-
*/
|
|
2497
|
-
function trim(str) {
|
|
2498
|
-
str = String(str);
|
|
2499
|
-
return str.replace(/^\s+|\s+$/g, '');
|
|
2500
|
-
}
|