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.
- package/batch/command.txt +1 -0
- package/batch/command_nakopad.txt +1 -0
- package/demo/browsers.html +1 -1
- package/demo/nako3/taberu.nako3 +5 -0
- package/doc/browsers.md +1 -1
- package/package.json +1 -1
- package/release/_hash.txt +24 -24
- package/release/_script-tags.txt +14 -14
- package/release/command.json +1 -1
- package/release/command.json.js +1 -1
- package/release/command_cnako3.json +1 -1
- package/release/command_list.json +1 -1
- package/release/editor.js +1 -1
- package/release/nako_gen_async.js +1 -1
- package/release/nako_gen_async.js.LICENSE.txt +20 -0
- package/release/plugin_caniuse.js +1 -1
- package/release/stats.json +1 -1
- package/release/version.js +1 -1
- package/release/wnako3.js +1 -1
- package/src/browsers.mjs +1 -1
- package/src/browsers.txt +0 -1
- package/src/cnako3mod.mjs +88 -64
- package/src/nako3.mjs +72 -53
- package/src/nako_gen.mjs +6 -12
- package/src/nako_global.mjs +2 -2
- package/src/nako_lex_rules.mjs +1 -1
- package/src/nako_lexer.mjs +83 -22
- package/src/nako_parser3.mjs +144 -33
- package/src/nako_parser_base.mjs +75 -6
- package/src/nako_version.mjs +2 -2
- package/src/plugin_system.mjs +27 -9
- package/test/common/nako_lexer_test.mjs +33 -0
- package/test/common/plugin_system_test.mjs +1 -1
- package/test/common/variable_scope_test.mjs +13 -0
- package/test/node/error_message_test.mjs +5 -3
- package/test/node/plugin_test.mjs +21 -3
- package/test/node/scope1.nako3 +10 -0
- package/test/node/scope2.nako3 +12 -0
- package/test/node/wnako3_editor_test.mjs +12 -0
- package/tools/nako3edit/index.nako3 +3 -0
package/src/nako_parser3.mjs
CHANGED
|
@@ -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
|
-
*
|
|
16
|
-
* @typedef {import('./nako3').
|
|
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
|
|
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:
|
|
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:
|
|
1313
|
-
value:
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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()
|
package/src/nako_parser_base.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
/**
|
|
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
|
/**
|
package/src/nako_version.mjs
CHANGED
package/src/plugin_system.mjs
CHANGED
|
@@ -7,9 +7,9 @@ export default {
|
|
|
7
7
|
type: 'const',
|
|
8
8
|
value: {
|
|
9
9
|
pluginName: 'plugin_system', // プラグインの名前
|
|
10
|
-
pluginVersion: '3.
|
|
10
|
+
pluginVersion: '3.3.4', // プラグインのバージョン
|
|
11
11
|
nakoRuntime: ['wnako', 'cnako', 'phpnako'], // 対象ランタイム
|
|
12
|
-
nakoVersion: '^3.
|
|
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[
|
|
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,
|
|
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.
|
|
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,
|
|
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.
|
|
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
|
-
|
|
2490
|
-
|
|
2506
|
+
if (sys.__v0.hasOwnProperty(key)) {
|
|
2507
|
+
f.push(key)
|
|
2508
|
+
}
|
|
2491
2509
|
}
|
|
2492
2510
|
return f
|
|
2493
2511
|
}
|