nadesiko3 3.3.45 → 3.3.49

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 (329) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +143 -132
  3. package/batch/browsers.template.md +3 -3
  4. package/batch/build_browsers.nako3 +72 -72
  5. package/batch/build_command.nako3 +44 -44
  6. package/batch/build_nako_version.nako3 +42 -42
  7. package/batch/calc_hash.nako3 +29 -29
  8. package/batch/cmd_txt2json.nako3 +74 -74
  9. package/batch/command.txt +270 -338
  10. package/batch/command_nakopad.txt +9 -69
  11. package/batch/download-extlib.nako3 +43 -43
  12. package/batch/gen_command_nakopad.nako3 +57 -57
  13. package/batch/jsplugin2text.nako3 +285 -285
  14. package/batch/pickup_command.nako3 +110 -110
  15. package/batch/pickup_reserved_words.nako3 +11 -11
  16. package/batch/publish_version.nako3 +46 -46
  17. package/batch/show_agents.js +14 -14
  18. package/batch/turtle2js.nako3 +21 -21
  19. package/bin/cnako3 +10 -10
  20. package/core/.editorconfig +6 -0
  21. package/core/.eslintrc.cjs +33 -0
  22. package/core/.github/dependabot.yml +7 -0
  23. package/core/.github/workflows/nodejs.yml +37 -0
  24. package/core/.github/workflows/super-linter.yml +61 -0
  25. package/core/.github/workflows/textlint.yml +199 -0
  26. package/core/LICENSE +21 -0
  27. package/core/README.md +66 -0
  28. package/core/batch/build_nako_version.nako3 +42 -0
  29. package/core/command/snako.mjs +105 -0
  30. package/core/command/snako.mts +116 -0
  31. package/core/index.mjs +21 -0
  32. package/core/index.mts +21 -0
  33. package/core/package.json +47 -0
  34. package/core/sample/hello.nako3 +7 -0
  35. package/core/sample/hoge.mjs +4 -0
  36. package/core/sample/hoge.mts +6 -0
  37. package/core/src/nako3.mjs +858 -0
  38. package/core/src/nako3.mts +967 -0
  39. package/core/src/nako_colors.mjs +78 -0
  40. package/core/src/nako_colors.mts +86 -0
  41. package/core/src/nako_core_version.mjs +8 -0
  42. package/core/src/nako_core_version.mts +19 -0
  43. package/core/src/nako_csv.mjs +185 -0
  44. package/core/src/nako_csv.mts +188 -0
  45. package/core/src/nako_errors.mjs +173 -0
  46. package/core/src/nako_errors.mts +197 -0
  47. package/core/src/nako_from_dncl.mjs +255 -0
  48. package/core/src/nako_from_dncl.mts +250 -0
  49. package/core/src/nako_gen.mjs +1648 -0
  50. package/core/src/nako_gen.mts +1719 -0
  51. package/core/src/nako_gen_async.mjs +1659 -0
  52. package/core/src/nako_gen_async.mts +1732 -0
  53. package/core/src/nako_global.mjs +107 -0
  54. package/core/src/nako_global.mts +138 -0
  55. package/core/src/nako_indent.mjs +445 -0
  56. package/core/src/nako_indent.mts +492 -0
  57. package/core/src/nako_josi_list.mjs +38 -0
  58. package/core/src/nako_josi_list.mts +45 -0
  59. package/core/src/nako_lex_rules.mjs +253 -0
  60. package/core/src/nako_lex_rules.mts +260 -0
  61. package/core/src/nako_lexer.mjs +609 -0
  62. package/core/src/nako_lexer.mts +612 -0
  63. package/core/src/nako_logger.mjs +199 -0
  64. package/core/src/nako_logger.mts +232 -0
  65. package/core/src/nako_parser3.mjs +2439 -0
  66. package/core/src/nako_parser3.mts +2195 -0
  67. package/core/src/nako_parser_base.mjs +370 -0
  68. package/core/src/nako_parser_base.mts +370 -0
  69. package/core/src/nako_parser_const.mjs +37 -0
  70. package/core/src/nako_parser_const.mts +37 -0
  71. package/core/src/nako_prepare.mjs +304 -0
  72. package/core/src/nako_prepare.mts +315 -0
  73. package/core/src/nako_reserved_words.mjs +38 -0
  74. package/core/src/nako_reserved_words.mts +38 -0
  75. package/core/src/nako_source_mapping.mjs +207 -0
  76. package/core/src/nako_source_mapping.mts +262 -0
  77. package/core/src/nako_test.mjs +37 -0
  78. package/core/src/nako_types.mjs +25 -0
  79. package/core/src/nako_types.mts +151 -0
  80. package/core/src/plugin_csv.mjs +49 -0
  81. package/core/src/plugin_csv.mts +50 -0
  82. package/core/src/plugin_math.mjs +328 -0
  83. package/core/src/plugin_math.mts +326 -0
  84. package/core/src/plugin_promise.mjs +91 -0
  85. package/core/src/plugin_promise.mts +91 -0
  86. package/core/src/plugin_system.mjs +2832 -0
  87. package/core/src/plugin_system.mts +2690 -0
  88. package/core/src/plugin_test.mjs +34 -0
  89. package/core/src/plugin_test.mts +34 -0
  90. package/core/test/array_test.mjs +34 -0
  91. package/core/test/basic_test.mjs +344 -0
  92. package/core/test/calc_test.mjs +140 -0
  93. package/core/test/core_module_test.mjs +23 -0
  94. package/core/test/debug_test.mjs +16 -0
  95. package/core/test/dncl_test.mjs +94 -0
  96. package/core/test/error_message_test.mjs +210 -0
  97. package/core/test/error_test.mjs +16 -0
  98. package/core/test/flow_test.mjs +373 -0
  99. package/core/test/func_call.mjs +160 -0
  100. package/core/test/func_test.mjs +149 -0
  101. package/core/test/indent_test.mjs +364 -0
  102. package/core/test/lex_test.mjs +168 -0
  103. package/core/test/literal_test.mjs +73 -0
  104. package/core/test/nako_lexer_test.mjs +35 -0
  105. package/core/test/nako_logger_test.mjs +76 -0
  106. package/core/test/nako_logger_test.mts +78 -0
  107. package/core/test/plugin_csv_test.mjs +38 -0
  108. package/core/test/plugin_promise_test.mjs +18 -0
  109. package/core/test/plugin_system_test.mjs +630 -0
  110. package/core/test/prepare_test.mjs +96 -0
  111. package/core/test/re_test.mjs +22 -0
  112. package/core/test/side_effects_test.mjs +92 -0
  113. package/core/test/variable_scope_test.mjs +149 -0
  114. package/core/tsconfig.json +101 -0
  115. package/demo/ace_editor.html +89 -89
  116. package/demo/ace_editor_tabs.html +161 -161
  117. package/demo/basic.html +71 -71
  118. package/demo/browsers.html +9 -10
  119. package/demo/css/basic.css +3 -3
  120. package/demo/css/common.css +157 -157
  121. package/demo/css/editor.css +8 -8
  122. package/demo/css/flow.css +3 -3
  123. package/demo/css/index.css +3 -3
  124. package/demo/flow.html +98 -98
  125. package/demo/graph.html +53 -53
  126. package/demo/image/nakopad-icon256.png +0 -0
  127. package/demo/index.html +133 -133
  128. package/demo/js/common.js +17 -17
  129. package/demo/js/turtle3d_test.js +44 -44
  130. package/demo/js/turtle_test.js +45 -45
  131. package/demo/nako3/calc.nako3 +4 -4
  132. package/demo/runscript.html +47 -47
  133. package/demo/runscript2.html +33 -33
  134. package/demo/runscript3.html +35 -35
  135. package/demo/runscript4.html +33 -33
  136. package/demo/turtle.html +58 -58
  137. package/demo/turtle2.html +141 -141
  138. package/demo/turtle3.html +279 -279
  139. package/demo/turtle3d.html +58 -58
  140. package/demo/turtle3d2.html +107 -107
  141. package/demo/version.html +24 -24
  142. package/doc/SETUP.md +157 -157
  143. package/doc/about.md +17 -17
  144. package/doc/browsers.md +26 -26
  145. package/doc/docgen.md +21 -21
  146. package/doc/editor.md +44 -44
  147. package/doc/files.md +39 -39
  148. package/doc/plugins.md +234 -234
  149. package/doc/release.md +79 -79
  150. package/doc/textlint.md +43 -43
  151. package/doc/win32.md +57 -57
  152. package/package.json +195 -192
  153. package/release/_hash.txt +28 -28
  154. package/release/_script-tags.txt +14 -14
  155. package/release/command.json +1 -1
  156. package/release/command.json.js +1 -1
  157. package/release/command_cnako3.json +1 -1
  158. package/release/command_list.json +1 -1
  159. package/release/editor.js +1 -1
  160. package/release/nako_gen_async.js +1 -1
  161. package/release/plugin_csv.js +1 -1
  162. package/release/stats.json +1 -1
  163. package/release/version.js +1 -1
  164. package/release/wnako3.js +1 -1
  165. package/release/wnako3webworker.js +1 -1
  166. package/src/browsers.txt +11 -12
  167. package/src/browsers_agents.json +2 -2
  168. package/src/browsers_agents.mjs +1 -1
  169. package/src/cnako3.mjs +17 -10
  170. package/src/cnako3.mts +18 -12
  171. package/src/cnako3mod.mjs +707 -687
  172. package/src/cnako3mod.mts +712 -696
  173. package/src/commander_ja.mjs +164 -164
  174. package/src/commander_ja.mts +161 -161
  175. package/src/enako3.mjs +68 -69
  176. package/src/era.mjs +22 -22
  177. package/src/image_turtle-elephant.mjs +2 -5
  178. package/src/image_turtle-panda.mjs +2 -5
  179. package/src/image_turtle64.mjs +2 -5
  180. package/src/index.mjs +9 -9
  181. package/src/index.mts +10 -11
  182. package/src/nako3editorfix.sfd +106 -106
  183. package/src/nako_version.mjs +8 -8
  184. package/src/nako_version.mts +2 -2
  185. package/src/plugin_browser.mjs +213 -212
  186. package/src/plugin_browser.mts +206 -205
  187. package/src/plugin_browser_ajax.mjs +399 -399
  188. package/src/plugin_browser_audio.mjs +109 -109
  189. package/src/plugin_browser_canvas.mjs +449 -449
  190. package/src/plugin_browser_chart.mjs +294 -294
  191. package/src/plugin_browser_color.mjs +49 -49
  192. package/src/plugin_browser_crypto.mjs +26 -26
  193. package/src/plugin_browser_dialog.mjs +53 -53
  194. package/src/plugin_browser_dom_basic.mjs +336 -336
  195. package/src/plugin_browser_dom_event.mjs +193 -193
  196. package/src/plugin_browser_dom_parts.mjs +396 -396
  197. package/src/plugin_browser_geolocation.mjs +51 -51
  198. package/src/plugin_browser_hotkey.mjs +25 -25
  199. package/src/plugin_browser_html.mjs +59 -59
  200. package/src/plugin_browser_in_worker.mjs +45 -45
  201. package/src/plugin_browser_location.mjs +21 -21
  202. package/src/plugin_browser_speech.mjs +111 -111
  203. package/src/plugin_browser_storage.mjs +121 -121
  204. package/src/plugin_browser_system.mjs +31 -31
  205. package/src/plugin_browser_websocket.mjs +73 -73
  206. package/src/plugin_caniuse.mjs +29 -29
  207. package/src/plugin_datetime.mjs +394 -394
  208. package/src/plugin_httpserver.mjs +277 -0
  209. package/src/plugin_httpserver.mts +286 -0
  210. package/src/plugin_kansuji.mjs +224 -224
  211. package/src/plugin_keigo.mjs +55 -55
  212. package/src/plugin_markup.mjs +32 -32
  213. package/src/plugin_node.mjs +1047 -1047
  214. package/src/plugin_node.mts +980 -980
  215. package/src/plugin_turtle.mjs +647 -647
  216. package/src/plugin_webworker.mjs +334 -334
  217. package/src/plugin_weykturtle3d.mjs +1214 -1214
  218. package/src/plugin_worker.mjs +95 -95
  219. package/src/repl.nako3 +63 -63
  220. package/src/wnako3.mjs +12 -12
  221. package/src/wnako3.mts +11 -11
  222. package/src/wnako3_editor.css +215 -215
  223. package/src/wnako3_editor.mjs +1542 -1542
  224. package/src/wnako3_editor.mts +1657 -1656
  225. package/src/wnako3mod.mjs +213 -213
  226. package/src/wnako3mod.mts +214 -214
  227. package/src/wnako3webworker.mjs +69 -68
  228. package/test/ace_editor/karma.config.js +94 -94
  229. package/test/ace_editor/test/.babelrc.json +3 -3
  230. package/test/ace_editor/test/ace_editor_test.js +178 -178
  231. package/test/ace_editor/test/html/custom_context.html +139 -139
  232. package/test/async/async_basic_test.mjs +122 -122
  233. package/test/browser/karma.config.js +221 -221
  234. package/test/browser/test/.babelrc.json +3 -3
  235. package/test/browser/test/compare_util.js +50 -50
  236. package/test/browser/test/html/div_basic.html +2 -2
  237. package/test/browser/test/html/event_dom_form.html +4 -4
  238. package/test/browser/test/html/event_dom_scrolldiv.html +5 -5
  239. package/test/browser/test/import_plugin_checker.js +24 -24
  240. package/test/browser/test/plugin_browser_test.js +51 -51
  241. package/test/browser/test/plugin_browser_test_ajax.js +123 -123
  242. package/test/browser/test/plugin_browser_test_color.js +18 -18
  243. package/test/browser/test/plugin_browser_test_dialog.js +72 -72
  244. package/test/browser/test/plugin_browser_test_dom_event.js +598 -598
  245. package/test/browser/test/plugin_browser_test_dom_parts.js +125 -125
  246. package/test/browser/test/plugin_browser_test_system.js +9 -9
  247. package/test/browser/test/plugin_turtle_test.js +817 -817
  248. package/test/browser/test/plugin_webworker_test.js +86 -86
  249. package/test/browser/test/require_test.js +68 -68
  250. package/test/bundled/karma.config.base.js +117 -117
  251. package/test/bundled/karma.config.js +86 -86
  252. package/test/bundled/test/.babelrc.json +3 -3
  253. package/test/bundled/test/bundled_test.js +69 -69
  254. package/test/bundled/test/html/custom_context.html +65 -65
  255. package/test/bundled/test/html/custom_debug.html +66 -66
  256. package/test/bundled/test4b.cmd +52 -52
  257. package/test/bundled/test_base/.babelrc.json +3 -3
  258. package/test/bundled/test_base/_checktool_test.js +25 -25
  259. package/test/bundled/test_base/basic_ajax_test.js +56 -56
  260. package/test/bundled/test_base/basic_async_test.js +18 -18
  261. package/test/bundled/test_base/basic_test.js +153 -153
  262. package/test/bundled/test_base/calc_test.js +132 -132
  263. package/test/bundled/test_base/css/browsers_box.css +114 -114
  264. package/test/bundled/test_base/html/custom_context.html +69 -69
  265. package/test/bundled/test_base/html/custom_debug.html +71 -71
  266. package/test/bundled/test_base/js/browsers_box.js +72 -72
  267. package/test/bundled/test_base/plugin_csv_test.js +37 -37
  268. package/test/bundled/test_base/plugin_datetime_test.js +115 -115
  269. package/test/bundled/test_base/plugin_kansuji_test.js +49 -49
  270. package/test/bundled/test_base/plugin_system_test.js +410 -410
  271. package/test/bundled/test_base/plugin_webworker_test.js +53 -53
  272. package/test/bundled/test_base/test_utils.js +191 -191
  273. package/test/common/plugin_browser_test.mjs +22 -24
  274. package/test/common/plugin_browser_ut_audio_test.mjs +108 -108
  275. package/test/common/plugin_browser_ut_color_test.mjs +21 -21
  276. package/test/common/plugin_browser_ut_dialog_test.mjs +100 -100
  277. package/test/common/plugin_browser_ut_html_test.mjs +13 -13
  278. package/test/common/plugin_browser_ut_system_test.mjs +10 -10
  279. package/test/common/plugin_markup_test.mjs +23 -23
  280. package/test/jsconfig.json +19 -19
  281. package/test/karma.config.js +91 -91
  282. package/test/node/async_test.mjs +96 -82
  283. package/test/node/commander_ja_test.mjs +89 -89
  284. package/test/node/error_message_test.mjs +243 -253
  285. package/test/node/kai_test.nako3 +6 -6
  286. package/test/node/node_test.mjs +60 -60
  287. package/test/node/plugin_broken.js.txt +3 -3
  288. package/test/node/plugin_browser_ut_ajax_test.mjs.todo +357 -357
  289. package/test/node/plugin_browser_ut_location_test.mjs +42 -42
  290. package/test/node/plugin_markup_test.mjs +47 -46
  291. package/test/node/plugin_math_test.mjs +45 -44
  292. package/test/node/plugin_node_test.mjs +98 -97
  293. package/test/node/plugin_test.mjs +44 -43
  294. package/test/node/relative_import_test_1.nako3 +1 -1
  295. package/test/node/relative_import_test_2.nako3 +2 -2
  296. package/test/node/require_nako3_test.mjs +67 -66
  297. package/test/node/requiretest.nako3 +4 -4
  298. package/test/node/requiretest_indirect.nako3 +1 -1
  299. package/test/node/requiretest_name.nako3 +5 -5
  300. package/test/node/runtime_error.nako3 +2 -2
  301. package/test/node/scope1.nako3 +10 -10
  302. package/test/node/scope2.nako3 +12 -12
  303. package/test/node/side_effects_test.mjs +39 -119
  304. package/test/node/sjis.txt +5 -5
  305. package/test/node/syntax_error.nako3 +1 -1
  306. package/test/node/wnako3_editor_test.mjs +384 -384
  307. package/tools/README.md +12 -7
  308. package/tools/check_new_version.nako3 +25 -25
  309. package/tools/nako3edit/html/daisyui/LICENSE +22 -22
  310. package/tools/nako3edit/html/daisyui/version_2.14.1 +1 -1
  311. package/tools/nako3edit/html/edit.html +170 -170
  312. package/tools/nako3edit/html/edit_plugin.js +6 -6
  313. package/tools/nako3edit/html/files.html +125 -125
  314. package/tools/nako3edit/html/nako3edit.css +65 -65
  315. package/tools/nako3edit/index.mjs +248 -244
  316. package/tools/nako3server/index.html +10 -0
  317. package/tools/nako3server/index.mjs +116 -116
  318. package/tools/nako3server/index.nako3 +34 -0
  319. package/release/nako_gen_async.js.LICENSE.txt +0 -35
  320. package/release/plugin_caniuse.js.LICENSE.txt +0 -11
  321. package/release/plugin_csv.js.LICENSE.txt +0 -15
  322. package/release/plugin_datetime.js.LICENSE.txt +0 -15
  323. package/release/plugin_kansuji.js.LICENSE.txt +0 -3
  324. package/release/plugin_markup.js.LICENSE.txt +0 -11
  325. package/release/plugin_turtle.js.LICENSE.txt +0 -15
  326. package/release/plugin_webworker.js.LICENSE.txt +0 -3
  327. package/release/plugin_weykturtle3d.js.LICENSE.txt +0 -3
  328. package/release/wnako3webworker.js.LICENSE.txt +0 -131
  329. package/tools/nako3edit/a.sqlite3 +0 -0
@@ -0,0 +1,1732 @@
1
+ /**
2
+ * file: nako_gen_async
3
+ * パーサーが生成した中間オブジェクトを実際のJavaScriptのコードに変換する。
4
+ * なお、扱いやすさ優先で、なでしこの一文を一つの関数として生成し、非同期実行する。
5
+ */
6
+
7
+ import { NakoSyntaxError, NakoError, NakoRuntimeError } from './nako_errors.mjs'
8
+ import nakoVersion from './nako_core_version.mjs'
9
+ import { NakoGen } from './nako_gen.mjs'
10
+ import { Ast, Token, SourceMap, FuncList } from './nako_types.mjs'
11
+ import { NakoCompiler } from './nako3.mjs'
12
+
13
+ /**
14
+ * なでしこのインタプリタコード
15
+ */
16
+ const NakoCodeNop = 'NOP'
17
+ const NakoCodeLabel = 'LBL'
18
+ const NakoCodeEOL = 'EOL'
19
+ const NakoCodeJump = 'JMP' // JUMP addr
20
+ const NakoCodeJumpIfTrue = 'JMP_T' // pop and jump addr
21
+ const NakoCodeJumpIfFalse = 'JMP_F' // pop and jump addr
22
+ const NakoCodeCall = 'CALL' // call addr
23
+ const NakoCodeCallObj = 'CALL_OBJ' // call addr
24
+ const NakoCodeReturn = 'RET'
25
+ const NakoCodeTry = 'TRY'
26
+ const NakoCodeCode = 'CODE'
27
+ const NakoCodeTagIsFuncpoint = 0x0F
28
+
29
+ /**
30
+ * なでしこのインタプリタが用いる簡易コードを表現するクラス
31
+ */
32
+ class NakoCode {
33
+ type: string
34
+ value: string
35
+ no: number
36
+ tag: number
37
+ /**
38
+ * @param type
39
+ * @param value
40
+ */
41
+ constructor (type: string, value: string) {
42
+ /** Codeのタイプ
43
+ * @type {string}
44
+ */
45
+ this.type = type
46
+ /** Codeの値 / ラベルならラベル名
47
+ * @type {string}
48
+ */
49
+ this.value = value
50
+ /** ラベルならジャンプ先
51
+ * @type {number}
52
+ */
53
+ this.no = -1
54
+ /** タグ
55
+ * @type {number}
56
+ */
57
+ this.tag = 0
58
+ }
59
+ }
60
+
61
+ interface FuncListSet {
62
+ isFunction: boolean
63
+ names: Set<unknown>
64
+ readonly: Set<string>
65
+ }
66
+
67
+ /**
68
+ * 構文木からJSのコードを生成するクラス
69
+ */
70
+ export class NakoGenASync {
71
+ nakoFuncList: FuncList
72
+ nakoTestList: FuncList
73
+ usedFuncSet: Set<string>
74
+ loopId: number
75
+ flagLoop: boolean
76
+ codeId: number
77
+ codeArray: Array<NakoCode>
78
+ labelContinue: NakoCode | null
79
+ labelBreak: NakoCode | null
80
+ labels: { [key:string]: number }
81
+ genMode: string
82
+ lastLineNo: string | null
83
+ varslistSet: FuncListSet[]
84
+ __self: NakoCompiler
85
+ varsSet: FuncListSet
86
+ speedMode: any
87
+ performanceMonitor: any
88
+ com: NakoCompiler
89
+ /**
90
+ * @param com
91
+ * @param {Ast} ast
92
+ * @param {boolean | string} isTest 文字列なら1つのテストだけを実行する
93
+ */
94
+ static generate (com: NakoCompiler, ast: Ast, isTest: boolean) {
95
+ const gen = new NakoGenASync(com)
96
+
97
+ // ユーザー定義関数をシステムに登録する
98
+ gen.registerFunction(ast)
99
+
100
+ // JSコードを生成する
101
+ let js = gen.convGen(ast, !!isTest)
102
+
103
+ // JSコードを実行するための事前ヘッダ部分の生成
104
+ js = gen.getDefFuncCode(isTest) + js
105
+ com.getLogger().trace('--- generate(非同期モード) ---\n' + js)
106
+
107
+ // テストの実行
108
+ if (js && isTest) {
109
+ js += '\n__self._runTests(__tests);\n'
110
+ }
111
+ return {
112
+ // なでしこの実行環境ありの場合
113
+ runtimeEnv: js,
114
+ // JavaScript単体で動かす場合
115
+ standalone:
116
+ `\
117
+ const nakoVersion = ${JSON.stringify(nakoVersion)};
118
+ ${NakoError.toString()}
119
+ ${NakoRuntimeError.toString()}
120
+ this.logger = {
121
+ error(message) { console.error(message) },
122
+ send(level, message) { console.log(message) },
123
+ };
124
+ this.__varslist = [{}, {}, {}];
125
+ this.__vars = this.__varslist[2];
126
+ this.__module = {};
127
+ this.__locals = {};
128
+ this.__labels = {};
129
+ this.__code = [];
130
+ this.__callstack = [];
131
+ this.__stack = [];
132
+ this.__genMode = '非同期モード';
133
+ try {
134
+ ${gen.getVarsCode()}
135
+ ${js}
136
+ } catch (err) {
137
+ if (!(err instanceof NakoRuntimeError)) {
138
+ err = new NakoRuntimeError(err, this.__varslist[0].line);
139
+ }
140
+ this.logger.error(err);
141
+ throw err;
142
+ }`,
143
+ gen // コード生成に使ったNakoGenのインスタンス
144
+ }
145
+ }
146
+
147
+ /**
148
+ * @param com コンパイラのインスタンス
149
+ */
150
+ constructor (com: NakoCompiler) {
151
+ this.com = com
152
+ /**
153
+ * 出力するJavaScriptコードのヘッダー部分で定義する必要のある関数。fnはjsのコード。
154
+ * プラグイン関数は含まれない。
155
+ */
156
+ this.nakoFuncList = { ...com.getNakoFuncList() }
157
+
158
+ /**
159
+ * なでしこで定義したテストの一覧
160
+ * @type {Record<string, { josi: string[][], fn: string, type: 'test_func' }>}
161
+ */
162
+ this.nakoTestList = {}
163
+
164
+ /**
165
+ * プログラム内で参照された関数のリスト。プラグインの命令を含む。
166
+ * JavaScript単体で実行するとき、このリストにある関数の定義をJavaScriptコードの先頭に付け足す。
167
+ * @type {Set<string>}
168
+ */
169
+ this.usedFuncSet = new Set()
170
+
171
+ /**
172
+ * ループ時の一時変数が被らないようにIDで管理
173
+ * @type {number}
174
+ */
175
+ this.loopId = 1
176
+
177
+ /**
178
+ * 変換中の処理が、ループの中かどうかを判定する
179
+ * @type {boolean}
180
+ */
181
+ this.flagLoop = false
182
+
183
+ /**
184
+ * 変換後のコード管理番号
185
+ * @type {number}
186
+ */
187
+ this.codeId = 0
188
+
189
+ /**
190
+ * 変換後のコードを保持する配列
191
+ * @type {Array<NakoCode>}
192
+ */
193
+ this.codeArray = []
194
+
195
+ /** @type {NakoCode | null} */
196
+ this.labelContinue = null
197
+ /** @type {NakoCode | null} */
198
+ this.labelBreak = null
199
+
200
+ /**
201
+ * ジャンプ先を表現するラベル
202
+ * @type {Object<string, number>}
203
+ */
204
+ this.labels = {}
205
+
206
+ // コンパイラのインスタンス
207
+ this.__self = com
208
+ /**
209
+ * コードジェネレータの種類
210
+ * @type {string}
211
+ */
212
+ this.genMode = '非同期モード'
213
+
214
+ /**
215
+ * 行番号とファイル名が分かるときは `l123:main.nako3`、行番号だけ分かるときは `l123`、そうでなければ任意の文字列。
216
+ * @type {string | null}
217
+ */
218
+ this.lastLineNo = null
219
+
220
+ /**
221
+ * スタック
222
+ * @type {{ isFunction: boolean, names: Set<string>, readonly: Set<string> }[]}
223
+ */
224
+ this.varslistSet = com.__varslist.map((v: any) => ({ isFunction: false, names: new Set(Object.keys(v)), readonly: new Set() }))
225
+
226
+ /**
227
+ * スタックトップ
228
+ * @type {{ isFunction: boolean, names: Set<string>, readonly: Set<string> }}
229
+ */
230
+ this.varsSet = { isFunction: false, names: new Set(), readonly: new Set() }
231
+ this.varslistSet[2] = this.varsSet
232
+
233
+ // 1以上のとき高速化する。
234
+ // 実行速度優先ブロック内で1増える。
235
+ this.speedMode = {
236
+ lineNumbers: 0, // 行番号を出力しない
237
+ implicitTypeCasting: 0, // 数値加算でparseFloatを出力しない
238
+ invalidSore: 0, // 「それ」を用いない
239
+ forcePure: 0 // 全てのシステム命令をpureとして扱う。命令からローカル変数への参照が出来なくなる。
240
+ }
241
+
242
+ // 1以上のとき測定をinjectする。
243
+ // パフォーマンスモニタのブロック内で1増える。
244
+ this.performanceMonitor = {
245
+ userFunction: 0, // 呼び出されたユーザ関数
246
+ systemFunction: 0, // システム関数(呼び出しコードを含む)
247
+ systemFunctionBody: 0 // システム関数(呼び出しコードを除く)
248
+ }
249
+ }
250
+
251
+ /**
252
+ * @param {import("./nako3").Ast} node
253
+ * @param {boolean} forceUpdate
254
+ */
255
+ convLineno (node: any, forceUpdate: boolean) {
256
+ if (this.speedMode.lineNumbers > 0) { return '' }
257
+
258
+ /** @type {string} */
259
+ let lineNo
260
+ if (typeof node.line !== 'number') {
261
+ lineNo = 'unknown'
262
+ } else if (typeof node.file !== 'string') {
263
+ lineNo = `l${node.line}`
264
+ } else {
265
+ lineNo = `l${node.line}:${node.file}`
266
+ }
267
+
268
+ // 強制的に行番号をアップデートするか
269
+ if (!forceUpdate) {
270
+ if (lineNo === this.lastLineNo) { return '' }
271
+ this.lastLineNo = lineNo
272
+ }
273
+ // 例: __v0.line='l1:main.nako3'
274
+ return `__v0.line=${JSON.stringify(lineNo)};`
275
+ }
276
+
277
+ /**
278
+ * ローカル変数のJavaScriptコードを生成する。
279
+ * 基本的に取得のために利用
280
+ * @param {string} name
281
+ */
282
+ varname (name: string) {
283
+ const keys = JSON.stringify(name)
284
+ return `sys.__vars[${keys}]`
285
+ }
286
+
287
+ /**
288
+ * プログラムの実行に必要な関数を書き出す(システム領域)
289
+ * @returns {string}
290
+ */
291
+ getVarsCode () {
292
+ let code = ''
293
+
294
+ // プログラム中で使った関数を列挙して書き出す
295
+ for (const key of Array.from(this.usedFuncSet.values())) {
296
+ const f = this.__self.__varslist[0][key]
297
+ const name = `this.__varslist[0]["${key}"]`
298
+ if (typeof (f) === 'function') { code += name + '=' + f.toString() + ';\n' } else { code += name + '=' + JSON.stringify(f) + ';\n' }
299
+ }
300
+ return code
301
+ }
302
+
303
+ /**
304
+ * プログラムの実行に必要な関数定義を書き出す(グローバル領域)
305
+ * convGenの結果を利用するため、convGenの後に呼び出すこと。
306
+ * @param {boolean | string} isTest テストかどうか。stringの場合は1つのテストのみ。
307
+ * @returns {string}
308
+ */
309
+ getDefFuncCode (isTest: string | boolean) {
310
+ let code = ''
311
+ // よく使う変数のショートカット
312
+ code += 'const __self = this.__self = this;\n'
313
+ code += 'const __varslist = this.__varslist;\n'
314
+ code += 'const __module = this.__module;\n'
315
+ code += 'const __v0 = this.__v0 = this.__varslist[0];\n'
316
+ code += 'const __v1 = this.__v1 = this.__varslist[1];\n'
317
+ code += 'const __vars = this.__vars = this.__varslist[2];\n'
318
+ code += 'const __code = this.__code;\n'
319
+
320
+ // なでしこの関数定義を行う
321
+ let nakoFuncCode = ''
322
+ for (const key in this.nakoFuncList) {
323
+ const f = this.nakoFuncList[key].fn
324
+ nakoFuncCode += '' +
325
+ `//[DEF_FUNC name='${key}']\n` +
326
+ `__v1["${key}"]=${f};\n;` +
327
+ `//[/DEF_FUNC name='${key}']\n`
328
+ }
329
+ if (nakoFuncCode !== '') { code += '__v0.line=\'関数の定義\';\n' + nakoFuncCode }
330
+
331
+ // プラグインの初期化関数を実行する
332
+ let pluginCode = ''
333
+ for (const name in this.__self.__module) {
334
+ const initkey = `!${name}:初期化`
335
+ if (this.varslistSet[0].names.has(initkey)) {
336
+ this.usedFuncSet.add(`!${name}:初期化`)
337
+ pluginCode += `__v0["!${name}:初期化"](__self);\n`
338
+ }
339
+ }
340
+ if (pluginCode !== '') { code += '__v0.line=\'プラグインの初期化\';\n' + pluginCode }
341
+
342
+ // テストの定義を行う
343
+ if (isTest) {
344
+ let testCode = 'const __tests = [];\n'
345
+
346
+ for (const key in this.nakoTestList) {
347
+ if (isTest === true || (typeof isTest === 'string' && isTest === key)) {
348
+ const f = this.nakoTestList[key].fn
349
+ testCode += `${f};\n;`
350
+ }
351
+ }
352
+
353
+ if (testCode !== '') {
354
+ code += '__v0.line=\'テストの定義\';\n'
355
+ code += testCode + '\n'
356
+ }
357
+ }
358
+
359
+ return code
360
+ }
361
+
362
+ /**
363
+ * プラグイン・オブジェクトを追加
364
+ * @param po プラグイン・オブジェクト
365
+ */
366
+ addPlugin (po: any) {
367
+ return this.__self.addPlugin(po)
368
+ }
369
+
370
+ /**
371
+ * プラグイン・オブジェクトを追加(ブラウザ向け)
372
+ * @param name オブジェクト名
373
+ * @param po 関数リスト
374
+ */
375
+ addPluginObject (name: any, po: any) {
376
+ this.__self.addPluginObject(name, po)
377
+ }
378
+
379
+ /**
380
+ * プラグイン・ファイルを追加(Node.js向け)
381
+ * @param objName オブジェクト名
382
+ * @param path ファイルパス
383
+ * @param po 登録するオブジェクト
384
+ */
385
+ addPluginFile (objName: any, path: any, po: any) {
386
+ this.__self.addPluginFile(objName, path, po)
387
+ }
388
+
389
+ /**
390
+ * 関数を追加する
391
+ * @param key 関数名
392
+ * @param josi 助詞
393
+ * @param fn 関数
394
+ */
395
+ addFunc (key: any, josi: any, fn: any) {
396
+ this.__self.addFunc(key, josi, fn)
397
+ }
398
+
399
+ /**
400
+ * プラグイン関数を参照する
401
+ * @param key プラグイン関数の関数名
402
+ * @returns プラグイン・オブジェクト
403
+ */
404
+ getFunc (key: any) {
405
+ return this.__self.getFunc(key)
406
+ }
407
+
408
+ /**
409
+ * 関数を先に登録してしまう
410
+ */
411
+ registerFunction (ast: any) {
412
+ if (ast.type !== 'block') { throw NakoSyntaxError.fromNode('構文解析に失敗しています。構文は必ずblockが先頭になります', ast) }
413
+
414
+ const registFunc = (node: { block: string | any[] }) => {
415
+ for (let i = 0; i < node.block.length; i++) {
416
+ const t = node.block[i]
417
+ if (t.type === 'def_func') {
418
+ const name = t.name.value
419
+ this.usedFuncSet.add(name)
420
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
421
+ this.__self.__varslist[1][name] = function () { } // 事前に適当な値を設定
422
+ this.nakoFuncList[name] = {
423
+ josi: t.name.meta.josi,
424
+ fn: '',
425
+ type: 'func'
426
+ }
427
+ } else
428
+ if (t.type === 'speed_mode') {
429
+ if (t.block.type === 'block') {
430
+ registFunc(t.block)
431
+ } else {
432
+ registFunc(t)
433
+ }
434
+ } else
435
+ if (t.type === 'performance_monitor') {
436
+ if (t.block.type === 'block') {
437
+ registFunc(t.block)
438
+ } else {
439
+ registFunc(t)
440
+ }
441
+ }
442
+ }
443
+ }
444
+ registFunc(ast)
445
+
446
+ // __self.__varslistの変更を反映
447
+ const initialNames = new Set()
448
+ if (this.speedMode.invalidSore === 0) {
449
+ initialNames.add('それ')
450
+ }
451
+ this.varsSet = { isFunction: false, names: initialNames, readonly: new Set() }
452
+ this.varslistSet = this.__self.__varslist.map(v => ({ isFunction: false, names: new Set(Object.keys(v)), readonly: new Set() }))
453
+ this.varslistSet[2] = this.varsSet
454
+ }
455
+
456
+ /**
457
+ * @param {Ast} node
458
+ * @param {boolean} isTest
459
+ */
460
+ convGen (node: any, isTest: boolean) {
461
+ // convert
462
+ this._convGen(node, true)
463
+
464
+ // ラベルアドレスの解決が必要なコード一覧
465
+ const needToFixAddr = new Set([
466
+ NakoCodeJump, NakoCodeJumpIfTrue, NakoCodeJumpIfFalse, NakoCodeCall, NakoCodeTry
467
+ ])
468
+
469
+ // コードの最適化をするか?
470
+ const optimization = true
471
+ let codes = this.codeArray
472
+ //
473
+ if (optimization) {
474
+ // NOPを削除
475
+ codes = codes.filter((code: { type: string }) => {
476
+ return code.type !== NakoCodeNop
477
+ })
478
+ // 未参照のラベルを探す - ただし関数呼び出しは削除しない
479
+ const usedLabels = new Set()
480
+ codes.forEach((code: { type: string; value: unknown }) => {
481
+ if (needToFixAddr.has(code.type)) {
482
+ usedLabels.add(code.value)
483
+ }
484
+ })
485
+ // 未参照のラベルを削除
486
+ codes = codes.filter((code: { type: string; tag: number; value: unknown }) => {
487
+ if (code.type !== NakoCodeLabel) { return true }
488
+ if (code.tag === NakoCodeTagIsFuncpoint) { return true }
489
+ return usedLabels.has(code.value)
490
+ })
491
+ // EOLが連続していたら削除する
492
+ let i = 0
493
+ while (i < codes.length - 1) {
494
+ if (codes[i].type === NakoCodeEOL && codes[i + 1].type === NakoCodeEOL) {
495
+ codes.splice(i + 1, 1)
496
+ continue
497
+ }
498
+ i++
499
+ }
500
+ this.codeArray = codes
501
+ }
502
+ // ラベルアドレスの解決
503
+ codes.forEach((code: { type: string; value: string | number }, index: any) => { // ラベルのアドレスを調べる
504
+ if (code.type === NakoCodeLabel) {
505
+ this.labels[code.value] = index
506
+ }
507
+ })
508
+ codes.forEach((code: { type: string; no: number; value: string | number }) => { // ラベルのアドレスを設定
509
+ if (needToFixAddr.has(code.type)) {
510
+ if (code.no < 0) {
511
+ code.no = this.labels[code.value]
512
+ }
513
+ }
514
+ })
515
+ let result = ''
516
+ // コードの生成
517
+ codes.forEach((code: { type: any; value: string; no: any }, index: any) => {
518
+ switch (code.type) {
519
+ case NakoCodeNop:
520
+ result += `case ${index}: break; // [NOP] ${code.value}\n`
521
+ break
522
+ case NakoCodeLabel:
523
+ result += `case ${index}: break; // [LABEL] ${code.value}\n`
524
+ break
525
+ case NakoCodeEOL:
526
+ result += `case ${index}: ${code.value}; break; // [EOL]\n`
527
+ break
528
+ case NakoCodeJump:
529
+ result += `case ${index}: sys.nextIndex = ${code.no}; break; // ${code.value}\n`
530
+ break
531
+ case NakoCodeJumpIfTrue:
532
+ result += `case ${index}: if (sys.__stack.pop()) { sys.nextIndex = ${code.no};} break; // ${code.value}\n`
533
+ break
534
+ case NakoCodeJumpIfFalse:
535
+ result += `case ${index}: if (!sys.__stack.pop()) { sys.nextIndex = ${code.no}} break; // ${code.value}\n`
536
+ break
537
+ case NakoCodeReturn:
538
+ result += `case ${index}: sys.__return(sys); break;\n`
539
+ break
540
+ case NakoCodeCall:
541
+ result += `case ${index}: sys.__call(${code.no}, sys); break; // ${code.value}\n`
542
+ break
543
+ case NakoCodeCallObj:
544
+ result += `case ${index}: sys.__callObj('${code.value}', ${index}, sys); break; // ${code.value}\n`
545
+ break
546
+ case NakoCodeTry:
547
+ result += `case ${index}: sys.tryIndex = ${code.no}; break; // TRY \n`
548
+ break
549
+ case NakoCodeCode:
550
+ {
551
+ // trim last
552
+ const s = code.value.replace(/\s+$/, '')
553
+ result += `case ${index}: {\n${s}\n};break;\n`
554
+ break
555
+ }
556
+ default:
557
+ throw new Error('invalid code type')
558
+ }
559
+ })
560
+ result = `
561
+ //-------------------------
562
+ // main_code
563
+ this.__labels = ${JSON.stringify(this.labels)};
564
+ this.nextAsync = (sys) => {
565
+ if (sys.index >= sys.codeSize || sys.index < 0) {return}
566
+ const __v0 = sys.__v0
567
+ try {
568
+ sys.inLoop = true
569
+ while (sys.index < sys.codeSize && sys.index >= 0) {
570
+ // console.log('@@[run]', sys.index)
571
+ switch (sys.index) {
572
+ // --- CODE.BEGIN ---
573
+ ${result}
574
+ // --- CODE.END ---
575
+ default:
576
+ sys.inLoop = false
577
+ console.log(sys.index, sys.__stack)
578
+ throw new Error('Invalid sys.index:' + sys.index)
579
+ break
580
+ }
581
+ // check next
582
+ if (sys.nextIndex >= 0) {
583
+ sys.index = sys.nextIndex
584
+ sys.nextIndex = -1
585
+ } else {
586
+ sys.index++
587
+ }
588
+ if (sys.async) {
589
+ sys.__saveSysenv(sys)
590
+ sys.async = false
591
+ break
592
+ }
593
+ } // end of while
594
+ sys.inLoop = false
595
+ } catch (e) {
596
+ sys.__errorAsync(e, sys)
597
+ }
598
+ }
599
+ this.__errorAsync = (e, sys) => { // エラーが起きた時呼び出す
600
+ sys.__v0["エラーメッセージ"] = e.message;
601
+ if (e.message == '__終わる__') {
602
+ sys.__stopAsync(sys)
603
+ return
604
+ }
605
+ if (sys.tryIndex >= 0) {
606
+ sys.index = sys.tryIndex;
607
+ setTimeout(() => {sys.nextAsync(sys)}, 1)
608
+ } else {
609
+ throw e
610
+ }
611
+ }
612
+ this.__call = (no, sys) => {
613
+ const info = {lastVars:sys.__vars, backNo: this.index + 1}
614
+ sys.__callstack.push(info);
615
+ sys.__vars = {"それ":""}
616
+ sys.__varslist.push(sys.__vars)
617
+ sys.nextIndex = no;
618
+ }
619
+ this.__return = sys => {
620
+ if (sys.__callstack.length === 0) {
621
+ sys.__destroySysenv(sys, sys.curSysenv.envid)
622
+ sys.index = -2
623
+ sys.nextIndex = -1
624
+ return
625
+ }
626
+ const sore = sys.__vars['それ'];
627
+ sys.__varslist.pop();
628
+ const info = sys.__callstack.pop();
629
+ sys.nextIndex = info.backNo;
630
+ sys.__vars = info.lastVars;
631
+ sys.__vars['それ'] = sore
632
+ sys.__stack.push(sore);
633
+ }
634
+ this.__resetAsync = sys => {
635
+ sys.index = 0
636
+ sys.codeSize = ${codes.length};
637
+ sys.async = false
638
+ sys.nextIndex = -1
639
+ sys.tryIndex = -1
640
+ }
641
+ this.__stopAsync = sys => {
642
+ sys.__resetAsync(sys)
643
+ sys.index = -1 // force stop!!
644
+ }
645
+ this.__callNakoCode = (no, backNo, sys) => {
646
+ this.__call(backNo, sys)
647
+ sys.nextIndex = no
648
+ const sysenv = sys.setAsync(sys)
649
+ setTimeout(() => {
650
+ // console.log('//__callNakoCode, back=', backNo, 'no=', no)
651
+ sys.compAsync(sys, sysenv)
652
+ } ,1)
653
+ }
654
+ this.__callNakoCodeEntry = (no, sys) => {
655
+ sys.__saveSysenv(sys)
656
+ sys.curSysenv = sys.__generateSysenv(sys)
657
+ sys.__restoreSysenv(sys)
658
+ sys.__vars = {"それ":""}
659
+ sys.__varslist.push(sys.__vars)
660
+ sys.index = no;
661
+ sys.nextAsync(sys)
662
+ }
663
+ this.__callObj = (vname, curNo, sys) => {
664
+ if (sys.__vars[vname]) {
665
+ const fname = sys.__vars[vname]
666
+ // console.log(sys.__labels)
667
+ if (fname && sys.__labels[fname]) {
668
+ const no = sys.__labels[fname]
669
+ sys.__call(no, sys)
670
+ return
671
+ } else {
672
+ console.log('vname=', vname, 'label=', fname)
673
+ }
674
+ }
675
+ throw new Error('async error in __callObj::', vname)
676
+ }
677
+ this.__generateSysenv = sys => {
678
+ sys.envid = ( sys.envid == null ? 0 : sys.envid ) + 1
679
+ const sysenv = {
680
+ callstack: [],
681
+ varstack: [],
682
+ varslist: [sys.__varslist[0], sys.__varslist[1], sys.__varslist[2]],
683
+ index: -1,
684
+ nextIndex: -1,
685
+ tryIndex: -1,
686
+ envid: sys.envid
687
+ }
688
+ sysenv.vars = sysenv.varslist[2]
689
+ if (sys.sysenvs == null) { sys.sysenvs={} }
690
+ sys.sysenvs[sys.envid] = sysenv
691
+ // console.log('generete envid '+sys.envid)
692
+ return sysenv
693
+ }
694
+ this.__destroySysenv = (sys, envid) => {
695
+ delete sys.sysenvs[envid]
696
+ // console.log('destroy envid '+envid)
697
+ }
698
+ this.__saveSysenv = sys => {
699
+ const sysenv = sys.curSysenv
700
+ sysenv.callstack = sys.__callstack
701
+ sysenv.varstack = sys.__stack
702
+ sysenv.varslist = sys.__varslist
703
+ sysenv.vars = sys.__vars
704
+ sysenv.index = sys.index
705
+ sysenv.nextIndex = sys.nextIndex
706
+ sysenv.tryIndex = sys.tryIndex
707
+ }
708
+ this.__restoreSysenv = sys => {
709
+ const sysenv = sys.curSysenv
710
+ sys.__callstack = sysenv.callstack
711
+ sys.__stack = sysenv.varstack
712
+ sys.__varslist = sysenv.varslist
713
+ sys.__vars = sysenv.vars
714
+ ___vars = sys.__vars
715
+ sys.index = sysenv.index
716
+ sys.nextIndex = sysenv.nextIndex
717
+ sys.tryIndex = sysenv.tryIndex
718
+ }
719
+ this.setAsync = sys => {
720
+ sys.async = true
721
+ return sys.curSysenv
722
+ }
723
+ this.compAsync = (sys,sysenv) => {
724
+ if (sys.async && sys.curSysenv != null && sysenv != null && sys.curSysenv.envid === sysenv.envid) {
725
+ sys.async = false
726
+ } else {
727
+ if (sys.curSysenv == null || sysenv == null || sys.curSysenv.envid !== sysenv.envid) {
728
+ sys.__saveSysenv(sys)
729
+ const envid = sys.curSysenv.envid
730
+ sys.curSysenv = sysenv
731
+ sys.__restoreSysenv(sys)
732
+ // console.log('switch envid '+envid+' to '+sys.curSysenv.envid)
733
+ }
734
+ sys.nextAsync(sys)
735
+ }
736
+ }
737
+
738
+ this.__resetAsync(this)
739
+ this.curSysenv = this.__generateSysenv(this)
740
+ this.nextAsync(this)
741
+ //-------------------------
742
+ `
743
+ if (isTest) {
744
+ return ''
745
+ } else {
746
+ return result
747
+ }
748
+ }
749
+
750
+ /**
751
+ * @param {Ast} node
752
+ * @param {boolean} isExpression
753
+ */
754
+ _convGen (node: any | null | undefined, isExpression: boolean) {
755
+ let code = ''
756
+ if (node instanceof Array) {
757
+ for (let i = 0; i < node.length; i++) {
758
+ const n = node[i]
759
+ code += this._convGen(n, isExpression)
760
+ }
761
+ return code
762
+ }
763
+ if (node === null) { return 'null' }
764
+ if (node === undefined) { return 'undefined' }
765
+ if (typeof (node) !== 'object') { return '' + node }
766
+ // switch
767
+ switch (node.type) {
768
+ // === NOP ===
769
+ case 'nop':
770
+ break
771
+ case 'comment':
772
+ if (!node.value) { node.value = '' }
773
+ this.addCode(new NakoCode(NakoCodeNop, node.value))
774
+ break
775
+ case 'eol':
776
+ this.addCode(new NakoCode(NakoCodeEOL, this.convLineno(node, true)))
777
+ break
778
+
779
+ // === 単純なコード変換 ===
780
+ case 'number':
781
+ this.addCodeStr(`sys.__stack.push(${node.value});//number`)
782
+ break
783
+ case 'string':
784
+ this.convString(node)
785
+ break
786
+ case 'word':
787
+ case 'variable':
788
+ this.convGetVar(node)
789
+ break
790
+ case 'op':
791
+ case 'calc':
792
+ this.convOp(node)
793
+ break
794
+ case 'renbun':
795
+ this.convRenbun(node)
796
+ break
797
+ case 'not':
798
+ this._convGen(node.value, true)
799
+ this.addCodeStr(
800
+ 'if (sys.__stack.length==0) throw new Error(\'NOTでスタックに値がありません\');' +
801
+ 'sys.__stack[sys.__stack.length-1] = (sys.__stack[sys.__stack.length-1]) ? 0:1')
802
+ break
803
+ case '配列参照':
804
+ this.convRefArray(node)
805
+ break
806
+ case 'json_array':
807
+ this.convJsonArray(node)
808
+ break
809
+ case 'json_obj':
810
+ this.convJsonObj(node)
811
+ break
812
+ case 'bool':
813
+ {
814
+ const b = (node.value) ? 'true' : 'false'
815
+ this.addCodeStr(`sys.__stack.push(${b})`)
816
+ break
817
+ }
818
+ case 'null':
819
+ this.addCodeStr('sys.__stack.push(null)')
820
+ break
821
+ case 'func':
822
+ case 'func_pointer':
823
+ case 'calc_func':
824
+ this.convFunc(node, isExpression) // 関数の呼び出し
825
+ break
826
+
827
+ // === 文の変換 ===
828
+ case 'let':
829
+ this.convLet(node)
830
+ break
831
+ case 'let_array':
832
+ this.convLetArray(node)
833
+ break
834
+ case 'block':
835
+ for (let i = 0; i < node.block.length; i++) {
836
+ const b = node.block[i]
837
+ this._convGen(b, false)
838
+ }
839
+ break
840
+ case 'if':
841
+ this.convIf(node)
842
+ break
843
+ case 'repeat_times':
844
+ this.convRepeatTimes(node)
845
+ break
846
+ case 'break':
847
+ this.addCodeStr(this.convCheckLoop(node, 'break'))
848
+ break
849
+ case 'continue':
850
+ this.addCodeStr(this.convCheckLoop(node, 'continue'))
851
+ break
852
+ case 'for':
853
+ this.convFor(node)
854
+ break
855
+ case 'foreach':
856
+ this.convForeach(node)
857
+ break
858
+ case 'while':
859
+ this.convWhile(node)
860
+ break
861
+ case 'switch':
862
+ this.convSwitch(node)
863
+ break
864
+ case 'return':
865
+ this.convReturn(node)
866
+ break
867
+ case 'end':
868
+ code += this.addCodeStr('__varslist[0][\'終\']();')
869
+ break
870
+ case 'def_local_var':
871
+ this.convDefLocalVar(node)
872
+ break
873
+ case 'def_local_varlist':
874
+ code += this.addCodeStr(this.convDefLocalVarlist(node))
875
+ break
876
+ case 'tikuji':
877
+ throw NakoSyntaxError.fromNode('「逐次実行」構文は「!非同期モード」では使えません。', node)
878
+ case 'speed_mode':
879
+ throw NakoSyntaxError.fromNode('「速度有線」構文は「!非同期モード」では使えません。', node)
880
+ case 'performance_monitor':
881
+ this.convPerformanceMonitor(node, isExpression)
882
+ break
883
+ case 'func_obj':
884
+ this.convFuncObj(node)
885
+ break
886
+ case 'def_test':
887
+ this.convDefTest(node)
888
+ break
889
+ case 'def_func':
890
+ code += this.addCodeStr(this.convDefFunc(node))
891
+ break
892
+ // TODO
893
+ case 'try_except':
894
+ code += this.convTryExcept(node)
895
+ break
896
+ case 'require':
897
+ code += this.convRequire(node)
898
+ break
899
+ default:
900
+ throw new Error('System Error: unknown_type=' + node.type)
901
+ }
902
+ return code
903
+ }
904
+
905
+ convRequire (node: any) {
906
+ const gen: NakoGen = new NakoGen(this.com)
907
+ this.addCodeStr(gen.convRequire(node))
908
+ return ''
909
+ }
910
+
911
+ /**
912
+ * add code to array
913
+ * @param {string} codeStr
914
+ * @returns {string}
915
+ */
916
+ addCodeStr (codeStr: string) {
917
+ if (codeStr === '') { return '' }
918
+ const a = codeStr.split('\n')
919
+ const a2 = a.map((row: string) => ' ' + row.replace(/\s+$/, ''))
920
+ const c = new NakoCode(NakoCodeCode, a2.join('\n'))
921
+ return this.addCode(c)
922
+ }
923
+
924
+ /**
925
+ * add code to array
926
+ * @param {NakoCode} code
927
+ * @returns {string}
928
+ */
929
+ addCode (code: NakoCode) {
930
+ this.codeArray[this.codeId] = code
931
+ this.codeId++
932
+ return ''
933
+ }
934
+
935
+ /**
936
+ * make label for jump
937
+ * @param {string} name
938
+ * @returns {NakoCode}
939
+ */
940
+ makeLabel (name: string) {
941
+ const uniqLabel = name + '_' + (this.loopId++)
942
+ return this.makeLabelDirectly(uniqLabel)
943
+ }
944
+
945
+ /**
946
+ * make label for function
947
+ * @param {string} labelName
948
+ * @returns {NakoCode}
949
+ */
950
+ makeLabelDirectly (labelName: string) {
951
+ const c = new NakoCode(NakoCodeLabel, labelName)
952
+ this.labels[labelName] = -1
953
+ return c
954
+ }
955
+
956
+ /**
957
+ * make Jump
958
+ * @param {NakoCode} label
959
+ * @returns {NakoCode}
960
+ */
961
+ makeJump (label: NakoCode) {
962
+ return new NakoCode(NakoCodeJump, label.value)
963
+ }
964
+
965
+ /**
966
+ * make Jump if true
967
+ * @param {NakoCode} label
968
+ * @returns {NakoCode}
969
+ */
970
+ makeJumpIfTrue (label: NakoCode) {
971
+ return new NakoCode(NakoCodeJumpIfTrue, label.value)
972
+ }
973
+
974
+ /**
975
+ * make Jump if false
976
+ * @param {NakoCode} label
977
+ * @returns {NakoCode}
978
+ */
979
+ makeJumpIfFalse (label: NakoCode) {
980
+ return new NakoCode(NakoCodeJumpIfFalse, label.value)
981
+ }
982
+
983
+ /**
984
+ * @param {Ast} node
985
+ */
986
+ convIf (node: { expr: any; block: any; falseBlock: any }) {
987
+ const labelBegin = this.makeLabel('もし:ここから')
988
+ const labelEnd = this.makeLabel('もし:ここまで')
989
+ const labelIfFalse = this.makeLabel('もし:違えば')
990
+ //
991
+ this.addCode(labelBegin)
992
+ this._convGen(node.expr, true)
993
+ this.addCode(this.makeJumpIfFalse(labelIfFalse))
994
+ this._convGen(node.block, false)
995
+ this.addCode(this.makeJump(labelEnd))
996
+ this.addCode(labelIfFalse)
997
+ if (node.falseBlock) {
998
+ this._convGen(node.falseBlock, false)
999
+ }
1000
+ this.addCode(labelEnd)
1001
+ return ''
1002
+ }
1003
+
1004
+ convRepeatTimes (node: { value: any; block: any }) {
1005
+ this.flagLoop = true
1006
+ this.varsSet.names.add('回数')
1007
+ this.varsSet.readonly.add('回数')
1008
+ // ループ管理変数を作成
1009
+ const loopVar = `sys.__tmp_i${this.loopId}`
1010
+ this.loopId++
1011
+ // ループ回数を取得
1012
+ const loopCount = `sys.__tmp_count${this.loopId}`
1013
+ this.loopId++
1014
+ this._convGen(node.value, true)
1015
+ this.addCodeStr(`${loopCount} = sys.__stack.pop(); ${loopVar} = 0;`)
1016
+
1017
+ const labelCheck = this.makeLabel('回:条件チェック')
1018
+ this.addCode(labelCheck)
1019
+ const labelEnd = this.makeLabel('回:ここまで')
1020
+ this.labelBreak = labelEnd
1021
+ this.labelContinue = labelCheck
1022
+
1023
+ // 繰り返し判定
1024
+ const kaisu = 'sys.__vars["回数"]'
1025
+ const cond =
1026
+ `${kaisu} = ++${loopVar}\n` +
1027
+ `sys.__stack.push(${loopVar} > ${loopCount})\n`
1028
+ this.addCodeStr(cond)
1029
+ this.addCode(this.makeJumpIfTrue(labelEnd))
1030
+ this.convGenLoop(node.block) // read block
1031
+ this.addCode(this.makeJump(labelCheck))
1032
+ this.addCode(labelEnd)
1033
+ this.flagLoop = false
1034
+ return ''
1035
+ }
1036
+
1037
+ /**
1038
+ * @param {string} name
1039
+ * @returns {{i: number, name: string, isTop: boolean, js: string} | null}
1040
+ */
1041
+ findVar (name: string) {
1042
+ // __vars ? (ローカル変数)
1043
+ if (this.varsSet.names.has(name)) {
1044
+ return { i: this.varslistSet.length - 1, name, isTop: true, js: `sys.__vars[${JSON.stringify(name)}]` }
1045
+ }
1046
+ // __varslist ?
1047
+ for (let i = 2; i >= 0; i--) {
1048
+ if (this.varslistSet[i].names.has(name)) {
1049
+ return { i, name, isTop: false, js: `sys.__varslist[${i}][${JSON.stringify(name)}]` }
1050
+ }
1051
+ }
1052
+
1053
+ return null
1054
+ }
1055
+
1056
+ /**
1057
+ * 定義済みの変数の参照
1058
+ * @param {string} name
1059
+ * @param {Ast} position
1060
+ */
1061
+ genVar (name: string, position: any) {
1062
+ const res = this.findVar(name)
1063
+ const lno = position.line
1064
+ if (res === null) {
1065
+ // 定義されていない名前の参照は変数の定義とみなす。
1066
+ // 多くの場合はundefined値を持つ変数であり分かりづらいバグを引き起こすが、
1067
+ // 「ナデシコする」などの命令の中で定義された変数の参照の場合があるため警告に留める。
1068
+ // ただし、自動的に定義される変数『引数』『それ』などは例外 #952
1069
+ if (name === '引数' || name === 'それ' || name === '対象' || name === '対象キー' || name === '回数') {
1070
+ // デフォルト定義されている変数名
1071
+ } else {
1072
+ this.__self.getLogger().warn(`変数『${name}』は定義されていません。`, position)
1073
+ }
1074
+ this.varsSet.names.add(name)
1075
+ return this.varname(name)
1076
+ }
1077
+
1078
+ const i = res.i
1079
+ // システム関数・変数の場合
1080
+ if (i === 0) {
1081
+ const pv = this.__self.getFunc(name)
1082
+ if (!pv) { return `${res.js}/*err:${lno}*/` }
1083
+ if (pv.type === 'const' || pv.type === 'var') { return res.js }
1084
+ if (pv.type === 'func') {
1085
+ if (!pv.josi) { throw new Error('[System Error]') }
1086
+ if (pv.josi.length === 0) { return `(${res.js}())` }
1087
+
1088
+ throw NakoSyntaxError.fromNode(`『${name}』が複文で使われました。単文で記述してください。(v1非互換)`, position)
1089
+ }
1090
+ throw NakoSyntaxError.fromNode(`『${name}』は関数であり参照できません。`, position)
1091
+ }
1092
+ return res.js
1093
+ }
1094
+
1095
+ convGetVar (node: { value: any }) {
1096
+ const name = node.value
1097
+ let varName = `sys.__vars[${JSON.stringify(name)}]`
1098
+ const o = this.findVar(name)
1099
+ if (o != null) { varName = o.js }
1100
+ this.addCodeStr(`sys.__stack.push(${varName});`)
1101
+ }
1102
+
1103
+ convComment (node: { value: any }) {
1104
+ let commentSrc = String(node.value)
1105
+ commentSrc = commentSrc.replace(/\n/g, '¶')
1106
+ const lineNo = this.convLineno(node, false)
1107
+ if (commentSrc === '' && lineNo === '') { return ';' }
1108
+ if (commentSrc === '') {
1109
+ return ';' + lineNo + '\n'
1110
+ }
1111
+ return ';' + lineNo + '//' + commentSrc + '\n'
1112
+ }
1113
+
1114
+ convReturn (node: any) {
1115
+ // 関数の中であれば利用可能
1116
+ if (this.varsSet.names.has('!関数')) { throw NakoSyntaxError.fromNode('『戻る』がありますが、関数定義内のみで使用可能です。', node) }
1117
+
1118
+ if (node.value) {
1119
+ this._convGen(node.value, true)
1120
+ this.addCodeStr('sys.__vars["それ"] = sys.__stack.pop()')
1121
+ }
1122
+ this.addCode(new NakoCode(NakoCodeReturn, ''))
1123
+ return ''
1124
+ }
1125
+
1126
+ convCheckLoop (node: Ast | Token | SourceMap, cmd: string) {
1127
+ // ループの中であれば利用可能
1128
+ if (!this.flagLoop) {
1129
+ const cmdj = (cmd === 'continue') ? '続ける' : '抜ける'
1130
+ throw NakoSyntaxError.fromNode(`『${cmdj}』文がありますが、それは繰り返しの中で利用してください。`, node)
1131
+ }
1132
+ if (cmd === 'continue') {
1133
+ if (this.labelContinue) { this.addCode(this.makeJump(this.labelContinue)) }
1134
+ } else {
1135
+ if (this.labelBreak) { this.addCode(this.makeJump(this.labelBreak)) }
1136
+ }
1137
+ return ''
1138
+ }
1139
+
1140
+ convDefFuncCommon (node: { meta: any; name: { meta: any }; block: any }, name: string) {
1141
+ // deffunc_code
1142
+ const isMumeiFunc = (name === '')
1143
+ let funcName = name
1144
+ if (isMumeiFunc) { funcName = `無名関数:${this.loopId++}` }
1145
+
1146
+ const labelEnd = this.makeLabel(`関数「${funcName}」:ここまで`)
1147
+ this.addCode(this.makeJump(labelEnd))
1148
+ const labelBegin = this.makeLabelDirectly(funcName)
1149
+ labelBegin.tag = NakoCodeTagIsFuncpoint // 削除対象からはずすため
1150
+ this.addCode(labelBegin)
1151
+
1152
+ //
1153
+ const initialNames = new Set()
1154
+ this.varsSet = { isFunction: true, names: initialNames, readonly: new Set() }
1155
+ this.varsSet.names.add('それ')
1156
+ // ローカル変数をPUSHする
1157
+ this.varslistSet.push(this.varsSet)
1158
+ // JSの引数と引数をバインド
1159
+ const meta = isMumeiFunc ? node.meta : node.name.meta
1160
+ let code = ''
1161
+ let codeCall = ''
1162
+ code += `//関数『${funcName}』の初期化処理\n`
1163
+ // 宣言済みの名前を保存
1164
+ // const varsDeclared = Array.from(this.varsSet.names.values())
1165
+ // 引数をローカル変数に設定 (スタックの末尾から取得する必要があるので、逆順に値を得る)
1166
+ code += '// 引数をローカル変数として登録\n'
1167
+ for (let i = meta.varnames.length - 1; i >= 0; i--) {
1168
+ const word = meta.varnames[i]
1169
+ code += ` ${this.varname(word)} = sys.__stack.pop();\n`
1170
+ this.varsSet.names.add(word)
1171
+ codeCall += '' // sys.__stack.push(arguments[${i}]);\n
1172
+ }
1173
+ code += '// ここまで:引数をローカル変数として登録\n'
1174
+ this.addCodeStr(code)
1175
+
1176
+ // 関数定義は、グローバル領域で。
1177
+ this.usedFuncSet.add(funcName)
1178
+ this.varslistSet[1].names.add(funcName)
1179
+ this.nakoFuncList[funcName] = {
1180
+ josi: meta.josi,
1181
+ fn: '(function(){\n' +
1182
+ ' const sys = (arguments.length > 0) ? arguments[arguments.length-1] : {}; \n' +
1183
+ ' if (sys.newenv) { \n' +
1184
+ ' sys.newenv = false\n' +
1185
+ ` sys.__callNakoCodeEntry(sys.__labels['${funcName}'], sys);` + '\n' +
1186
+ ' } else {\n' +
1187
+ ' ' + codeCall + '\n' +
1188
+ ` sys.__callNakoCode(sys.__labels['${funcName}'], sys.nextIndex, sys);` + '\n' +
1189
+ ' if (!sys.inLoop) { sys.nextAsync(sys) }\n' +
1190
+ ' } })',
1191
+ type: 'func'
1192
+ }
1193
+
1194
+ // ブロックを解析
1195
+ this._convGen(node.block, false)
1196
+
1197
+ this.varslistSet.pop()
1198
+ this.varsSet = this.varslistSet[this.varslistSet.length - 1]
1199
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
1200
+ this.__self.__varslist[1][funcName] = function () {}
1201
+
1202
+ this.addCode(new NakoCode(NakoCodeReturn, ''))
1203
+ this.addCode(labelEnd)
1204
+
1205
+ // 無名関数の定義であれば無名関数をPUSH
1206
+ if (!name) {
1207
+ this.addCodeStr(`sys.__stack.push('${funcName}')`)
1208
+ }
1209
+ return ''
1210
+ }
1211
+
1212
+ convDefTest (node: Ast | Token | SourceMap) {
1213
+ throw NakoSyntaxError.fromNode('テスト構文は!非同期モードでは使えません。', node)
1214
+ }
1215
+
1216
+ convDefFunc (node: any) {
1217
+ const name = NakoGen.getFuncName(node.name.value)
1218
+ this.convDefFuncCommon(node, name)
1219
+ // ★この時点では関数のコードを生成しない★
1220
+ // プログラム冒頭でコード生成時に関数定義を行う
1221
+ return ''
1222
+ }
1223
+
1224
+ convFuncObj (node: any) {
1225
+ return this.convDefFuncCommon(node, '')
1226
+ }
1227
+
1228
+ convJsonObj (node: { value: any }) {
1229
+ const list = node.value
1230
+ const objName = `sys.__tmp_obj${this.loopId++}`
1231
+ this.addCodeStr(objName + '={}; // convJsonObj::ここから')
1232
+ list.forEach((e: { value: any; key: any }) => {
1233
+ this._convGen(e.value, true)
1234
+ this._convGen(e.key, true)
1235
+ this.addCodeStr(`${objName}[sys.__stack.pop()]=sys.__stack.pop()`)
1236
+ })
1237
+ this.addCodeStr(`this.__stack.push(${objName}); delete $objName; // convJsonObj::ここまで`)
1238
+ return ''
1239
+ }
1240
+
1241
+ convJsonArray (node: { value: any }) {
1242
+ const list = node.value
1243
+ this.addCode(this.makeLabel('convJsonArray::ここから'))
1244
+ list.forEach((e: any) => this._convGen(e, true))
1245
+ const size = list.length
1246
+ this.addCodeStr(`sys.__stack.push(sys.__stack.splice(sys.__stack.length-${size},${size}))`)
1247
+ return ''
1248
+ }
1249
+
1250
+ convRefArray (node: { name: any; index: any }) {
1251
+ // 名前をPUSH
1252
+ this._convGen(node.name, true)
1253
+ const list = node.index
1254
+ for (let i = 0; i < list.length; i++) {
1255
+ // push index
1256
+ this._convGen(list[i], true)
1257
+ // pop index & push value
1258
+ this.addCodeStr(
1259
+ 'const idx = sys.__stack.pop();\n' +
1260
+ 'const obj = sys.__stack.pop();\n' +
1261
+ 'sys.__stack.push(obj[idx]);')
1262
+ }
1263
+ return ''
1264
+ }
1265
+
1266
+ convLetArray (node: { value: any; name: any; index: any }) {
1267
+ // 代入する値をPUSH
1268
+ this._convGen(node.value, true)
1269
+
1270
+ // 変数を取得
1271
+ this._convGen(node.name, true)
1272
+ const list = node.index
1273
+ for (let i = 0; i < list.length; i++) {
1274
+ this._convGen(list[i], true)
1275
+ if (i === list.length - 1) { // 代入
1276
+ this.addCodeStr(
1277
+ 'const idx = this.__stack.pop();' +
1278
+ 'const obj = this.__stack.pop();' +
1279
+ 'const val = this.__stack.pop();' +
1280
+ 'obj[idx]=val;')
1281
+ break
1282
+ }
1283
+ // index アクセス
1284
+ this.addCodeStr(
1285
+ 'const idx = sys.__stack.pop();\n' +
1286
+ 'const obj = sys.__stack.pop();\n' +
1287
+ 'sys.__stack.push(obj[idx]);')
1288
+ }
1289
+ return ''
1290
+ }
1291
+
1292
+ convGenLoop (node: any) {
1293
+ const tmpflag = this.flagLoop
1294
+ this.flagLoop = true
1295
+ try {
1296
+ return this._convGen(node, false)
1297
+ } finally {
1298
+ this.flagLoop = tmpflag
1299
+ }
1300
+ }
1301
+
1302
+ convFor (node: { word: { value: any } | null; from: any; to: any; block: any }) {
1303
+ this.flagLoop = true
1304
+ // ループ変数について
1305
+ let word
1306
+ if (node.word !== null) { // ループ変数を使う時
1307
+ const varName = node.word.value
1308
+ this.varsSet.names.add(varName)
1309
+ word = this.varname(varName)
1310
+ } else {
1311
+ this.varsSet.names.add('dummy')
1312
+ word = this.varname('dummy')
1313
+ }
1314
+ const sore = this.varname('それ')
1315
+ const idLoop = this.loopId++
1316
+ const varI = `sys.__tmp__i${idLoop}`
1317
+ // ループ条件を変数に入れる用
1318
+ const varTo = `sys.__tmp__to${idLoop}`
1319
+ // ループ条件を確認
1320
+ this._convGen(node.from, true)
1321
+ this._convGen(node.to, true)
1322
+ this.addCodeStr(`${varTo}=sys.__stack.pop();${varI}=sys.__stack.pop();`)
1323
+ // ループ変数を初期化
1324
+ this.addCodeStr(`${sore} = ${word} = ${varI}`)
1325
+ // 繰り返し判定
1326
+ const labelCheck = this.makeLabel('繰返:条件確認')
1327
+ const labelInc = this.makeLabel('繰返:加算')
1328
+ this.addCode(labelCheck)
1329
+ const labelEnd = this.makeLabel('繰返:ここまで')
1330
+ this.addCodeStr(`sys.__stack.push(${word} <= ${varTo})`)
1331
+ this.addCode(this.makeJumpIfFalse(labelEnd))
1332
+ this.labelContinue = labelInc
1333
+ this.labelBreak = labelEnd
1334
+ // ループ内のブロック内容を得る
1335
+ this.convGenLoop(node.block) // block
1336
+ this.addCode(labelInc)
1337
+ this.addCodeStr(`${sore} = ++${word};`)
1338
+ this.addCode(this.makeJump(labelCheck))
1339
+ this.addCode(labelEnd)
1340
+ this.addCodeStr(`delete ${varI};delete ${varTo};//繰返:掃除`)
1341
+ this.flagLoop = false
1342
+ return ''
1343
+ }
1344
+
1345
+ convForeach (node: any) {
1346
+ this.flagLoop = true
1347
+ // 対象を用意する
1348
+ let taisyo = '__v0["対象"]'
1349
+ const taisyoKey = '__v0["対象キー"]'
1350
+ if (node.name) {
1351
+ taisyo = this.varname(node.name.value)
1352
+ this.varsSet.names.add(node.name.value)
1353
+ }
1354
+ // 反復対象を調べる
1355
+ const target = node.target
1356
+ if (target === null) {
1357
+ throw NakoSyntaxError.fromNode('『反復』の対象がありません。', node)
1358
+ }
1359
+
1360
+ const sore = this.varname('それ')
1361
+ const targetArray = `sys.__tmp__target${this.loopId++}`
1362
+ const targetKeys = `sys.__tmp__keys${this.loopId++}`
1363
+ const loopVar = `sys.__tmp__i${this.loopId++}`
1364
+ const loopCount = `sys.__tmp__count${this.loopId++}`
1365
+
1366
+ // 反復対象を評価
1367
+ this._convGen(node.target, true)
1368
+ // どのように反復するか判定
1369
+ const initCode =
1370
+ '// 反復: 初期化\n' +
1371
+ `${targetArray} = sys.__stack.pop();\n` +
1372
+ `${loopVar} = 0;\n` +
1373
+ // 文字列や数値なら反復できるように配列に入れる
1374
+ `if (typeof(${targetArray}) == 'string' || typeof(${targetArray}) == 'number') { ${targetArray} = [${targetArray}]; }\n` +
1375
+ // Objectならキー一覧を得る
1376
+ `if (${targetArray} instanceof Array) { ${loopCount} = ${targetArray}.length; }\n` +
1377
+ 'else { // キーの一覧を得る\n' +
1378
+ ` ${targetKeys} = Object.keys(${targetArray}); \n` +
1379
+ ' // hasOwnPropertyがfalseならばkeyを消す処理\n' +
1380
+ ` ${targetKeys} = ${targetKeys}.filter((key)=>{ return ${targetArray}.hasOwnProperty(key) })\n` +
1381
+ ` ${loopCount} = ${targetKeys}.length;\n` +
1382
+ '}\n'
1383
+ this.addCodeStr(initCode)
1384
+ const labelCheck = this.makeLabel('反復:条件確認')
1385
+ const labelInc = this.makeLabel('反復:加算')
1386
+ const labelEnd = this.makeLabel('反復:ここまで')
1387
+ this.labelBreak = labelEnd
1388
+ this.labelContinue = labelInc
1389
+ this.addCode(labelCheck)
1390
+ const setTarget =
1391
+ `if (${targetArray} instanceof Array) {\n` +
1392
+ // eslint-disable-next-line no-irregular-whitespace
1393
+ ` ${taisyo} = ${sore} = ${targetArray}[${loopVar}]; ${taisyoKey} = ${loopVar};\n` +
1394
+ '} else {\n' +
1395
+ ` ${taisyoKey} = ${targetKeys}[${loopVar}]; ${taisyo} = ${sore} = ${targetArray}[${taisyoKey}];\n` +
1396
+ '}\n'
1397
+ this.addCodeStr(`${setTarget}\nsys.__stack.push(${loopVar} < ${loopCount});`)
1398
+ this.addCode(this.makeJumpIfFalse(labelEnd))
1399
+ // 反復ブロックを定義
1400
+ this.convGenLoop(node.block) // block
1401
+ // 加算
1402
+ this.addCode(labelInc)
1403
+ this.addCodeStr(`${loopVar}++`)
1404
+ this.addCode(this.makeJump(labelCheck))
1405
+ this.addCode(labelEnd)
1406
+ this.flagLoop = false
1407
+ return ''
1408
+ }
1409
+
1410
+ convWhile (node: { cond: any; block: any }) {
1411
+ this.flagLoop = true
1412
+ const labelBegin = this.makeLabel('間:ここから')
1413
+ const labelEnd = this.makeLabel('間:ここまで')
1414
+ this.labelContinue = labelBegin
1415
+ this.labelBreak = labelEnd
1416
+ this.addCode(labelBegin)
1417
+ // 条件をスタックに
1418
+ this._convGen(node.cond, true)
1419
+ this.addCode(this.makeJumpIfFalse(labelEnd))
1420
+ // ブロックを追加
1421
+ this.convGenLoop(node.block)
1422
+ this.addCode(this.makeJump(labelBegin))
1423
+ this.addCode(labelEnd)
1424
+ this.flagLoop = false
1425
+ return ''
1426
+ }
1427
+
1428
+ /**
1429
+ * @param {Ast} _node
1430
+ * @param {boolean} _isExpression
1431
+ */
1432
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1433
+ convSpeedMode (_node: any, _isExpression: any) {
1434
+ return ''
1435
+ }
1436
+
1437
+ /**
1438
+ * @param {Ast} node
1439
+ * @param {boolean} isExpression
1440
+ */
1441
+ convPerformanceMonitor (node: { options: { [x: string]: any }; block: any }, isExpression: any) {
1442
+ const prev = { ...this.performanceMonitor }
1443
+ if (node.options['ユーザ関数']) {
1444
+ this.performanceMonitor.userFunction++
1445
+ }
1446
+ if (node.options['システム関数本体']) {
1447
+ this.performanceMonitor.systemFunctionBody++
1448
+ }
1449
+ if (node.options['システム関数']) {
1450
+ this.performanceMonitor.systemFunction++
1451
+ }
1452
+ this._convGen(node.block, isExpression)
1453
+ this.performanceMonitor = prev
1454
+ }
1455
+
1456
+ convSwitch (node: { value: any; cases: any }) {
1457
+ // 値をPUSH
1458
+ this._convGen(node.value, true)
1459
+ const varValue = `sys.__tmp__i${this.loopId++}`
1460
+ this.addCodeStr(`${varValue} = sys.__stack.pop()`)
1461
+ const labelEnd = this.makeLabel('条件分岐:ここまで')
1462
+ const cases = node.cases
1463
+ for (let i = 0; i < cases.length; i++) {
1464
+ const cvalue = cases[i][0]
1465
+ if (cvalue.type === '違えば') {
1466
+ this.convGenLoop(cases[i][1])
1467
+ } else {
1468
+ const nextLabel = this.makeLabel('条件分岐:次')
1469
+ this._convGen(cvalue, true)
1470
+ this.addCodeStr(`sys.__stack.push(sys.__stack.pop() == ${varValue})`)
1471
+ this.addCode(this.makeJumpIfFalse(nextLabel))
1472
+ this.convGenLoop(cases[i][1])
1473
+ this.addCode(this.makeJump(labelEnd))
1474
+ this.addCode(nextLabel)
1475
+ }
1476
+ }
1477
+ this.addCode(labelEnd)
1478
+ this.addCodeStr(`delete ${varValue}//条件分岐:掃除`)
1479
+ return ''
1480
+ }
1481
+
1482
+ convFuncGetArgsCalcType (funcName: string, func: any, node: { args: string | any[] }) {
1483
+ const opts:any = {}
1484
+ for (let i = 0; i < node.args.length; i++) {
1485
+ const arg = node.args[i]
1486
+ if (i === 0 && arg === null) {
1487
+ this.addCodeStr('sys.__stack.push(sys.__vars[\'それ\'])')
1488
+ opts.sore = true
1489
+ } else {
1490
+ // 関数の引数を評価
1491
+ this._convGen(arg, true)
1492
+ }
1493
+ }
1494
+ return opts
1495
+ }
1496
+
1497
+ getPluginList () {
1498
+ const r = []
1499
+ for (const name in this.__self.__module) { r.push(name) }
1500
+ return r
1501
+ }
1502
+
1503
+ /**
1504
+ * 関数の呼び出し
1505
+ * @param {Ast} node
1506
+ * @param {boolean} isExpression
1507
+ * @returns string コード
1508
+ */
1509
+ convFunc (node: any, isExpression: any) {
1510
+ let isJSFunc = false
1511
+ let isMumeiFunc = false
1512
+ const funcName = NakoGen.getFuncName(node.name)
1513
+ const res = this.findVar(funcName)
1514
+ if (res === null) {
1515
+ throw NakoSyntaxError.fromNode(`関数『${funcName}』が見当たりません。有効プラグイン=[` + this.getPluginList().join(', ') + ']', node)
1516
+ }
1517
+ let func
1518
+ if (res.i === 0) { // plugin function
1519
+ func = this.__self.getFunc(funcName)
1520
+ if (func.type !== 'func') {
1521
+ throw NakoSyntaxError.fromNode(`『${funcName}』は関数ではありません。`, node)
1522
+ }
1523
+ isJSFunc = true
1524
+ } else {
1525
+ func = this.nakoFuncList[funcName]
1526
+ // 無名関数の可能性
1527
+ if (func === undefined) {
1528
+ isMumeiFunc = true
1529
+ func = { return_none: false }
1530
+ }
1531
+ }
1532
+ // 関数の参照渡しか?
1533
+ if (node.type === 'func_pointer') {
1534
+ return res.js
1535
+ }
1536
+ // 関数の参照渡しでない場合
1537
+ // 関数定義より助詞を一つずつ調べる
1538
+ const argsOpts = this.convFuncGetArgsCalcType(funcName, func, node)
1539
+ // function
1540
+ this.usedFuncSet.add(funcName)
1541
+ let funcBegin = ''
1542
+ let funcEnd = ''
1543
+ // setter?
1544
+ if (node.setter) {
1545
+ funcBegin += ';__self.isSetter = true;\n'
1546
+ funcEnd += ';__self.isSetter = false;\n'
1547
+ }
1548
+ // 変数「それ」が補完されていることをヒントとして出力
1549
+ if (argsOpts.sore) { funcBegin += '/*[sore]*/' }
1550
+
1551
+ // 引数をスタックに積む
1552
+ const arcCount = node.args.length
1553
+ // 必要な引数分だけスタックから下ろして呼び出す
1554
+ let code = ''
1555
+ if (isJSFunc) {
1556
+ code += funcBegin
1557
+ code += `const args = sys.__stack.splice(sys.__stack.length - ${arcCount}, ${arcCount});\n`
1558
+ // code += `console.log("call:${funcName}", args, 'sys');\n`
1559
+ code += 'args.push(sys);\n'
1560
+ code += `const ret = ${res.js}.apply(sys, args);\n`
1561
+ if (!func.return_none) {
1562
+ code += 'sys.__vars[\'それ\'] = ret;\n'
1563
+ if (isExpression) {
1564
+ code += 'sys.__stack.push(ret);\n'
1565
+ }
1566
+ }
1567
+ code += funcEnd
1568
+ this.addCodeStr(code)
1569
+ } else {
1570
+ if (isMumeiFunc) {
1571
+ this.addCode(new NakoCode(NakoCodeCallObj, funcName))
1572
+ } else {
1573
+ this.addCode(new NakoCode(NakoCodeCall, funcName))
1574
+ }
1575
+ if (!isExpression) {
1576
+ this.addCodeStr('sys.__stack.pop();// 戻り値を利用しない関数呼出')
1577
+ }
1578
+ }
1579
+ }
1580
+
1581
+ convRenbun (node: { left: any; right: any }) {
1582
+ this._convGen(node.left, false)
1583
+ this._convGen(node.right, true)
1584
+ }
1585
+
1586
+ convOp (node: { operator: any; left: any; right: any }) {
1587
+ const OP_TBL = { // トークン名からJS演算子
1588
+ '&': '+""+',
1589
+ eq: '==',
1590
+ noteq: '!=',
1591
+ '===': '===',
1592
+ '!==': '!==',
1593
+ gt: '>',
1594
+ lt: '<',
1595
+ gteq: '>=',
1596
+ lteq: '<=',
1597
+ and: '&&',
1598
+ or: '||',
1599
+ shift_l: '<<',
1600
+ shift_r: '>>',
1601
+ shift_r0: '>>>',
1602
+ '÷': '/'
1603
+ }
1604
+ const op = node.operator // 演算子
1605
+ // 値はスタックに載せられる
1606
+ // left
1607
+ this._convGen(node.left, true)
1608
+ // right
1609
+ this._convGen(node.right, true)
1610
+ // calc
1611
+ let code =
1612
+ 'const rv = sys.__stack.pop();\n' +
1613
+ 'const lv = sys.__stack.pop();\n'
1614
+ if (op === '^') {
1615
+ code += 'const v = (Math.pow(lv, rv))\n'
1616
+ } else {
1617
+ const op2 = (OP_TBL as any)[op] || op
1618
+ code += `const v = ((lv) ${op2} (rv));\n`
1619
+ }
1620
+ // code += `if (isNaN(v) && '${op}' != '&') { console.log('ERROR:${op}', lv, rv) }\n`
1621
+ code += `sys.__stack.push(v); //op:${op}\n`
1622
+ this.addCodeStr(code)
1623
+ }
1624
+
1625
+ convLet (node: any) {
1626
+ let code = ''
1627
+ // 値をスタックに載せる
1628
+ if (node.value === null) {
1629
+ // 値が省略されたら「それ」を載せる
1630
+ this.addCodeStr('sys.__stack.push(sys.__vars[\'それ\'])')
1631
+ } else {
1632
+ // 値がある場合
1633
+ this._convGen(node.value, true)
1634
+ }
1635
+ // 変数名
1636
+ const name = node.name.value
1637
+ const res = this.findVar(name)
1638
+ if (res === null) {
1639
+ this.varsSet.names.add(name)
1640
+ code = `${this.varname(name)}=sys.__stack.pop();`
1641
+ } else {
1642
+ // 定数ならエラーを出す
1643
+ if (this.varslistSet[res.i].readonly.has(name)) {
1644
+ throw NakoSyntaxError.fromNode(
1645
+ `定数『${name}』は既に定義済みなので、値を代入することはできません。`, node)
1646
+ }
1647
+ code = `${res.js}=sys.__stack.pop();`
1648
+ }
1649
+ this.addCodeStr(code + '//let')
1650
+ }
1651
+
1652
+ convDefLocalVar (node: any) {
1653
+ if (node.value === null) {
1654
+ this.addCodeStr('sys.__stack.push(null)')
1655
+ } else {
1656
+ this._convGen(node.value, true)
1657
+ }
1658
+ const name = node.name.value
1659
+ const vtype = node.vartype // 変数 or 定数
1660
+ // 二重定義?
1661
+ if (this.varsSet.names.has(name)) { throw NakoSyntaxError.fromNode(`${vtype}『${name}』の二重定義はできません。`, node) }
1662
+ this.varsSet.names.add(name)
1663
+ // 定数?
1664
+ if (vtype === '定数') {
1665
+ this.varsSet.readonly.add(name)
1666
+ }
1667
+ this.addCodeStr(`${this.varname(name)}=sys.__stack.pop()`)
1668
+ return ''
1669
+ }
1670
+
1671
+ // #563 複数変数への代入
1672
+ convDefLocalVarlist (node: any) {
1673
+ const vtype = node.vartype // 変数 or 定数
1674
+ if (node.value === null) {
1675
+ this.addCodeStr('sys.__stack.push(null)')
1676
+ } else {
1677
+ this._convGen(node.value, true)
1678
+ }
1679
+ const varI = `sys.__tmp_i${this.loopId}`
1680
+ this.loopId++
1681
+ this.addCodeStr(`${varI}=sys.__stack.pop();if (!(${varI} instanceof Array)) { ${varI}=[${varI}] }`)
1682
+ for (const nameObj of node.names) {
1683
+ const name = nameObj.value
1684
+ // 二重定義?
1685
+ if (this.varsSet.names.has(name)) { throw NakoSyntaxError.fromNode(`${vtype}『${name}』の二重定義はできません。`, node) }
1686
+ //
1687
+ this.varsSet.names.add(name)
1688
+ if (vtype === '定数') {
1689
+ this.varsSet.readonly.add(name)
1690
+ }
1691
+ const vname = this.varname(name)
1692
+ this.addCodeStr(`${vname}=${varI}.pop()`)
1693
+ }
1694
+ this.addCodeStr(`delete ${varI}//複数代入:掃除`)
1695
+ return ''
1696
+ }
1697
+
1698
+ convString (node: { value: string; mode: any }) {
1699
+ let value = '' + node.value
1700
+ const mode = node.mode
1701
+ value = value.replace(/\\/g, '\\\\')
1702
+ value = value.replace(/"/g, '\\"')
1703
+ value = value.replace(/\r/g, '\\r')
1704
+ value = value.replace(/\n/g, '\\n')
1705
+ if (mode === 'ex') {
1706
+ throw new Error('[システムエラー] ジェネレーターでの文字列の展開はサポートしていません')
1707
+ }
1708
+ this.addCodeStr(`sys.__stack.push("${value}")//string`)
1709
+ return '"' + value + '"'
1710
+ }
1711
+
1712
+ convTryExcept (node: { block: any; errBlock: any }) {
1713
+ const labelExcept = this.makeLabel('エラー監視:ならば')
1714
+ const labelEnd = this.makeLabel('エラー監視:ここまで')
1715
+
1716
+ // エラーをひっかけるように設定
1717
+ this.addCode(new NakoCode(NakoCodeTry, labelExcept.value))
1718
+
1719
+ this._convGen(node.block, false)
1720
+ this.addCode(this.makeJump(labelEnd))
1721
+ this.addCode(labelExcept)
1722
+ this._convGen(node.errBlock, false)
1723
+ this.addCode(labelEnd)
1724
+ }
1725
+ }
1726
+
1727
+ // ブラウザに登録する
1728
+ if (typeof (navigator) === 'object' && typeof ((navigator as any).nako3) === 'object') {
1729
+ // Webブラウザの場合
1730
+ const nako3: any = (navigator as any).nako3
1731
+ if (nako3.addCodeGenerator) { nako3.addCodeGenerator('非同期モード', NakoGenASync) }
1732
+ }