nadesiko3 3.7.2 → 3.7.3

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/core/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nadesiko3core",
3
- "version": "3.7.2",
3
+ "version": "3.7.3",
4
4
  "description": "Japanese Programming Language Nadesiko v3 core",
5
5
  "main": "index.mjs",
6
6
  "type": "module",
@@ -9,7 +9,7 @@ import { Ast, AstBlocks } from './nako_ast.mjs'
9
9
  // parser / lexer
10
10
  import { NakoParser } from './nako_parser3.mjs'
11
11
  import { NakoLexer } from './nako_lexer.mjs'
12
- import { NakoPrepare, ConvertResult } from './nako_prepare.mjs'
12
+ import { NakoPrepare } from './nako_prepare.mjs'
13
13
  import { NakoGen, generateJS, NakoGenOptions, NakoGenResult } from './nako_gen.mjs'
14
14
  import { convertInlineIndent, convertIndentSyntax } from './nako_indent_inline.mjs'
15
15
  import { convertDNCL } from './nako_from_dncl.mjs'
@@ -1,8 +1,8 @@
1
1
  // 実際のバージョン定義 (自動生成されるので以下を編集しない)
2
2
  const coreVersion = {
3
- version: '3.7.2',
3
+ version: '3.7.3',
4
4
  major: 3,
5
5
  minor: 7,
6
- patch: 2
6
+ patch: 3
7
7
  };
8
8
  export default coreVersion;
@@ -11,9 +11,9 @@ export interface NakoCoreVersion {
11
11
  }
12
12
  // 実際のバージョン定義 (自動生成されるので以下を編集しない)
13
13
  const coreVersion: NakoCoreVersion = {
14
- version: '3.7.2',
14
+ version: '3.7.3',
15
15
  major: 3,
16
16
  minor: 7,
17
- patch: 2
17
+ patch: 3
18
18
  }
19
19
  export default coreVersion
@@ -402,11 +402,18 @@ export class NakoParser extends NakoParserBase {
402
402
  this.localvars.set(fnName, { 'type': 'var', 'value': '' });
403
403
  }
404
404
  block = this.yBlock();
405
+ // 「ここまで」のチェック
405
406
  if (this.check('ここまで')) {
406
- this.get();
407
+ this.get(); // skip 'ここまで'
407
408
  }
408
409
  else {
409
- throw NakoSyntaxError.fromNode('『ここまで』がありません。関数定義の末尾に必要です。', def);
410
+ // 「ここまで」が見当たらない
411
+ const nextWordO = this.peek();
412
+ let nextWord = JSON.stringify(nextWordO);
413
+ if (nextWordO && nextWordO.type && nextWordO.value) {
414
+ nextWord = nextWordO.value;
415
+ }
416
+ throw NakoSyntaxError.fromNode(`『ここまで』がありません。関数定義の末尾に必要です。『${nextWord}』の前に『ここまで』を記述してください。`, def);
410
417
  }
411
418
  this.loadStack();
412
419
  }
@@ -1409,6 +1416,9 @@ export class NakoParser extends NakoParserBase {
1409
1416
  if (!word || (word.type !== 'word' && word.type !== 'func' && word.type !== 'ref_array')) {
1410
1417
  throw NakoSyntaxError.fromNode('代入文で代入先の変数が見当たりません。『(変数名)に(値)を代入』のように使います。', dainyu);
1411
1418
  }
1419
+ if (word.type === 'func') {
1420
+ throw NakoSyntaxError.fromNode('関数『' + word.name + '』に代入できません。『(変数名)に(値)を代入』のように使います。', dainyu);
1421
+ }
1412
1422
  // 配列への代入
1413
1423
  if (word.type === 'ref_array') {
1414
1424
  const indexArray = word.index || [];
@@ -1949,9 +1959,10 @@ export class NakoParser extends NakoParserBase {
1949
1959
  };
1950
1960
  }
1951
1961
  }
1952
- if (this.accept(['定数', 'word', 'eq', this.yCalc])) {
1953
- const word = this.createVar(this.y[1], true, this.isExportDefault);
1954
- const astValue = this.y[3] || this.yNop();
1962
+ if (this.accept(['定数', 'word', 'eq'])) {
1963
+ const constName = this.y[1];
1964
+ const word = this.createVar(constName, true, this.isExportDefault);
1965
+ const astValue = this.yCalc() || this.yNop();
1955
1966
  return {
1956
1967
  type: 'def_local_var',
1957
1968
  name: word.value,
@@ -1961,7 +1972,7 @@ export class NakoParser extends NakoParserBase {
1961
1972
  end: this.peekSourceMap()
1962
1973
  };
1963
1974
  }
1964
- if (this.accept(['定数', 'word', '{', 'word', '}', 'eq', this.yCalc])) {
1975
+ if (this.accept(['定数', 'word', '{', 'word', '}', 'eq'])) {
1965
1976
  let isExport = this.isExportDefault;
1966
1977
  const attr = this.y[3].value;
1967
1978
  if (attr === '公開') {
@@ -1977,7 +1988,7 @@ export class NakoParser extends NakoParserBase {
1977
1988
  this.logger.warn(`不明な定数属性『${attr}』が指定されています。`);
1978
1989
  }
1979
1990
  const word = this.createVar(this.y[1], true, isExport);
1980
- const astValue = this.y[6] || this.yNop();
1991
+ const astValue = this.yCalc() || this.yNop();
1981
1992
  return {
1982
1993
  type: 'def_local_var',
1983
1994
  name: word.value,
@@ -1989,7 +2000,7 @@ export class NakoParser extends NakoParserBase {
1989
2000
  };
1990
2001
  }
1991
2002
  // 複数定数への代入 #563
1992
- if (this.accept(['定数', this.yJSONArray, 'eq', this.yCalc])) {
2003
+ if (this.accept(['定数', this.yJSONArray, 'eq'])) {
1993
2004
  const names = this.y[1];
1994
2005
  // check array
1995
2006
  if (names && names.blocks instanceof Array) {
@@ -2003,7 +2014,7 @@ export class NakoParser extends NakoParserBase {
2003
2014
  throw NakoSyntaxError.fromNode('複数定数の代入文でエラー。『定数[A,B,C]=[1,2,3]』の書式で記述してください。', this.y[0]);
2004
2015
  }
2005
2016
  const namesAst = this._tokensToNodes(this.createVarList(names.blocks, true, this.isExportDefault));
2006
- const astValue = this.y[3] || this.yNop();
2017
+ const astValue = this.yCalc() || this.yNop();
2007
2018
  return {
2008
2019
  type: 'def_local_varlist',
2009
2020
  names: namesAst,
@@ -2014,7 +2025,7 @@ export class NakoParser extends NakoParserBase {
2014
2025
  };
2015
2026
  }
2016
2027
  // 複数変数への代入 #563
2017
- if (this.accept(['変数', this.yJSONArray, 'eq', this.yCalc])) {
2028
+ if (this.accept(['変数', this.yJSONArray, 'eq'])) {
2018
2029
  const names = this.y[1];
2019
2030
  // check array
2020
2031
  if (names && names.blocks instanceof Array) {
@@ -2028,7 +2039,7 @@ export class NakoParser extends NakoParserBase {
2028
2039
  throw NakoSyntaxError.fromNode('複数変数の代入文でエラー。『変数[A,B,C]=[1,2,3]』の書式で記述してください。', this.y[0]);
2029
2040
  }
2030
2041
  const namesAst = this._tokensToNodes(this.createVarList(names.blocks, false, this.isExportDefault));
2031
- const astValue = this.y[3] || this.yNop();
2042
+ const astValue = this.yCalc() || this.yNop();
2032
2043
  return {
2033
2044
  type: 'def_local_varlist',
2034
2045
  names: namesAst,
@@ -2041,10 +2052,10 @@ export class NakoParser extends NakoParserBase {
2041
2052
  // 複数変数への代入 #563
2042
2053
  if (this.check2(['word', 'comma', 'word'])) {
2043
2054
  // 2 word
2044
- if (this.accept(['word', 'comma', 'word', 'eq', this.yCalc])) {
2055
+ if (this.accept(['word', 'comma', 'word', 'eq'])) {
2045
2056
  let names = [this.y[0], this.y[2]];
2046
2057
  names = this.createVarList(names, false, this.isExportDefault);
2047
- const astValue = this.y[4] || this.yNop();
2058
+ const astValue = this.yCalc() || this.yNop();
2048
2059
  return {
2049
2060
  type: 'def_local_varlist',
2050
2061
  names,
@@ -2055,10 +2066,10 @@ export class NakoParser extends NakoParserBase {
2055
2066
  };
2056
2067
  }
2057
2068
  // 3 word
2058
- if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'eq', this.yCalc])) {
2069
+ if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'eq'])) {
2059
2070
  let names = [this.y[0], this.y[2], this.y[4]];
2060
2071
  names = this.createVarList(names, false, this.isExportDefault);
2061
- const astValue = this.y[6] || this.yNop();
2072
+ const astValue = this.yCalc() || this.yNop();
2062
2073
  return {
2063
2074
  type: 'def_local_varlist',
2064
2075
  names,
@@ -2069,10 +2080,10 @@ export class NakoParser extends NakoParserBase {
2069
2080
  };
2070
2081
  }
2071
2082
  // 4 word
2072
- if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'eq', this.yCalc])) {
2083
+ if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'eq'])) {
2073
2084
  let names = [this.y[0], this.y[2], this.y[4], this.y[6]];
2074
2085
  names = this.createVarList(names, false, this.isExportDefault);
2075
- const astValue = this.y[8] || this.yNop();
2086
+ const astValue = this.yCalc() || this.yNop();
2076
2087
  return {
2077
2088
  type: 'def_local_varlist',
2078
2089
  names,
@@ -2083,10 +2094,10 @@ export class NakoParser extends NakoParserBase {
2083
2094
  };
2084
2095
  }
2085
2096
  // 5 word
2086
- if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'eq', this.yCalc])) {
2097
+ if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'eq'])) {
2087
2098
  let names = [this.y[0], this.y[2], this.y[4], this.y[6], this.y[8]];
2088
2099
  names = this.createVarList(names, false, this.isExportDefault);
2089
- const astValue = this.y[10] || this.yNop();
2100
+ const astValue = this.yCalc() || this.yNop();
2090
2101
  return {
2091
2102
  type: 'def_local_varlist',
2092
2103
  names,
@@ -344,7 +344,16 @@ export class NakoParser extends NakoParserBase {
344
344
  this.localvars.set(fnName, { 'type': 'var', 'value': '' })
345
345
  }
346
346
  block = this.yBlock()
347
- if (this.check('ここまで')) { this.get() } else { throw NakoSyntaxError.fromNode('『ここまで』がありません。関数定義の末尾に必要です。', def) }
347
+ // 「ここまで」のチェック
348
+ if (this.check('ここまで')) {
349
+ this.get() // skip 'ここまで'
350
+ } else {
351
+ // 「ここまで」が見当たらない
352
+ const nextWordO = this.peek()
353
+ let nextWord = JSON.stringify(nextWordO)
354
+ if (nextWordO && nextWordO.type && nextWordO.value) { nextWord = nextWordO.value }
355
+ throw NakoSyntaxError.fromNode(`『ここまで』がありません。関数定義の末尾に必要です。『${nextWord}』の前に『ここまで』を記述してください。`, def)
356
+ }
348
357
  this.loadStack()
349
358
  } else {
350
359
  this.saveStack()
@@ -1221,6 +1230,9 @@ export class NakoParser extends NakoParserBase {
1221
1230
  if (!word || (word.type !== 'word' && word.type !== 'func' && word.type !== 'ref_array')) {
1222
1231
  throw NakoSyntaxError.fromNode('代入文で代入先の変数が見当たりません。『(変数名)に(値)を代入』のように使います。', dainyu)
1223
1232
  }
1233
+ if (word.type === 'func') {
1234
+ throw NakoSyntaxError.fromNode('関数『' + word.name + '』に代入できません。『(変数名)に(値)を代入』のように使います。', dainyu)
1235
+ }
1224
1236
  // 配列への代入
1225
1237
  if (word.type === 'ref_array') {
1226
1238
  const indexArray = word.index || []
@@ -1691,9 +1703,10 @@ export class NakoParser extends NakoParserBase {
1691
1703
  }
1692
1704
  }
1693
1705
 
1694
- if (this.accept(['定数', 'word', 'eq', this.yCalc])) {
1695
- const word = this.createVar(this.y[1], true, this.isExportDefault)
1696
- const astValue = this.y[3] || this.yNop()
1706
+ if (this.accept(['定数', 'word', 'eq'])) {
1707
+ const constName = this.y[1]
1708
+ const word = this.createVar(constName, true, this.isExportDefault)
1709
+ const astValue = this.yCalc() || this.yNop()
1697
1710
  return {
1698
1711
  type: 'def_local_var',
1699
1712
  name: (word as AstStrValue).value,
@@ -1704,12 +1717,12 @@ export class NakoParser extends NakoParserBase {
1704
1717
  } as AstDefVar
1705
1718
  }
1706
1719
 
1707
- if (this.accept(['定数', 'word', '{', 'word', '}', 'eq', this.yCalc])) {
1720
+ if (this.accept(['定数', 'word', '{', 'word', '}', 'eq'])) {
1708
1721
  let isExport : boolean = this.isExportDefault
1709
1722
  const attr = this.y[3].value
1710
1723
  if (attr === '公開') { isExport = true } else if (attr === '非公開') { isExport = false } else if (attr === 'エクスポート') { isExport = true } else { this.logger.warn(`不明な定数属性『${attr}』が指定されています。`) }
1711
1724
  const word = this.createVar(this.y[1], true, isExport)
1712
- const astValue = this.y[6] || this.yNop()
1725
+ const astValue = this.yCalc() || this.yNop()
1713
1726
  return {
1714
1727
  type: 'def_local_var',
1715
1728
  name: (word as AstStrValue).value,
@@ -1722,7 +1735,7 @@ export class NakoParser extends NakoParserBase {
1722
1735
  }
1723
1736
 
1724
1737
  // 複数定数への代入 #563
1725
- if (this.accept(['定数', this.yJSONArray, 'eq', this.yCalc])) {
1738
+ if (this.accept(['定数', this.yJSONArray, 'eq'])) {
1726
1739
  const names = this.y[1]
1727
1740
  // check array
1728
1741
  if (names && names.blocks instanceof Array) {
@@ -1735,7 +1748,7 @@ export class NakoParser extends NakoParserBase {
1735
1748
  throw NakoSyntaxError.fromNode('複数定数の代入文でエラー。『定数[A,B,C]=[1,2,3]』の書式で記述してください。', this.y[0])
1736
1749
  }
1737
1750
  const namesAst = this._tokensToNodes(this.createVarList(names.blocks, true, this.isExportDefault))
1738
- const astValue = this.y[3] || this.yNop()
1751
+ const astValue = this.yCalc() || this.yNop()
1739
1752
  return {
1740
1753
  type: 'def_local_varlist',
1741
1754
  names: namesAst,
@@ -1746,7 +1759,7 @@ export class NakoParser extends NakoParserBase {
1746
1759
  } as AstDefVarList
1747
1760
  }
1748
1761
  // 複数変数への代入 #563
1749
- if (this.accept(['変数', this.yJSONArray, 'eq', this.yCalc])) {
1762
+ if (this.accept(['変数', this.yJSONArray, 'eq'])) {
1750
1763
  const names: AstBlocks = this.y[1]
1751
1764
  // check array
1752
1765
  if (names && names.blocks instanceof Array) {
@@ -1759,7 +1772,7 @@ export class NakoParser extends NakoParserBase {
1759
1772
  throw NakoSyntaxError.fromNode('複数変数の代入文でエラー。『変数[A,B,C]=[1,2,3]』の書式で記述してください。', this.y[0])
1760
1773
  }
1761
1774
  const namesAst = this._tokensToNodes(this.createVarList(names.blocks as Token[], false, this.isExportDefault))
1762
- const astValue = this.y[3] || this.yNop()
1775
+ const astValue = this.yCalc() || this.yNop()
1763
1776
  return {
1764
1777
  type: 'def_local_varlist',
1765
1778
  names: namesAst,
@@ -1773,10 +1786,10 @@ export class NakoParser extends NakoParserBase {
1773
1786
  // 複数変数への代入 #563
1774
1787
  if (this.check2(['word', 'comma', 'word'])) {
1775
1788
  // 2 word
1776
- if (this.accept(['word', 'comma', 'word', 'eq', this.yCalc])) {
1789
+ if (this.accept(['word', 'comma', 'word', 'eq'])) {
1777
1790
  let names = [this.y[0], this.y[2]]
1778
1791
  names = this.createVarList(names, false, this.isExportDefault)
1779
- const astValue = this.y[4] || this.yNop()
1792
+ const astValue = this.yCalc() || this.yNop()
1780
1793
  return {
1781
1794
  type: 'def_local_varlist',
1782
1795
  names,
@@ -1787,10 +1800,10 @@ export class NakoParser extends NakoParserBase {
1787
1800
  } as AstDefVarList
1788
1801
  }
1789
1802
  // 3 word
1790
- if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'eq', this.yCalc])) {
1803
+ if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'eq'])) {
1791
1804
  let names = [this.y[0], this.y[2], this.y[4]]
1792
1805
  names = this.createVarList(names, false, this.isExportDefault)
1793
- const astValue = this.y[6] || this.yNop()
1806
+ const astValue = this.yCalc() || this.yNop()
1794
1807
  return {
1795
1808
  type: 'def_local_varlist',
1796
1809
  names,
@@ -1801,10 +1814,10 @@ export class NakoParser extends NakoParserBase {
1801
1814
  } as AstDefVarList
1802
1815
  }
1803
1816
  // 4 word
1804
- if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'eq', this.yCalc])) {
1817
+ if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'eq'])) {
1805
1818
  let names = [this.y[0], this.y[2], this.y[4], this.y[6]]
1806
1819
  names = this.createVarList(names, false, this.isExportDefault)
1807
- const astValue = this.y[8] || this.yNop()
1820
+ const astValue = this.yCalc() || this.yNop()
1808
1821
  return {
1809
1822
  type: 'def_local_varlist',
1810
1823
  names,
@@ -1815,10 +1828,10 @@ export class NakoParser extends NakoParserBase {
1815
1828
  } as AstDefVarList
1816
1829
  }
1817
1830
  // 5 word
1818
- if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'eq', this.yCalc])) {
1831
+ if (this.accept(['word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'comma', 'word', 'eq'])) {
1819
1832
  let names = [this.y[0], this.y[2], this.y[4], this.y[6], this.y[8]]
1820
1833
  names = this.createVarList(names, false, this.isExportDefault)
1821
- const astValue = this.y[10] || this.yNop()
1834
+ const astValue = this.yCalc() || this.yNop()
1822
1835
  return {
1823
1836
  type: 'def_local_varlist',
1824
1837
  names,
@@ -403,7 +403,39 @@ export default {
403
403
  isVariableJosi: false,
404
404
  pure: true,
405
405
  fn: function (a, b) {
406
- return a + b;
406
+ if (typeof (a) === 'bigint' || typeof (b) === 'bigint') {
407
+ return BigInt(a) + BigInt(b);
408
+ }
409
+ return parseFloat(a) + parseFloat(b);
410
+ }
411
+ },
412
+ '合計': {
413
+ type: 'func',
414
+ josi: [['と', 'を', 'の']],
415
+ isVariableJosi: true,
416
+ pure: true,
417
+ fn: function (...a) {
418
+ const sys = a.pop(); // remove NakoSystem
419
+ if (a.length >= 1 && a[0] instanceof Array) {
420
+ return sys.__exec('配列合計', [a[0], sys]);
421
+ }
422
+ let isBigInt = false;
423
+ let sum = 0;
424
+ for (const v of a) {
425
+ if (typeof (v) === 'bigint') {
426
+ isBigInt = true;
427
+ break;
428
+ }
429
+ sum += parseFloat(v);
430
+ }
431
+ if (isBigInt) {
432
+ let bigsum = 0n;
433
+ for (const v of a) {
434
+ bigsum += BigInt(v);
435
+ }
436
+ return bigsum;
437
+ }
438
+ return sum;
407
439
  }
408
440
  },
409
441
  '引': {
@@ -1259,6 +1291,16 @@ export default {
1259
1291
  return a.join('');
1260
1292
  },
1261
1293
  },
1294
+ '文字列連結': {
1295
+ type: 'func',
1296
+ josi: [['と', 'を']],
1297
+ pure: true,
1298
+ isVariableJosi: true,
1299
+ fn: function (...a) {
1300
+ a.pop(); // NakoSystemを取り除く
1301
+ return a.join('');
1302
+ },
1303
+ },
1262
1304
  '文字列分解': {
1263
1305
  type: 'func',
1264
1306
  josi: [['を', 'の', 'で']],
@@ -1347,7 +1389,11 @@ export default {
1347
1389
  // return (s.substring(s.length - cnt, s.length))
1348
1390
  // サロゲートペアを考慮
1349
1391
  const strArray = Array.from(s);
1350
- return strArray.slice(strArray.length - cnt, strArray.length).join('');
1392
+ let index = strArray.length - cnt;
1393
+ if (index < 0) {
1394
+ index = 0;
1395
+ }
1396
+ return strArray.slice(index, strArray.length).join('');
1351
1397
  }
1352
1398
  },
1353
1399
  '区切': {
@@ -377,13 +377,45 @@ export default {
377
377
  },
378
378
 
379
379
  // @四則演算
380
- '足': { // @AとBを足す // @たす
380
+ '足': { // @AとBを足す(算術演算を行う) // @たす
381
381
  type: 'func',
382
382
  josi: [['に', 'と'], ['を']],
383
383
  isVariableJosi: false,
384
384
  pure: true,
385
385
  fn: function (a: any, b: any) {
386
- return a + b
386
+ if (typeof(a) === 'bigint' || typeof(b) === 'bigint') {
387
+ return BigInt(a) + BigInt(b)
388
+ }
389
+ return parseFloat(a) + parseFloat(b)
390
+ }
391
+ },
392
+ '合計': { // @引数(可変)に指定した値を全て合計して返す // @ごうけい
393
+ type: 'func',
394
+ josi: [['と', 'を', 'の']],
395
+ isVariableJosi: true,
396
+ pure: true,
397
+ fn: function (...a: any) {
398
+ const sys = a.pop() // remove NakoSystem
399
+ if (a.length >= 1 && a[0] instanceof Array) {
400
+ return sys.__exec('配列合計', [a[0], sys])
401
+ }
402
+ let isBigInt = false
403
+ let sum = 0
404
+ for (const v of a) {
405
+ if (typeof(v) === 'bigint') {
406
+ isBigInt = true
407
+ break
408
+ }
409
+ sum += parseFloat(v)
410
+ }
411
+ if (isBigInt) {
412
+ let bigsum = 0n
413
+ for (const v of a) {
414
+ bigsum += BigInt(v)
415
+ }
416
+ return bigsum
417
+ }
418
+ return sum
387
419
  }
388
420
  },
389
421
  '引': { // @AからBを引く // @ひく
@@ -1206,6 +1238,16 @@ export default {
1206
1238
  return a.join('')
1207
1239
  },
1208
1240
  },
1241
+ '文字列連結': { // @引数(可変)に指定した文字列を連結して文字列を返す // @もじれつれんけつ
1242
+ type: 'func',
1243
+ josi: [['と', 'を']],
1244
+ pure: true,
1245
+ isVariableJosi: true,
1246
+ fn: function (...a: any) {
1247
+ a.pop() // NakoSystemを取り除く
1248
+ return a.join('')
1249
+ },
1250
+ },
1209
1251
  '文字列分解': { // @文字列Vを一文字ずつに分解して返す // @もじれつぶんかい
1210
1252
  type: 'func',
1211
1253
  josi: [['を', 'の', 'で']],
@@ -1290,7 +1332,9 @@ export default {
1290
1332
  // return (s.substring(s.length - cnt, s.length))
1291
1333
  // サロゲートペアを考慮
1292
1334
  const strArray = Array.from(s)
1293
- return strArray.slice(strArray.length - cnt, strArray.length).join('')
1335
+ let index = strArray.length - cnt
1336
+ if (index < 0) { index = 0 }
1337
+ return strArray.slice(index, strArray.length).join('')
1294
1338
  }
1295
1339
  },
1296
1340
  '区切': { // @文字列Sを区切り文字Aで区切って配列で返す // @くぎる
@@ -328,10 +328,22 @@ describe('basic', async () => {
328
328
  await cmp('変数[A,B]=[1];Aを表示;Bを表示;', '1\nundefined')
329
329
  await cmp('変数[A,B,C,D]=[1,2,3,4];Dを表示;', '4')
330
330
  })
331
+ it('定数複数代入', async () => {
332
+ await cmp('定数[A,B] = [1,2]; 「{A}:{B}」を表示', '1:2')
333
+ await cmp('定数[A,B,C] = [1,2,3]; 「{A}:{B}:{C}」を表示', '1:2:3')
334
+ await cmp('定数[A,B,C,D] = [1,2,3,4,5]; 「{A}:{B}:{C}:{D}」を表示', '1:2:3:4')
335
+ await cmp('定数[A,B,C,D,E] = [1,2,3,4,5]; 「{A}:{B}:{C}:{D}:{E}」を表示', '1:2:3:4:5')
336
+ })
331
337
  it('複数代入文の問題 #1027', async () => {
332
338
  await cmp('塊=[[0,0],[1,1]];塊を反復\nx,y=対象;💧;塊をJSONエンコードして表示。', '[[0,0],[1,1]]')
333
339
  await cmp('x=1;y=2;x,y=[y,x];xを表示', '2')
334
340
  })
341
+ it('変数の複数代入', async () => {
342
+ await cmp('A,B = [1,2]; 「{A}:{B}」を表示', '1:2')
343
+ await cmp('A,B,C = [1,2,3]; 「{A}:{B}:{C}」を表示', '1:2:3')
344
+ await cmp('A,B,C,D = [1,2,3,4,5]; 「{A}:{B}:{C}:{D}」を表示', '1:2:3:4')
345
+ await cmp('A,B,C,D,E = [1,2,3,4,5]; 「{A}:{B}:{C}:{D}:{E}」を表示', '1:2:3:4:5')
346
+ })
335
347
  it('もし文で「ならば」の前の空行でエラー #1079', async () => {
336
348
  await cmp('A=5;もし、A > 3 ならば「OK」と表示;', 'OK')
337
349
  })
@@ -411,4 +423,8 @@ describe('basic', async () => {
411
423
  await cmp('《リンゴの値段》=500;《リンゴの値段》を表示', '500') // #672 大なり記号ではなく、二重カッコであることに注意
412
424
  await cmp('${リンゴの値段}=500;${リンゴの値段}を表示', '500') // #1836
413
425
  })
426
+ it('特別名前トークンのテスト #672 #1836', async () => {
427
+ await cmp('《リンゴの値段》=500;《リンゴの値段》を表示', '500') // #672 大なり記号ではなく、二重カッコであることに注意
428
+ await cmp('${リンゴの値段}=500;${リンゴの値段}を表示', '500') // #1836
429
+ })
414
430
  })
@@ -287,4 +287,11 @@ describe('calc_test.js', async () => {
287
287
  await cmp('N="2";Nを1減らす。Nを表示。', '1')
288
288
  await cmp('N="2";Nを"1"減らす。Nを表示。', '1')
289
289
  })
290
+
291
+ it('文字列を「足す」命令に与えた時、算術演算する #1958', async () => {
292
+ await cmp('"1"に"3"を足して表示。', '4')
293
+ await cmp('1に"3"を足して表示', '4')
294
+ await cmp('"1"に3を足して表示', '4')
295
+ await cmp('1nに3nを足して表示', '4')
296
+ })
290
297
  })
@@ -777,5 +777,17 @@ describe('plugin_system_test', async () => {
777
777
  await cmp('「A」と「B」と「C」と「D」を連結して表示', 'ABCD')
778
778
  await cmp('「A」と「B」を連結して表示', 'AB')
779
779
  await cmp('「A」を連結して表示', 'A')
780
+ await cmp('「A」と「B」と「C」と「D」を文字列連結して表示', 'ABCD')
781
+ })
782
+ it('文字右部分で元の文字列の長さを超える場合の処理がおかしい #1975', async () => {
783
+ await cmp('「12345」の0文字右部分を表示', '')
784
+ await cmp('「12345」の1文字右部分を表示', '5')
785
+ await cmp('「12345」の3文字右部分を表示', '345')
786
+ await cmp('「12345」の6文字右部分を表示', '12345')
787
+ })
788
+ it('関数「合計」を追加 #1991', async () => {
789
+ await cmp('1と2と3を合計して表示', '6')
790
+ await cmp('1と2と3の合計を表示', '6')
791
+ await cmp('[4,5,6]の合計を表示', '15')
780
792
  })
781
793
  })
package/doc/files.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # なでしこを構成するファイルたち
2
2
 
3
- ## src/nako3.mjs
3
+ ## core/src/nako3.mjs
4
4
 
5
5
  なでしこコンパイラ本体。なでしこのソースコードをJSに変換する。変換処理は、次のように行われる。
6
6
 
@@ -9,15 +9,15 @@
9
9
  - (3) 構文木(中間表現)
10
10
  - (3) JavaScriptソース
11
11
 
12
- ## src/nako_prepare.mjs
12
+ ## core/src/nako_prepare.mjs
13
13
 
14
14
  なでしこのソースコードの前置処理を行うもの。主に全角半角の変換処理を行う。
15
15
 
16
- ## src/nako_parser3.mjs
16
+ ## core/src/nako_parser3.mjs
17
17
 
18
18
  なでしこ構文から構文木を生成するもの。
19
19
 
20
- ## src/nako_gen.mjs
20
+ ## core/src/nako_gen.mjs
21
21
 
22
22
  構文木を元に、JavaScriptのコードを生成するもの。
23
23
 
package/doc/plugins.md CHANGED
@@ -207,7 +207,7 @@ const value = sys.__getSysVar('変数名')
207
207
  sys.__setSysVar('変数名', value)
208
208
  ```
209
209
 
210
- なお、プラグインでは、次のメソッドが使えるようになる。(すべてsrc/plugin_system.jsで定義されている。システム関数の初期化時に、これらの関数が追加される)
210
+ なお、プラグインでは、次のメソッドが使えるようになる。(すべてcore/src/plugin_system.mjsで定義されている。システム関数の初期化時に、これらの関数が追加される)
211
211
 
212
212
  - sys.__findVar(name)
213
213
  - sys.__exec(name, params)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nadesiko3",
3
- "version": "3.7.2",
3
+ "version": "3.7.3",
4
4
  "description": "Japanese Programming Language",
5
5
  "type": "module",
6
6
  "main": "src/index.mjs",
@@ -101,7 +101,7 @@
101
101
  "@types/node": "^22.0.2",
102
102
  "@types/opener": "^1.4.3",
103
103
  "@types/shell-quote": "^1.7.5",
104
- "babel-loader": "^9.1.3",
104
+ "babel-loader": "^10.0.0",
105
105
  "browserslist": "^4.23.0",
106
106
  "buffer": "^6.0.3",
107
107
  "chai": "^5.1.0",
@@ -111,7 +111,7 @@
111
111
  "crypto-browserify": "^3.12.0",
112
112
  "css-loader": "^7.1.1",
113
113
  "es6-promise": "^4.2.8",
114
- "esbuild": "0.25.0",
114
+ "esbuild": "0.25.1",
115
115
  "eslint": "^8.57.0",
116
116
  "eslint-config-standard": "^17.1.0",
117
117
  "eslint-plugin-import": "^2.29.1",