nadesiko3 3.7.20 → 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.
Files changed (162) hide show
  1. package/batch/command.txt +483 -445
  2. package/batch/jsplugin2text.nako3 +1 -1
  3. package/batch/pickup_command.nako3 +12 -0
  4. package/core/command/snako.mts +5 -1
  5. package/core/deno/snako.ts +5 -1
  6. package/core/package-lock.json +382 -21
  7. package/core/package.json +4 -4
  8. package/core/src/README.md +98 -0
  9. package/core/src/nako3.mts +178 -614
  10. package/core/src/nako_basic_plugins.mts +39 -0
  11. package/core/src/nako_core_version.mts +2 -2
  12. package/core/src/nako_csv.mts +0 -1
  13. package/core/src/nako_event.mts +49 -0
  14. package/core/src/nako_gen.mts +291 -202
  15. package/core/src/nako_indent_inline.mts +2 -2
  16. package/core/src/nako_lex_rules.mts +1 -1
  17. package/core/src/nako_parser3.mts +106 -165
  18. package/core/src/nako_parser_async.mts +97 -0
  19. package/core/src/nako_parser_base.mts +4 -55
  20. package/core/src/nako_parser_message.mts +105 -0
  21. package/core/src/nako_parser_operator.mts +93 -0
  22. package/core/src/nako_plugin_manager.mts +260 -0
  23. package/core/src/nako_require.mts +292 -0
  24. package/core/src/nako_runner.mts +191 -0
  25. package/core/src/nako_tokenizer.mts +221 -0
  26. package/core/src/plugin_csv.mts +1 -1
  27. package/core/src/plugin_system.mts +34 -3259
  28. package/core/src/plugin_system_array.mts +699 -0
  29. package/core/src/plugin_system_datetime.mts +368 -0
  30. package/core/src/plugin_system_debug.mts +403 -0
  31. package/core/src/plugin_system_dict.mts +85 -0
  32. package/core/src/plugin_system_json.mts +73 -0
  33. package/core/src/plugin_system_math.mts +383 -0
  34. package/core/src/plugin_system_regexp.mts +120 -0
  35. package/core/src/plugin_system_stdio.mts +86 -0
  36. package/core/src/plugin_system_string.mts +666 -0
  37. package/core/src/plugin_system_timer.mts +152 -0
  38. package/core/src/plugin_system_types.mts +151 -0
  39. package/core/src/plugin_system_url.mts +193 -0
  40. package/core/src/plugin_toml.mts +3 -3
  41. package/core/test/fixtures/README.md +39 -0
  42. package/core/test/fixtures/make_parser_ast_golden.mjs +31 -0
  43. package/core/test/fixtures/parser_ast_golden.json +8027 -0
  44. package/core/test/fixtures/parser_corpus.mjs +120 -0
  45. package/core/test/indent_test.mjs +6 -0
  46. package/core/test/nako_basic_plugins_test.mjs +44 -0
  47. package/core/test/nako_event_test.mjs +85 -0
  48. package/core/test/nako_gen_perf_test.mjs +178 -0
  49. package/core/test/nako_parser_async_test.mjs +112 -0
  50. package/core/test/nako_parser_test.mjs +160 -0
  51. package/core/test/nako_plugin_manager_test.mjs +185 -0
  52. package/core/test/nako_require_test.mjs +153 -0
  53. package/core/test/nako_runner_test.mjs +114 -0
  54. package/core/test/nako_tokenizer_test.mjs +115 -0
  55. package/core/test/plugin_system_debug_test.mjs +141 -0
  56. package/core/test/plugin_system_split_test.mjs +179 -0
  57. package/core/test/plugin_system_test.mjs +6 -0
  58. package/core/tsconfig.json +0 -1
  59. package/package.json +24 -34
  60. package/release/_hash.txt +40 -40
  61. package/release/_script-tags.txt +16 -16
  62. package/release/command.json +1 -1
  63. package/release/command.json.js +1 -1
  64. package/release/command_cnako3.json +1 -1
  65. package/release/command_list.json +1 -1
  66. package/release/edit_main.js +6 -6
  67. package/release/edit_main.js.map +3 -3
  68. package/release/editor.js +6 -6
  69. package/release/plugin_datetime.js +1 -1
  70. package/release/plugin_datetime.js.map +3 -3
  71. package/release/plugin_keigo.js.map +3 -3
  72. package/release/plugin_markup.js +47 -47
  73. package/release/plugin_markup.js.map +3 -3
  74. package/release/plugin_weykturtle3d.js +1 -1
  75. package/release/plugin_weykturtle3d.js.map +3 -3
  76. package/release/version.js +2 -2
  77. package/release/version_main.js +2 -2
  78. package/release/version_main.js.map +2 -2
  79. package/release/wnako3.js +187 -214
  80. package/release/wnako3.js.map +4 -4
  81. package/release/wnako3webworker.js +172 -199
  82. package/release/wnako3webworker.js.map +4 -4
  83. package/src/cnako3mod.mjs +8 -4
  84. package/src/cnako3mod.mts +8 -4
  85. package/src/nako_version.mjs +2 -2
  86. package/src/nako_version.mts +2 -2
  87. package/src/plugin_browser_ajax.mjs +4 -4
  88. package/src/plugin_browser_ajax.mts +4 -4
  89. package/src/plugin_browser_audio.mjs +10 -10
  90. package/src/plugin_browser_audio.mts +10 -10
  91. package/src/plugin_browser_camera.mjs +4 -4
  92. package/src/plugin_browser_camera.mts +4 -4
  93. package/src/plugin_browser_canvas.mjs +2 -2
  94. package/src/plugin_browser_canvas.mts +2 -2
  95. package/src/plugin_browser_crypto.mjs +3 -3
  96. package/src/plugin_browser_crypto.mts +3 -3
  97. package/src/plugin_browser_dom_event.mjs +1 -1
  98. package/src/plugin_browser_dom_event.mts +1 -1
  99. package/src/plugin_browser_geolocation.mjs +1 -1
  100. package/src/plugin_browser_geolocation.mts +1 -1
  101. package/src/plugin_browser_hotkey.mjs +1 -1
  102. package/src/plugin_browser_hotkey.mts +1 -1
  103. package/src/plugin_browser_html.mjs +1 -1
  104. package/src/plugin_browser_html.mts +1 -1
  105. package/src/plugin_browser_location.mjs +1 -1
  106. package/src/plugin_browser_location.mts +1 -1
  107. package/src/plugin_browser_speech.mjs +1 -1
  108. package/src/plugin_browser_speech.mts +1 -1
  109. package/src/plugin_browser_storage.mjs +2 -2
  110. package/src/plugin_browser_storage.mts +2 -2
  111. package/src/plugin_httpserver.mjs +186 -15
  112. package/src/plugin_httpserver.mts +178 -12
  113. package/src/plugin_keigo.mjs +2 -2
  114. package/src/plugin_keigo.mts +2 -2
  115. package/src/plugin_node.mjs +48 -49
  116. package/src/plugin_node.mts +53 -54
  117. package/src/plugin_weykturtle3d.mjs +56 -56
  118. package/src/plugin_weykturtle3d.mts +56 -56
  119. package/src/wnako3.mjs +1 -1
  120. package/src/wnako3.mts +1 -1
  121. package/src/wnako3_editor.mjs +5 -5
  122. package/src/wnako3_editor.mts +5 -5
  123. package/src/wnako3mod.mjs +5 -2
  124. package/src/wnako3mod.mts +5 -2
  125. package/test/common/wnako3mod_test.mjs +48 -0
  126. package/test/node/package_json_test.mjs +17 -0
  127. package/test/node/plugin_httpserver_test.mjs +239 -0
  128. package/tools/nako3server/index.nako3 +4 -2
  129. package/core/src/nako3.mjs +0 -1021
  130. package/core/src/nako_ast.mjs +0 -4
  131. package/core/src/nako_colors.mjs +0 -77
  132. package/core/src/nako_core_version.mjs +0 -8
  133. package/core/src/nako_csv.mjs +0 -193
  134. package/core/src/nako_errors.mjs +0 -166
  135. package/core/src/nako_from_dncl.mjs +0 -285
  136. package/core/src/nako_from_dncl2.mjs +0 -347
  137. package/core/src/nako_gen.mjs +0 -2500
  138. package/core/src/nako_global.mjs +0 -138
  139. package/core/src/nako_indent.mjs +0 -442
  140. package/core/src/nako_indent_chars.mjs +0 -29
  141. package/core/src/nako_indent_inline.mjs +0 -361
  142. package/core/src/nako_josi_list.mjs +0 -47
  143. package/core/src/nako_lex_rules.mjs +0 -319
  144. package/core/src/nako_lexer.mjs +0 -794
  145. package/core/src/nako_logger.mjs +0 -221
  146. package/core/src/nako_parser3.mjs +0 -3250
  147. package/core/src/nako_parser_base.mjs +0 -403
  148. package/core/src/nako_parser_const.mjs +0 -37
  149. package/core/src/nako_prepare.mjs +0 -329
  150. package/core/src/nako_reserved_words.mjs +0 -42
  151. package/core/src/nako_source_mapping.mjs +0 -207
  152. package/core/src/nako_test.mjs +0 -37
  153. package/core/src/nako_token.mjs +0 -1
  154. package/core/src/nako_tools.mjs +0 -53
  155. package/core/src/nako_types.mjs +0 -14
  156. package/core/src/plugin_api.mjs +0 -4
  157. package/core/src/plugin_csv.mjs +0 -97
  158. package/core/src/plugin_math.mjs +0 -352
  159. package/core/src/plugin_promise.mjs +0 -102
  160. package/core/src/plugin_system.mjs +0 -3810
  161. package/core/src/plugin_test.mjs +0 -52
  162. package/core/src/plugin_toml.mjs +0 -39
@@ -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, FuncArgs, NewEmptyToken, SourceMap } from './nako_types.mjs'
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
- this.isModifiedNodes = false
31
- this._checkAsyncFn(result)
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 words: string[] = []
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 `未解決の単語があります: [${desc}]\n次の命令の可能性があります:\n${descFunc}`
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 this.infixToAST(args)
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()
@@ -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()
@@ -2573,6 +2560,10 @@ export class NakoParser extends NakoParserBase {
2573
2560
  return null
2574
2561
  }
2575
2562
 
2563
+ // ---------------------------------------------------------------------------
2564
+ // 変数名の解決と登録
2565
+ // ---------------------------------------------------------------------------
2566
+
2576
2567
  /** 変数を生成 */
2577
2568
  createVar(word: Token|Ast, isConst: boolean, isExport: boolean): Token|Ast {
2578
2569
  let gname: string = (word as AstStrValue).value
@@ -2630,6 +2621,10 @@ export class NakoParser extends NakoParserBase {
2630
2621
  return words
2631
2622
  }
2632
2623
 
2624
+ // ---------------------------------------------------------------------------
2625
+ // JSON/配列リテラル
2626
+ // ---------------------------------------------------------------------------
2627
+
2633
2628
  yJSONObjectValue(): Ast[] {
2634
2629
  // 戻り値の形式
2635
2630
  // Astblocks.blocks = [key1, value1, key2, value2, key3, value3 ...]
@@ -2804,6 +2799,10 @@ export class NakoParser extends NakoParserBase {
2804
2799
  return null
2805
2800
  }
2806
2801
 
2802
+ // ---------------------------------------------------------------------------
2803
+ // エラー監視
2804
+ // ---------------------------------------------------------------------------
2805
+
2807
2806
  /** エラー監視構文 */
2808
2807
  yTryExcept(): AstBlocks | null {
2809
2808
  const map = this.peekSourceMap()
@@ -2834,67 +2833,9 @@ export class NakoParser extends NakoParserBase {
2834
2833
  }
2835
2834
  }
2836
2835
 
2837
- /** 関数ごとにasyncFnが必要か確認する */
2838
- _checkAsyncFn(node: Ast): boolean {
2839
- if (!node) { return false }
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
- }
2836
+ // ---------------------------------------------------------------------------
2837
+ // TokenからAstへの変換
2838
+ // ---------------------------------------------------------------------------
2898
2839
 
2899
2840
  /** TokenをそのままNodeに変換するメソッド(ただし簡単なものだけ対応)
2900
2841
  * @returns {Ast[]}
@@ -0,0 +1,97 @@
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 } from './nako_ast.mjs'
14
+ import { FuncList } from './nako_types.mjs'
15
+
16
+ /** 走査中に AST を書き換えたかどうかを持ち回るための入れ物 */
17
+ interface CheckContext {
18
+ modified: boolean
19
+ }
20
+
21
+ /**
22
+ * AST を走査して関数ごとに asyncFn が必要かどうかを確認し、必要なら書き換える。
23
+ *
24
+ * @param node 走査対象の AST
25
+ * @param funclist 関数一覧(呼び出し先が非同期かどうかの判定に使う)
26
+ * @returns AST を書き換えたら true。呼び出し側は false になるまで繰り返すこと
27
+ */
28
+ export function checkAsyncFn (node: Ast, funclist: FuncList): boolean {
29
+ const ctx: CheckContext = { modified: false }
30
+ checkNode(node, funclist, ctx)
31
+ return ctx.modified
32
+ }
33
+
34
+ /**
35
+ * ノードが非同期処理を含むかどうかを返す(必要に応じて AST を書き換える)
36
+ * @returns 非同期処理を含むなら true
37
+ */
38
+ function checkNode (node: Ast, funclist: FuncList, ctx: CheckContext): boolean {
39
+ if (!node) { return false }
40
+ // 関数定義があれば関数
41
+ if (node.type === 'def_func' || node.type === 'def_test' || node.type === 'func_obj') {
42
+ // 関数定義でasyncFnが指定されているならtrueを返す
43
+ const def: AstDefFunc = node as AstDefFunc
44
+ if (def.asyncFn) { return true } // 既にasyncFnが指定されている
45
+ // 関数定義の中身を調べてasyncFnであるならtrueに変更する
46
+ let isAsyncFn = false
47
+ for (const n of def.blocks) {
48
+ if (checkNode(n, funclist, ctx)) {
49
+ isAsyncFn = true
50
+ def.asyncFn = isAsyncFn
51
+ def.meta.asyncFn = isAsyncFn
52
+ ctx.modified = true
53
+ return true
54
+ }
55
+ }
56
+ }
57
+ // 関数呼び出しを調べて非同期処理が必要ならtrueを返す
58
+ if (node.type === 'func') {
59
+ // 関数呼び出し自体が非同期処理ならtrueを返す
60
+ const callNode: AstCallFunc = node as AstCallFunc
61
+ if (callNode.asyncFn) {
62
+ return true
63
+ }
64
+ // 続けて、以下の関数呼び出しの引数などに非同期処理があるかどうか調べる
65
+ // 関数の引数は、node.blocksに格納されている
66
+ if (callNode.blocks) {
67
+ for (const n of callNode.blocks) {
68
+ if (checkNode(n, funclist, ctx)) {
69
+ callNode.asyncFn = true
70
+ ctx.modified = true
71
+ return true
72
+ }
73
+ }
74
+ }
75
+ // さらに、関数のリンクを調べる
76
+ const func = funclist.get(callNode.name)
77
+ if (func && func.asyncFn) {
78
+ callNode.asyncFn = true
79
+ ctx.modified = true
80
+ return true
81
+ }
82
+ return false
83
+ }
84
+ // 連文 ... 現在、効率は悪いが非同期で実行することになっている
85
+ if (node.type === 'renbun') {
86
+ return true
87
+ }
88
+ // その他
89
+ if ((node as AstBlocks).blocks) {
90
+ for (const n of (node as AstBlocks).blocks) {
91
+ if (checkNode(n, funclist, ctx)) {
92
+ return true
93
+ }
94
+ }
95
+ }
96
+ return false
97
+ }
@@ -1,8 +1,9 @@
1
1
 
2
2
  import { NakoLogger } from './nako_logger.mjs'
3
3
  import { FuncList, FuncListItem, SourceMap, NewEmptyToken, ExportMap } from './nako_types.mjs'
4
- import { Ast, AstBlocks, AstOperator, AstConst, AstStrValue } from './nako_ast.mjs'
4
+ import { Ast } from './nako_ast.mjs'
5
5
  import { Token, TokenType } from './nako_token.mjs'
6
+ import { nodeToStr } from './nako_parser_message.mjs'
6
7
 
7
8
  /**
8
9
  * なでしこの構文解析のためのユーティリティクラス
@@ -31,7 +32,6 @@ export class NakoParserBase {
31
32
  protected isReadingCalc: boolean
32
33
  protected isExportDefault: boolean
33
34
  protected isExportStack: boolean[]
34
- protected isModifiedNodes: boolean
35
35
 
36
36
  constructor(logger: NakoLogger) {
37
37
  this.logger = logger
@@ -78,7 +78,6 @@ export class NakoParserBase {
78
78
  this.isExportDefault = true
79
79
  this.isExportStack = []
80
80
  this.moduleExport = new Map()
81
- this.isModifiedNodes = false
82
81
 
83
82
  this.init()
84
83
  }
@@ -110,7 +109,6 @@ export class NakoParserBase {
110
109
  this.arrayIndexFrom = 0
111
110
  this.flagReverseArrayIndex = false
112
111
  this.flagCheckArrayInit = false
113
- this.isModifiedNodes = false
114
112
  }
115
113
 
116
114
  setFuncList(funclist: FuncList) {
@@ -359,56 +357,7 @@ export class NakoParserBase {
359
357
  * @param {boolean} debugMode
360
358
  */
361
359
  nodeToStr(node: Ast|Token|null, opts: {depth: number, typeName?: string}, debugMode: boolean): string {
362
- const depth = opts.depth - 1
363
- const typeName = (name: string) => (opts.typeName !== undefined) ? opts.typeName : name
364
- const debug = debugMode ? (' debug: ' + JSON.stringify(node, null, 2)) : ''
365
- if (!node) { return '(NULL)' }
366
- switch (node.type) {
367
- case 'not':
368
- if (depth >= 0) {
369
- const subNode: Ast = (node as AstBlocks).blocks[0]
370
- return `${typeName('')}『${this.nodeToStr(subNode, { depth }, debugMode)}に演算子『not』を適用した式${debug}』`
371
- } else {
372
- return `${typeName('演算子')}『not』`
373
- }
374
- case 'op': {
375
- const node2: AstOperator = node as AstOperator
376
- let operator: string = node2.operator || ''
377
- const table:{[key: string]: string} = { eq: '=', not: '!', gt: '>', lt: '<', and: 'かつ', or: 'または' }
378
- if (operator in table) {
379
- operator = table[operator]
380
- }
381
- if (depth >= 0) {
382
- const left: string = this.nodeToStr(node2.blocks[0], { depth }, debugMode)
383
- const right: string = this.nodeToStr(node2.blocks[1], { depth }, debugMode)
384
- if (node2.operator === 'eq') {
385
- return `${typeName('')}『${left}と${right}が等しいかどうかの比較${debug}』`
386
- }
387
- return `${typeName('')}『${left}と${right}に演算子『${operator}』を適用した式${debug}』`
388
- } else {
389
- return `${typeName('演算子')}『${operator}${debug}』`
390
- }
391
- }
392
- case 'number':
393
- return `${typeName('数値')}${(node as AstConst).value}`
394
- case 'bigint':
395
- return `${typeName('巨大整数')}${(node as AstConst).value}`
396
- case 'string':
397
- return `${typeName('文字列')}『${(node as AstConst).value}${debug}』`
398
- case 'word':
399
- return `${typeName('単語')}『${(node as AstStrValue).value}${debug}』`
400
- case 'func':
401
- return `${typeName('関数')}『${node.name || (node as AstStrValue).value}${debug}』`
402
- case 'eol':
403
- return '行の末尾'
404
- case 'eof':
405
- return 'ファイルの末尾'
406
- default: {
407
- let name:any = node.name
408
- if (name) { name = (node as AstStrValue).value }
409
- if (typeof name !== 'string') { name = node.type }
410
- return `${typeName('')}『${name}${debug}』`
411
- }
412
- }
360
+ // (実体は nako_parser_message.mts nodeToStr) #2364
361
+ return nodeToStr(node, opts, debugMode)
413
362
  }
414
363
  }