nadesiko3 3.2.48 → 3.2.52

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.
@@ -538,6 +538,10 @@
538
538
  !*** ./node_modules/core-js/modules/es.function.name.js ***!
539
539
  \**********************************************************/
540
540
 
541
+ /*!**********************************************************!*\
542
+ !*** ./node_modules/core-js/modules/es.number.is-nan.js ***!
543
+ \**********************************************************/
544
+
541
545
  /*!**********************************************************!*\
542
546
  !*** ./node_modules/core-js/modules/es.object.assign.js ***!
543
547
  \**********************************************************/
package/src/nako3.js CHANGED
@@ -87,10 +87,10 @@ function NakoGen (mode) {
87
87
  * checkInit?: boolean
88
88
  * }} Ast
89
89
  *
90
- * @typedef {(
91
- * | { type: 'func', josi: string[][], pure?: boolean, fn?: Function, return_none: boolean }
90
+ * @typedef {
91
+ * | { type: 'func', josi: string[][], pure?: boolean, fn?: Function, return_none: boolean, asyncFn: boolean }
92
92
  * | { type: 'var' | 'const', value: any}
93
- * )} NakoFunction
93
+ * } NakoFunction
94
94
  */
95
95
 
96
96
  class NakoCompiler {
@@ -123,7 +123,7 @@ class NakoCompiler {
123
123
  this.pluginfiles = {} // 取り込んだファイル一覧
124
124
  this.isSetter = false // 代入的関数呼び出しを管理(#290)
125
125
  this.commandlist = new Set() // プラグインで定義された定数・変数・関数の名前
126
- /** @type {Record<string, { josi: string[][], fn: string, type: 'func' }>} */
126
+ /** @type {Record<string, { josi: string[][], fn: string, type: 'func', asyncFn: boolean }>} */
127
127
  this.nako_func = {} // __v1に配置するJavaScriptのコードで定義された関数
128
128
 
129
129
  this.logger = new NakoLogger()
@@ -758,7 +758,7 @@ class NakoCompiler {
758
758
  throw new Error('プラグインの追加でエラー。')
759
759
  }
760
760
  // コマンドを登録するか?
761
- if (key === '初期化' || key.substr(0, 1) === '!') { // 登録しない関数名
761
+ if (key === '初期化' || key.substring(0, 1) === '!') { // 登録しない関数名
762
762
  continue
763
763
  }
764
764
  this.commandlist.add(key)
@@ -811,10 +811,11 @@ class NakoCompiler {
811
811
  * @param {string} key 関数名
812
812
  * @param {string[][]} josi 助詞
813
813
  * @param {Function} fn 関数
814
- * @param {boolean} returnNone 値を返す関数の場合はfalseを設定する。
814
+ * @param {boolean} returnNone 値を返す関数の場合はfalseを指定
815
+ * @param {boolean} asyncFn Promiseを返す関数かを指定
815
816
  */
816
- addFunc (key, josi, fn, returnNone = true) {
817
- this.funclist[key] = { josi, fn, type: 'func', return_none: returnNone }
817
+ addFunc (key, josi, fn, returnNone = true, asyncFn = false) {
818
+ this.funclist[key] = { josi, fn, type: 'func', return_none: returnNone, asyncFn }
818
819
  this.pluginFunclist[key] = cloneAsJSON(this.funclist[key])
819
820
  this.__varslist[0][key] = fn
820
821
  }
@@ -27,7 +27,7 @@ function isIndentSyntaxEnabled(src) {
27
27
  const keywords = DNCL_KEYWORDS
28
28
  const lines = src.split('\n', 30)
29
29
  for (const line of lines) {
30
- const line2 = line.replace('!', '!')
30
+ const line2 = line.replace(/(!|💡)/, '!')
31
31
  if (keywords.indexOf(line2) >= 0) {
32
32
  return true
33
33
  }
package/src/nako_gen.js CHANGED
@@ -8,6 +8,17 @@
8
8
 
9
9
  const { NakoSyntaxError, NakoError, NakoRuntimeError } = require('./nako_errors')
10
10
  const nakoVersion = require('./nako_version')
11
+ const isIE11 = () => {
12
+ if (typeof(window) == 'object' && window.navigator && window.navigator.userAgent) {
13
+ return (window.navigator.userAgent.indexOf('MSIE') >= 0)
14
+ }
15
+ return false
16
+ }
17
+
18
+ // なでしこで定義した関数の開始コードと終了コード
19
+ const topOfFunction = '(function(){\n'
20
+ const endOfFunction = '})'
21
+ const topOfFunctionAsync = '(async function(){\n'
11
22
 
12
23
  /**
13
24
  * @typedef {import("./nako3").Ast} Ast
@@ -24,13 +35,18 @@ class NakoGen {
24
35
  static generate (com, ast, isTest) {
25
36
  const gen = new NakoGen(com)
26
37
 
27
- // ユーザー定義関数をシステムに登録する
38
+ // ※ [関数定義に関するコード生成のヒント]
39
+ // ※ 関数の名前だけを(1)で登録して、(2)で実際に関数のコードを生成する。
40
+ // ※ ただし(2)では生成するだけなので、(3)でプログラム冒頭に関数定義のコードを記述する。
41
+ // この順番を変えることはできない (グローバル変数が認識できなくなったり、関数定義のタイミングがずれる)
42
+
43
+ // (1) ユーザー定義関数をシステムに登録する
28
44
  gen.registerFunction(ast)
29
45
 
30
- // JSコードを生成する
46
+ // (2) JSコードを生成する
31
47
  let js = gen.convGen(ast, !!isTest)
32
-
33
- // JSコードを実行するための事前ヘッダ部分の生成
48
+
49
+ // (3) JSコードを実行するための事前ヘッダ部分の生成
34
50
  js = gen.getDefFuncCode(isTest) + js
35
51
 
36
52
  // テストの実行
@@ -39,11 +55,7 @@ class NakoGen {
39
55
  }
40
56
  // async method
41
57
  if (gen.numAsyncFn > 0) {
42
- let canAsync = true
43
- if (typeof(window) == 'object' && window.navigator && window.navigator.userAgent) {
44
- const ua = window.navigator.userAgent
45
- canAsync = (ua.indexOf('MSIE') === -1)
46
- }
58
+ let canAsync = !isIE11()
47
59
  if (canAsync) {
48
60
  js = `
49
61
  // <nadesiko3::gen::async>
@@ -130,6 +142,12 @@ try {
130
142
  * @type {number}
131
143
  */
132
144
  this.numAsyncFn = 0
145
+ /**
146
+ * 関数定義の際、関数の中でasyncFn=trueの関数を呼び出したかどうかを調べる
147
+ * @type {boolean}
148
+ * @see convDefFuncCommon
149
+ */
150
+ this.usedAsyncFn = false
133
151
 
134
152
  /**
135
153
  * 変換中の処理が、ループの中かどうかを判定する
@@ -181,10 +199,20 @@ try {
181
199
  systemFunctionBody: 0 // システム関数(呼び出しコードを除く)
182
200
  }
183
201
 
202
+ /**
203
+ * 未定義の変数の警告を行う
204
+ * @type { boolean }
205
+ */
206
+ this.warnUndefinedVar = true
207
+
184
208
  // 暫定変数
209
+ /** @type { number } */
185
210
  this.warnUndefinedReturnUserFunc = 1
186
- this.warnUndefinedCallingUserFuncArgs = 1
187
- this.warnUndefinedCallingSystemFuncArgs = 1
211
+ /** @type { number } */
212
+ this.warnUndefinedCallingUserFunc = 1
213
+ /** @type { number } */
214
+ this.warnUndefinedCallingSystemFunc = 1
215
+ /** @type { number } */
188
216
  this.warnUndefinedCalledUserFuncArgs = 1
189
217
  }
190
218
 
@@ -297,8 +325,9 @@ try {
297
325
  let nakoFuncCode = ''
298
326
  for (const key in this.nako_func) {
299
327
  const f = this.nako_func[key].fn
328
+ const isAsync = this.nako_func[key].asyncFn ? 'true' : 'false'
300
329
  nakoFuncCode += '' +
301
- `//[DEF_FUNC name='${key}']\n` +
330
+ `//[DEF_FUNC name='${key}' asyncFn=${isAsync}]\n` +
302
331
  `__v1["${key}"]=${f};\n;` +
303
332
  `//[/DEF_FUNC name='${key}']\n`
304
333
  }
@@ -396,6 +425,11 @@ try {
396
425
  registerFunction (ast) {
397
426
  if (ast.type !== 'block') { throw NakoSyntaxError.fromNode('構文解析に失敗しています。構文は必ずblockが先頭になります', ast) }
398
427
 
428
+ /** 関数一覧
429
+ * @type {Array<{name: string, node: Object}>}
430
+ */
431
+ const funcList = []
432
+ // なでしこ関数を定義して this.nako_func[name] に定義する
399
433
  const registFunc = (node) => {
400
434
  for (let i = 0; i < node.block.length; i++) {
401
435
  const t = node.block[i]
@@ -403,20 +437,24 @@ try {
403
437
  const name = t.name.value
404
438
  this.used_func.add(name)
405
439
  this.__self.__varslist[1][name] = function () { } // 事前に適当な値を設定
440
+ this.varslistSet[1].names.add(name) // global
406
441
  this.nako_func[name] = {
407
442
  josi: t.name.meta.josi,
408
443
  fn: '',
409
- type: 'func'
444
+ type: 'func',
445
+ asyncFn: false
410
446
  }
411
- } else
412
- if (t.type === 'speed_mode') {
447
+ funcList.push({name: name, node: t})
448
+ }
449
+ // 実行速度優先 などのオプションが付いている場合の処理
450
+ else if (t.type === 'speed_mode') {
413
451
  if (t.block.type === 'block') {
414
452
  registFunc(t.block)
415
453
  } else {
416
454
  registFunc(t)
417
455
  }
418
- } else
419
- if (t.type === 'performance_monitor') {
456
+ }
457
+ else if (t.type === 'performance_monitor') {
420
458
  if (t.block.type === 'block') {
421
459
  registFunc(t.block)
422
460
  } else {
@@ -425,6 +463,7 @@ try {
425
463
  }
426
464
  }
427
465
  }
466
+ // 関数の登録
428
467
  registFunc(ast)
429
468
 
430
469
  // __self.__varslistの変更を反映
@@ -435,6 +474,15 @@ try {
435
474
  this.varsSet = { isFunction: false, names: initialNames, readonly: new Set() }
436
475
  this.varslistSet = this.__self.__varslist.map((v) => ({ isFunction: false, names: new Set(Object.keys(v)), readonly: new Set() }))
437
476
  this.varslistSet[2] = this.varsSet
477
+
478
+ // 非同期関数(asyncFn)があるかどうかテストする
479
+ // 後ほど改めて再度同じ関数を呼ぶため、警告などは抑止する
480
+ const tmpWarn = this.warnUndefinedVar
481
+ this.warnUndefinedVar = false // 未定義の変数の警告を抑止 #1192
482
+ for (let ff of funcList) {
483
+ this.convDefFuncCommon(ff.node, ff.name)
484
+ }
485
+ this.warnUndefinedVar = tmpWarn
438
486
  }
439
487
 
440
488
  /**
@@ -524,7 +572,7 @@ try {
524
572
  case 'func':
525
573
  case 'func_pointer':
526
574
  case 'calc_func':
527
- code += this.convFunc(node, isExpression)
575
+ code += this.convCallFunc(node, isExpression)
528
576
  break
529
577
  case 'if':
530
578
  code += this.convIf(node)
@@ -635,7 +683,9 @@ try {
635
683
  if (name === '引数' || name === 'それ' || name === '対象' || name === '対象キー') {
636
684
  // デフォルト定義されている変数名
637
685
  } else {
638
- this.__self.logger.warn(`変数『${name}』は定義されていません。`, position)
686
+ if (this.warnUndefinedVar) {
687
+ this.__self.logger.warn(`変数『${name}』は定義されていません。`, position)
688
+ }
639
689
  }
640
690
  this.varsSet.names.add(name)
641
691
  return this.varname(name)
@@ -734,8 +784,6 @@ try {
734
784
  'try {\n'
735
785
  performanceMonitorInjectAtEnd = '} finally { performanceMonitorEnd(); }\n'
736
786
  }
737
- const topOfFunction = '(function(){\n'
738
- const endOfFunction = '})'
739
787
  let variableDeclarations = ''
740
788
  let popStack = ''
741
789
  const initialNames = new Set()
@@ -756,7 +804,7 @@ try {
756
804
  const meta = (!name) ? node.meta : node.name.meta
757
805
  for (let i = 0; i < meta.varnames.length; i++) {
758
806
  const word = meta.varnames[i]
759
- if (this.warnUndefinedCalledUserFunc === 0) {
807
+ if (this.warnUndefinedCalledUserFuncArgs === 0) {
760
808
  code += ` ${this.varname(word)} = arguments[${i}];\n`
761
809
  } else
762
810
  if (name) {
@@ -770,13 +818,19 @@ try {
770
818
  if (name) {
771
819
  this.used_func.add(name)
772
820
  this.varslistSet[1].names.add(name)
773
- this.nako_func[name] = {
774
- josi: node.name.meta.josi,
775
- fn: '',
776
- type: 'func'
821
+ if (this.nako_func[name] === undefined) {
822
+ // 既に generate で作成済みのはず(念のため)
823
+ this.nako_func[name] = {
824
+ josi: node.name.meta.josi,
825
+ fn: '',
826
+ type: 'func',
827
+ asyncFn: false
828
+ }
777
829
  }
778
830
  }
779
831
  // ブロックを解析
832
+ const oldUsedAsyncFn = this.usedAsyncFn
833
+ this.usedAsyncFn = false
780
834
  const block = this._convGen(node.block, false)
781
835
  code += block.split('\n').map((line) => ' ' + line).join('\n') + '\n'
782
836
  // 関数の最後に、変数「それ」をreturnするようにする
@@ -785,6 +839,10 @@ try {
785
839
  }
786
840
  // パフォーマンスモニタ:ユーザ関数のinject
787
841
  code += performanceMonitorInjectAtEnd
842
+ // ブロックでasyncFnを使ったか
843
+ if (name && this.usedAsyncFn) {
844
+ this.nako_func[name].asyncFn = true
845
+ }
788
846
  // 関数の末尾に、ローカル変数をPOP
789
847
 
790
848
  // 関数内で定義されたローカル変数の宣言
@@ -808,15 +866,23 @@ try {
808
866
  variableDeclarations += ` ${this.varname('それ')} = '';`
809
867
  }
810
868
  }
811
- code = topOfFunction + performanceMonitorInjectAtStart + variableDeclarations + code + popStack
869
+ // usedAsyncFnの値に応じて関数定義の方法を変更
870
+ const tof = (this.usedAsyncFn) ? topOfFunctionAsync : topOfFunction
871
+ // 関数コード全体を構築
872
+ code = tof + performanceMonitorInjectAtStart + variableDeclarations + code + popStack
812
873
  code += endOfFunction
813
874
 
814
- if (name) { this.nako_func[name].fn = code }
875
+ // 名前があれば、関数を登録する
876
+ if (name) {
877
+ this.nako_func[name].fn = code
878
+ this.nako_func[name].asyncFn = this.usedAsyncFn
879
+ meta.asyncFn = this.usedAsyncFn
880
+ }
881
+ this.usedAsyncFn = oldUsedAsyncFn // 以前の値を戻す
815
882
 
816
883
  this.varslistSet.pop()
817
884
  this.varsSet = this.varslistSet[this.varslistSet.length - 1]
818
- if (name) { this.__self.__varslist[1][name] = code }
819
-
885
+ if (name) {this.__self.__varslist[1][name] = code }
820
886
  return code
821
887
  }
822
888
 
@@ -842,10 +908,12 @@ try {
842
908
  }
843
909
 
844
910
  convDefFunc (node) {
911
+ // ※ [関数定義のメモ]
912
+ // ※ 関数の定義はプログラムの冒頭に移される。
913
+ // ※ そのため、生成されたコードはここでは返さない
914
+ // ※ registerFunction を参照
845
915
  const name = NakoGen.getFuncName(node.name.value)
846
916
  this.convDefFuncCommon(node, name)
847
- // ★この時点では関数のコードを生成しない★
848
- // プログラム冒頭でコード生成時に関数定義を行う
849
917
  return ''
850
918
  }
851
919
 
@@ -1192,12 +1260,14 @@ try {
1192
1260
  * @param {boolean} isExpression
1193
1261
  * @returns string コード
1194
1262
  */
1195
- convFunc (node, isExpression) {
1263
+ convCallFunc (node, isExpression) {
1196
1264
  const funcName = NakoGen.getFuncName(node.name)
1197
1265
  const res = this.findVar(funcName)
1198
1266
  if (res === null) {
1199
1267
  throw NakoSyntaxError.fromNode(`関数『${funcName}』が見当たりません。有効プラグイン=[` + this.getPluginList().join(', ') + ']', node)
1200
1268
  }
1269
+ // どの関数を呼び出すのか関数を特定する
1270
+ /** @type {import('./nako3').NakoFunction} */
1201
1271
  let func
1202
1272
  if (res.i === 0) { // plugin function
1203
1273
  func = this.__self.funclist[funcName]
@@ -1213,9 +1283,6 @@ try {
1213
1283
  if (node.type === 'func_pointer') {
1214
1284
  return res.js
1215
1285
  }
1216
- // なでしこで定義した関数?
1217
- // const isUserFunc = (typeof(func.fn) === 'string')
1218
- // console.log('@@@', funcName, typeof(func.fn))
1219
1286
 
1220
1287
  // 関数の参照渡しでない場合
1221
1288
  // 関数定義より助詞を一つずつ調べる
@@ -1280,6 +1347,7 @@ try {
1280
1347
  }
1281
1348
 
1282
1349
  // 関数呼び出しコードの構築
1350
+ /** @type {string} */
1283
1351
  let argsCode
1284
1352
  if ((this.warnUndefinedCallingUserFunc === 0 && res.i !== 0) || (this.warnUndefinedCallingSystemFunc === 0 && res.i === 0)) {
1285
1353
  argsCode = args.join(',')
@@ -1304,6 +1372,7 @@ try {
1304
1372
  funcDef = `async ${funcDef}`
1305
1373
  funcCall = `await ${funcCall}`
1306
1374
  this.numAsyncFn++
1375
+ this.usedAsyncFn = true
1307
1376
  }
1308
1377
  if (res.i === 0 && this.performanceMonitor.systemFunctionBody !== 0) {
1309
1378
  let key = funcName
@@ -27,7 +27,8 @@ function isIndentSyntaxEnabled (code) {
27
27
  const keywords = ['!インデント構文', '!ここまでだるい']
28
28
  const lines = code.split('\n', 30)
29
29
  for (const line of lines) {
30
- const s9 = line.substr(0, 8).replace('!', '!')
30
+ const sline = line.replace(/^(!|💡)/, '!')
31
+ const s9 = sline.substring(0, 8)
31
32
  if (keywords.indexOf(s9) >= 0) {
32
33
  return true
33
34
  }
@@ -54,7 +54,7 @@ module.exports = {
54
54
  { name: 'noteq', pattern: /^(≠|<>|!=)/ },
55
55
  { name: '←', pattern: /^(←|<--)/ }, // 関数呼び出し演算子 #891 #899
56
56
  { name: 'eq', pattern: /^(=|🟰)/ },
57
- { name: 'line_comment', pattern: /^!(インデント構文|ここまでだるい)[^\n]*/ },
57
+ { name: 'line_comment', pattern: /^(!|💡)(インデント構文|ここまでだるい)[^\n]*/ }, // #1184
58
58
  { name: 'not', pattern: /^(!|💡)/ }, // #1184
59
59
  { name: 'gt', pattern: /^>/ },
60
60
  { name: 'lt', pattern: /^</ },
package/src/nako_lexer.js CHANGED
@@ -236,6 +236,7 @@ class NakoLexer {
236
236
  type: 'func',
237
237
  josi,
238
238
  fn: null,
239
+ asyncFn: false,
239
240
  varnames,
240
241
  funcPointers
241
242
  }
@@ -498,7 +499,7 @@ class NakoLexer {
498
499
  columnCurrent = column
499
500
  lineCurrent = line
500
501
  column += m[0].length
501
- src = src.substr(m[0].length)
502
+ src = src.substring(m[0].length)
502
503
  if ((rule.name === 'eol' && value === '\n') || rule.name === '_eol') {
503
504
  value = line++
504
505
  column = 1
@@ -509,7 +510,7 @@ class NakoLexer {
509
510
  // 単位があれば読み飛ばす
510
511
  const um = lexRules.unitRE.exec(src)
511
512
  if (um) {
512
- src = src.substr(um[0].length)
513
+ src = src.substring(um[0].length)
513
514
  column += m[0].length
514
515
  }
515
516
  }
@@ -520,10 +521,10 @@ class NakoLexer {
520
521
  if (j) {
521
522
  josi = j[0].replace(/^\s+/, '')
522
523
  column += j[0].length
523
- src = src.substr(j[0].length)
524
+ src = src.substring(j[0].length)
524
525
  // 助詞の直後にあるカンマを無視 #877
525
526
  if (src.charAt(0) === ',') {
526
- src = src.substr(1)
527
+ src = src.substring(1)
527
528
  }
528
529
  // 「**である」なら削除 #939 #974
529
530
  if (removeJosiMap[josi]) { josi = '' }
@@ -1,8 +1,8 @@
1
1
  // なでしこバージョン
2
2
  const nakoVersion = {
3
- version: '3.2.48',
3
+ version: '3.2.52',
4
4
  major: 3,
5
5
  minor: 2,
6
- patch: 48
6
+ patch: 52
7
7
  }
8
8
  module.exports = nakoVersion
@@ -553,18 +553,6 @@ const PluginNode = {
553
553
  },
554
554
  return_none: true
555
555
  },
556
- '秒待': { // @NodeでN秒待つ // @びょうまつ
557
- type: 'func',
558
- josi: [['']],
559
- pure: true,
560
- fn: function (sec, sys) {
561
- const msleep = (n) => {
562
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, n) // eslint-disable-line no-undef
563
- }
564
- msleep(sec * 1000)
565
- },
566
- return_none: true
567
- },
568
556
  'OS取得': { // @OSプラットフォームを返す(darwin/win32/linux) // @OSしゅとく
569
557
  type: 'func',
570
558
  josi: [],
@@ -129,6 +129,19 @@ describe('basic', () => {
129
129
  '2'
130
130
  )
131
131
  })
132
+ it('💡のインデント構文 #1184', () => {
133
+ cmp(
134
+ '💡インデント構文\n' +
135
+ '3で条件分岐\n' +
136
+ ' 2ならば\n' +
137
+ ' 2を表示\n' +
138
+ ' 3ならば\n' +
139
+ ' 3を表示\n' +
140
+ ' 違えば\n' +
141
+ ' 5を表示\n',
142
+ '3'
143
+ )
144
+ })
132
145
  it('独立した助詞『ならば』の位置の取得', () => {
133
146
  const out = nako.lex('もし存在するならば\nここまで', '')
134
147
  const sonzai = out.tokens.find((t) => t.value === '存在')
@@ -87,5 +87,9 @@ describe('dncl (#1140)', () => {
87
87
  cmpNako('!DNCLモード\n7/2を表示する', '3.5')
88
88
  cmpNako('!DNCLモード\n7÷2を表示する', '3')
89
89
  })
90
+ it('「!」を💡で書けるようにする #1184', () =>{
91
+ cmpNako('💡DNCLモード\n7/2を表示する', '3.5')
92
+ cmpNako('💡DNCLモード\n7÷2を表示する', '3')
93
+ })
90
94
  })
91
95