nadesiko3 3.7.21 → 3.7.23
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/README.md +20 -1
- package/batch/command.txt +370 -334
- package/batch/generate_command_list.mjs +102 -0
- package/batch/jsplugin2text.nako3 +1 -1
- package/batch/pickup_command.nako3 +12 -0
- package/batch/search_command.mjs +34 -0
- package/batch/search_command.nako3 +430 -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 +7 -4
- package/core/sample/algorithms/README.md +43 -0
- package/core/sample/algorithms/graph/dijkstra.nako3 +47 -0
- package/core/sample/algorithms/graph/kruskal.nako3 +69 -0
- package/core/sample/algorithms/math/euclidean_gcd.nako3 +15 -0
- package/core/sample/algorithms/math/sieve_of_eratosthenes.nako3 +26 -0
- package/core/sample/algorithms/search/binary_search.nako3 +17 -0
- package/core/sample/algorithms/search/breadth_first_search.nako3 +33 -0
- package/core/sample/algorithms/search/depth_first_search.nako3 +25 -0
- package/core/sample/algorithms/sort/heap_sort.nako3 +37 -0
- package/core/sample/algorithms/sort/insertion_sort.nako3 +18 -0
- package/core/sample/algorithms/sort/merge_sort.nako3 +40 -0
- package/core/sample/algorithms/sort/quick_sort.nako3 +36 -0
- package/core/sample/algorithms/string/knuth_morris_pratt.nako3 +50 -0
- package/core/sample/algorithms/string/run_length_encoding.nako3 +25 -0
- 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 +320 -209
- package/core/src/nako_global.mts +18 -0
- package/core/src/nako_indent_inline.mts +2 -2
- package/core/src/nako_lex_rules.mts +1 -1
- package/core/src/nako_parser3.mts +111 -166
- package/core/src/nako_parser_async.mts +165 -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 +208 -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/algorithm_samples_test.mjs +58 -0
- package/core/test/algorithms/graph/dijkstra_test.nako3 +21 -0
- package/core/test/algorithms/graph/kruskal_test.nako3 +21 -0
- package/core/test/algorithms/helper.mjs +13 -0
- package/core/test/algorithms/math/euclidean_gcd_test.nako3 +13 -0
- package/core/test/algorithms/math/sieve_of_eratosthenes_test.nako3 +10 -0
- package/core/test/algorithms/search/binary_search_test.nako3 +15 -0
- package/core/test/algorithms/search/breadth_first_search_test.nako3 +13 -0
- package/core/test/algorithms/search/depth_first_search_test.nako3 +13 -0
- package/core/test/algorithms/sort/heap_sort_test.nako3 +13 -0
- package/core/test/algorithms/sort/insertion_sort_test.nako3 +13 -0
- package/core/test/algorithms/sort/merge_sort_test.nako3 +18 -0
- package/core/test/algorithms/sort/quick_sort_test.nako3 +34 -0
- package/core/test/algorithms/string/knuth_morris_pratt_test.nako3 +16 -0
- package/core/test/algorithms/string/run_length_encoding_test.nako3 +13 -0
- package/core/test/array_test.mjs +3 -0
- 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/func_call.mjs +18 -0
- package/core/test/func_test.mjs +28 -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 +127 -0
- package/core/test/nako_gen_perf_test.mjs +178 -0
- package/core/test/nako_parser_async_test.mjs +385 -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 +174 -0
- package/core/test/nako_tokenizer_test.mjs +115 -0
- package/core/test/plugin_system_debug_test.mjs +138 -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/demo/browsers.html +1 -1
- package/doc/SETUP.md +1 -1
- package/doc/ai-code-generation.md +136 -0
- package/doc/browsers.md +1 -1
- package/doc/command_list.json +16842 -0
- package/doc/search_command.md +222 -0
- package/doc/syntax-nako3.md +344 -0
- package/package.json +29 -26
- package/release/_hash.txt +40 -40
- 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_caniuse.js +1 -1
- package/release/plugin_caniuse.js.map +2 -2
- 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 +219 -230
- package/release/wnako3.js.map +4 -4
- package/release/wnako3webworker.js +193 -204
- package/release/wnako3webworker.js.map +4 -4
- package/src/browsers.mjs +1 -1
- package/src/browsers.txt +0 -1
- 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/test/nako3edit/index_nako3_test.mjs +282 -0
- package/test/nako3server/index_nako3_test.mjs +239 -0
- package/test/node/ai_code_generation_guide_test.mjs +29 -0
- package/test/node/node_version_support_test.mjs +45 -0
- package/test/node/search_command_test.mjs +174 -0
- package/tools/nako3edit/AGENTS.md +23 -0
- package/tools/nako3edit/index.nako3 +404 -0
- package/tools/nako3server/AGENTS.md +23 -0
- package/tools/nako3server/index.nako3 +156 -23
- 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_global.mts
CHANGED
|
@@ -143,6 +143,19 @@ export class NakoGlobal {
|
|
|
143
143
|
this.logger.stdout(text)
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
+
/**
|
|
147
|
+
* プラグインの初期化が完了しているかどうかを調べる (#2064)
|
|
148
|
+
* @param pname プラグイン名
|
|
149
|
+
* @param po プラグイン・オブジェクト
|
|
150
|
+
*/
|
|
151
|
+
private isPluginInitialized(pname: string, po: {[key: string]: any}): boolean {
|
|
152
|
+
const initKey = `!${pname}:初期化`
|
|
153
|
+
// 初期化関数を持たないプラグインは、常に初期化済みとみなす
|
|
154
|
+
if (!po[initKey]) { return true }
|
|
155
|
+
// 初期化関数は生成されたJavaScriptの中で実行され、完了すると「初期化済」が設定される
|
|
156
|
+
return this.__varslist[0].has(`${initKey}済`)
|
|
157
|
+
}
|
|
158
|
+
|
|
146
159
|
/**
|
|
147
160
|
* 毎プラグインの「!クリア」関数を実行
|
|
148
161
|
*/
|
|
@@ -152,6 +165,11 @@ export class NakoGlobal {
|
|
|
152
165
|
const clearName = '!クリア'
|
|
153
166
|
for (const pname in this.pluginfiles) {
|
|
154
167
|
const po = this.__module[pname]
|
|
168
|
+
if (!po) { continue }
|
|
169
|
+
// 初期化されていないプラグインのクリア関数は呼ばない (#2064)
|
|
170
|
+
// (メモ) プラグインの初期化は生成されたJavaScriptの中で行われるため、
|
|
171
|
+
// コンパイルや実行に失敗すると初期化されないまま実行環境が残ることがある。
|
|
172
|
+
if (!this.isPluginInitialized(pname, po)) { continue }
|
|
155
173
|
if (po[clearName] && po[clearName].fn) {
|
|
156
174
|
try {
|
|
157
175
|
po[clearName].fn(this)
|
|
@@ -221,7 +221,7 @@ const INDENT_MODE_KEYWORDS = ['!インデント構文', '!ここまでだるい'
|
|
|
221
221
|
/** インデント構文 --- インデントを見て"ここまで"を自動挿入 (#596) */
|
|
222
222
|
export function convertIndentSyntax(tokens: Token[]): Token[] {
|
|
223
223
|
// インデント構文の変換が必要か?
|
|
224
|
-
if (!
|
|
224
|
+
if (!useIndentSyntax(tokens)) { return tokens }
|
|
225
225
|
// 『ここまで』があったらエラーを出す
|
|
226
226
|
for (const t of tokens) {
|
|
227
227
|
if (t.type === 'ここまで') {
|
|
@@ -321,7 +321,7 @@ export function convertIndentSyntax(tokens: Token[]): Token[] {
|
|
|
321
321
|
return result
|
|
322
322
|
}
|
|
323
323
|
|
|
324
|
-
function
|
|
324
|
+
function useIndentSyntax(tokens: Token[]) : boolean {
|
|
325
325
|
// インデント構文が必要かチェック (最初の100個をチェック)
|
|
326
326
|
for (let i = 0; i < tokens.length; i++) {
|
|
327
327
|
if (i > 100) { break }
|
|
@@ -42,7 +42,7 @@ export const rules: NakoLexRule[] = [
|
|
|
42
42
|
{ name: 'eol', pattern: /^\n/ },
|
|
43
43
|
{ name: 'eol', pattern: /^;/ },
|
|
44
44
|
// eslint-disable-next-line no-irregular-whitespace
|
|
45
|
-
{ name: 'space', pattern: /^(\x20|\
|
|
45
|
+
{ name: 'space', pattern: /^(\x20|\t| |・|⎿ |└||)+/ }, // #877,#1015
|
|
46
46
|
{ name: 'comma', pattern: /^,/ },
|
|
47
47
|
{ name: 'line_comment', pattern: /^#[^\n]*/ },
|
|
48
48
|
{ name: 'line_comment', pattern: /^\/\/[^\n]*/ },
|
|
@@ -1,12 +1,50 @@
|
|
|
1
1
|
|
|
2
2
|
/**
|
|
3
3
|
* nadesiko v3 parser
|
|
4
|
+
*
|
|
5
|
+
* 再帰下降パーサ。トークン列を読み進めながら構文木(Ast)を組み立てる。
|
|
6
|
+
* 各構文規則は `yXxx` という名前のメソッドで、カーソル(this.index)と
|
|
7
|
+
* 計算用スタック(this.stack)を共有しながら相互に呼び合う。
|
|
8
|
+
* カーソル操作・スタック操作・変数検索は基底クラス NakoParserBase にある。
|
|
9
|
+
*
|
|
10
|
+
* ## 構文規則の呼び出し関係 (#2364)
|
|
11
|
+
*
|
|
12
|
+
* ```
|
|
13
|
+
* parse
|
|
14
|
+
* └ startParser → ySentenceList → ySentence ─┬ yIF / yAtohantei / yTryExcept / yDebugPrint
|
|
15
|
+
* ├ yDNCLMode / ySetGenMode / ySpeedMode ...
|
|
16
|
+
* ├ yLet ── yLetArrayAt / yLetArrayBracket
|
|
17
|
+
* ├ yDefFunc / yDefTest → yDefFuncCommon
|
|
18
|
+
* └ yCall ─┬ yDainyu / ySadameru / yIncDec
|
|
19
|
+
* ├ yRepeatTime / yWhile / yFor /
|
|
20
|
+
* │ yForEach / ySwitch / yReturn
|
|
21
|
+
* └ yCallFunc → yMumeiFunc
|
|
22
|
+
*
|
|
23
|
+
* yCalc → yGetArg ─┬ yRange
|
|
24
|
+
* ├ yGetArgOperator → infixToAST() … nako_parser_operator.mts
|
|
25
|
+
* └ yValue ─┬ yValueKakko / yValueWord / yMumeiFunc
|
|
26
|
+
* └ yJSONArray / yJSONObject → yJSONArrayValue /
|
|
27
|
+
* yJSONObjectValue → yCalc
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* 上の図は主要な流れだけを示したもので、実際には
|
|
31
|
+
* `ySentence ↔ yBlock ↔ yCall ↔ yCalc ↔ yValue ↔ yJSON*` が
|
|
32
|
+
* 大きな相互再帰を成している。この相互再帰があるため、構文規則そのものは
|
|
33
|
+
* ファイルを分けても結合が下がらない。分離してあるのは、
|
|
34
|
+
* 相互再帰の外側にあってカーソルにもスタックにも触れないものだけ。
|
|
35
|
+
*
|
|
36
|
+
* - `nako_parser_operator.mts` … 演算子の優先順位による構文木の組み立て
|
|
37
|
+
* - `nako_parser_async.mts` … 解析後に asyncFn を伝播させる後処理パス
|
|
38
|
+
* - `nako_parser_message.mts` … エラーメッセージの組み立て
|
|
4
39
|
*/
|
|
5
40
|
import { opPriority, RenbunJosi, operatorList } from './nako_parser_const.mjs'
|
|
6
41
|
import { NakoParserBase } from './nako_parser_base.mjs'
|
|
42
|
+
import { infixToAST } from './nako_parser_operator.mjs'
|
|
43
|
+
import { checkAsyncFn } from './nako_parser_async.mjs'
|
|
44
|
+
import { makeStackBalanceReport } from './nako_parser_message.mjs'
|
|
7
45
|
import { NakoSyntaxError } from './nako_errors.mjs'
|
|
8
46
|
import { NakoLexer } from './nako_lexer.mjs'
|
|
9
|
-
import { FuncListItemType,
|
|
47
|
+
import { FuncListItemType, NewEmptyToken, SourceMap } from './nako_types.mjs'
|
|
10
48
|
import { NodeType, Ast, AstEol, AstBlocks, AstOperator, AstConst, AstLet, AstLetArray, AstIf, AstWhile, AstAtohantei, AstFor, AstForeach, AstSwitch, AstRepeatTimes, AstDefFunc, AstCallFunc, AstStrValue, AstDefVar, AstDefVarList } from './nako_ast.mjs'
|
|
11
49
|
import { Token, TokenDefFunc, TokenCallFunc } from './nako_token.mjs'
|
|
12
50
|
|
|
@@ -27,12 +65,8 @@ export class NakoParser extends NakoParserBase {
|
|
|
27
65
|
const result = this.startParser()
|
|
28
66
|
|
|
29
67
|
// 関数毎に非同期処理が必要かどうかを判定する
|
|
30
|
-
|
|
31
|
-
this.
|
|
32
|
-
while (this.isModifiedNodes) {
|
|
33
|
-
this.isModifiedNodes = false
|
|
34
|
-
this._checkAsyncFn(result)
|
|
35
|
-
}
|
|
68
|
+
// 「非同期関数を呼ぶ関数もまた非同期」と伝播していくので、変化が無くなるまで繰り返す
|
|
69
|
+
while (checkAsyncFn(result, this.funclist)) { /* 変化が無くなるまで繰り返す */ }
|
|
36
70
|
|
|
37
71
|
return result
|
|
38
72
|
}
|
|
@@ -79,34 +113,13 @@ export class NakoParser extends NakoParserBase {
|
|
|
79
113
|
return { type: 'block', blocks, josi: '', ...map, end: this.peekSourceMap() }
|
|
80
114
|
}
|
|
81
115
|
|
|
82
|
-
/** 余剰スタックのレポートを作る
|
|
116
|
+
/** 余剰スタックのレポートを作る
|
|
117
|
+
* (レポートの組み立ては nako_parser_message.mts の makeStackBalanceReport) #2364
|
|
118
|
+
*/
|
|
83
119
|
makeStackBalanceReport(): string {
|
|
84
|
-
const
|
|
85
|
-
this.stack.forEach((t) => {
|
|
86
|
-
let w = this.nodeToStr(t, { depth: 1 }, false)
|
|
87
|
-
if (t.josi) { w += t.josi }
|
|
88
|
-
words.push(w)
|
|
89
|
-
})
|
|
90
|
-
const desc = words.join(',')
|
|
91
|
-
// 最近使った関数の使い方レポートを作る #1093
|
|
92
|
-
let descFunc = ''
|
|
93
|
-
const chA = 'A'.charCodeAt(0)
|
|
94
|
-
for (const f of this.recentlyCalledFunc) {
|
|
95
|
-
descFunc += ' - '
|
|
96
|
-
let no = 0
|
|
97
|
-
const josiA: FuncArgs | undefined = (f).josi
|
|
98
|
-
if (josiA) {
|
|
99
|
-
for (const arg of josiA) {
|
|
100
|
-
const ch = String.fromCharCode(chA + no)
|
|
101
|
-
descFunc += ch
|
|
102
|
-
if (arg.length === 1) { descFunc += arg[0] } else { descFunc += `(${arg.join('|')})` }
|
|
103
|
-
no++
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
descFunc += String(f.name) + '\n'
|
|
107
|
-
}
|
|
120
|
+
const report = makeStackBalanceReport(this.stack, this.recentlyCalledFunc)
|
|
108
121
|
this.recentlyCalledFunc = []
|
|
109
|
-
return
|
|
122
|
+
return report
|
|
110
123
|
}
|
|
111
124
|
|
|
112
125
|
yEOL(): AstEol | null {
|
|
@@ -196,6 +209,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
196
209
|
return null
|
|
197
210
|
}
|
|
198
211
|
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
// 実行モードの指定と廃止された構文
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
|
|
199
216
|
/** [廃止] 非同期モード #11 @returns {Ast} */
|
|
200
217
|
yASyncMode(): Ast {
|
|
201
218
|
this.logger.error('『非同期モード』構文は廃止されました(https://nadesi.com/v3/doc/go.php?1028)。', this.peek())
|
|
@@ -240,6 +257,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
240
257
|
return { type: 'run_mode', value: mode, ...map, end: this.peekSourceMap() }
|
|
241
258
|
}
|
|
242
259
|
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
// ブロックと関数定義
|
|
262
|
+
// ---------------------------------------------------------------------------
|
|
263
|
+
|
|
243
264
|
/** @returns {AstBlocks} */
|
|
244
265
|
yBlock(): AstBlocks {
|
|
245
266
|
const map = this.peekSourceMap()
|
|
@@ -387,6 +408,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
387
408
|
}
|
|
388
409
|
}
|
|
389
410
|
|
|
411
|
+
// ---------------------------------------------------------------------------
|
|
412
|
+
// 条件分岐(もし文)
|
|
413
|
+
// ---------------------------------------------------------------------------
|
|
414
|
+
|
|
390
415
|
/** 「もし」文の条件を取得 */
|
|
391
416
|
yIFCond(): Ast {
|
|
392
417
|
const map = this.peekSourceMap()
|
|
@@ -534,6 +559,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
534
559
|
}
|
|
535
560
|
}
|
|
536
561
|
|
|
562
|
+
// ---------------------------------------------------------------------------
|
|
563
|
+
// 実行速度・パフォーマンスの指定
|
|
564
|
+
// ---------------------------------------------------------------------------
|
|
565
|
+
|
|
537
566
|
ySpeedMode(): AstBlocks | null {
|
|
538
567
|
const map: SourceMap = this.peekSourceMap()
|
|
539
568
|
if (!this.check2(['string', '実行速度優先'])) {
|
|
@@ -649,6 +678,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
649
678
|
return { type: 'eol', ...this.peekSourceMap(), end: this.peekSourceMap() }
|
|
650
679
|
}
|
|
651
680
|
|
|
681
|
+
// ---------------------------------------------------------------------------
|
|
682
|
+
// 引数の取得と演算子
|
|
683
|
+
// ---------------------------------------------------------------------------
|
|
684
|
+
|
|
652
685
|
/**
|
|
653
686
|
* 1つ目の値を与え、その後に続く計算式を取得し、優先規則に沿って並び替えして戻す
|
|
654
687
|
* @param {Ast} firstValue
|
|
@@ -675,7 +708,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
675
708
|
}
|
|
676
709
|
if (args.length === 0) { return null }
|
|
677
710
|
if (args.length === 1) { return args[0] }
|
|
678
|
-
return
|
|
711
|
+
return infixToAST(args, this.logger)
|
|
679
712
|
}
|
|
680
713
|
|
|
681
714
|
/**
|
|
@@ -743,76 +776,6 @@ export class NakoParser extends NakoParserBase {
|
|
|
743
776
|
return this.yGetArgOperator(value1)
|
|
744
777
|
}
|
|
745
778
|
|
|
746
|
-
infixToPolish(list: Ast[]): Ast[] {
|
|
747
|
-
// 中間記法から逆ポーランドに変換
|
|
748
|
-
const priority = (t: Ast) => {
|
|
749
|
-
if (opPriority[t.type]) { return opPriority[t.type] }
|
|
750
|
-
return 10
|
|
751
|
-
}
|
|
752
|
-
const stack: Ast[] = []
|
|
753
|
-
const polish: Ast[] = []
|
|
754
|
-
while (list.length > 0) {
|
|
755
|
-
const t = list.shift()
|
|
756
|
-
if (!t) { break }
|
|
757
|
-
while (stack.length > 0) { // 優先順位を見て移動する
|
|
758
|
-
const sTop = stack[stack.length - 1]
|
|
759
|
-
if (priority(t) > priority(sTop)) { break }
|
|
760
|
-
const tpop = stack.pop()
|
|
761
|
-
if (!tpop) {
|
|
762
|
-
this.logger.error('計算式に間違いがあります。', t)
|
|
763
|
-
break
|
|
764
|
-
}
|
|
765
|
-
polish.push(tpop)
|
|
766
|
-
}
|
|
767
|
-
stack.push(t)
|
|
768
|
-
}
|
|
769
|
-
// 残った要素を積み替える
|
|
770
|
-
while (stack.length > 0) {
|
|
771
|
-
const t = stack.pop()
|
|
772
|
-
if (t) { polish.push(t) }
|
|
773
|
-
}
|
|
774
|
-
return polish
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
/** @returns {Ast | null} */
|
|
778
|
-
infixToAST(list: Ast[]): Ast | null {
|
|
779
|
-
if (list.length === 0) { return null }
|
|
780
|
-
// 逆ポーランドを構文木に
|
|
781
|
-
const josi = list[list.length - 1].josi
|
|
782
|
-
const node = list[list.length - 1]
|
|
783
|
-
const polish = this.infixToPolish(list)
|
|
784
|
-
/** @type {Ast[]} */
|
|
785
|
-
const stack = []
|
|
786
|
-
for (const t of polish) {
|
|
787
|
-
if (!opPriority[t.type]) { // 演算子ではない
|
|
788
|
-
stack.push(t)
|
|
789
|
-
continue
|
|
790
|
-
}
|
|
791
|
-
const b:Ast|undefined = stack.pop()
|
|
792
|
-
const a:Ast|undefined = stack.pop()
|
|
793
|
-
if (a === undefined || b === undefined) {
|
|
794
|
-
this.logger.debug('--- 計算式(逆ポーランド) ---\n' + JSON.stringify(polish))
|
|
795
|
-
throw NakoSyntaxError.fromNode('計算式でエラー', node)
|
|
796
|
-
}
|
|
797
|
-
/** @type {AstOperator} */
|
|
798
|
-
const op: AstOperator = {
|
|
799
|
-
type: 'op',
|
|
800
|
-
operator: t.type,
|
|
801
|
-
blocks: [a, b],
|
|
802
|
-
josi,
|
|
803
|
-
startOffset: a.startOffset,
|
|
804
|
-
endOffset: a.endOffset,
|
|
805
|
-
line: a.line,
|
|
806
|
-
column: a.column,
|
|
807
|
-
file: a.file
|
|
808
|
-
}
|
|
809
|
-
stack.push(op)
|
|
810
|
-
}
|
|
811
|
-
const ans = stack.pop()
|
|
812
|
-
if (!ans) { return null }
|
|
813
|
-
return ans
|
|
814
|
-
}
|
|
815
|
-
|
|
816
779
|
yGetArgParen(y: Ast[], funcName?: string): Ast[] { // C言語風呼び出しでカッコの中を取得
|
|
817
780
|
let isClose = false
|
|
818
781
|
const si = this.stack.length
|
|
@@ -867,6 +830,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
867
830
|
return node
|
|
868
831
|
}
|
|
869
832
|
|
|
833
|
+
// ---------------------------------------------------------------------------
|
|
834
|
+
// 繰り返しと条件分岐の各構文
|
|
835
|
+
// ---------------------------------------------------------------------------
|
|
836
|
+
|
|
870
837
|
/** @returns {AstRepeatTimes | null} */
|
|
871
838
|
yRepeatTime(): AstRepeatTimes | null {
|
|
872
839
|
const map = this.peekSourceMap()
|
|
@@ -1202,6 +1169,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
1202
1169
|
return ast
|
|
1203
1170
|
}
|
|
1204
1171
|
|
|
1172
|
+
// ---------------------------------------------------------------------------
|
|
1173
|
+
// 無名関数
|
|
1174
|
+
// ---------------------------------------------------------------------------
|
|
1175
|
+
|
|
1205
1176
|
/** 無名関数
|
|
1206
1177
|
* @returns {AstDefFunc|null}
|
|
1207
1178
|
*/
|
|
@@ -1263,6 +1234,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
1263
1234
|
}
|
|
1264
1235
|
}
|
|
1265
1236
|
|
|
1237
|
+
// ---------------------------------------------------------------------------
|
|
1238
|
+
// 代入文と増減
|
|
1239
|
+
// ---------------------------------------------------------------------------
|
|
1240
|
+
|
|
1266
1241
|
/** 代入構文 */
|
|
1267
1242
|
yDainyu(): AstBlocks | null {
|
|
1268
1243
|
const map = this.peekSourceMap()
|
|
@@ -1380,6 +1355,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
1380
1355
|
}
|
|
1381
1356
|
}
|
|
1382
1357
|
|
|
1358
|
+
// ---------------------------------------------------------------------------
|
|
1359
|
+
// 関数呼び出し
|
|
1360
|
+
// ---------------------------------------------------------------------------
|
|
1361
|
+
|
|
1383
1362
|
yCall(): Ast | null {
|
|
1384
1363
|
if (this.isEOF()) { return null }
|
|
1385
1364
|
|
|
@@ -1577,6 +1556,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
1577
1556
|
return null
|
|
1578
1557
|
}
|
|
1579
1558
|
|
|
1559
|
+
// ---------------------------------------------------------------------------
|
|
1560
|
+
// 代入・変数定義と配列要素への代入
|
|
1561
|
+
// ---------------------------------------------------------------------------
|
|
1562
|
+
|
|
1580
1563
|
/** @returns {Ast | null} */
|
|
1581
1564
|
yLet(): AstBlocks | null {
|
|
1582
1565
|
const map = this.peekSourceMap()
|
|
@@ -2117,7 +2100,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
2117
2100
|
} as AstLet
|
|
2118
2101
|
}
|
|
2119
2102
|
// 二次元配列 + オブジェクトプロパティ構文 --- word[a, b]$c = d
|
|
2120
|
-
if (this.accept(['word', '[', this.yCalc, '
|
|
2103
|
+
if (this.accept(['word', '[', this.yCalc, 'comma', this.yCalc, ']', '$', 'word', 'eq', this.yCalc])) {
|
|
2121
2104
|
const astValue = this.y[9]
|
|
2122
2105
|
const astIndexes = this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4])])
|
|
2123
2106
|
const astProp = this.y[7]
|
|
@@ -2157,6 +2140,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
2157
2140
|
return null
|
|
2158
2141
|
}
|
|
2159
2142
|
|
|
2143
|
+
// ---------------------------------------------------------------------------
|
|
2144
|
+
// 計算式と値
|
|
2145
|
+
// ---------------------------------------------------------------------------
|
|
2146
|
+
|
|
2160
2147
|
/** @returns {Ast | null} */
|
|
2161
2148
|
yCalc(): Ast|null {
|
|
2162
2149
|
const map = this.peekSourceMap()
|
|
@@ -2180,6 +2167,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
2180
2167
|
let fCalc:Ast = t1
|
|
2181
2168
|
// それが連文か助詞を読んで確認
|
|
2182
2169
|
if (RenbunJosi.indexOf(t1.josi || '') >= 0) {
|
|
2170
|
+
// 『(式)して戻す』のように、式の途中に『戻す』文は書けない (#2064)
|
|
2171
|
+
if (this.check('戻る')) {
|
|
2172
|
+
throw NakoSyntaxError.fromNode('式の中で『戻す(戻る)』文は使えません。『(値)を(変数)に代入』などで一度値を受け取ってから『(変数)を戻す』と書いてください。', map)
|
|
2173
|
+
}
|
|
2183
2174
|
// 連文なら右側を読んで左側とくっつける
|
|
2184
2175
|
const t2 = this.yCalc()
|
|
2185
2176
|
if (t2) {
|
|
@@ -2573,6 +2564,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
2573
2564
|
return null
|
|
2574
2565
|
}
|
|
2575
2566
|
|
|
2567
|
+
// ---------------------------------------------------------------------------
|
|
2568
|
+
// 変数名の解決と登録
|
|
2569
|
+
// ---------------------------------------------------------------------------
|
|
2570
|
+
|
|
2576
2571
|
/** 変数を生成 */
|
|
2577
2572
|
createVar(word: Token|Ast, isConst: boolean, isExport: boolean): Token|Ast {
|
|
2578
2573
|
let gname: string = (word as AstStrValue).value
|
|
@@ -2630,6 +2625,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
2630
2625
|
return words
|
|
2631
2626
|
}
|
|
2632
2627
|
|
|
2628
|
+
// ---------------------------------------------------------------------------
|
|
2629
|
+
// JSON/配列リテラル
|
|
2630
|
+
// ---------------------------------------------------------------------------
|
|
2631
|
+
|
|
2633
2632
|
yJSONObjectValue(): Ast[] {
|
|
2634
2633
|
// 戻り値の形式
|
|
2635
2634
|
// Astblocks.blocks = [key1, value1, key2, value2, key3, value3 ...]
|
|
@@ -2804,6 +2803,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
2804
2803
|
return null
|
|
2805
2804
|
}
|
|
2806
2805
|
|
|
2806
|
+
// ---------------------------------------------------------------------------
|
|
2807
|
+
// エラー監視
|
|
2808
|
+
// ---------------------------------------------------------------------------
|
|
2809
|
+
|
|
2807
2810
|
/** エラー監視構文 */
|
|
2808
2811
|
yTryExcept(): AstBlocks | null {
|
|
2809
2812
|
const map = this.peekSourceMap()
|
|
@@ -2834,67 +2837,9 @@ export class NakoParser extends NakoParserBase {
|
|
|
2834
2837
|
}
|
|
2835
2838
|
}
|
|
2836
2839
|
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
// 関数定義があれば関数
|
|
2841
|
-
if (node.type === 'def_func' || node.type === 'def_test' || node.type === 'func_obj') {
|
|
2842
|
-
// 関数定義でasyncFnが指定されているならtrueを返す
|
|
2843
|
-
const def: AstDefFunc = node as AstDefFunc
|
|
2844
|
-
if (def.asyncFn) { return true } // 既にasyncFnが指定されている
|
|
2845
|
-
// 関数定義の中身を調べてasyncFnであるならtrueに変更する
|
|
2846
|
-
let isAsyncFn = false
|
|
2847
|
-
for (const n of def.blocks) {
|
|
2848
|
-
if (this._checkAsyncFn(n)) {
|
|
2849
|
-
isAsyncFn = true
|
|
2850
|
-
def.asyncFn = isAsyncFn
|
|
2851
|
-
def.meta.asyncFn = isAsyncFn
|
|
2852
|
-
this.isModifiedNodes = true
|
|
2853
|
-
return true
|
|
2854
|
-
}
|
|
2855
|
-
}
|
|
2856
|
-
}
|
|
2857
|
-
// 関数呼び出しを調べて非同期処理が必要ならtrueを返す
|
|
2858
|
-
if (node.type === 'func') {
|
|
2859
|
-
// 関数呼び出し自体が非同期処理ならtrueを返す
|
|
2860
|
-
const callNode: AstCallFunc = node as AstCallFunc
|
|
2861
|
-
if (callNode.asyncFn) {
|
|
2862
|
-
return true
|
|
2863
|
-
}
|
|
2864
|
-
// 続けて、以下の関数呼び出しの引数などに非同期処理があるかどうか調べる
|
|
2865
|
-
// 関数の引数は、node.blocksに格納されている
|
|
2866
|
-
if (callNode.blocks) {
|
|
2867
|
-
for (const n of callNode.blocks) {
|
|
2868
|
-
if (this._checkAsyncFn(n)) {
|
|
2869
|
-
callNode.asyncFn = true
|
|
2870
|
-
this.isModifiedNodes = true
|
|
2871
|
-
return true
|
|
2872
|
-
}
|
|
2873
|
-
}
|
|
2874
|
-
}
|
|
2875
|
-
// さらに、関数のリンクを調べる
|
|
2876
|
-
const func = this.funclist.get(callNode.name)
|
|
2877
|
-
if (func && func.asyncFn) {
|
|
2878
|
-
callNode.asyncFn = true
|
|
2879
|
-
this.isModifiedNodes = true
|
|
2880
|
-
return true
|
|
2881
|
-
}
|
|
2882
|
-
return false
|
|
2883
|
-
}
|
|
2884
|
-
// 連文 ... 現在、効率は悪いが非同期で実行することになっている
|
|
2885
|
-
if (node.type === 'renbun') {
|
|
2886
|
-
return true
|
|
2887
|
-
}
|
|
2888
|
-
// その他
|
|
2889
|
-
if ((node as AstBlocks).blocks) {
|
|
2890
|
-
for (const n of (node as AstBlocks).blocks) {
|
|
2891
|
-
if (this._checkAsyncFn(n)) {
|
|
2892
|
-
return true
|
|
2893
|
-
}
|
|
2894
|
-
}
|
|
2895
|
-
}
|
|
2896
|
-
return false
|
|
2897
|
-
}
|
|
2840
|
+
// ---------------------------------------------------------------------------
|
|
2841
|
+
// TokenからAstへの変換
|
|
2842
|
+
// ---------------------------------------------------------------------------
|
|
2898
2843
|
|
|
2899
2844
|
/** TokenをそのままNodeに変換するメソッド(ただし簡単なものだけ対応)
|
|
2900
2845
|
* @returns {Ast[]}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 構文解析後の AST を走査して、非同期処理(asyncFn)の要否を判定するモジュール
|
|
3
|
+
*
|
|
4
|
+
* NakoParser から分離した (#2364)。
|
|
5
|
+
* 構文解析が完了した後に AST 全体を走査する後処理パスであり、
|
|
6
|
+
* トークンのカーソルにも計算用スタックにも一切触れない。
|
|
7
|
+
* (実体は nako_parser3.mts の NakoParser._checkAsyncFn だった)
|
|
8
|
+
*
|
|
9
|
+
* 非同期の情報は「非同期関数を呼ぶ関数もまた非同期」という形で伝播していくため、
|
|
10
|
+
* 1 回の走査では行き渡らないことがある。呼び出し側は変化が無くなるまで
|
|
11
|
+
* `checkAsyncFn()` を繰り返し呼ぶこと。
|
|
12
|
+
*/
|
|
13
|
+
import { Ast, AstBlocks, AstDefFunc, AstCallFunc, AstLet } from './nako_ast.mjs'
|
|
14
|
+
import { FuncList } from './nako_types.mjs'
|
|
15
|
+
|
|
16
|
+
/** 走査中に AST を書き換えたかどうかを持ち回るための入れ物 */
|
|
17
|
+
interface CheckContext {
|
|
18
|
+
modified: boolean
|
|
19
|
+
/**
|
|
20
|
+
* 無名関数を保持している変数名 → その無名関数が非同期かどうか
|
|
21
|
+
*
|
|
22
|
+
* `F=●()...ここまで` のように変数へ代入された無名関数は funclist に載らないため、
|
|
23
|
+
* 代入を覚えておかないと `F()` の呼び出しに asyncFn を付けられない。
|
|
24
|
+
* 変数のシャドーイングを考慮して、関数定義ごとにスコープを積む。
|
|
25
|
+
*
|
|
26
|
+
* 同期な無名関数の代入も記録する。記録しないと、内側のスコープで同名の変数へ
|
|
27
|
+
* 同期な無名関数を代入しても外側の非同期な代入が見えてしまう。
|
|
28
|
+
*/
|
|
29
|
+
funcObjVarScopes: Map<string, boolean>[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* AST を走査して関数ごとに asyncFn が必要かどうかを確認し、必要なら書き換える。
|
|
34
|
+
*
|
|
35
|
+
* @param node 走査対象の AST
|
|
36
|
+
* @param funclist 関数一覧(呼び出し先が非同期かどうかの判定に使う)
|
|
37
|
+
* @returns AST を書き換えたら true。呼び出し側は false になるまで繰り返すこと
|
|
38
|
+
*/
|
|
39
|
+
export function checkAsyncFn (node: Ast, funclist: FuncList): boolean {
|
|
40
|
+
const ctx: CheckContext = { modified: false, funcObjVarScopes: [new Map()] }
|
|
41
|
+
checkNode(node, funclist, ctx)
|
|
42
|
+
return ctx.modified
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 変数名が非同期の無名関数を指しているかどうかを、内側のスコープから順に調べる。
|
|
47
|
+
* 見つかった時点で打ち切るので、内側の代入が外側の代入をシャドーイングする。
|
|
48
|
+
*/
|
|
49
|
+
function isAsyncVar (ctx: CheckContext, name: string): boolean {
|
|
50
|
+
for (let i = ctx.funcObjVarScopes.length - 1; i >= 0; i--) {
|
|
51
|
+
const asyncFn = ctx.funcObjVarScopes[i].get(name)
|
|
52
|
+
if (asyncFn !== undefined) { return asyncFn }
|
|
53
|
+
}
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 変数へ無名関数を代入していたら、現在のスコープに覚えておく
|
|
59
|
+
* (`let` と `def_local_var` はどちらも blocks[0] が代入する値)
|
|
60
|
+
*
|
|
61
|
+
* 無名関数以外の代入は記録しない。`F=Gの参照` のような代入まで同期扱いにすると、
|
|
62
|
+
* 逆に await の付け漏れという、より悪い誤りになるため。
|
|
63
|
+
*/
|
|
64
|
+
function checkFuncObjVarAssign (node: Ast, ctx: CheckContext): void {
|
|
65
|
+
const letNode = node as AstLet
|
|
66
|
+
if (!letNode.name) { return }
|
|
67
|
+
const value = (letNode.blocks || [])[0]
|
|
68
|
+
if (!value || value.type !== 'func_obj') { return }
|
|
69
|
+
const scope = ctx.funcObjVarScopes[ctx.funcObjVarScopes.length - 1]
|
|
70
|
+
scope.set(letNode.name, !!(value as AstDefFunc).asyncFn)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* ノードが非同期処理を含むかどうかを返す(必要に応じて AST を書き換える)
|
|
75
|
+
* @returns 非同期処理を含むなら true
|
|
76
|
+
*/
|
|
77
|
+
function checkNode (node: Ast, funclist: FuncList, ctx: CheckContext): boolean {
|
|
78
|
+
if (!node) { return false }
|
|
79
|
+
// 関数定義があれば関数
|
|
80
|
+
if (node.type === 'def_func' || node.type === 'def_test' || node.type === 'func_obj') {
|
|
81
|
+
const def: AstDefFunc = node as AstDefFunc
|
|
82
|
+
// 既に非同期と分かっていても中身の走査は省略しない。
|
|
83
|
+
// 途中で打ち切ると、それより後ろにある呼び出しに asyncFn が付かなくなる
|
|
84
|
+
ctx.funcObjVarScopes.push(new Map())
|
|
85
|
+
let isAsyncFn = false
|
|
86
|
+
for (const n of def.blocks) {
|
|
87
|
+
if (checkNode(n, funclist, ctx)) { isAsyncFn = true }
|
|
88
|
+
}
|
|
89
|
+
ctx.funcObjVarScopes.pop()
|
|
90
|
+
// 関数定義の中身が非同期であるならasyncFnをtrueに変更する
|
|
91
|
+
if (isAsyncFn && !def.asyncFn) {
|
|
92
|
+
def.asyncFn = true
|
|
93
|
+
def.meta.asyncFn = true
|
|
94
|
+
ctx.modified = true
|
|
95
|
+
}
|
|
96
|
+
if (!def.asyncFn) { return false }
|
|
97
|
+
// 後から判明した非同期情報を、呼び出し側の判定に使う関数一覧にも反映する
|
|
98
|
+
const func = funclist.get(def.name)
|
|
99
|
+
if (func && !func.asyncFn) {
|
|
100
|
+
func.asyncFn = true
|
|
101
|
+
ctx.modified = true
|
|
102
|
+
}
|
|
103
|
+
return true
|
|
104
|
+
}
|
|
105
|
+
// 変数へ代入された無名関数を覚えておく(呼び出し側の判定に使う)
|
|
106
|
+
if (node.type === 'let' || node.type === 'def_local_var') {
|
|
107
|
+
let containsAsync = false
|
|
108
|
+
for (const n of (node as AstBlocks).blocks) {
|
|
109
|
+
if (checkNode(n, funclist, ctx)) { containsAsync = true }
|
|
110
|
+
}
|
|
111
|
+
checkFuncObjVarAssign(node, ctx)
|
|
112
|
+
return containsAsync
|
|
113
|
+
}
|
|
114
|
+
// 関数呼び出しを調べて非同期処理が必要ならtrueを返す
|
|
115
|
+
if (node.type === 'func') {
|
|
116
|
+
// 関数呼び出し自体が非同期処理ならtrueを返す
|
|
117
|
+
const callNode: AstCallFunc = node as AstCallFunc
|
|
118
|
+
if (callNode.asyncFn) {
|
|
119
|
+
return true
|
|
120
|
+
}
|
|
121
|
+
// 続けて、以下の関数呼び出しの引数などに非同期処理があるかどうか調べる
|
|
122
|
+
// 関数の引数は、node.blocksに格納されている
|
|
123
|
+
// (2つ目以降の引数にも asyncFn が必要なので、最初の1つで打ち切らない)
|
|
124
|
+
if (callNode.blocks) {
|
|
125
|
+
let hasAsyncArg = false
|
|
126
|
+
for (const n of callNode.blocks) {
|
|
127
|
+
if (checkNode(n, funclist, ctx)) { hasAsyncArg = true }
|
|
128
|
+
}
|
|
129
|
+
if (hasAsyncArg) {
|
|
130
|
+
callNode.asyncFn = true
|
|
131
|
+
ctx.modified = true
|
|
132
|
+
return true
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// さらに、関数のリンクを調べる
|
|
136
|
+
const func = funclist.get(callNode.name)
|
|
137
|
+
if (func && func.asyncFn) {
|
|
138
|
+
callNode.asyncFn = true
|
|
139
|
+
ctx.modified = true
|
|
140
|
+
return true
|
|
141
|
+
}
|
|
142
|
+
// 非同期の無名関数を保持している変数の呼び出しかどうかを調べる
|
|
143
|
+
if (isAsyncVar(ctx, callNode.name)) {
|
|
144
|
+
callNode.asyncFn = true
|
|
145
|
+
ctx.modified = true
|
|
146
|
+
return true
|
|
147
|
+
}
|
|
148
|
+
return false
|
|
149
|
+
}
|
|
150
|
+
// 連文 ... 現在、効率は悪いが非同期で実行することになっている
|
|
151
|
+
if (node.type === 'renbun') {
|
|
152
|
+
return true
|
|
153
|
+
}
|
|
154
|
+
// その他
|
|
155
|
+
if ((node as AstBlocks).blocks) {
|
|
156
|
+
let containsAsync = false
|
|
157
|
+
for (const n of (node as AstBlocks).blocks) {
|
|
158
|
+
if (checkNode(n, funclist, ctx)) {
|
|
159
|
+
containsAsync = true
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return containsAsync
|
|
163
|
+
}
|
|
164
|
+
return false
|
|
165
|
+
}
|