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
@@ -3,7 +3,8 @@
3
3
  import { opPriority } from './nako_parser_const.mjs'
4
4
 
5
5
  // 予約語句
6
- // (memo)「回」「間」「繰返」「反復」「抜」「続」「戻」「代入」などは replaceWord で word から変換
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
- setInput2 (tokens, isFirst) {
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.replaceWord(this.result)
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 } else if (t.type === 'func') { isFuncPointer = true } else if (t.type !== '|' && t.type !== 'comma') {
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.substr(0, t.value.length - 1)
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
- funcName = tokens[i++].value
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
- replaceWord (tokens) {
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 fo = this.funclist[t.value]
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.substr(m[0].length)
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.substr(0, 3) + '...',
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
  }