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_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
|
}
|