nadesiko3 3.3.49 → 3.3.50

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 (342) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +143 -143
  3. package/batch/.DS_Store +0 -0
  4. package/batch/browsers.template.md +3 -3
  5. package/batch/build_browsers.nako3 +72 -72
  6. package/batch/build_command.nako3 +44 -44
  7. package/batch/build_nako_version.nako3 +42 -42
  8. package/batch/calc_hash.nako3 +29 -29
  9. package/batch/cmd_txt2json.nako3 +74 -74
  10. package/batch/command.txt +79 -0
  11. package/batch/command_nakopad.txt +69 -0
  12. package/batch/download-extlib.nako3 +43 -43
  13. package/batch/gen_command_nakopad.nako3 +57 -57
  14. package/batch/jsplugin2text.nako3 +285 -285
  15. package/batch/pickup_command.nako3 +110 -110
  16. package/batch/pickup_reserved_words.nako3 +11 -11
  17. package/batch/publish_version.nako3 +46 -46
  18. package/batch/show_agents.js +14 -14
  19. package/batch/turtle2js.nako3 +21 -21
  20. package/bin/cnako3 +10 -10
  21. package/core/LICENSE +21 -21
  22. package/core/README.md +66 -66
  23. package/core/batch/build_nako_version.nako3 +42 -42
  24. package/core/command/snako.mjs +105 -105
  25. package/core/command/snako.mts +116 -116
  26. package/core/index.mjs +21 -21
  27. package/core/package.json +47 -47
  28. package/core/sample/hello.nako3 +7 -7
  29. package/core/sample/hoge.mjs +4 -4
  30. package/core/sample/hoge.mts +6 -6
  31. package/core/src/nako3.mjs +864 -858
  32. package/core/src/nako3.mts +976 -967
  33. package/core/src/nako_colors.mjs +78 -78
  34. package/core/src/nako_colors.mts +86 -86
  35. package/core/src/nako_core_version.mjs +8 -8
  36. package/core/src/nako_core_version.mts +19 -19
  37. package/core/src/nako_csv.mjs +185 -185
  38. package/core/src/nako_csv.mts +188 -188
  39. package/core/src/nako_errors.mjs +173 -173
  40. package/core/src/nako_errors.mts +197 -197
  41. package/core/src/nako_from_dncl.mjs +255 -255
  42. package/core/src/nako_from_dncl.mts +250 -250
  43. package/core/src/nako_gen.mjs +1647 -1648
  44. package/core/src/nako_gen.mts +1718 -1719
  45. package/core/src/nako_gen_async.mjs +1659 -1659
  46. package/core/src/nako_gen_async.mts +1732 -1732
  47. package/core/src/nako_global.mjs +107 -107
  48. package/core/src/nako_global.mts +138 -138
  49. package/core/src/nako_indent.mjs +445 -445
  50. package/core/src/nako_indent.mts +492 -492
  51. package/core/src/nako_josi_list.mjs +38 -38
  52. package/core/src/nako_josi_list.mts +45 -45
  53. package/core/src/nako_lex_rules.mjs +253 -253
  54. package/core/src/nako_lex_rules.mts +260 -260
  55. package/core/src/nako_lexer.mjs +609 -609
  56. package/core/src/nako_lexer.mts +612 -612
  57. package/core/src/nako_logger.mjs +199 -199
  58. package/core/src/nako_logger.mts +232 -232
  59. package/core/src/nako_parser3.mjs +2439 -2439
  60. package/core/src/nako_parser3.mts +2195 -2195
  61. package/core/src/nako_parser_base.mjs +370 -370
  62. package/core/src/nako_parser_base.mts +370 -370
  63. package/core/src/nako_parser_const.mjs +37 -37
  64. package/core/src/nako_parser_const.mts +37 -37
  65. package/core/src/nako_prepare.mjs +304 -304
  66. package/core/src/nako_prepare.mts +315 -315
  67. package/core/src/nako_reserved_words.mjs +38 -38
  68. package/core/src/nako_reserved_words.mts +38 -38
  69. package/core/src/nako_source_mapping.mjs +207 -207
  70. package/core/src/nako_source_mapping.mts +262 -262
  71. package/core/src/nako_test.mjs +37 -37
  72. package/core/src/nako_types.mjs +25 -25
  73. package/core/src/nako_types.mts +151 -151
  74. package/core/src/plugin_csv.mjs +49 -49
  75. package/core/src/plugin_csv.mts +50 -50
  76. package/core/src/plugin_math.mjs +328 -328
  77. package/core/src/plugin_math.mts +326 -326
  78. package/core/src/plugin_promise.mjs +91 -91
  79. package/core/src/plugin_promise.mts +91 -91
  80. package/core/src/plugin_system.mjs +2832 -2832
  81. package/core/src/plugin_system.mts +2690 -2690
  82. package/core/src/plugin_test.mjs +34 -34
  83. package/core/src/plugin_test.mts +34 -34
  84. package/demo/.DS_Store +0 -0
  85. package/demo/ace_editor.html +89 -89
  86. package/demo/ace_editor_tabs.html +161 -161
  87. package/demo/basic.html +71 -71
  88. package/demo/browsers.html +10 -9
  89. package/demo/css/basic.css +3 -3
  90. package/demo/css/common.css +157 -157
  91. package/demo/css/editor.css +8 -8
  92. package/demo/css/flow.css +3 -3
  93. package/demo/css/index.css +3 -3
  94. package/demo/extlib/.DS_Store +0 -0
  95. package/demo/flow.html +98 -98
  96. package/demo/graph.html +53 -53
  97. package/demo/image/nakopad-icon256.png +0 -0
  98. package/demo/index.html +133 -133
  99. package/demo/js/common.js +17 -17
  100. package/demo/js/turtle3d_test.js +44 -44
  101. package/demo/js/turtle_test.js +45 -45
  102. package/demo/nako3/calc.nako3 +4 -4
  103. package/demo/runscript.html +47 -47
  104. package/demo/runscript2.html +33 -33
  105. package/demo/runscript3.html +35 -35
  106. package/demo/runscript4.html +33 -33
  107. package/demo/turtle.html +58 -58
  108. package/demo/turtle2.html +141 -141
  109. package/demo/turtle3.html +279 -279
  110. package/demo/turtle3d.html +58 -58
  111. package/demo/turtle3d2.html +107 -107
  112. package/demo/version.html +24 -24
  113. package/doc/SETUP.md +157 -157
  114. package/doc/about.md +17 -17
  115. package/doc/browsers.md +26 -26
  116. package/doc/docgen.md +21 -21
  117. package/doc/editor.md +44 -44
  118. package/doc/files.md +39 -39
  119. package/doc/plugins.md +234 -234
  120. package/doc/release.md +79 -79
  121. package/doc/textlint.md +43 -43
  122. package/doc/win32.md +57 -57
  123. package/package.json +195 -195
  124. package/release/_hash.txt +28 -28
  125. package/release/_script-tags.txt +14 -14
  126. package/release/command.json +1 -1
  127. package/release/command.json.js +1 -1
  128. package/release/command_cnako3.json +1 -1
  129. package/release/command_list.json +1 -1
  130. package/release/editor.js +1 -1
  131. package/release/nako_gen_async.js +1 -1
  132. package/release/nako_gen_async.js.LICENSE.txt +35 -0
  133. package/release/plugin_caniuse.js.LICENSE.txt +11 -0
  134. package/release/plugin_csv.js +1 -1
  135. package/release/plugin_csv.js.LICENSE.txt +15 -0
  136. package/release/plugin_datetime.js.LICENSE.txt +15 -0
  137. package/release/plugin_kansuji.js.LICENSE.txt +3 -0
  138. package/release/plugin_markup.js.LICENSE.txt +11 -0
  139. package/release/plugin_turtle.js.LICENSE.txt +15 -0
  140. package/release/plugin_webworker.js.LICENSE.txt +3 -0
  141. package/release/plugin_weykturtle3d.js.LICENSE.txt +3 -0
  142. package/release/stats.json +1 -1
  143. package/release/version.js +1 -1
  144. package/release/wnako3.js +1 -1
  145. package/release/wnako3webworker.js +1 -1
  146. package/release/wnako3webworker.js.LICENSE.txt +131 -0
  147. package/src/.DS_Store +0 -0
  148. package/src/browsers.txt +12 -11
  149. package/src/browsers_agents.json +2 -2
  150. package/src/browsers_agents.mjs +1 -1
  151. package/src/cnako3.mjs +17 -17
  152. package/src/cnako3.mts +18 -18
  153. package/src/cnako3mod.mjs +707 -707
  154. package/src/cnako3mod.mts +712 -712
  155. package/src/commander_ja.mjs +164 -164
  156. package/src/commander_ja.mts +161 -161
  157. package/src/enako3.mjs +68 -68
  158. package/src/era.mjs +22 -22
  159. package/src/image_turtle-elephant.mjs +2 -2
  160. package/src/image_turtle-panda.mjs +2 -2
  161. package/src/image_turtle64.mjs +2 -2
  162. package/src/index.mjs +9 -9
  163. package/src/index.mts +10 -10
  164. package/src/nako3editorfix.sfd +106 -106
  165. package/src/nako_version.mjs +8 -8
  166. package/src/nako_version.mts +2 -2
  167. package/src/plugin_browser.mjs +213 -213
  168. package/src/plugin_browser.mts +206 -206
  169. package/src/plugin_browser_ajax.mjs +399 -399
  170. package/src/plugin_browser_audio.mjs +109 -109
  171. package/src/plugin_browser_canvas.mjs +449 -449
  172. package/src/plugin_browser_chart.mjs +294 -294
  173. package/src/plugin_browser_color.mjs +49 -49
  174. package/src/plugin_browser_crypto.mjs +26 -26
  175. package/src/plugin_browser_dialog.mjs +53 -53
  176. package/src/plugin_browser_dom_basic.mjs +336 -336
  177. package/src/plugin_browser_dom_event.mjs +193 -193
  178. package/src/plugin_browser_dom_parts.mjs +396 -396
  179. package/src/plugin_browser_geolocation.mjs +51 -51
  180. package/src/plugin_browser_hotkey.mjs +25 -25
  181. package/src/plugin_browser_html.mjs +59 -59
  182. package/src/plugin_browser_in_worker.mjs +45 -45
  183. package/src/plugin_browser_location.mjs +21 -21
  184. package/src/plugin_browser_speech.mjs +111 -111
  185. package/src/plugin_browser_storage.mjs +121 -121
  186. package/src/plugin_browser_system.mjs +31 -31
  187. package/src/plugin_browser_websocket.mjs +73 -73
  188. package/src/plugin_caniuse.mjs +29 -29
  189. package/src/plugin_datetime.mjs +394 -394
  190. package/src/plugin_httpserver.mjs +277 -277
  191. package/src/plugin_httpserver.mts +286 -286
  192. package/src/plugin_kansuji.mjs +224 -224
  193. package/src/plugin_keigo.mjs +55 -55
  194. package/src/plugin_markup.mjs +32 -32
  195. package/src/plugin_node.mjs +1047 -1047
  196. package/src/plugin_node.mts +980 -980
  197. package/src/plugin_turtle.mjs +647 -647
  198. package/src/plugin_webworker.mjs +334 -334
  199. package/src/plugin_weykturtle3d.mjs +1214 -1214
  200. package/src/plugin_worker.mjs +95 -95
  201. package/src/repl.nako3 +63 -63
  202. package/src/wnako3.mjs +12 -12
  203. package/src/wnako3.mts +11 -11
  204. package/src/wnako3_editor.css +215 -215
  205. package/src/wnako3_editor.mjs +1542 -1542
  206. package/src/wnako3_editor.mts +1658 -1657
  207. package/src/wnako3mod.mjs +213 -213
  208. package/src/wnako3mod.mts +214 -214
  209. package/src/wnako3webworker.mjs +69 -69
  210. package/test/.DS_Store +0 -0
  211. package/test/ace_editor/karma.config.js +94 -94
  212. package/test/ace_editor/test/.babelrc.json +3 -3
  213. package/test/ace_editor/test/ace_editor_test.js +178 -178
  214. package/test/ace_editor/test/html/custom_context.html +139 -139
  215. package/test/async/async_basic_test.mjs +122 -122
  216. package/test/browser/.DS_Store +0 -0
  217. package/test/browser/karma.config.js +221 -221
  218. package/test/browser/test/.babelrc.json +3 -3
  219. package/test/browser/test/compare_util.js +50 -50
  220. package/test/browser/test/html/div_basic.html +2 -2
  221. package/test/browser/test/html/event_dom_form.html +4 -4
  222. package/test/browser/test/html/event_dom_scrolldiv.html +5 -5
  223. package/test/browser/test/import_plugin_checker.js +24 -24
  224. package/test/browser/test/plugin_browser_test.js +51 -51
  225. package/test/browser/test/plugin_browser_test_ajax.js +123 -123
  226. package/test/browser/test/plugin_browser_test_color.js +18 -18
  227. package/test/browser/test/plugin_browser_test_dialog.js +72 -72
  228. package/test/browser/test/plugin_browser_test_dom_event.js +598 -598
  229. package/test/browser/test/plugin_browser_test_dom_parts.js +125 -125
  230. package/test/browser/test/plugin_browser_test_system.js +9 -9
  231. package/test/browser/test/plugin_turtle_test.js +817 -817
  232. package/test/browser/test/plugin_webworker_test.js +86 -86
  233. package/test/browser/test/require_test.js +68 -68
  234. package/test/bundled/.DS_Store +0 -0
  235. package/test/bundled/karma.config.base.js +117 -117
  236. package/test/bundled/karma.config.js +86 -86
  237. package/test/bundled/test/.babelrc.json +3 -3
  238. package/test/bundled/test/bundled_test.js +69 -69
  239. package/test/bundled/test/html/custom_context.html +65 -65
  240. package/test/bundled/test/html/custom_debug.html +66 -66
  241. package/test/bundled/test4b.cmd +52 -52
  242. package/test/bundled/test_base/.DS_Store +0 -0
  243. package/test/bundled/test_base/.babelrc.json +3 -3
  244. package/test/bundled/test_base/_checktool_test.js +25 -25
  245. package/test/bundled/test_base/basic_ajax_test.js +56 -56
  246. package/test/bundled/test_base/basic_async_test.js +18 -18
  247. package/test/bundled/test_base/basic_test.js +153 -153
  248. package/test/bundled/test_base/calc_test.js +132 -132
  249. package/test/bundled/test_base/css/browsers_box.css +114 -114
  250. package/test/bundled/test_base/html/custom_context.html +69 -69
  251. package/test/bundled/test_base/html/custom_debug.html +71 -71
  252. package/test/bundled/test_base/js/browsers_box.js +72 -72
  253. package/test/bundled/test_base/plugin_csv_test.js +37 -37
  254. package/test/bundled/test_base/plugin_datetime_test.js +115 -115
  255. package/test/bundled/test_base/plugin_kansuji_test.js +49 -49
  256. package/test/bundled/test_base/plugin_system_test.js +410 -410
  257. package/test/bundled/test_base/plugin_webworker_test.js +53 -53
  258. package/test/bundled/test_base/test_utils.js +191 -191
  259. package/test/common/.DS_Store +0 -0
  260. package/test/common/plugin_browser_test.mjs +22 -22
  261. package/test/common/plugin_browser_ut_audio_test.mjs +108 -108
  262. package/test/common/plugin_browser_ut_color_test.mjs +21 -21
  263. package/test/common/plugin_browser_ut_dialog_test.mjs +100 -100
  264. package/test/common/plugin_browser_ut_html_test.mjs +13 -13
  265. package/test/common/plugin_browser_ut_system_test.mjs +10 -10
  266. package/test/common/plugin_markup_test.mjs +23 -23
  267. package/test/jsconfig.json +19 -19
  268. package/test/karma.config.js +91 -91
  269. package/test/node/.DS_Store +0 -0
  270. package/test/node/async_test.mjs +96 -96
  271. package/test/node/commander_ja_test.mjs +89 -89
  272. package/test/node/error_message_test.mjs +243 -243
  273. package/test/node/kai_test.nako3 +6 -6
  274. package/test/node/node_test.mjs +60 -60
  275. package/test/node/plugin_broken.js.txt +3 -3
  276. package/test/node/plugin_browser_ut_ajax_test.mjs.todo +357 -357
  277. package/test/node/plugin_browser_ut_location_test.mjs +42 -42
  278. package/test/node/plugin_markup_test.mjs +47 -47
  279. package/test/node/plugin_math_test.mjs +45 -45
  280. package/test/node/plugin_node_test.mjs +98 -98
  281. package/test/node/plugin_test.mjs +44 -44
  282. package/test/node/relative_import_test_1.nako3 +1 -1
  283. package/test/node/relative_import_test_2.nako3 +2 -2
  284. package/test/node/require_nako3_test.mjs +67 -67
  285. package/test/node/requiretest.nako3 +4 -4
  286. package/test/node/requiretest_indirect.nako3 +1 -1
  287. package/test/node/requiretest_name.nako3 +5 -5
  288. package/test/node/runtime_error.nako3 +2 -2
  289. package/test/node/scope1.nako3 +10 -10
  290. package/test/node/scope2.nako3 +12 -12
  291. package/test/node/side_effects_test.mjs +39 -39
  292. package/test/node/sjis.txt +5 -5
  293. package/test/node/syntax_error.nako3 +1 -1
  294. package/test/node/wnako3_editor_test.mjs +384 -384
  295. package/tools/.DS_Store +0 -0
  296. package/tools/README.md +12 -12
  297. package/tools/check_new_version.nako3 +25 -25
  298. package/tools/nako3edit/.DS_Store +0 -0
  299. package/tools/nako3edit/a.sqlite3 +0 -0
  300. package/tools/nako3edit/html/.DS_Store +0 -0
  301. package/tools/nako3edit/html/daisyui/LICENSE +22 -22
  302. package/tools/nako3edit/html/daisyui/version_2.14.1 +1 -1
  303. package/tools/nako3edit/html/edit.html +170 -170
  304. package/tools/nako3edit/html/edit_plugin.js +6 -6
  305. package/tools/nako3edit/html/files.html +125 -125
  306. package/tools/nako3edit/html/nako3edit.css +65 -65
  307. package/tools/nako3edit/index.mjs +248 -248
  308. package/tools/nako3server/index.html +10 -10
  309. package/tools/nako3server/index.mjs +116 -116
  310. package/tools/nako3server/index.nako3 +34 -34
  311. package/core/.editorconfig +0 -6
  312. package/core/.eslintrc.cjs +0 -33
  313. package/core/.github/dependabot.yml +0 -7
  314. package/core/.github/workflows/nodejs.yml +0 -37
  315. package/core/.github/workflows/super-linter.yml +0 -61
  316. package/core/.github/workflows/textlint.yml +0 -199
  317. package/core/index.mts +0 -21
  318. package/core/test/array_test.mjs +0 -34
  319. package/core/test/basic_test.mjs +0 -344
  320. package/core/test/calc_test.mjs +0 -140
  321. package/core/test/core_module_test.mjs +0 -23
  322. package/core/test/debug_test.mjs +0 -16
  323. package/core/test/dncl_test.mjs +0 -94
  324. package/core/test/error_message_test.mjs +0 -210
  325. package/core/test/error_test.mjs +0 -16
  326. package/core/test/flow_test.mjs +0 -373
  327. package/core/test/func_call.mjs +0 -160
  328. package/core/test/func_test.mjs +0 -149
  329. package/core/test/indent_test.mjs +0 -364
  330. package/core/test/lex_test.mjs +0 -168
  331. package/core/test/literal_test.mjs +0 -73
  332. package/core/test/nako_lexer_test.mjs +0 -35
  333. package/core/test/nako_logger_test.mjs +0 -76
  334. package/core/test/nako_logger_test.mts +0 -78
  335. package/core/test/plugin_csv_test.mjs +0 -38
  336. package/core/test/plugin_promise_test.mjs +0 -18
  337. package/core/test/plugin_system_test.mjs +0 -630
  338. package/core/test/prepare_test.mjs +0 -96
  339. package/core/test/re_test.mjs +0 -22
  340. package/core/test/side_effects_test.mjs +0 -92
  341. package/core/test/variable_scope_test.mjs +0 -149
  342. package/core/tsconfig.json +0 -101
@@ -1,609 +1,609 @@
1
- // なでしこの字句解析を行う
2
- // 既に全角半角を揃えたコードに対して字句解析を行う
3
- import { opPriority } from './nako_parser_const.mjs';
4
- // 予約語句
5
- // (memo)「回」「間」「繰返」「反復」「抜」「続」「戻」「代入」などは _replaceWord で word から変換
6
- /** @types {Record<string, string>} */
7
- import reservedWords from './nako_reserved_words.mjs';
8
- // 助詞の一覧
9
- import { josiRE, removeJosiMap, tararebaMap } from './nako_josi_list.mjs';
10
- // 字句解析ルールの一覧
11
- import { rules, unitRE } from './nako_lex_rules.mjs';
12
- import { NakoLexerError, InternalLexerError } from './nako_errors.mjs';
13
- export class NakoLexer {
14
- /**
15
- * @param logger
16
- */
17
- constructor(logger) {
18
- this.logger = logger; // 字句解析した際,確認された関数の一覧
19
- this.funclist = {};
20
- this.modList = []; // 字句解析した際,取り込むモジュール一覧 --- nako3::lex で更新される
21
- this.result = [];
22
- this.modName = 'main.nako3'; // モジュール名
23
- }
24
- /** 関数一覧をセット */
25
- setFuncList(listObj) {
26
- this.funclist = listObj;
27
- }
28
- /**
29
- * @param tokens
30
- * @param {boolean} isFirst
31
- * @param {string} filename
32
- */
33
- replaceTokens(tokens, isFirst, filename) {
34
- this.result = tokens;
35
- this.modName = NakoLexer.filenameToModName(filename);
36
- // 関数の定義があれば funclist を更新
37
- NakoLexer.preDefineFunc(tokens, this.logger, this.funclist);
38
- this._replaceWord(this.result);
39
- if (isFirst) {
40
- if (this.result.length > 0) {
41
- const eof = this.result[this.result.length - 1];
42
- this.result.push({
43
- type: 'eol',
44
- line: eof.line,
45
- column: 0,
46
- file: eof.file,
47
- josi: '',
48
- value: '---',
49
- startOffset: eof.startOffset,
50
- endOffset: eof.endOffset,
51
- rawJosi: ''
52
- }); // 改行
53
- this.result.push({
54
- type: 'eof',
55
- line: eof.line,
56
- column: 0,
57
- file: eof.file,
58
- josi: '',
59
- value: '',
60
- startOffset: eof.startOffset,
61
- endOffset: eof.endOffset,
62
- rawJosi: ''
63
- }); // ファイル末尾
64
- }
65
- else {
66
- this.result.push({
67
- type: 'eol',
68
- line: 0,
69
- column: 0,
70
- file: '',
71
- josi: '',
72
- value: '---',
73
- startOffset: 0,
74
- endOffset: 0,
75
- rawJosi: ''
76
- }); // 改行
77
- this.result.push({
78
- type: 'eof',
79
- line: 0,
80
- column: 0,
81
- file: '',
82
- josi: '',
83
- value: '',
84
- startOffset: 0,
85
- endOffset: 0,
86
- rawJosi: ''
87
- }); // ファイル末尾
88
- }
89
- }
90
- return this.result;
91
- }
92
- /**
93
- * ファイル内で定義されている関数名を列挙する。結果はfunclistに書き込む。その他のトークンの置換処理も行う。
94
- * シンタックスハイライトの処理から呼び出すためにstaticメソッドにしている。
95
- * @param {Token[]} tokens
96
- * @param {import('./nako_logger.mjs').NakoLogger} logger
97
- * @param {FuncList} funclist
98
- */
99
- static preDefineFunc(tokens, logger, funclist) {
100
- // 関数を先読みして定義
101
- let i = 0;
102
- let isFuncPointer = false;
103
- const readArgs = () => {
104
- const args = [];
105
- const keys = {};
106
- if (tokens[i].type !== '(') {
107
- return [];
108
- }
109
- i++;
110
- while (tokens[i]) {
111
- const t = tokens[i];
112
- i++;
113
- if (t.type === ')') {
114
- break;
115
- }
116
- if (t.type === 'func') {
117
- isFuncPointer = true;
118
- }
119
- else if (t.type !== '|' && t.type !== 'comma') {
120
- if (isFuncPointer) {
121
- t.funcPointer = true;
122
- isFuncPointer = false;
123
- }
124
- args.push(t);
125
- if (!keys[t.value]) {
126
- keys[t.value] = [];
127
- }
128
- keys[t.value].push(t.josi);
129
- }
130
- }
131
- const varnames = [];
132
- const funcPointers = [];
133
- const result = [];
134
- const already = {};
135
- for (const arg of args) {
136
- if (!already[arg.value]) {
137
- const josi = keys[arg.value];
138
- result.push(josi);
139
- varnames.push(arg.value);
140
- if (arg.funcPointer) {
141
- funcPointers.push(arg.value);
142
- }
143
- else {
144
- funcPointers.push(null);
145
- }
146
- already[arg.value] = true;
147
- }
148
- }
149
- return [result, varnames, funcPointers];
150
- };
151
- // トークンを一つずつ確認
152
- while (i < tokens.length) {
153
- // タイプの置換
154
- const t = tokens[i];
155
- // 無名関数の定義:「xxには**」があった場合 ... 暗黙的な関数定義とする
156
- if ((t.type === 'word' && t.josi === 'には') || (t.type === 'word' && t.josi === 'は~')) {
157
- t.josi = 'には';
158
- tokens.splice(i + 1, 0, { type: 'def_func', value: '関数', line: t.line, column: t.column, file: t.file, josi: '', startOffset: t.endOffset, endOffset: t.endOffset, rawJosi: '', tag: '無名関数' });
159
- i++;
160
- continue;
161
- }
162
- // N回をN|回に置換
163
- if (t.type === 'word' && t.josi === '' && t.value.length >= 2) {
164
- if (t.value.match(/回$/)) {
165
- t.value = t.value.substring(0, t.value.length - 1);
166
- // N回を挿入
167
- if (!t.endOffset) {
168
- t.endOffset = 1;
169
- }
170
- const kai = { type: '回', value: '回', line: t.line, column: t.column, file: t.file, josi: '', startOffset: t.endOffset - 1, endOffset: t.endOffset, rawJosi: '' };
171
- tokens.splice(i + 1, 0, kai);
172
- t.endOffset--;
173
- i++;
174
- }
175
- }
176
- // 予約語の置換
177
- if (t.type === 'word' && reservedWords[t.value]) {
178
- t.type = reservedWords[t.value];
179
- if (t.value === 'そう') {
180
- t.value = 'それ';
181
- }
182
- }
183
- // 関数定義の確認
184
- if (t.type !== 'def_test' && t.type !== 'def_func') {
185
- i++;
186
- continue;
187
- }
188
- // 無名関数か普通関数定義かを判定する (1つ前が改行かどうかで判定)
189
- let isMumei = true;
190
- let prevToken = { type: 'eol' };
191
- if (i >= 1) {
192
- prevToken = tokens[i - 1];
193
- }
194
- if (prevToken.type === 'eol') {
195
- isMumei = false;
196
- }
197
- // 関数名や引数を得る
198
- const defToken = t;
199
- i++; // skip "●" or "関数"
200
- let josi = [];
201
- let varnames = [];
202
- let funcPointers = [];
203
- let funcName = '';
204
- let funcNameToken = null;
205
- // 関数名の前に引数定義
206
- if (tokens[i] && tokens[i].type === '(') {
207
- [josi, varnames, funcPointers] = readArgs();
208
- }
209
- // 関数名を得る
210
- if (!isMumei && tokens[i] && tokens[i].type === 'word') {
211
- funcNameToken = tokens[i++];
212
- funcName = funcNameToken.value;
213
- }
214
- // 関数名の後で引数定義
215
- if (josi.length === 0 && tokens[i] && tokens[i].type === '(') {
216
- [josi, varnames, funcPointers] = readArgs();
217
- }
218
- // 名前のある関数定義ならば関数テーブルに関数名を登録
219
- // 無名関数は登録しないように気をつける
220
- if (funcName !== '' && funcNameToken) {
221
- const modName = NakoLexer.filenameToModName(t.file);
222
- funcName = modName + '__' + funcName;
223
- if (funcName in funclist) { // 関数の二重定義を警告
224
- // main__は省略 #1223
225
- const dispName = funcName.replace(/^main__/, '');
226
- logger.warn(`関数『${dispName}』は既に定義されています。`, defToken);
227
- }
228
- funcNameToken.value = funcName;
229
- funclist[funcName] = {
230
- type: 'func',
231
- josi,
232
- fn: null,
233
- asyncFn: false,
234
- varnames,
235
- funcPointers
236
- };
237
- }
238
- // 無名関数のために
239
- defToken.meta = {
240
- type: 'func',
241
- josi,
242
- varnames,
243
- funcPointers
244
- };
245
- }
246
- }
247
- /** 文字列を{と}の部分で分割する。中括弧が対応していない場合nullを返す。 */
248
- splitStringEx(code) {
249
- /** @type {string[]} */
250
- const list = [];
251
- // "A{B}C{D}E" -> ["A", "B}C", "D}E"] -> ["A", "B", "C", "D", "E"]
252
- // "A{B}C}D{E}F" -> ["A", "B}C}D", "E}F"] -> ["A", "B", "C}D", "E", "F"]
253
- const arr = code.split(/[{{]/);
254
- list.push(arr[0]);
255
- for (const s of arr.slice(1)) {
256
- const end = s.replace('}', '}').indexOf('}');
257
- if (end === -1) {
258
- return null;
259
- }
260
- list.push(s.slice(0, end), s.slice(end + 1));
261
- }
262
- return list;
263
- }
264
- _replaceWord(tokens) {
265
- let comment = [];
266
- let i = 0;
267
- const getLastType = () => {
268
- if (i <= 0) {
269
- return 'eol';
270
- }
271
- return tokens[i - 1].type;
272
- };
273
- const modSelf = (tokens.length > 0) ? NakoLexer.filenameToModName(tokens[0].file) : 'main.nako3';
274
- while (i < tokens.length) {
275
- const t = tokens[i];
276
- // 関数を強制的に置換( word => func )
277
- if (t.type === 'word' && t.value !== 'それ') {
278
- // 関数を変換
279
- const funcName = t.value;
280
- if (funcName.indexOf('__') < 0) {
281
- // 自身のモジュール名を検索
282
- const gname1 = `${modSelf}__${funcName}`;
283
- const gfo1 = this.funclist[gname1];
284
- if (gfo1 && gfo1.type === 'func') {
285
- t.type = 'func';
286
- t.meta = gfo1;
287
- t.value = gname1;
288
- continue;
289
- }
290
- // モジュール関数を置換
291
- for (const mod of this.modList) {
292
- const gname = `${mod}__${funcName}`;
293
- const gfo = this.funclist[gname];
294
- if (gfo && gfo.type === 'func') {
295
- t.type = 'func';
296
- t.meta = gfo;
297
- t.value = gname;
298
- break;
299
- }
300
- }
301
- if (t.type === 'func') {
302
- continue;
303
- }
304
- }
305
- const fo = this.funclist[funcName];
306
- if (fo && fo.type === 'func') {
307
- t.type = 'func';
308
- t.meta = fo;
309
- }
310
- }
311
- // 数字につくマイナス記号を判定
312
- // (ng) 5 - 3 || word - 3
313
- // (ok) (行頭)-3 || 1 * -3 || Aに -3を 足す
314
- if (t.type === '-' && tokens[i + 1] && tokens[i + 1].type === 'number') {
315
- // 一つ前の語句が、(行頭|演算子|助詞付きの語句)なら 負数である
316
- const ltype = getLastType();
317
- if (ltype === 'eol' || opPriority[ltype] || tokens[i - 1].josi !== '') {
318
- tokens.splice(i, 1); // remove '-'
319
- tokens[i].value *= -1;
320
- }
321
- }
322
- // 助詞の「は」を = に展開
323
- if (t.josi === undefined) {
324
- t.josi = '';
325
- }
326
- if (t.josi === 'は') {
327
- if (!t.rawJosi) {
328
- t.rawJosi = t.josi;
329
- }
330
- const startOffset = (t.endOffset === undefined) ? undefined : t.endOffset - t.rawJosi.length;
331
- tokens.splice(i + 1, 0, {
332
- type: 'eq',
333
- line: t.line,
334
- column: t.column,
335
- file: t.file,
336
- startOffset,
337
- endOffset: t.endOffset,
338
- josi: '',
339
- rawJosi: '',
340
- value: undefined
341
- });
342
- i += 2;
343
- t.josi = t.rawJosi = '';
344
- t.endOffset = startOffset;
345
- continue;
346
- }
347
- // 「とは」を一つの単語にする
348
- if (t.josi === 'とは') {
349
- if (!t.rawJosi) {
350
- t.rawJosi = t.josi;
351
- }
352
- const startOffset = t.endOffset === undefined ? undefined : t.endOffset - t.rawJosi.length;
353
- tokens.splice(i + 1, 0, {
354
- type: t.josi,
355
- line: t.line,
356
- column: t.column,
357
- file: t.file,
358
- startOffset,
359
- endOffset: t.endOffset,
360
- josi: '',
361
- rawJosi: '',
362
- value: undefined
363
- });
364
- t.josi = t.rawJosi = '';
365
- t.endOffset = startOffset;
366
- i += 2;
367
- continue;
368
- }
369
- // 助詞のならばをトークンとする
370
- if (tararebaMap[t.josi]) {
371
- const josi = (t.josi === 'でなければ' || t.josi === 'なければ') ? 'でなければ' : 'ならば';
372
- if (!t.rawJosi) {
373
- t.rawJosi = josi;
374
- }
375
- const startOffset = t.endOffset === undefined ? undefined : t.endOffset - t.rawJosi.length;
376
- tokens.splice(i + 1, 0, {
377
- type: 'ならば',
378
- value: josi,
379
- line: t.line,
380
- column: t.column,
381
- file: t.file,
382
- startOffset,
383
- endOffset: t.endOffset,
384
- josi: '',
385
- rawJosi: ''
386
- });
387
- t.josi = t.rawJosi = '';
388
- t.endOffset = startOffset;
389
- i += 2;
390
- continue;
391
- }
392
- // '_' + 改行 を飛ばす (演算子直後に改行を入れたい場合に使う)
393
- if (t.type === '_eol') {
394
- tokens.splice(i, 1);
395
- continue;
396
- }
397
- // コメントを飛ばす
398
- if (t.type === 'line_comment' || t.type === 'range_comment') {
399
- comment.push(t.value);
400
- tokens.splice(i, 1);
401
- continue;
402
- }
403
- // 改行にコメントを埋め込む
404
- if (t.type === 'eol') {
405
- t.value = comment.join('/');
406
- comment = [];
407
- }
408
- i++;
409
- }
410
- }
411
- /**
412
- * @param {string} src
413
- * @param {number} line
414
- * @param {string} filename
415
- * @returns {Token[]}
416
- */
417
- tokenize(src, line, filename) {
418
- const srcLength = src.length;
419
- const result = [];
420
- let columnCurrent;
421
- let lineCurrent;
422
- let column = 1;
423
- let isDefTest = false;
424
- while (src !== '') {
425
- let ok = false;
426
- // 各ルールについて
427
- for (const rule of rules) {
428
- // 正規表現でマッチ
429
- const m = rule.pattern.exec(src);
430
- if (!m) {
431
- continue;
432
- }
433
- ok = true;
434
- // 空白ならスキップ
435
- if (rule.name === 'space') {
436
- column += m[0].length;
437
- src = src.substring(m[0].length);
438
- continue;
439
- }
440
- // マッチしたルールがコールバックを持つなら
441
- if (rule.cbParser) {
442
- // コールバックを呼ぶ
443
- /** @type {{ src: string, res: string, josi: string, numEOL: number }} */
444
- let rp;
445
- if (isDefTest && rule.name === 'word') {
446
- rp = rule.cbParser(src, false);
447
- }
448
- else {
449
- try {
450
- rp = rule.cbParser(src);
451
- }
452
- catch (e) {
453
- throw new NakoLexerError(e.message, srcLength - src.length, srcLength - src.length + 1, line, filename);
454
- }
455
- }
456
- if (rule.name === 'string_ex') {
457
- // 展開あり文字列 → aaa{x}bbb{x}cccc
458
- const list = this.splitStringEx(rp.res);
459
- if (list === null) {
460
- throw new InternalLexerError('展開あり文字列で値の埋め込み{...}が対応していません。', srcLength - src.length, srcLength - rp.src.length, line, filename);
461
- }
462
- let offset = 0;
463
- for (let i = 0; i < list.length; i++) {
464
- const josi = (i === list.length - 1) ? rp.josi : '';
465
- if (i % 2 === 0) {
466
- result.push({
467
- type: 'string',
468
- value: list[i],
469
- file: filename,
470
- josi,
471
- line,
472
- column,
473
- preprocessedCodeOffset: srcLength - src.length + offset,
474
- preprocessedCodeLength: list[i].length + 2 + josi.length
475
- });
476
- // 先頭なら'"...{'、それ以外なら'}...{'、最後は何でも良い
477
- offset += list[i].length + 2;
478
- }
479
- else {
480
- result.push({ type: '&', value: '&', josi: '', file: filename, line, column, preprocessedCodeOffset: srcLength - src.length + offset, preprocessedCodeLength: 0 });
481
- result.push({ type: '(', value: '(', josi: '', file: filename, line, column, preprocessedCodeOffset: srcLength - src.length + offset, preprocessedCodeLength: 0 });
482
- result.push({ type: 'code', value: list[i], josi: '', file: filename, line, column, preprocessedCodeOffset: srcLength - src.length + offset, preprocessedCodeLength: list[i].length });
483
- result.push({ type: ')', value: ')', josi: '', file: filename, line, column, preprocessedCodeOffset: srcLength - src.length + offset + list[i].length, preprocessedCodeLength: 0 });
484
- result.push({ type: '&', value: '&', josi: '', file: filename, line, column, preprocessedCodeOffset: srcLength - src.length + offset + list[i].length, preprocessedCodeLength: 0 });
485
- offset += list[i].length;
486
- }
487
- }
488
- line += rp.numEOL;
489
- column += src.length - rp.src.length;
490
- src = rp.src;
491
- if (rp.numEOL > 0) {
492
- column = 1;
493
- }
494
- break;
495
- }
496
- columnCurrent = column;
497
- column += src.length - rp.src.length;
498
- result.push({ type: rule.name, value: rp.res, josi: rp.josi, line, column: columnCurrent, file: filename, preprocessedCodeOffset: srcLength - src.length, preprocessedCodeLength: src.length - rp.src.length });
499
- src = rp.src;
500
- line += rp.numEOL;
501
- if (rp.numEOL > 0) {
502
- column = 1;
503
- }
504
- break;
505
- }
506
- // ソースを進める前に位置を計算
507
- const srcOffset = srcLength - src.length;
508
- // 値を変換する必要があるか?
509
- let value = m[0];
510
- if (rule.cb) {
511
- value = rule.cb(value);
512
- }
513
- // ソースを進める
514
- columnCurrent = column;
515
- lineCurrent = line;
516
- column += m[0].length;
517
- src = src.substring(m[0].length);
518
- if ((rule.name === 'eol' && value === '\n') || rule.name === '_eol') {
519
- value = line++;
520
- column = 1;
521
- }
522
- // 数値なら単位を持つか? --- #994
523
- if (rule.name === 'number') {
524
- // 単位があれば読み飛ばす
525
- const um = unitRE.exec(src);
526
- if (um) {
527
- src = src.substring(um[0].length);
528
- column += m[0].length;
529
- }
530
- }
531
- let josi = '';
532
- if (rule.readJosi) {
533
- const j = josiRE.exec(src);
534
- if (j) {
535
- josi = j[0].replace(/^\s+/, '');
536
- column += j[0].length;
537
- src = src.substring(j[0].length);
538
- // 助詞の直後にあるカンマを無視 #877
539
- if (src.charAt(0) === ',') {
540
- src = src.substring(1);
541
- }
542
- // 「**である」なら削除 #939 #974
543
- if (removeJosiMap[josi]) {
544
- josi = '';
545
- }
546
- }
547
- }
548
- switch (rule.name) {
549
- case 'def_test': {
550
- isDefTest = true;
551
- break;
552
- }
553
- case 'eol': {
554
- isDefTest = false;
555
- break;
556
- }
557
- default: {
558
- break;
559
- }
560
- }
561
- // ここまで‰(#682) を処理
562
- if (rule.name === 'dec_lineno') {
563
- line--;
564
- continue;
565
- }
566
- result.push({
567
- type: rule.name,
568
- value,
569
- line: lineCurrent,
570
- column: columnCurrent,
571
- file: filename,
572
- josi,
573
- preprocessedCodeOffset: srcOffset,
574
- preprocessedCodeLength: (srcLength - src.length) - srcOffset
575
- });
576
- break;
577
- }
578
- if (!ok) {
579
- throw new InternalLexerError('未知の語句: ' + src.substring(0, 3) + '...', srcLength - src.length, srcLength - srcLength + 3, line, filename);
580
- }
581
- }
582
- return result;
583
- }
584
- // トークン配列をtype文字列に変換
585
- static tokensToTypeStr(tokens, sep) {
586
- const a = tokens.map((v) => {
587
- return v.type;
588
- });
589
- return a.join(sep);
590
- }
591
- /**
592
- * ファイル名からモジュール名へ変換
593
- * @param {string} filename
594
- * @returns {string}
595
- */
596
- static filenameToModName(filename) {
597
- if (!filename) {
598
- return 'main';
599
- }
600
- // パスがあればパスを削除
601
- filename = filename.replace(/[\\:]/g, '/'); // Windowsのpath記号を/に置換
602
- if (filename.indexOf('/') >= 0) {
603
- const a = filename.split('/');
604
- filename = a[a.length - 1];
605
- }
606
- filename = filename.replace(/\.nako3?$/, '');
607
- return filename;
608
- }
609
- }
1
+ // なでしこの字句解析を行う
2
+ // 既に全角半角を揃えたコードに対して字句解析を行う
3
+ import { opPriority } from './nako_parser_const.mjs';
4
+ // 予約語句
5
+ // (memo)「回」「間」「繰返」「反復」「抜」「続」「戻」「代入」などは _replaceWord で word から変換
6
+ /** @types {Record<string, string>} */
7
+ import reservedWords from './nako_reserved_words.mjs';
8
+ // 助詞の一覧
9
+ import { josiRE, removeJosiMap, tararebaMap } from './nako_josi_list.mjs';
10
+ // 字句解析ルールの一覧
11
+ import { rules, unitRE } from './nako_lex_rules.mjs';
12
+ import { NakoLexerError, InternalLexerError } from './nako_errors.mjs';
13
+ export class NakoLexer {
14
+ /**
15
+ * @param logger
16
+ */
17
+ constructor(logger) {
18
+ this.logger = logger; // 字句解析した際,確認された関数の一覧
19
+ this.funclist = {};
20
+ this.modList = []; // 字句解析した際,取り込むモジュール一覧 --- nako3::lex で更新される
21
+ this.result = [];
22
+ this.modName = 'main.nako3'; // モジュール名
23
+ }
24
+ /** 関数一覧をセット */
25
+ setFuncList(listObj) {
26
+ this.funclist = listObj;
27
+ }
28
+ /**
29
+ * @param tokens
30
+ * @param {boolean} isFirst
31
+ * @param {string} filename
32
+ */
33
+ replaceTokens(tokens, isFirst, filename) {
34
+ this.result = tokens;
35
+ this.modName = NakoLexer.filenameToModName(filename);
36
+ // 関数の定義があれば funclist を更新
37
+ NakoLexer.preDefineFunc(tokens, this.logger, this.funclist);
38
+ this._replaceWord(this.result);
39
+ if (isFirst) {
40
+ if (this.result.length > 0) {
41
+ const eof = this.result[this.result.length - 1];
42
+ this.result.push({
43
+ type: 'eol',
44
+ line: eof.line,
45
+ column: 0,
46
+ file: eof.file,
47
+ josi: '',
48
+ value: '---',
49
+ startOffset: eof.startOffset,
50
+ endOffset: eof.endOffset,
51
+ rawJosi: ''
52
+ }); // 改行
53
+ this.result.push({
54
+ type: 'eof',
55
+ line: eof.line,
56
+ column: 0,
57
+ file: eof.file,
58
+ josi: '',
59
+ value: '',
60
+ startOffset: eof.startOffset,
61
+ endOffset: eof.endOffset,
62
+ rawJosi: ''
63
+ }); // ファイル末尾
64
+ }
65
+ else {
66
+ this.result.push({
67
+ type: 'eol',
68
+ line: 0,
69
+ column: 0,
70
+ file: '',
71
+ josi: '',
72
+ value: '---',
73
+ startOffset: 0,
74
+ endOffset: 0,
75
+ rawJosi: ''
76
+ }); // 改行
77
+ this.result.push({
78
+ type: 'eof',
79
+ line: 0,
80
+ column: 0,
81
+ file: '',
82
+ josi: '',
83
+ value: '',
84
+ startOffset: 0,
85
+ endOffset: 0,
86
+ rawJosi: ''
87
+ }); // ファイル末尾
88
+ }
89
+ }
90
+ return this.result;
91
+ }
92
+ /**
93
+ * ファイル内で定義されている関数名を列挙する。結果はfunclistに書き込む。その他のトークンの置換処理も行う。
94
+ * シンタックスハイライトの処理から呼び出すためにstaticメソッドにしている。
95
+ * @param {Token[]} tokens
96
+ * @param {import('./nako_logger.mjs').NakoLogger} logger
97
+ * @param {FuncList} funclist
98
+ */
99
+ static preDefineFunc(tokens, logger, funclist) {
100
+ // 関数を先読みして定義
101
+ let i = 0;
102
+ let isFuncPointer = false;
103
+ const readArgs = () => {
104
+ const args = [];
105
+ const keys = {};
106
+ if (tokens[i].type !== '(') {
107
+ return [];
108
+ }
109
+ i++;
110
+ while (tokens[i]) {
111
+ const t = tokens[i];
112
+ i++;
113
+ if (t.type === ')') {
114
+ break;
115
+ }
116
+ if (t.type === 'func') {
117
+ isFuncPointer = true;
118
+ }
119
+ else if (t.type !== '|' && t.type !== 'comma') {
120
+ if (isFuncPointer) {
121
+ t.funcPointer = true;
122
+ isFuncPointer = false;
123
+ }
124
+ args.push(t);
125
+ if (!keys[t.value]) {
126
+ keys[t.value] = [];
127
+ }
128
+ keys[t.value].push(t.josi);
129
+ }
130
+ }
131
+ const varnames = [];
132
+ const funcPointers = [];
133
+ const result = [];
134
+ const already = {};
135
+ for (const arg of args) {
136
+ if (!already[arg.value]) {
137
+ const josi = keys[arg.value];
138
+ result.push(josi);
139
+ varnames.push(arg.value);
140
+ if (arg.funcPointer) {
141
+ funcPointers.push(arg.value);
142
+ }
143
+ else {
144
+ funcPointers.push(null);
145
+ }
146
+ already[arg.value] = true;
147
+ }
148
+ }
149
+ return [result, varnames, funcPointers];
150
+ };
151
+ // トークンを一つずつ確認
152
+ while (i < tokens.length) {
153
+ // タイプの置換
154
+ const t = tokens[i];
155
+ // 無名関数の定義:「xxには**」があった場合 ... 暗黙的な関数定義とする
156
+ if ((t.type === 'word' && t.josi === 'には') || (t.type === 'word' && t.josi === 'は~')) {
157
+ t.josi = 'には';
158
+ tokens.splice(i + 1, 0, { type: 'def_func', value: '関数', line: t.line, column: t.column, file: t.file, josi: '', startOffset: t.endOffset, endOffset: t.endOffset, rawJosi: '', tag: '無名関数' });
159
+ i++;
160
+ continue;
161
+ }
162
+ // N回をN|回に置換
163
+ if (t.type === 'word' && t.josi === '' && t.value.length >= 2) {
164
+ if (t.value.match(/回$/)) {
165
+ t.value = t.value.substring(0, t.value.length - 1);
166
+ // N回を挿入
167
+ if (!t.endOffset) {
168
+ t.endOffset = 1;
169
+ }
170
+ const kai = { type: '回', value: '回', line: t.line, column: t.column, file: t.file, josi: '', startOffset: t.endOffset - 1, endOffset: t.endOffset, rawJosi: '' };
171
+ tokens.splice(i + 1, 0, kai);
172
+ t.endOffset--;
173
+ i++;
174
+ }
175
+ }
176
+ // 予約語の置換
177
+ if (t.type === 'word' && reservedWords[t.value]) {
178
+ t.type = reservedWords[t.value];
179
+ if (t.value === 'そう') {
180
+ t.value = 'それ';
181
+ }
182
+ }
183
+ // 関数定義の確認
184
+ if (t.type !== 'def_test' && t.type !== 'def_func') {
185
+ i++;
186
+ continue;
187
+ }
188
+ // 無名関数か普通関数定義かを判定する (1つ前が改行かどうかで判定)
189
+ let isMumei = true;
190
+ let prevToken = { type: 'eol' };
191
+ if (i >= 1) {
192
+ prevToken = tokens[i - 1];
193
+ }
194
+ if (prevToken.type === 'eol') {
195
+ isMumei = false;
196
+ }
197
+ // 関数名や引数を得る
198
+ const defToken = t;
199
+ i++; // skip "●" or "関数"
200
+ let josi = [];
201
+ let varnames = [];
202
+ let funcPointers = [];
203
+ let funcName = '';
204
+ let funcNameToken = null;
205
+ // 関数名の前に引数定義
206
+ if (tokens[i] && tokens[i].type === '(') {
207
+ [josi, varnames, funcPointers] = readArgs();
208
+ }
209
+ // 関数名を得る
210
+ if (!isMumei && tokens[i] && tokens[i].type === 'word') {
211
+ funcNameToken = tokens[i++];
212
+ funcName = funcNameToken.value;
213
+ }
214
+ // 関数名の後で引数定義
215
+ if (josi.length === 0 && tokens[i] && tokens[i].type === '(') {
216
+ [josi, varnames, funcPointers] = readArgs();
217
+ }
218
+ // 名前のある関数定義ならば関数テーブルに関数名を登録
219
+ // 無名関数は登録しないように気をつける
220
+ if (funcName !== '' && funcNameToken) {
221
+ const modName = NakoLexer.filenameToModName(t.file);
222
+ funcName = modName + '__' + funcName;
223
+ if (funcName in funclist) { // 関数の二重定義を警告
224
+ // main__は省略 #1223
225
+ const dispName = funcName.replace(/^main__/, '');
226
+ logger.warn(`関数『${dispName}』は既に定義されています。`, defToken);
227
+ }
228
+ funcNameToken.value = funcName;
229
+ funclist[funcName] = {
230
+ type: 'func',
231
+ josi,
232
+ fn: null,
233
+ asyncFn: false,
234
+ varnames,
235
+ funcPointers
236
+ };
237
+ }
238
+ // 無名関数のために
239
+ defToken.meta = {
240
+ type: 'func',
241
+ josi,
242
+ varnames,
243
+ funcPointers
244
+ };
245
+ }
246
+ }
247
+ /** 文字列を{と}の部分で分割する。中括弧が対応していない場合nullを返す。 */
248
+ splitStringEx(code) {
249
+ /** @type {string[]} */
250
+ const list = [];
251
+ // "A{B}C{D}E" -> ["A", "B}C", "D}E"] -> ["A", "B", "C", "D", "E"]
252
+ // "A{B}C}D{E}F" -> ["A", "B}C}D", "E}F"] -> ["A", "B", "C}D", "E", "F"]
253
+ const arr = code.split(/[{{]/);
254
+ list.push(arr[0]);
255
+ for (const s of arr.slice(1)) {
256
+ const end = s.replace('}', '}').indexOf('}');
257
+ if (end === -1) {
258
+ return null;
259
+ }
260
+ list.push(s.slice(0, end), s.slice(end + 1));
261
+ }
262
+ return list;
263
+ }
264
+ _replaceWord(tokens) {
265
+ let comment = [];
266
+ let i = 0;
267
+ const getLastType = () => {
268
+ if (i <= 0) {
269
+ return 'eol';
270
+ }
271
+ return tokens[i - 1].type;
272
+ };
273
+ const modSelf = (tokens.length > 0) ? NakoLexer.filenameToModName(tokens[0].file) : 'main.nako3';
274
+ while (i < tokens.length) {
275
+ const t = tokens[i];
276
+ // 関数を強制的に置換( word => func )
277
+ if (t.type === 'word' && t.value !== 'それ') {
278
+ // 関数を変換
279
+ const funcName = t.value;
280
+ if (funcName.indexOf('__') < 0) {
281
+ // 自身のモジュール名を検索
282
+ const gname1 = `${modSelf}__${funcName}`;
283
+ const gfo1 = this.funclist[gname1];
284
+ if (gfo1 && gfo1.type === 'func') {
285
+ t.type = 'func';
286
+ t.meta = gfo1;
287
+ t.value = gname1;
288
+ continue;
289
+ }
290
+ // モジュール関数を置換
291
+ for (const mod of this.modList) {
292
+ const gname = `${mod}__${funcName}`;
293
+ const gfo = this.funclist[gname];
294
+ if (gfo && gfo.type === 'func') {
295
+ t.type = 'func';
296
+ t.meta = gfo;
297
+ t.value = gname;
298
+ break;
299
+ }
300
+ }
301
+ if (t.type === 'func') {
302
+ continue;
303
+ }
304
+ }
305
+ const fo = this.funclist[funcName];
306
+ if (fo && fo.type === 'func') {
307
+ t.type = 'func';
308
+ t.meta = fo;
309
+ }
310
+ }
311
+ // 数字につくマイナス記号を判定
312
+ // (ng) 5 - 3 || word - 3
313
+ // (ok) (行頭)-3 || 1 * -3 || Aに -3を 足す
314
+ if (t.type === '-' && tokens[i + 1] && tokens[i + 1].type === 'number') {
315
+ // 一つ前の語句が、(行頭|演算子|助詞付きの語句)なら 負数である
316
+ const ltype = getLastType();
317
+ if (ltype === 'eol' || opPriority[ltype] || tokens[i - 1].josi !== '') {
318
+ tokens.splice(i, 1); // remove '-'
319
+ tokens[i].value *= -1;
320
+ }
321
+ }
322
+ // 助詞の「は」を = に展開
323
+ if (t.josi === undefined) {
324
+ t.josi = '';
325
+ }
326
+ if (t.josi === 'は') {
327
+ if (!t.rawJosi) {
328
+ t.rawJosi = t.josi;
329
+ }
330
+ const startOffset = (t.endOffset === undefined) ? undefined : t.endOffset - t.rawJosi.length;
331
+ tokens.splice(i + 1, 0, {
332
+ type: 'eq',
333
+ line: t.line,
334
+ column: t.column,
335
+ file: t.file,
336
+ startOffset,
337
+ endOffset: t.endOffset,
338
+ josi: '',
339
+ rawJosi: '',
340
+ value: undefined
341
+ });
342
+ i += 2;
343
+ t.josi = t.rawJosi = '';
344
+ t.endOffset = startOffset;
345
+ continue;
346
+ }
347
+ // 「とは」を一つの単語にする
348
+ if (t.josi === 'とは') {
349
+ if (!t.rawJosi) {
350
+ t.rawJosi = t.josi;
351
+ }
352
+ const startOffset = t.endOffset === undefined ? undefined : t.endOffset - t.rawJosi.length;
353
+ tokens.splice(i + 1, 0, {
354
+ type: t.josi,
355
+ line: t.line,
356
+ column: t.column,
357
+ file: t.file,
358
+ startOffset,
359
+ endOffset: t.endOffset,
360
+ josi: '',
361
+ rawJosi: '',
362
+ value: undefined
363
+ });
364
+ t.josi = t.rawJosi = '';
365
+ t.endOffset = startOffset;
366
+ i += 2;
367
+ continue;
368
+ }
369
+ // 助詞のならばをトークンとする
370
+ if (tararebaMap[t.josi]) {
371
+ const josi = (t.josi === 'でなければ' || t.josi === 'なければ') ? 'でなければ' : 'ならば';
372
+ if (!t.rawJosi) {
373
+ t.rawJosi = josi;
374
+ }
375
+ const startOffset = t.endOffset === undefined ? undefined : t.endOffset - t.rawJosi.length;
376
+ tokens.splice(i + 1, 0, {
377
+ type: 'ならば',
378
+ value: josi,
379
+ line: t.line,
380
+ column: t.column,
381
+ file: t.file,
382
+ startOffset,
383
+ endOffset: t.endOffset,
384
+ josi: '',
385
+ rawJosi: ''
386
+ });
387
+ t.josi = t.rawJosi = '';
388
+ t.endOffset = startOffset;
389
+ i += 2;
390
+ continue;
391
+ }
392
+ // '_' + 改行 を飛ばす (演算子直後に改行を入れたい場合に使う)
393
+ if (t.type === '_eol') {
394
+ tokens.splice(i, 1);
395
+ continue;
396
+ }
397
+ // コメントを飛ばす
398
+ if (t.type === 'line_comment' || t.type === 'range_comment') {
399
+ comment.push(t.value);
400
+ tokens.splice(i, 1);
401
+ continue;
402
+ }
403
+ // 改行にコメントを埋め込む
404
+ if (t.type === 'eol') {
405
+ t.value = comment.join('/');
406
+ comment = [];
407
+ }
408
+ i++;
409
+ }
410
+ }
411
+ /**
412
+ * @param {string} src
413
+ * @param {number} line
414
+ * @param {string} filename
415
+ * @returns {Token[]}
416
+ */
417
+ tokenize(src, line, filename) {
418
+ const srcLength = src.length;
419
+ const result = [];
420
+ let columnCurrent;
421
+ let lineCurrent;
422
+ let column = 1;
423
+ let isDefTest = false;
424
+ while (src !== '') {
425
+ let ok = false;
426
+ // 各ルールについて
427
+ for (const rule of rules) {
428
+ // 正規表現でマッチ
429
+ const m = rule.pattern.exec(src);
430
+ if (!m) {
431
+ continue;
432
+ }
433
+ ok = true;
434
+ // 空白ならスキップ
435
+ if (rule.name === 'space') {
436
+ column += m[0].length;
437
+ src = src.substring(m[0].length);
438
+ continue;
439
+ }
440
+ // マッチしたルールがコールバックを持つなら
441
+ if (rule.cbParser) {
442
+ // コールバックを呼ぶ
443
+ /** @type {{ src: string, res: string, josi: string, numEOL: number }} */
444
+ let rp;
445
+ if (isDefTest && rule.name === 'word') {
446
+ rp = rule.cbParser(src, false);
447
+ }
448
+ else {
449
+ try {
450
+ rp = rule.cbParser(src);
451
+ }
452
+ catch (e) {
453
+ throw new NakoLexerError(e.message, srcLength - src.length, srcLength - src.length + 1, line, filename);
454
+ }
455
+ }
456
+ if (rule.name === 'string_ex') {
457
+ // 展開あり文字列 → aaa{x}bbb{x}cccc
458
+ const list = this.splitStringEx(rp.res);
459
+ if (list === null) {
460
+ throw new InternalLexerError('展開あり文字列で値の埋め込み{...}が対応していません。', srcLength - src.length, srcLength - rp.src.length, line, filename);
461
+ }
462
+ let offset = 0;
463
+ for (let i = 0; i < list.length; i++) {
464
+ const josi = (i === list.length - 1) ? rp.josi : '';
465
+ if (i % 2 === 0) {
466
+ result.push({
467
+ type: 'string',
468
+ value: list[i],
469
+ file: filename,
470
+ josi,
471
+ line,
472
+ column,
473
+ preprocessedCodeOffset: srcLength - src.length + offset,
474
+ preprocessedCodeLength: list[i].length + 2 + josi.length
475
+ });
476
+ // 先頭なら'"...{'、それ以外なら'}...{'、最後は何でも良い
477
+ offset += list[i].length + 2;
478
+ }
479
+ else {
480
+ result.push({ type: '&', value: '&', josi: '', file: filename, line, column, preprocessedCodeOffset: srcLength - src.length + offset, preprocessedCodeLength: 0 });
481
+ result.push({ type: '(', value: '(', josi: '', file: filename, line, column, preprocessedCodeOffset: srcLength - src.length + offset, preprocessedCodeLength: 0 });
482
+ result.push({ type: 'code', value: list[i], josi: '', file: filename, line, column, preprocessedCodeOffset: srcLength - src.length + offset, preprocessedCodeLength: list[i].length });
483
+ result.push({ type: ')', value: ')', josi: '', file: filename, line, column, preprocessedCodeOffset: srcLength - src.length + offset + list[i].length, preprocessedCodeLength: 0 });
484
+ result.push({ type: '&', value: '&', josi: '', file: filename, line, column, preprocessedCodeOffset: srcLength - src.length + offset + list[i].length, preprocessedCodeLength: 0 });
485
+ offset += list[i].length;
486
+ }
487
+ }
488
+ line += rp.numEOL;
489
+ column += src.length - rp.src.length;
490
+ src = rp.src;
491
+ if (rp.numEOL > 0) {
492
+ column = 1;
493
+ }
494
+ break;
495
+ }
496
+ columnCurrent = column;
497
+ column += src.length - rp.src.length;
498
+ result.push({ type: rule.name, value: rp.res, josi: rp.josi, line, column: columnCurrent, file: filename, preprocessedCodeOffset: srcLength - src.length, preprocessedCodeLength: src.length - rp.src.length });
499
+ src = rp.src;
500
+ line += rp.numEOL;
501
+ if (rp.numEOL > 0) {
502
+ column = 1;
503
+ }
504
+ break;
505
+ }
506
+ // ソースを進める前に位置を計算
507
+ const srcOffset = srcLength - src.length;
508
+ // 値を変換する必要があるか?
509
+ let value = m[0];
510
+ if (rule.cb) {
511
+ value = rule.cb(value);
512
+ }
513
+ // ソースを進める
514
+ columnCurrent = column;
515
+ lineCurrent = line;
516
+ column += m[0].length;
517
+ src = src.substring(m[0].length);
518
+ if ((rule.name === 'eol' && value === '\n') || rule.name === '_eol') {
519
+ value = line++;
520
+ column = 1;
521
+ }
522
+ // 数値なら単位を持つか? --- #994
523
+ if (rule.name === 'number') {
524
+ // 単位があれば読み飛ばす
525
+ const um = unitRE.exec(src);
526
+ if (um) {
527
+ src = src.substring(um[0].length);
528
+ column += m[0].length;
529
+ }
530
+ }
531
+ let josi = '';
532
+ if (rule.readJosi) {
533
+ const j = josiRE.exec(src);
534
+ if (j) {
535
+ josi = j[0].replace(/^\s+/, '');
536
+ column += j[0].length;
537
+ src = src.substring(j[0].length);
538
+ // 助詞の直後にあるカンマを無視 #877
539
+ if (src.charAt(0) === ',') {
540
+ src = src.substring(1);
541
+ }
542
+ // 「**である」なら削除 #939 #974
543
+ if (removeJosiMap[josi]) {
544
+ josi = '';
545
+ }
546
+ }
547
+ }
548
+ switch (rule.name) {
549
+ case 'def_test': {
550
+ isDefTest = true;
551
+ break;
552
+ }
553
+ case 'eol': {
554
+ isDefTest = false;
555
+ break;
556
+ }
557
+ default: {
558
+ break;
559
+ }
560
+ }
561
+ // ここまで‰(#682) を処理
562
+ if (rule.name === 'dec_lineno') {
563
+ line--;
564
+ continue;
565
+ }
566
+ result.push({
567
+ type: rule.name,
568
+ value,
569
+ line: lineCurrent,
570
+ column: columnCurrent,
571
+ file: filename,
572
+ josi,
573
+ preprocessedCodeOffset: srcOffset,
574
+ preprocessedCodeLength: (srcLength - src.length) - srcOffset
575
+ });
576
+ break;
577
+ }
578
+ if (!ok) {
579
+ throw new InternalLexerError('未知の語句: ' + src.substring(0, 3) + '...', srcLength - src.length, srcLength - srcLength + 3, line, filename);
580
+ }
581
+ }
582
+ return result;
583
+ }
584
+ // トークン配列をtype文字列に変換
585
+ static tokensToTypeStr(tokens, sep) {
586
+ const a = tokens.map((v) => {
587
+ return v.type;
588
+ });
589
+ return a.join(sep);
590
+ }
591
+ /**
592
+ * ファイル名からモジュール名へ変換
593
+ * @param {string} filename
594
+ * @returns {string}
595
+ */
596
+ static filenameToModName(filename) {
597
+ if (!filename) {
598
+ return 'main';
599
+ }
600
+ // パスがあればパスを削除
601
+ filename = filename.replace(/[\\:]/g, '/'); // Windowsのpath記号を/に置換
602
+ if (filename.indexOf('/') >= 0) {
603
+ const a = filename.split('/');
604
+ filename = a[a.length - 1];
605
+ }
606
+ filename = filename.replace(/\.nako3?$/, '');
607
+ return filename;
608
+ }
609
+ }