nadesiko3 3.3.3 → 3.3.6
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/browsers.template.md +3 -0
- package/batch/build_browsers.nako3 +72 -0
- package/batch/build_command.nako3 +44 -0
- package/batch/build_nako_version.nako3 +14 -0
- package/batch/calc_hash.nako3 +29 -0
- package/batch/cmd_txt2json.nako3 +72 -0
- package/batch/command.txt +1047 -0
- package/batch/command_nakopad.txt +997 -0
- package/batch/download-extlib.nako3 +43 -0
- package/batch/gen_command_nakopad.nako3 +57 -0
- package/batch/jsplugin2text.nako3 +269 -0
- package/batch/pickup_command.nako3 +84 -0
- package/batch/pickup_reserved_words.nako3 +11 -0
- package/batch/publish_version.nako3 +46 -0
- package/batch/show_agents.js +14 -0
- package/batch/turtle2js.nako3 +21 -0
- package/demo/browsers.html +1 -1
- package/demo/nako3/taberu.nako3 +5 -0
- package/doc/browsers.md +1 -1
- package/package.json +8 -6
- 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 +137 -28
- 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/node/async_test.mjs +1 -2
- package/test/node/commander_ja_test.mjs +1 -1
- package/test/node/error_message_test.mjs +8 -6
- package/test/node/node_test.mjs +2 -2
- package/test/node/{plugin_browser_ut_ajax_test.mjs → plugin_browser_ut_ajax_test.mjs.todo} +2 -2
- package/test/node/plugin_browser_ut_location_test.mjs +1 -1
- package/test/node/plugin_markup_test.mjs +3 -3
- package/test/node/plugin_math_test.mjs +2 -2
- package/test/node/plugin_node_test.mjs +3 -3
- package/test/node/plugin_test.mjs +22 -4
- package/test/node/require_nako3_test.mjs +2 -2
- package/test/node/scope1.nako3 +10 -0
- package/test/node/scope2.nako3 +12 -0
- package/test/node/side_effects_test.mjs +4 -4
- package/test/node/wnako3_editor_test.mjs +17 -5
- package/tools/nako3edit/html/edit.html +1 -1
- package/tools/nako3edit/index.nako3 +3 -0
package/src/nako_lexer.mjs
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import { opPriority } from './nako_parser_const.mjs'
|
|
4
4
|
|
|
5
5
|
// 予約語句
|
|
6
|
-
// (memo)「回」「間」「繰返」「反復」「抜」「続」「戻」「代入」などは
|
|
6
|
+
// (memo)「回」「間」「繰返」「反復」「抜」「続」「戻」「代入」などは _replaceWord で word から変換
|
|
7
|
+
/** @types {Record<string, string>} */
|
|
7
8
|
import reservedWords from './nako_reserved_words.mjs'
|
|
8
9
|
|
|
9
10
|
// 助詞の一覧
|
|
@@ -15,7 +16,7 @@ import { rules, unitRE } from './nako_lex_rules.mjs'
|
|
|
15
16
|
import { NakoLexerError, InternalLexerError } from './nako_errors.mjs'
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
|
-
* @typedef {import('./nako3').TokenWithSourceMap} TokenWithSourceMap
|
|
19
|
+
* @typedef {import('./nako3.mjs').TokenWithSourceMap} TokenWithSourceMap
|
|
19
20
|
* @typedef {{
|
|
20
21
|
* type: string;
|
|
21
22
|
* value: unknown;
|
|
@@ -40,37 +41,43 @@ import { NakoLexerError, InternalLexerError } from './nako_errors.mjs'
|
|
|
40
41
|
* value: unknown
|
|
41
42
|
* }
|
|
42
43
|
* )>} FuncList
|
|
43
|
-
|
|
44
|
+
*/
|
|
44
45
|
|
|
45
46
|
export class NakoLexer {
|
|
46
47
|
/**
|
|
47
|
-
* @param {import("./nako_logger")} logger
|
|
48
|
+
* @param {import("./nako_logger.mjs").NakoLogger} logger
|
|
48
49
|
*/
|
|
49
50
|
constructor (logger) {
|
|
51
|
+
/* @type {import("./nako_logger.mjs").NakoLogger} */
|
|
50
52
|
this.logger = logger
|
|
51
|
-
/** @type {FuncList} */
|
|
53
|
+
/** 字句解析した際,確認された関数の一覧 @type {FuncList} */
|
|
52
54
|
this.funclist = {}
|
|
55
|
+
/** 字句解析した際,取り込むモジュール一覧
|
|
56
|
+
* nako3::lex で更新される
|
|
57
|
+
* @type {Array<string>}
|
|
58
|
+
*/
|
|
59
|
+
this.modList = []
|
|
53
60
|
/** @type {TokenWithSourceMap[]} */
|
|
54
61
|
this.result = []
|
|
62
|
+
/** モジュール名 */
|
|
63
|
+
this.modName = 'inline'
|
|
55
64
|
}
|
|
56
65
|
|
|
57
66
|
setFuncList (listObj) {
|
|
58
67
|
this.funclist = listObj
|
|
59
68
|
}
|
|
60
69
|
|
|
61
|
-
setInput (code, line, filename) {
|
|
62
|
-
// 最初に全部を区切ってしまう
|
|
63
|
-
return this.tokenize(code, line, filename)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
70
|
/**
|
|
67
71
|
* @param {TokenWithSourceMap[]} tokens
|
|
72
|
+
* @param {boolean} isFirst
|
|
73
|
+
* @param {string} filename
|
|
68
74
|
*/
|
|
69
|
-
|
|
75
|
+
replaceTokens (tokens, isFirst, filename) {
|
|
70
76
|
this.result = tokens
|
|
77
|
+
this.modName = NakoLexer.filenameToModName(filename)
|
|
71
78
|
// 関数の定義があれば funclist を更新
|
|
72
79
|
NakoLexer.preDefineFunc(tokens, this.logger, this.funclist)
|
|
73
|
-
this.
|
|
80
|
+
this._replaceWord(this.result)
|
|
74
81
|
|
|
75
82
|
if (isFirst) {
|
|
76
83
|
if (this.result.length > 0) {
|
|
@@ -129,7 +136,7 @@ export class NakoLexer {
|
|
|
129
136
|
* ファイル内で定義されている関数名を列挙する。結果はfunclistに書き込む。その他のトークンの置換処理も行う。
|
|
130
137
|
* シンタックスハイライトの処理から呼び出すためにstaticメソッドにしている。
|
|
131
138
|
* @param {TokenWithSourceMap[]} tokens
|
|
132
|
-
* @param {import('./nako_logger')} logger
|
|
139
|
+
* @param {import('./nako_logger.mjs').NakoLogger} logger
|
|
133
140
|
* @param {FuncList} funclist
|
|
134
141
|
*/
|
|
135
142
|
static preDefineFunc (tokens, logger, funclist) {
|
|
@@ -144,7 +151,9 @@ export class NakoLexer {
|
|
|
144
151
|
while (tokens[i]) {
|
|
145
152
|
const t = tokens[i]
|
|
146
153
|
i++
|
|
147
|
-
if (t.type === ')') { break }
|
|
154
|
+
if (t.type === ')') { break }
|
|
155
|
+
if (t.type === 'func') { isFuncPointer = true }
|
|
156
|
+
else if (t.type !== '|' && t.type !== 'comma') {
|
|
148
157
|
if (isFuncPointer) {
|
|
149
158
|
t.funcPointer = true
|
|
150
159
|
isFuncPointer = false
|
|
@@ -186,7 +195,7 @@ export class NakoLexer {
|
|
|
186
195
|
// N回をN|回に置換
|
|
187
196
|
if (t.type === 'word' && t.josi === '' && t.value.length >= 2) {
|
|
188
197
|
if (t.value.match(/回$/)) {
|
|
189
|
-
t.value = t.value.
|
|
198
|
+
t.value = t.value.substring(0, t.value.length - 1)
|
|
190
199
|
tokens.splice(i + 1, 0, { type: '回', value: '回', line: t.line, column: t.column, file: t.file, josi: '', startOffset: t.endOffset - 1, endOffset: t.endOffset, rawJosi: '' })
|
|
191
200
|
t.endOffset--
|
|
192
201
|
i++
|
|
@@ -214,12 +223,14 @@ export class NakoLexer {
|
|
|
214
223
|
let varnames = []
|
|
215
224
|
let funcPointers = []
|
|
216
225
|
let funcName = ''
|
|
226
|
+
let funcNameToken
|
|
217
227
|
// 関数名の前に引数定義
|
|
218
228
|
if (tokens[i] && tokens[i].type === '(') { [josi, varnames, funcPointers] = readArgs() }
|
|
219
229
|
|
|
220
230
|
// 関数名を得る
|
|
221
231
|
if (!isMumei && tokens[i] && tokens[i].type === 'word') {
|
|
222
|
-
|
|
232
|
+
funcNameToken = tokens[i++]
|
|
233
|
+
funcName = funcNameToken.value
|
|
223
234
|
}
|
|
224
235
|
|
|
225
236
|
// 関数名の後で引数定義
|
|
@@ -228,9 +239,12 @@ export class NakoLexer {
|
|
|
228
239
|
// 名前のある関数定義ならば関数テーブルに関数名を登録
|
|
229
240
|
// 無名関数は登録しないように気をつける
|
|
230
241
|
if (funcName !== '') {
|
|
242
|
+
const modName = NakoLexer.filenameToModName(t.file)
|
|
243
|
+
funcName = modName + '__' + funcName
|
|
231
244
|
if (funcName in funclist) { // 関数の二重定義を警告
|
|
232
245
|
logger.warn(`関数『${funcName}』は既に定義されています。`, defToken)
|
|
233
246
|
}
|
|
247
|
+
funcNameToken.value = funcName
|
|
234
248
|
funclist[funcName] = {
|
|
235
249
|
type: 'func',
|
|
236
250
|
josi,
|
|
@@ -240,7 +254,6 @@ export class NakoLexer {
|
|
|
240
254
|
funcPointers
|
|
241
255
|
}
|
|
242
256
|
}
|
|
243
|
-
|
|
244
257
|
// 無名関数のために
|
|
245
258
|
defToken.meta = { josi, varnames, funcPointers }
|
|
246
259
|
}
|
|
@@ -273,22 +286,47 @@ export class NakoLexer {
|
|
|
273
286
|
/**
|
|
274
287
|
* @param {TokenWithSourceMap[]} tokens
|
|
275
288
|
*/
|
|
276
|
-
|
|
289
|
+
_replaceWord (tokens) {
|
|
277
290
|
let comment = []
|
|
278
291
|
let i = 0
|
|
279
292
|
const getLastType = () => {
|
|
280
293
|
if (i <= 0) { return 'eol' }
|
|
281
294
|
return tokens[i - 1].type
|
|
282
295
|
}
|
|
296
|
+
const modSelf = (tokens.length > 0) ? NakoLexer.filenameToModName(tokens[0].file) : 'inline'
|
|
283
297
|
while (i < tokens.length) {
|
|
284
298
|
const t = tokens[i]
|
|
299
|
+
// 関数を強制的に置換( word => func )
|
|
285
300
|
if (t.type === 'word' && t.value !== 'それ') {
|
|
286
301
|
// 関数を変換
|
|
287
|
-
const
|
|
302
|
+
const funcName = t.value
|
|
303
|
+
if (funcName.indexOf('__') < 0) {
|
|
304
|
+
// 自身のモジュール名を検索
|
|
305
|
+
const gname1 = `${modSelf}__${funcName}`
|
|
306
|
+
const gfo1 = this.funclist[gname1]
|
|
307
|
+
if (gfo1 && gfo1.type === 'func') {
|
|
308
|
+
t.type = 'func'
|
|
309
|
+
t.meta = gfo1
|
|
310
|
+
t.value = gname1
|
|
311
|
+
continue
|
|
312
|
+
}
|
|
313
|
+
// モジュール関数を置換
|
|
314
|
+
for (let mod of this.modList) {
|
|
315
|
+
const gname = `${mod}__${funcName}`
|
|
316
|
+
const gfo = this.funclist[gname]
|
|
317
|
+
if (gfo && gfo.type === 'func') {
|
|
318
|
+
t.type = 'func'
|
|
319
|
+
t.meta = gfo
|
|
320
|
+
t.value = gname
|
|
321
|
+
break
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (t.type === 'func') { continue }
|
|
325
|
+
}
|
|
326
|
+
const fo = this.funclist[funcName]
|
|
288
327
|
if (fo && fo.type === 'func') {
|
|
289
328
|
t.type = 'func'
|
|
290
329
|
t.meta = fo
|
|
291
|
-
continue
|
|
292
330
|
}
|
|
293
331
|
}
|
|
294
332
|
// 数字につくマイナス記号を判定
|
|
@@ -406,7 +444,7 @@ export class NakoLexer {
|
|
|
406
444
|
// 空白ならスキップ
|
|
407
445
|
if (rule.name === 'space') {
|
|
408
446
|
column += m[0].length
|
|
409
|
-
src = src.
|
|
447
|
+
src = src.substring(m[0].length)
|
|
410
448
|
continue
|
|
411
449
|
}
|
|
412
450
|
// マッチしたルールがコールバックを持つなら
|
|
@@ -562,7 +600,7 @@ export class NakoLexer {
|
|
|
562
600
|
break
|
|
563
601
|
}
|
|
564
602
|
if (!ok) {
|
|
565
|
-
throw new InternalLexerError('未知の語句: ' + src.
|
|
603
|
+
throw new InternalLexerError('未知の語句: ' + src.substring(0, 3) + '...',
|
|
566
604
|
srcLength - src.length,
|
|
567
605
|
srcLength - srcLength + 3,
|
|
568
606
|
line
|
|
@@ -571,4 +609,27 @@ export class NakoLexer {
|
|
|
571
609
|
}
|
|
572
610
|
return result
|
|
573
611
|
}
|
|
612
|
+
// トークン配列をtype文字列に変換
|
|
613
|
+
static tokensToTypeStr(tokens, sep) {
|
|
614
|
+
const a = tokens.map((v) => {
|
|
615
|
+
return v.type
|
|
616
|
+
})
|
|
617
|
+
return a.join(sep)
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* ファイル名からモジュール名へ変換
|
|
621
|
+
* @param {string} filename
|
|
622
|
+
* @returns {string}
|
|
623
|
+
*/
|
|
624
|
+
static filenameToModName(filename) {
|
|
625
|
+
if (!filename) { return 'inline' }
|
|
626
|
+
// パスがあればパスを削除
|
|
627
|
+
filename = filename.replace(/[\\:]/g, '/') // Windowsのpath記号を/に置換
|
|
628
|
+
if (filename.indexOf('/') >= 0) {
|
|
629
|
+
const a = filename.split('/')
|
|
630
|
+
filename = a[a.length - 1]
|
|
631
|
+
}
|
|
632
|
+
filename = filename.replace(/\.nako3?$/, '')
|
|
633
|
+
return filename
|
|
634
|
+
}
|
|
574
635
|
}
|
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,
|
|
@@ -1031,7 +1065,6 @@ export class NakoParser extends NakoParserBase {
|
|
|
1031
1065
|
if (sadameru === null) { return null }
|
|
1032
1066
|
const word = this.popStack(['を'])
|
|
1033
1067
|
const value = this.popStack(['へ', 'に'])
|
|
1034
|
-
console.log(word)
|
|
1035
1068
|
if (!word || (word.type !== 'word' && word.type !== 'func' && word.type !== '配列参照')) {
|
|
1036
1069
|
throw NakoSyntaxError.fromNode('『定める』文で定数が見当たりません。『(定数名)を(値)に定める』のように使います。', sadameru)
|
|
1037
1070
|
}
|
|
@@ -1174,6 +1207,9 @@ export class NakoParser extends NakoParserBase {
|
|
|
1174
1207
|
// 最近使った関数を記録
|
|
1175
1208
|
this.recentlyCalledFunc.push({name: t.value, ...f})
|
|
1176
1209
|
|
|
1210
|
+
// 呼び出す関数が非同期呼び出しが必要(asyncFn)ならマーク
|
|
1211
|
+
if (f && f.asyncFn) { this.usedFuncFn = true }
|
|
1212
|
+
|
|
1177
1213
|
// 関数の引数を取り出す処理
|
|
1178
1214
|
const args = []
|
|
1179
1215
|
let nullCount = 0
|
|
@@ -1211,9 +1247,17 @@ export class NakoParser extends NakoParserBase {
|
|
|
1211
1247
|
if (nullCount >= 2 && (valueCount > 0 || t.josi === '' || keizokuJosi.indexOf(t.josi) >= 0)) { throw NakoSyntaxError.fromNode(`関数『${t.value}』の引数が不足しています。`, t) }
|
|
1212
1248
|
|
|
1213
1249
|
const funcNode = { type: 'func', name: t.value, args: args, josi: t.josi, ...map, end: this.peekSourceMap() }
|
|
1250
|
+
// 「プラグイン名設定」か
|
|
1251
|
+
if (funcNode.name === 'プラグイン名設定') {
|
|
1252
|
+
let fname = args[0].value
|
|
1253
|
+
if (fname === 'メイン') { fname = args[0].file }
|
|
1254
|
+
this.modName = NakoLexer.filenameToModName(fname)
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1214
1257
|
// 言い切りならそこで一度切る
|
|
1215
1258
|
if (t.josi === '') { return funcNode }
|
|
1216
1259
|
|
|
1260
|
+
|
|
1217
1261
|
// **して、** の場合も一度切る
|
|
1218
1262
|
if (keizokuJosi.indexOf(t.josi) >= 0) {
|
|
1219
1263
|
funcNode.josi = 'して'
|
|
@@ -1307,10 +1351,12 @@ export class NakoParser extends NakoParserBase {
|
|
|
1307
1351
|
throw new Error('値が空です。')
|
|
1308
1352
|
}
|
|
1309
1353
|
if (this.check('comma')) { this.get() } // skip comma (ex) name1=val1, name2=val2
|
|
1354
|
+
const nameToken = this.getVarName(this.y[0])
|
|
1355
|
+
const valueToken = this.y[2]
|
|
1310
1356
|
return {
|
|
1311
1357
|
type: 'let',
|
|
1312
|
-
name:
|
|
1313
|
-
value:
|
|
1358
|
+
name: nameToken,
|
|
1359
|
+
value: valueToken,
|
|
1314
1360
|
...map,
|
|
1315
1361
|
end: this.peekSourceMap()
|
|
1316
1362
|
}
|
|
@@ -1348,7 +1394,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1348
1394
|
|
|
1349
1395
|
// ローカル変数定義
|
|
1350
1396
|
if (this.accept(['word', 'とは'])) {
|
|
1351
|
-
|
|
1397
|
+
let word = this.getVarName(this.y[0])
|
|
1352
1398
|
if (!this.checkTypes(['変数', '定数'])) {
|
|
1353
1399
|
throw NakoSyntaxError.fromNode('ローカル変数『' + word.value + '』の定義エラー', word)
|
|
1354
1400
|
}
|
|
@@ -1372,9 +1418,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
1372
1418
|
}
|
|
1373
1419
|
// ローカル変数定義(その2)
|
|
1374
1420
|
if (this.accept(['変数', 'word', 'eq', this.yCalc])) {
|
|
1421
|
+
let word = this.getVarName(this.y[1])
|
|
1375
1422
|
return {
|
|
1376
1423
|
type: 'def_local_var',
|
|
1377
|
-
name:
|
|
1424
|
+
name: word,
|
|
1378
1425
|
vartype: '変数',
|
|
1379
1426
|
value: this.y[3],
|
|
1380
1427
|
...map,
|
|
@@ -1383,9 +1430,10 @@ export class NakoParser extends NakoParserBase {
|
|
|
1383
1430
|
}
|
|
1384
1431
|
|
|
1385
1432
|
if (this.accept(['定数', 'word', 'eq', this.yCalc])) {
|
|
1433
|
+
let word = this.getVarName(this.y[1])
|
|
1386
1434
|
return {
|
|
1387
1435
|
type: 'def_local_var',
|
|
1388
|
-
name:
|
|
1436
|
+
name: word,
|
|
1389
1437
|
vartype: '定数',
|
|
1390
1438
|
value: this.y[3],
|
|
1391
1439
|
...map,
|
|
@@ -1406,6 +1454,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1406
1454
|
} else {
|
|
1407
1455
|
throw NakoSyntaxError.fromNode('複数定数の代入文でエラー。『定数[A,B,C]=[1,2,3]』の書式で記述してください。', this.y[0])
|
|
1408
1456
|
}
|
|
1457
|
+
names.value = this.getVarNameList(names.value)
|
|
1409
1458
|
return {
|
|
1410
1459
|
type: 'def_local_varlist',
|
|
1411
1460
|
names: names.value,
|
|
@@ -1428,6 +1477,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1428
1477
|
} else {
|
|
1429
1478
|
throw NakoSyntaxError.fromNode('複数変数の代入文でエラー。『変数[A,B,C]=[1,2,3]』の書式で記述してください。', this.y[0])
|
|
1430
1479
|
}
|
|
1480
|
+
names.value = this.getVarNameList(names.value)
|
|
1431
1481
|
return {
|
|
1432
1482
|
type: 'def_local_varlist',
|
|
1433
1483
|
names: names.value,
|
|
@@ -1442,9 +1492,11 @@ export class NakoParser extends NakoParserBase {
|
|
|
1442
1492
|
if (this.check2(['word', 'comma', 'word'])) {
|
|
1443
1493
|
// 2 word
|
|
1444
1494
|
if (this.accept(['word', 'comma', 'word', 'eq', this.yCalc])) {
|
|
1495
|
+
let names = [this.y[0], this.y[2]]
|
|
1496
|
+
names = this.getVarNameList(names)
|
|
1445
1497
|
return {
|
|
1446
1498
|
type: 'def_local_varlist',
|
|
1447
|
-
names
|
|
1499
|
+
names,
|
|
1448
1500
|
vartype: '変数',
|
|
1449
1501
|
value: this.y[4],
|
|
1450
1502
|
...map,
|
|
@@ -1453,9 +1505,11 @@ export class NakoParser extends NakoParserBase {
|
|
|
1453
1505
|
}
|
|
1454
1506
|
// 3 word
|
|
1455
1507
|
if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'eq', this.yCalc])) {
|
|
1508
|
+
let names = [this.y[0], this.y[2], this.y[4]]
|
|
1509
|
+
names = this.getVarNameList(names)
|
|
1456
1510
|
return {
|
|
1457
1511
|
type: 'def_local_varlist',
|
|
1458
|
-
names
|
|
1512
|
+
names,
|
|
1459
1513
|
vartype: '変数',
|
|
1460
1514
|
value: this.y[6],
|
|
1461
1515
|
...map,
|
|
@@ -1464,9 +1518,11 @@ export class NakoParser extends NakoParserBase {
|
|
|
1464
1518
|
}
|
|
1465
1519
|
// 4 word
|
|
1466
1520
|
if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'eq', this.yCalc])) {
|
|
1521
|
+
let names = [this.y[0], this.y[2], this.y[4], this.y[6]]
|
|
1522
|
+
names = this.getVarNameList(names)
|
|
1467
1523
|
return {
|
|
1468
1524
|
type: 'def_local_varlist',
|
|
1469
|
-
names
|
|
1525
|
+
names,
|
|
1470
1526
|
vartype: '変数',
|
|
1471
1527
|
value: this.y[8],
|
|
1472
1528
|
...map,
|
|
@@ -1475,9 +1531,11 @@ export class NakoParser extends NakoParserBase {
|
|
|
1475
1531
|
}
|
|
1476
1532
|
// 5 word
|
|
1477
1533
|
if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'eq', this.yCalc])) {
|
|
1534
|
+
let names = [this.y[0], this.y[2], this.y[4], this.y[6], this.y[8]]
|
|
1535
|
+
names = this.getVarNameList(names)
|
|
1478
1536
|
return {
|
|
1479
1537
|
type: 'def_local_varlist',
|
|
1480
|
-
names
|
|
1538
|
+
names,
|
|
1481
1539
|
vartype: '変数',
|
|
1482
1540
|
value: this.y[10],
|
|
1483
1541
|
...map,
|
|
@@ -1528,7 +1586,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1528
1586
|
if (this.accept(['word', '@', this.yValue, 'eq', this.yCalc])) {
|
|
1529
1587
|
return {
|
|
1530
1588
|
type: 'let_array',
|
|
1531
|
-
name: this.y[0],
|
|
1589
|
+
name: this.getVarName(this.y[0]),
|
|
1532
1590
|
index: [this.checkArrayIndex(this.y[2])],
|
|
1533
1591
|
value: this.y[4],
|
|
1534
1592
|
...map,
|
|
@@ -1540,7 +1598,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1540
1598
|
if (this.accept(['word', '@', this.yValue, '@', this.yValue, 'eq', this.yCalc])) {
|
|
1541
1599
|
return {
|
|
1542
1600
|
type: 'let_array',
|
|
1543
|
-
name: this.y[0],
|
|
1601
|
+
name: this.getVarName(this.y[0]),
|
|
1544
1602
|
index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4])]),
|
|
1545
1603
|
value: this.y[6],
|
|
1546
1604
|
...map,
|
|
@@ -1552,7 +1610,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1552
1610
|
if (this.accept(['word', '@', this.yValue, '@', this.yValue, '@', this.yValue, 'eq', this.yCalc])) {
|
|
1553
1611
|
return {
|
|
1554
1612
|
type: 'let_array',
|
|
1555
|
-
name: this.y[0],
|
|
1613
|
+
name: this.getVarName(this.y[0]),
|
|
1556
1614
|
index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4]), this.checkArrayIndex(this.y[6])]),
|
|
1557
1615
|
value: this.y[8],
|
|
1558
1616
|
...map,
|
|
@@ -1564,7 +1622,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1564
1622
|
if (this.accept(['word', '@', this.yValue, 'comma', this.yValue, 'eq', this.yCalc])) {
|
|
1565
1623
|
return {
|
|
1566
1624
|
type: 'let_array',
|
|
1567
|
-
name: this.y[0],
|
|
1625
|
+
name: this.getVarName(this.y[0]),
|
|
1568
1626
|
index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4])]),
|
|
1569
1627
|
value: this.y[6],
|
|
1570
1628
|
...map,
|
|
@@ -1576,7 +1634,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1576
1634
|
if (this.accept(['word', '@', this.yValue, 'comma', this.yValue, 'comma', this.yValue, 'eq', this.yCalc])) {
|
|
1577
1635
|
return {
|
|
1578
1636
|
type: 'let_array',
|
|
1579
|
-
name: this.y[0],
|
|
1637
|
+
name: this.getVarName(this.y[0]),
|
|
1580
1638
|
index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4]), this.checkArrayIndex(this.y[6])]),
|
|
1581
1639
|
value: this.y[8],
|
|
1582
1640
|
...map,
|
|
@@ -1592,7 +1650,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1592
1650
|
if (this.accept(['word', '[', this.yCalc, ']', 'eq', this.yCalc])) {
|
|
1593
1651
|
return {
|
|
1594
1652
|
type: 'let_array',
|
|
1595
|
-
name: this.y[0],
|
|
1653
|
+
name: this.getVarName(this.y[0]),
|
|
1596
1654
|
index: [this.checkArrayIndex(this.y[2])],
|
|
1597
1655
|
value: this.y[5],
|
|
1598
1656
|
...map,
|
|
@@ -1604,7 +1662,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1604
1662
|
if (this.accept(['word', '[', this.yCalc, ']', '[', this.yCalc, ']', 'eq', this.yCalc])) {
|
|
1605
1663
|
return {
|
|
1606
1664
|
type: 'let_array',
|
|
1607
|
-
name: this.y[0],
|
|
1665
|
+
name: this.getVarName(this.y[0]),
|
|
1608
1666
|
index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[5])]),
|
|
1609
1667
|
value: this.y[8],
|
|
1610
1668
|
tag: '2',
|
|
@@ -1615,7 +1673,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1615
1673
|
if (this.accept(['word', '[', this.yCalc, 'comma', this.yCalc, ']', 'eq', this.yCalc])) {
|
|
1616
1674
|
return {
|
|
1617
1675
|
type: 'let_array',
|
|
1618
|
-
name: this.y[0],
|
|
1676
|
+
name: this.getVarName(this.y[0]),
|
|
1619
1677
|
index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4])]),
|
|
1620
1678
|
value: this.y[7],
|
|
1621
1679
|
tag: '2',
|
|
@@ -1628,7 +1686,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1628
1686
|
if (this.accept(['word', '[', this.yCalc, ']', '[', this.yCalc, ']', '[', this.yCalc, ']', 'eq', this.yCalc])) {
|
|
1629
1687
|
return {
|
|
1630
1688
|
type: 'let_array',
|
|
1631
|
-
name: this.y[0],
|
|
1689
|
+
name: this.getVarName(this.y[0]),
|
|
1632
1690
|
index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[5]), this.checkArrayIndex(this.y[8])]),
|
|
1633
1691
|
value: this.y[11],
|
|
1634
1692
|
...map,
|
|
@@ -1638,7 +1696,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1638
1696
|
if (this.accept(['word', '[', this.yCalc, 'comma', this.yCalc, 'comma', this.yCalc, ']', 'eq', this.yCalc])) {
|
|
1639
1697
|
return {
|
|
1640
1698
|
type: 'let_array',
|
|
1641
|
-
name: this.y[0],
|
|
1699
|
+
name: this.getVarName(this.y[0]),
|
|
1642
1700
|
index: this.checkArrayReverse([this.checkArrayIndex(this.y[2]), this.checkArrayIndex(this.y[4]), this.checkArrayIndex(this.y[6])]),
|
|
1643
1701
|
value: this.y[9],
|
|
1644
1702
|
...map,
|
|
@@ -1746,7 +1804,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1746
1804
|
// 一語関数
|
|
1747
1805
|
const splitType = operatorList.concat(['eol', ')', ']', 'ならば', '回', '間', '反復', '条件分岐'])
|
|
1748
1806
|
if (this.check2(['func', splitType])) {
|
|
1749
|
-
const f = this.get()
|
|
1807
|
+
const f = this.getVarNameRef(this.get())
|
|
1750
1808
|
return {
|
|
1751
1809
|
type: 'func',
|
|
1752
1810
|
name: f.value,
|
|
@@ -1762,7 +1820,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1762
1820
|
if (this.accept([['func', 'word'], '(', this.yGetArgParen, ')'])) {
|
|
1763
1821
|
return {
|
|
1764
1822
|
type: 'func',
|
|
1765
|
-
name: this.y[0].value,
|
|
1823
|
+
name: this.getVarNameRef(this.y[0]).value,
|
|
1766
1824
|
args: this.y[2],
|
|
1767
1825
|
josi: this.y[3].josi,
|
|
1768
1826
|
...map,
|
|
@@ -1843,7 +1901,7 @@ export class NakoParser extends NakoParserBase {
|
|
|
1843
1901
|
yValueWord () {
|
|
1844
1902
|
const map = this.peekSourceMap()
|
|
1845
1903
|
if (this.check('word')) {
|
|
1846
|
-
const word = this.get()
|
|
1904
|
+
const word = this.getVarNameRef(this.get())
|
|
1847
1905
|
if (this.skipRefArray) { return word }
|
|
1848
1906
|
|
|
1849
1907
|
// word[n] || word@n
|
|
@@ -1867,6 +1925,57 @@ export class NakoParser extends NakoParserBase {
|
|
|
1867
1925
|
return null
|
|
1868
1926
|
}
|
|
1869
1927
|
|
|
1928
|
+
/** 変数名を検索して解決する
|
|
1929
|
+
* @param {TokenWithSourceMap} word
|
|
1930
|
+
* @return {TokenWithSourceMap}
|
|
1931
|
+
*/
|
|
1932
|
+
getVarName(word) {
|
|
1933
|
+
// check word name
|
|
1934
|
+
const f = this.findVar(word.value)
|
|
1935
|
+
if (!f) { // 変数が見つからない
|
|
1936
|
+
if (this.funcLevel === 0 && word.value.indexOf('__') < 0) {
|
|
1937
|
+
const gname = this.modName + '__' + word.value
|
|
1938
|
+
word.value = gname
|
|
1939
|
+
this.funclist[gname] = {type: 'var', value: ''}
|
|
1940
|
+
} else {
|
|
1941
|
+
this.localvars[word.value] = {type: 'var', value: ''}
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
if (f && f.scope === 'global') {
|
|
1945
|
+
word.value = f.name
|
|
1946
|
+
}
|
|
1947
|
+
return word
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
/** 変数名を検索して解決する
|
|
1951
|
+
* @param {TokenWithSourceMap} word
|
|
1952
|
+
* @return {TokenWithSourceMap}
|
|
1953
|
+
*/
|
|
1954
|
+
getVarNameRef(word) {
|
|
1955
|
+
// check word name
|
|
1956
|
+
const f = this.findVar(word.value)
|
|
1957
|
+
if (!f) { // 変数が見つからない
|
|
1958
|
+
if (this.funcLevel === 0 && word.value.indexOf('__') < 0) {
|
|
1959
|
+
word.value = this.modName + '__' + word.value
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
if (f && f.scope === 'global') {
|
|
1963
|
+
word.value = f.name
|
|
1964
|
+
}
|
|
1965
|
+
return word
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
/** 複数の変数名を検索して解決する
|
|
1969
|
+
* @param {TokenWithSourceMap[]} words
|
|
1970
|
+
* @return {TokenWithSourceMap[]}
|
|
1971
|
+
*/
|
|
1972
|
+
getVarNameList(words) {
|
|
1973
|
+
for (let i = 0; i < words.length; i++) {
|
|
1974
|
+
words[i] = this.getVarName(words[i])
|
|
1975
|
+
}
|
|
1976
|
+
return words
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1870
1979
|
yJSONObjectValue () {
|
|
1871
1980
|
const a = []
|
|
1872
1981
|
const firstToken = this.peek()
|