nadesiko3 3.3.4 → 3.3.7

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 (40) hide show
  1. package/batch/command.txt +1 -0
  2. package/batch/command_nakopad.txt +1 -0
  3. package/demo/browsers.html +1 -1
  4. package/demo/nako3/taberu.nako3 +5 -0
  5. package/doc/browsers.md +1 -1
  6. package/package.json +1 -1
  7. package/release/_hash.txt +24 -24
  8. package/release/_script-tags.txt +14 -14
  9. package/release/command.json +1 -1
  10. package/release/command.json.js +1 -1
  11. package/release/command_cnako3.json +1 -1
  12. package/release/command_list.json +1 -1
  13. package/release/editor.js +1 -1
  14. package/release/nako_gen_async.js +1 -1
  15. package/release/nako_gen_async.js.LICENSE.txt +20 -0
  16. package/release/plugin_caniuse.js +1 -1
  17. package/release/stats.json +1 -1
  18. package/release/version.js +1 -1
  19. package/release/wnako3.js +1 -1
  20. package/src/browsers.mjs +1 -1
  21. package/src/browsers.txt +0 -1
  22. package/src/cnako3mod.mjs +88 -64
  23. package/src/nako3.mjs +72 -53
  24. package/src/nako_gen.mjs +6 -12
  25. package/src/nako_global.mjs +2 -2
  26. package/src/nako_lex_rules.mjs +1 -1
  27. package/src/nako_lexer.mjs +83 -22
  28. package/src/nako_parser3.mjs +144 -33
  29. package/src/nako_parser_base.mjs +75 -6
  30. package/src/nako_version.mjs +2 -2
  31. package/src/plugin_system.mjs +27 -9
  32. package/test/common/nako_lexer_test.mjs +33 -0
  33. package/test/common/plugin_system_test.mjs +1 -1
  34. package/test/common/variable_scope_test.mjs +13 -0
  35. package/test/node/error_message_test.mjs +5 -3
  36. package/test/node/plugin_test.mjs +21 -3
  37. package/test/node/scope1.nako3 +10 -0
  38. package/test/node/scope2.nako3 +12 -0
  39. package/test/node/wnako3_editor_test.mjs +12 -0
  40. package/tools/nako3edit/index.nako3 +3 -0
@@ -4,6 +4,7 @@
4
4
  import { opPriority, keizokuJosi } from './nako_parser_const.mjs'
5
5
  import { NakoParserBase } from './nako_parser_base.mjs'
6
6
  import { NakoSyntaxError } from './nako_errors.mjs'
7
+ import { NakoLexer } from './nako_lexer.mjs'
7
8
 
8
9
  /**
9
10
  * @type {string[]}
@@ -12,20 +13,24 @@ const operatorList = []
12
13
  for (const key in opPriority) { operatorList.push(key) }
13
14
 
14
15
  /**
15
- * @typedef {import('./nako3').TokenWithSourceMap} TokenWithSourceMap
16
- * @typedef {import('./nako3').Ast} Ast
16
+ * 構文解析を行うクラス
17
+ * @typedef {import('./nako3.mjs').TokenWithSourceMap} TokenWithSourceMap
18
+ * @typedef {import('./nako3.mjs').Ast} Ast
17
19
  */
18
-
19
20
  // @ts-ignore
20
21
  export class NakoParser extends NakoParserBase {
21
22
  /**
23
+ * 構文解析を実行する
22
24
  * @param {TokenWithSourceMap[]} tokens 字句解析済みのトークンの配列
25
+ * @param {string} filename 解析対象のモジュール名
23
26
  * @return {Ast} AST(構文木)
24
27
  */
25
- parse (tokens) {
28
+ parse (tokens, filename) {
26
29
  this.reset()
27
30
  /** @type {TokenWithSourceMap[]} */
28
31
  this.tokens = tokens
32
+ this.modName = NakoLexer.filenameToModName(filename)
33
+ this.modList.push(this.modName)
29
34
  // 解析開始
30
35
  return this.startParser()
31
36
  }
@@ -107,7 +112,7 @@ export class NakoParser extends NakoParserBase {
107
112
  if (this.check('逐次実行')) { return this.yTikuji() }
108
113
  if (this.accept(['抜ける'])) { return { type: 'break', josi: '', ...map, end: this.peekSourceMap() } }
109
114
  if (this.accept(['続ける'])) { return { type: 'continue', josi: '', ...map, end: this.peekSourceMap() } }
110
- if (this.accept(['require', 'string', '取込'])) { return { type: 'require', value: this.y[1].value, josi: '', ...map, end: this.peekSourceMap() } }
115
+ if (this.accept(['require', 'string', '取込'])) { return this.yRequire() }
111
116
  if (this.accept(['not', '非同期モード'])) { return this.yASyncMode() }
112
117
  if (this.accept(['not', 'DNCLモード'])) { return this.yDNCLMode() }
113
118
  if (this.accept(['not', 'string', 'モード設定'])) { return this.ySetGenMode(this.y[1].value) }
@@ -172,6 +177,27 @@ export class NakoParser extends NakoParserBase {
172
177
  return { type: 'eol', ...map, end: this.peekSourceMap() }
173
178
  }
174
179
 
180
+ /** @returns {Ast} */
181
+ yRequire () {
182
+ const nameToken = this.y[1]
183
+ const filename = nameToken.value
184
+ const modName = NakoLexer.filenameToModName(filename)
185
+ if (this.modList.indexOf(modName) < 0) {
186
+ // 優先度が最も高いのは modList[0]
187
+ // [memo] モジュールの検索優先度は、下に書くほど高くなる
188
+ const modSelf = this.modList.shift()
189
+ this.modList.unshift(modName)
190
+ this.modList.unshift(modSelf)
191
+ }
192
+ return {
193
+ type: 'require',
194
+ value: filename,
195
+ josi: '',
196
+ ...this.peekSourceMap(),
197
+ end: this.peekSourceMap()
198
+ }
199
+ }
200
+
175
201
  /** @returns {Ast} */
176
202
  yBlock () {
177
203
  const map = this.peekSourceMap()
@@ -243,9 +269,12 @@ export class NakoParser extends NakoParserBase {
243
269
  if (this.check('とは')) { this.get() }
244
270
  let block = null
245
271
  let multiline = false
272
+ let funcFn = false
246
273
  if (this.check('ここから')) { multiline = true }
247
274
  if (this.check('eol')) { multiline = true }
248
275
  try {
276
+ this.funcLevel++
277
+ this.usedFuncFn = false
249
278
  if (multiline) {
250
279
  this.saveStack()
251
280
  block = this.yBlock()
@@ -256,6 +285,8 @@ export class NakoParser extends NakoParserBase {
256
285
  block = this.ySentence()
257
286
  this.loadStack()
258
287
  }
288
+ this.funcLevel--
289
+ funcFn = this.usedFuncFn
259
290
  } catch (err) {
260
291
  this.logger.debug(this.nodeToStr(funcName, { depth: 0, typeName: '関数' }, true) +
261
292
  'の定義で以下のエラーがありました。\n' + err.message, def)
@@ -268,6 +299,7 @@ export class NakoParser extends NakoParserBase {
268
299
  name: funcName,
269
300
  args: defArgs,
270
301
  block,
302
+ funcFn,
271
303
  josi: '',
272
304
  ...map,
273
305
  end: this.peekSourceMap()
@@ -975,6 +1007,7 @@ export class NakoParser extends NakoParserBase {
975
1007
  // 「,」を飛ばす
976
1008
  if (this.check('comma')) { this.get() }
977
1009
  // ブロックを読む
1010
+ this.funcLevel++
978
1011
  this.saveStack()
979
1012
  const block = this.yBlock()
980
1013
  // 末尾の「ここまで」をチェック - もしなければエラーにする #1045
@@ -983,6 +1016,7 @@ export class NakoParser extends NakoParserBase {
983
1016
  }
984
1017
  this.get() // skip ここまで
985
1018
  this.loadStack()
1019
+ this.funcLevel--
986
1020
  return {
987
1021
  type: 'func_obj',
988
1022
  args,
@@ -994,7 +1028,7 @@ export class NakoParser extends NakoParserBase {
994
1028
  }
995
1029
  }
996
1030
 
997
- /** @returns {import('./nako3').Ast | null | undefined} */
1031
+ /** @returns {import('./nako3.mjs').Ast | null | undefined} */
998
1032
  yDainyu () {
999
1033
  const map = this.peekSourceMap()
1000
1034
  const dainyu = this.get() // 代入
@@ -1017,21 +1051,21 @@ export class NakoParser extends NakoParserBase {
1017
1051
  };
1018
1052
  }
1019
1053
  // 一般的な変数への代入
1054
+ const word2 = this.getVarName(word)
1020
1055
  return {
1021
- type: 'let', name: word,
1056
+ type: 'let', name: word2,
1022
1057
  value: value, josi: '',
1023
1058
  ...map, end: this.peekSourceMap()
1024
1059
  }
1025
1060
  }
1026
1061
 
1027
- /** @returns {import('./nako3').Ast | null | undefined} */
1062
+ /** @returns {import('./nako3.mjs').Ast | null | undefined} */
1028
1063
  ySadameru () {
1029
1064
  const map = this.peekSourceMap()
1030
1065
  const sadameru = this.get() // 定める
1031
1066
  if (sadameru === null) { return null }
1032
1067
  const word = this.popStack(['を'])
1033
1068
  const value = this.popStack(['へ', 'に'])
1034
- console.log(word)
1035
1069
  if (!word || (word.type !== 'word' && word.type !== 'func' && word.type !== '配列参照')) {
1036
1070
  throw NakoSyntaxError.fromNode('『定める』文で定数が見当たりません。『(定数名)を(値)に定める』のように使います。', sadameru)
1037
1071
  }
@@ -1042,7 +1076,7 @@ export class NakoParser extends NakoParserBase {
1042
1076
  };
1043
1077
  }
1044
1078
 
1045
- /** @returns {import('./nako3').Ast | null | undefined} */
1079
+ /** @returns {import('./nako3.mjs').Ast | null | undefined} */
1046
1080
  yIncDec () {
1047
1081
  const map = this.peekSourceMap()
1048
1082
  const action = this.get() // (増やす|減らす)
@@ -1077,7 +1111,7 @@ export class NakoParser extends NakoParserBase {
1077
1111
  };
1078
1112
  }
1079
1113
 
1080
- /** @returns {import('./nako3').Ast | null | undefined} */
1114
+ /** @returns {import('./nako3.mjs').Ast | null | undefined} */
1081
1115
  yCall () {
1082
1116
  if (this.isEOF()) { return null }
1083
1117
 
@@ -1174,6 +1208,9 @@ export class NakoParser extends NakoParserBase {
1174
1208
  // 最近使った関数を記録
1175
1209
  this.recentlyCalledFunc.push({name: t.value, ...f})
1176
1210
 
1211
+ // 呼び出す関数が非同期呼び出しが必要(asyncFn)ならマーク
1212
+ if (f && f.asyncFn) { this.usedFuncFn = true }
1213
+
1177
1214
  // 関数の引数を取り出す処理
1178
1215
  const args = []
1179
1216
  let nullCount = 0
@@ -1211,9 +1248,17 @@ export class NakoParser extends NakoParserBase {
1211
1248
  if (nullCount >= 2 && (valueCount > 0 || t.josi === '' || keizokuJosi.indexOf(t.josi) >= 0)) { throw NakoSyntaxError.fromNode(`関数『${t.value}』の引数が不足しています。`, t) }
1212
1249
 
1213
1250
  const funcNode = { type: 'func', name: t.value, args: args, josi: t.josi, ...map, end: this.peekSourceMap() }
1251
+ // 「プラグイン名設定」か
1252
+ if (funcNode.name === 'プラグイン名設定') {
1253
+ let fname = args[0].value
1254
+ if (fname === 'メイン') { fname = args[0].file }
1255
+ this.modName = NakoLexer.filenameToModName(fname)
1256
+ }
1257
+
1214
1258
  // 言い切りならそこで一度切る
1215
1259
  if (t.josi === '') { return funcNode }
1216
1260
 
1261
+
1217
1262
  // **して、** の場合も一度切る
1218
1263
  if (keizokuJosi.indexOf(t.josi) >= 0) {
1219
1264
  funcNode.josi = 'して'
@@ -1307,10 +1352,12 @@ export class NakoParser extends NakoParserBase {
1307
1352
  throw new Error('値が空です。')
1308
1353
  }
1309
1354
  if (this.check('comma')) { this.get() } // skip comma (ex) name1=val1, name2=val2
1355
+ const nameToken = this.getVarName(this.y[0])
1356
+ const valueToken = this.y[2]
1310
1357
  return {
1311
1358
  type: 'let',
1312
- name: this.y[0],
1313
- value: this.y[2],
1359
+ name: nameToken,
1360
+ value: valueToken,
1314
1361
  ...map,
1315
1362
  end: this.peekSourceMap()
1316
1363
  }
@@ -1348,7 +1395,7 @@ export class NakoParser extends NakoParserBase {
1348
1395
 
1349
1396
  // ローカル変数定義
1350
1397
  if (this.accept(['word', 'とは'])) {
1351
- const word = this.y[0]
1398
+ let word = this.getVarName(this.y[0])
1352
1399
  if (!this.checkTypes(['変数', '定数'])) {
1353
1400
  throw NakoSyntaxError.fromNode('ローカル変数『' + word.value + '』の定義エラー', word)
1354
1401
  }
@@ -1372,9 +1419,10 @@ export class NakoParser extends NakoParserBase {
1372
1419
  }
1373
1420
  // ローカル変数定義(その2)
1374
1421
  if (this.accept(['変数', 'word', 'eq', this.yCalc])) {
1422
+ let word = this.getVarName(this.y[1])
1375
1423
  return {
1376
1424
  type: 'def_local_var',
1377
- name: this.y[1],
1425
+ name: word,
1378
1426
  vartype: '変数',
1379
1427
  value: this.y[3],
1380
1428
  ...map,
@@ -1383,9 +1431,10 @@ export class NakoParser extends NakoParserBase {
1383
1431
  }
1384
1432
 
1385
1433
  if (this.accept(['定数', 'word', 'eq', this.yCalc])) {
1434
+ let word = this.getVarName(this.y[1])
1386
1435
  return {
1387
1436
  type: 'def_local_var',
1388
- name: this.y[1],
1437
+ name: word,
1389
1438
  vartype: '定数',
1390
1439
  value: this.y[3],
1391
1440
  ...map,
@@ -1406,6 +1455,7 @@ export class NakoParser extends NakoParserBase {
1406
1455
  } else {
1407
1456
  throw NakoSyntaxError.fromNode('複数定数の代入文でエラー。『定数[A,B,C]=[1,2,3]』の書式で記述してください。', this.y[0])
1408
1457
  }
1458
+ names.value = this.getVarNameList(names.value)
1409
1459
  return {
1410
1460
  type: 'def_local_varlist',
1411
1461
  names: names.value,
@@ -1428,6 +1478,7 @@ export class NakoParser extends NakoParserBase {
1428
1478
  } else {
1429
1479
  throw NakoSyntaxError.fromNode('複数変数の代入文でエラー。『変数[A,B,C]=[1,2,3]』の書式で記述してください。', this.y[0])
1430
1480
  }
1481
+ names.value = this.getVarNameList(names.value)
1431
1482
  return {
1432
1483
  type: 'def_local_varlist',
1433
1484
  names: names.value,
@@ -1442,9 +1493,11 @@ export class NakoParser extends NakoParserBase {
1442
1493
  if (this.check2(['word', 'comma', 'word'])) {
1443
1494
  // 2 word
1444
1495
  if (this.accept(['word', 'comma', 'word', 'eq', this.yCalc])) {
1496
+ let names = [this.y[0], this.y[2]]
1497
+ names = this.getVarNameList(names)
1445
1498
  return {
1446
1499
  type: 'def_local_varlist',
1447
- names: [this.y[0], this.y[2]],
1500
+ names,
1448
1501
  vartype: '変数',
1449
1502
  value: this.y[4],
1450
1503
  ...map,
@@ -1453,9 +1506,11 @@ export class NakoParser extends NakoParserBase {
1453
1506
  }
1454
1507
  // 3 word
1455
1508
  if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'eq', this.yCalc])) {
1509
+ let names = [this.y[0], this.y[2], this.y[4]]
1510
+ names = this.getVarNameList(names)
1456
1511
  return {
1457
1512
  type: 'def_local_varlist',
1458
- names: [this.y[0], this.y[2], this.y[4]],
1513
+ names,
1459
1514
  vartype: '変数',
1460
1515
  value: this.y[6],
1461
1516
  ...map,
@@ -1464,9 +1519,11 @@ export class NakoParser extends NakoParserBase {
1464
1519
  }
1465
1520
  // 4 word
1466
1521
  if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'eq', this.yCalc])) {
1522
+ let names = [this.y[0], this.y[2], this.y[4], this.y[6]]
1523
+ names = this.getVarNameList(names)
1467
1524
  return {
1468
1525
  type: 'def_local_varlist',
1469
- names: [this.y[0], this.y[2], this.y[4], this.y[6]],
1526
+ names,
1470
1527
  vartype: '変数',
1471
1528
  value: this.y[8],
1472
1529
  ...map,
@@ -1475,9 +1532,11 @@ export class NakoParser extends NakoParserBase {
1475
1532
  }
1476
1533
  // 5 word
1477
1534
  if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'eq', this.yCalc])) {
1535
+ let names = [this.y[0], this.y[2], this.y[4], this.y[6], this.y[8]]
1536
+ names = this.getVarNameList(names)
1478
1537
  return {
1479
1538
  type: 'def_local_varlist',
1480
- names: [this.y[0], this.y[2], this.y[4], this.y[6], this.y[8]],
1539
+ names,
1481
1540
  vartype: '変数',
1482
1541
  value: this.y[10],
1483
1542
  ...map,
@@ -1528,7 +1587,7 @@ export class NakoParser extends NakoParserBase {
1528
1587
  if (this.accept(['word', '@', this.yValue, 'eq', this.yCalc])) {
1529
1588
  return {
1530
1589
  type: 'let_array',
1531
- name: this.y[0],
1590
+ name: this.getVarName(this.y[0]),
1532
1591
  index: [this.checkArrayIndex(this.y[2])],
1533
1592
  value: this.y[4],
1534
1593
  ...map,
@@ -1540,7 +1599,7 @@ export class NakoParser extends NakoParserBase {
1540
1599
  if (this.accept(['word', '@', this.yValue, '@', this.yValue, 'eq', this.yCalc])) {
1541
1600
  return {
1542
1601
  type: 'let_array',
1543
- name: this.y[0],
1602
+ name: this.getVarName(this.y[0]),
1544
1603
  index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4])]),
1545
1604
  value: this.y[6],
1546
1605
  ...map,
@@ -1552,7 +1611,7 @@ export class NakoParser extends NakoParserBase {
1552
1611
  if (this.accept(['word', '@', this.yValue, '@', this.yValue, '@', this.yValue, 'eq', this.yCalc])) {
1553
1612
  return {
1554
1613
  type: 'let_array',
1555
- name: this.y[0],
1614
+ name: this.getVarName(this.y[0]),
1556
1615
  index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4]), this.checkArrayIndex(this.y[6])]),
1557
1616
  value: this.y[8],
1558
1617
  ...map,
@@ -1564,7 +1623,7 @@ export class NakoParser extends NakoParserBase {
1564
1623
  if (this.accept(['word', '@', this.yValue, 'comma', this.yValue, 'eq', this.yCalc])) {
1565
1624
  return {
1566
1625
  type: 'let_array',
1567
- name: this.y[0],
1626
+ name: this.getVarName(this.y[0]),
1568
1627
  index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4])]),
1569
1628
  value: this.y[6],
1570
1629
  ...map,
@@ -1576,7 +1635,7 @@ export class NakoParser extends NakoParserBase {
1576
1635
  if (this.accept(['word', '@', this.yValue, 'comma', this.yValue, 'comma', this.yValue, 'eq', this.yCalc])) {
1577
1636
  return {
1578
1637
  type: 'let_array',
1579
- name: this.y[0],
1638
+ name: this.getVarName(this.y[0]),
1580
1639
  index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4]), this.checkArrayIndex(this.y[6])]),
1581
1640
  value: this.y[8],
1582
1641
  ...map,
@@ -1592,7 +1651,7 @@ export class NakoParser extends NakoParserBase {
1592
1651
  if (this.accept(['word', '[', this.yCalc, ']', 'eq', this.yCalc])) {
1593
1652
  return {
1594
1653
  type: 'let_array',
1595
- name: this.y[0],
1654
+ name: this.getVarName(this.y[0]),
1596
1655
  index: [this.checkArrayIndex(this.y[2])],
1597
1656
  value: this.y[5],
1598
1657
  ...map,
@@ -1604,7 +1663,7 @@ export class NakoParser extends NakoParserBase {
1604
1663
  if (this.accept(['word', '[', this.yCalc, ']', '[', this.yCalc, ']', 'eq', this.yCalc])) {
1605
1664
  return {
1606
1665
  type: 'let_array',
1607
- name: this.y[0],
1666
+ name: this.getVarName(this.y[0]),
1608
1667
  index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[5])]),
1609
1668
  value: this.y[8],
1610
1669
  tag: '2',
@@ -1615,7 +1674,7 @@ export class NakoParser extends NakoParserBase {
1615
1674
  if (this.accept(['word', '[', this.yCalc, 'comma', this.yCalc, ']', 'eq', this.yCalc])) {
1616
1675
  return {
1617
1676
  type: 'let_array',
1618
- name: this.y[0],
1677
+ name: this.getVarName(this.y[0]),
1619
1678
  index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4])]),
1620
1679
  value: this.y[7],
1621
1680
  tag: '2',
@@ -1628,7 +1687,7 @@ export class NakoParser extends NakoParserBase {
1628
1687
  if (this.accept(['word', '[', this.yCalc, ']', '[', this.yCalc, ']', '[', this.yCalc, ']', 'eq', this.yCalc])) {
1629
1688
  return {
1630
1689
  type: 'let_array',
1631
- name: this.y[0],
1690
+ name: this.getVarName(this.y[0]),
1632
1691
  index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[5]), this.checkArrayIndex(this.y[8])]),
1633
1692
  value: this.y[11],
1634
1693
  ...map,
@@ -1638,7 +1697,7 @@ export class NakoParser extends NakoParserBase {
1638
1697
  if (this.accept(['word', '[', this.yCalc, 'comma', this.yCalc, 'comma', this.yCalc, ']', 'eq', this.yCalc])) {
1639
1698
  return {
1640
1699
  type: 'let_array',
1641
- name: this.y[0],
1700
+ name: this.getVarName(this.y[0]),
1642
1701
  index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4]), this.checkArrayIndex(this.y[6])]),
1643
1702
  value: this.y[9],
1644
1703
  ...map,
@@ -1746,7 +1805,7 @@ export class NakoParser extends NakoParserBase {
1746
1805
  // 一語関数
1747
1806
  const splitType = operatorList.concat(['eol', ')', ']', 'ならば', '回', '間', '反復', '条件分岐'])
1748
1807
  if (this.check2(['func', splitType])) {
1749
- const f = this.get()
1808
+ const f = this.getVarNameRef(this.get())
1750
1809
  return {
1751
1810
  type: 'func',
1752
1811
  name: f.value,
@@ -1762,7 +1821,7 @@ export class NakoParser extends NakoParserBase {
1762
1821
  if (this.accept([['func', 'word'], '(', this.yGetArgParen, ')'])) {
1763
1822
  return {
1764
1823
  type: 'func',
1765
- name: this.y[0].value,
1824
+ name: this.getVarNameRef(this.y[0]).value,
1766
1825
  args: this.y[2],
1767
1826
  josi: this.y[3].josi,
1768
1827
  ...map,
@@ -1843,7 +1902,7 @@ export class NakoParser extends NakoParserBase {
1843
1902
  yValueWord () {
1844
1903
  const map = this.peekSourceMap()
1845
1904
  if (this.check('word')) {
1846
- const word = this.get()
1905
+ const word = this.getVarNameRef(this.get())
1847
1906
  if (this.skipRefArray) { return word }
1848
1907
 
1849
1908
  // word[n] || word@n
@@ -1867,6 +1926,58 @@ export class NakoParser extends NakoParserBase {
1867
1926
  return null
1868
1927
  }
1869
1928
 
1929
+ /** 変数名を検索して解決する
1930
+ * @param {TokenWithSourceMap} word
1931
+ * @return {TokenWithSourceMap}
1932
+ */
1933
+ getVarName(word) {
1934
+ // check word name
1935
+ const f = this.findVar(word.value)
1936
+ if (!f) { // 変数が見つからない
1937
+ if (this.funcLevel === 0) { // global
1938
+ let gname = word.value
1939
+ if (gname.indexOf('__') < 0) { gname = this.modName + '__' + word.value }
1940
+ this.funclist[gname] = {type: 'var', value: ''}
1941
+ word.value = gname
1942
+ } else { // local
1943
+ this.localvars[word.value] = {type: 'var', value: ''}
1944
+ }
1945
+ }
1946
+ else if (f && f.scope === 'global') {
1947
+ word.value = f.name
1948
+ }
1949
+ return word
1950
+ }
1951
+
1952
+ /** 変数名を検索して解決する
1953
+ * @param {TokenWithSourceMap} word
1954
+ * @return {TokenWithSourceMap}
1955
+ */
1956
+ getVarNameRef(word) {
1957
+ // check word name
1958
+ const f = this.findVar(word.value)
1959
+ if (!f) { // 変数が見つからない
1960
+ if (this.funcLevel === 0 && word.value.indexOf('__') < 0) {
1961
+ word.value = this.modName + '__' + word.value
1962
+ }
1963
+ }
1964
+ if (f && f.scope === 'global') {
1965
+ word.value = f.name
1966
+ }
1967
+ return word
1968
+ }
1969
+
1970
+ /** 複数の変数名を検索して解決する
1971
+ * @param {TokenWithSourceMap[]} words
1972
+ * @return {TokenWithSourceMap[]}
1973
+ */
1974
+ getVarNameList(words) {
1975
+ for (let i = 0; i < words.length; i++) {
1976
+ words[i] = this.getVarName(words[i])
1977
+ }
1978
+ return words
1979
+ }
1980
+
1870
1981
  yJSONObjectValue () {
1871
1982
  const a = []
1872
1983
  const firstToken = this.peek()
@@ -3,26 +3,40 @@
3
3
  */
4
4
  export class NakoParserBase {
5
5
  /**
6
- * @param {import("./nako_logger")} logger
6
+ * @param {import("./nako_logger.mjs")} logger
7
7
  */
8
8
  constructor (logger) {
9
9
  this.logger = logger
10
10
  /** @type any[] */
11
11
  this.stackList = [] // 関数定義の際にスタックが混乱しないように整理する
12
- this.init()
13
- /** @type {import('./nako3').TokenWithSourceMap[]} */
12
+ /** @type {import('./nako3.mjs').TokenWithSourceMap[]} */
14
13
  this.tokens = []
15
- /** @type {import('./nako3').Ast[]} */
14
+ /** @type {import('./nako3.mjs').Ast[]} */
16
15
  this.stack = []
17
16
  this.index = 0
18
- /** @type {import('./nako3').Ast[]} */
17
+ /** トークン出現チェック(accept関数)に利用する
18
+ * @type {import('./nako3.mjs').Ast[]}
19
+ */
19
20
  this.y = []
21
+ /** モジュル名 @type {string} */
22
+ this.modName = 'inline'
23
+ /** 利用するモジュールの名前一覧 @type {Array[string]} */
24
+ this.modList = []
25
+ /** グローバル変数・関数の確認用 */
26
+ this.funclist = {}
27
+ this.funcLevel = 0
28
+ this.usedFuncFn = false // funcFnの呼び出しがあるかどうか
29
+ /** ローカル変数の確認用 */
30
+ this.localvars = {'それ': {type: 'var', value: ''}}
31
+ /** コード生成器の名前 */
20
32
  this.genMode = 'sync' // #637
21
33
  this.arrayIndexFrom = 0 // #1140
22
34
  this.flagReverseArrayIndex = false // #1140
23
35
  this.flagCheckArrayInit = false // #1140
24
36
  /** @type Object[] */
25
37
  this.recentlyCalledFunc = [] // 最近呼び出した関数(余剰エラーの報告に使う)
38
+
39
+ this.init()
26
40
  }
27
41
 
28
42
  init () {
@@ -31,7 +45,7 @@ export class NakoParserBase {
31
45
  }
32
46
 
33
47
  reset () {
34
- /** @type {import('./nako3').TokenWithSourceMap[]} */
48
+ /** @type {import('./nako3.mjs').TokenWithSourceMap[]} */
35
49
  this.tokens = [] // 字句解析済みのトークンの一覧を保存
36
50
  this.index = 0 // tokens[] のどこまで読んだかを管理する
37
51
  this.stack = [] // 計算用のスタック ... 直接は操作せず、pushStack() popStack() を介して使う
@@ -75,6 +89,61 @@ export class NakoParserBase {
75
89
 
76
90
  loadStack () {
77
91
  this.stack = this.stackList.pop()
92
+ this.localvars = {'それ': {type: 'var', value: ''}}
93
+ }
94
+
95
+ /** 変数名を探す
96
+ * @param {string} name
97
+ * @returns {any}変数名の情報
98
+ */
99
+ findVar(name) {
100
+ // モジュール名を含んでいる?
101
+ if (name.indexOf('__') >= 0) {
102
+ if (this.funclist[name]) {
103
+ return {
104
+ name,
105
+ scope: 'global',
106
+ info: this.funclist[name]
107
+ }
108
+ } else { return undefined }
109
+ }
110
+ // ローカル変数?
111
+ if (this.localvars[name]) {
112
+ return {
113
+ name: name,
114
+ scope: 'local',
115
+ info: this.localvars[name]
116
+ }
117
+ }
118
+ // グローバル変数(自身)?
119
+ const gnameSelf = `${this.modName}__${name}`
120
+ if (this.funclist[gnameSelf]) {
121
+ return {
122
+ name: gnameSelf,
123
+ scope: 'global',
124
+ info: this.funclist[gnameSelf]
125
+ }
126
+ }
127
+ // グローバル変数(モジュールを検索)?
128
+ for (let mod of this.modList) {
129
+ const gname = `${mod}__${name}`
130
+ if (this.funclist[gname]) {
131
+ return {
132
+ name: gname,
133
+ scope: 'global',
134
+ info: this.funclist[gname]
135
+ }
136
+ }
137
+ }
138
+ // システム変数 (funclistを普通に検索)
139
+ if (this.funclist[name]) {
140
+ return {
141
+ name,
142
+ scope: 'system',
143
+ info: this.funclist[name]
144
+ }
145
+ }
146
+ return undefined
78
147
  }
79
148
 
80
149
  /**
@@ -1,7 +1,7 @@
1
1
  // なでしこバージョン
2
2
  export default {
3
- version: '3.3.4',
3
+ version: '3.3.7',
4
4
  major: 3,
5
5
  minor: 3,
6
- patch: 4
6
+ patch: 7
7
7
  }
@@ -7,9 +7,9 @@ export default {
7
7
  type: 'const',
8
8
  value: {
9
9
  pluginName: 'plugin_system', // プラグインの名前
10
- pluginVersion: '3.2.24', // プラグインのバージョン
10
+ pluginVersion: '3.3.4', // プラグインのバージョン
11
11
  nakoRuntime: ['wnako', 'cnako', 'phpnako'], // 対象ランタイム
12
- nakoVersion: '^3.2.24' // 要求なでしこバージョン
12
+ nakoVersion: '^3.3.4' // 要求なでしこバージョン
13
13
  }
14
14
  },
15
15
  '初期化': {
@@ -22,9 +22,11 @@ export default {
22
22
  sys.__findVar = function (nameStr, def) {
23
23
  if (typeof nameStr === 'function') { return nameStr }
24
24
  if (sys.__locals[nameStr]) { return sys.__locals[nameStr] }
25
+ let modName = (typeof(sys.__modName) !== 'undefined') ? sys.__modName : 'inline'
26
+ let gname = (nameStr.indexOf('__') >= 0) ? nameStr : modName + '__' + nameStr
25
27
  for (let i = 2; i >= 0; i--) {
26
28
  const scope = sys.__varslist[i]
27
- if (scope[nameStr]) { return scope[nameStr] }
29
+ if (scope[gname]) { return scope[gname] }
28
30
  }
29
31
  return def
30
32
  }
@@ -558,10 +560,10 @@ export default {
558
560
  throw new Error('非同期モードでは「ナデシコ」は利用できません。')
559
561
  }
560
562
  sys.__varslist[0]['表示ログ'] = ''
561
- sys.__self.runEx(code, 'immediate-code.nako3', { resetEnv: false, resetLog: true })
563
+ sys.__self.runEx(code, sys.__modName, { resetEnv: false, resetLog: true })
562
564
  const out = sys.__varslist[0]['表示ログ'] + ''
563
565
  if (out) {
564
- sys.logger.send('stdout', out)
566
+ sys.logger.trace(out)
565
567
  }
566
568
  return out
567
569
  }
@@ -573,10 +575,10 @@ export default {
573
575
  if (sys.__genMode === '非同期モード') {
574
576
  throw new Error('非同期モードでは「ナデシコ続」は利用できません。')
575
577
  }
576
- sys.__self.runEx(code, 'immediate-code.nako3', { resetEnv: false, resetLog: false })
578
+ sys.__self.runEx(code, sys.__modName, { resetEnv: false, resetLog: false })
577
579
  const out = sys.__varslist[0]['表示ログ'] + ''
578
580
  if (out) {
579
- sys.logger.send('stdout', out)
581
+ sys.logger.trace(out)
580
582
  }
581
583
  return out
582
584
  }
@@ -2479,6 +2481,21 @@ export default {
2479
2481
  throw new Error(s)
2480
2482
  }
2481
2483
  },
2484
+ 'グローバル関数一覧取得': { // @グローバル変数にある関数一覧を取得 // @ぐろーばるかんすういちらんしゅとく
2485
+ type: 'func',
2486
+ josi: [],
2487
+ pure: true,
2488
+ fn: function (sys) {
2489
+ console.log(sys.__varslist[2])
2490
+ const f = []
2491
+ for (const key in sys.__varslist[1]) {
2492
+ if (sys.__v0.hasOwnProperty(key)) {
2493
+ f.push(key)
2494
+ }
2495
+ }
2496
+ return f
2497
+ }
2498
+ },
2482
2499
  'システム関数一覧取得': { // @システム関数の一覧を取得 // @しすてむかんすういちらんしゅとく
2483
2500
  type: 'func',
2484
2501
  josi: [],
@@ -2486,8 +2503,9 @@ export default {
2486
2503
  fn: function (sys) {
2487
2504
  const f = []
2488
2505
  for (const key in sys.__v0) {
2489
- const ff = sys.__v0[key]
2490
- if (typeof ff === 'function') { f.push(key) }
2506
+ if (sys.__v0.hasOwnProperty(key)) {
2507
+ f.push(key)
2508
+ }
2491
2509
  }
2492
2510
  return f
2493
2511
  }