nadesiko3 3.2.35 → 3.2.39

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.
@@ -18,6 +18,8 @@
18
18
  "定",
19
19
  "逐次実行",
20
20
  "条件分岐",
21
+ "増",
22
+ "減",
21
23
  "変数",
22
24
  "定数",
23
25
  "エラー監視",
@@ -77,20 +77,77 @@ function dncl2nako(src, filename) {
77
77
  'を実行し,そうでなければ': '違えば',
78
78
  'を実行し、そうでなければ': '違えば',
79
79
  'を繰り返す': 'ここまで',
80
- '改行なしで表示': '継続表示',
80
+ '改行なしで表示': '連続無改行表示',
81
81
  'のすべての値を0にする': '=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]',
82
82
  'ずつ増やしながら':'ずつ増やし繰り返す',
83
83
  'ずつ減らしながら':'ずつ減らし繰り返す',
84
+ '二進で表示': '二進表示',
84
85
  }
85
-
86
+ let peekChar = () => src.charAt(0)
87
+ let nextChar = () => {
88
+ let ch = src.charAt(0)
89
+ src = src.substring(1)
90
+ return ch
91
+ }
92
+ // 文字列を判定するフラグ
93
+ let flagStr = false
94
+ let poolStr = ''
95
+ let endStr = ''
96
+ // 結果
86
97
  let result = ''
87
98
  while (src !='') {
88
99
  // 代入記号を変更
89
100
  const ch = src.charAt(0)
101
+ if (flagStr) {
102
+ if (ch === endStr) {
103
+ result += poolStr + endStr
104
+ poolStr = ''
105
+ flagStr = false
106
+ nextChar()
107
+ continue
108
+ }
109
+ poolStr += nextChar()
110
+ continue
111
+ }
112
+ // 文字列?
113
+ if (ch == '"') {
114
+ flagStr = true
115
+ endStr = '"'
116
+ poolStr = nextChar()
117
+ continue
118
+ }
119
+ if (ch == '「') {
120
+ flagStr = true
121
+ endStr = '」'
122
+ poolStr = nextChar()
123
+ continue
124
+ }
125
+ if (ch == '『') {
126
+ flagStr = true
127
+ endStr = '』'
128
+ poolStr = nextChar()
129
+ continue
130
+ }
90
131
  // 空白を飛ばす
91
132
  if (ch === ' ' || ch === ' ' || ch == '\t') {
92
- result += ch
93
- src = src.substring(1)
133
+ result += nextChar()
134
+ continue
135
+ }
136
+ // 表示を連続表示に置き換える
137
+ if (src.substring(0, 3) === 'を表示') {
138
+ result += 'を連続表示'
139
+ src = src.substring(3)
140
+ continue
141
+ }
142
+ if (src.substring(0, 4) === 'を 表示') {
143
+ result += 'を連続表示'
144
+ src = src.substring(4)
145
+ continue
146
+ }
147
+ // 乱数を乱数範囲に置き換える
148
+ if (src.substring(0, 2) === '乱数' && src.substring(0, 4) !== '乱数範囲') {
149
+ result += '乱数範囲'
150
+ src = src.substring(2)
94
151
  continue
95
152
  }
96
153
  // 1行先読み
@@ -101,62 +158,6 @@ function dncl2nako(src, filename) {
101
158
  } else {
102
159
  line = src
103
160
  }
104
- //「var を n 増やす」を「var = var + 1」と置き換える
105
- const r = line.match(/^([a-zA-Z_][a-zA-Z0-9_]*)\s*を\s*([0-9a-zA-Z_]+)\s*(増やす|減らす)/)
106
- if (r) {
107
- const var_name = r[1]
108
- const inc_val = r[2]
109
- const inc_dec = r[3]
110
- if (inc_dec == '増やす') {
111
- result += `${var_name} = ${var_name} + ${inc_val};`
112
- } else {
113
- result += `${var_name} = ${var_name} - ${inc_val};`
114
- }
115
- src = src.substring(r[0].length)
116
- continue
117
- }
118
- //「S1とS2とS3を表示する」を「(S1)&(S2)&S3)を表示」と置き換える
119
- // あまりスマートではないが手抜きで
120
- if (line.indexOf('表示') >= 0) {
121
- const r5 = line.match(/^(.+?)と(.+?)と(.+?)と(.+?)と(.+?)を表示/)
122
- if (r5) {
123
- const s1 = r5[1]
124
- const s2 = r5[2]
125
- const s3 = r5[3]
126
- const s4 = r5[4]
127
- const s5 = r5[4]
128
- result += `(${s1})&(${s2})&(${s3})&(${s4})&(${s5})を表示`
129
- src = src.substring(r5[0].length)
130
- continue
131
- }
132
- const r4 = line.match(/^(.+?)と(.+?)と(.+?)と(.+?)を表示/)
133
- if (r4) {
134
- const s1 = r4[1]
135
- const s2 = r4[2]
136
- const s3 = r4[3]
137
- const s4 = r4[4]
138
- result += `(${s1})&(${s2})&(${s3})&(${s4})を表示`
139
- src = src.substring(r4[0].length)
140
- continue
141
- }
142
- const r3 = line.match(/^(.+?)と(.+?)と(.+?)を表示/)
143
- if (r3) {
144
- const s1 = r3[1]
145
- const s2 = r3[2]
146
- const s3 = r3[3]
147
- result += `(${s1})&(${s2})&(${s3})を表示`
148
- src = src.substring(r3[0].length)
149
- continue
150
- }
151
- const r2 = line.match(/^(.+?)と(.+?)を表示/)
152
- if (r2) {
153
- const s1 = r2[1]
154
- const s2 = r2[2]
155
- result += `(${s1})&(${s2})を表示`
156
- src = src.substring(r2[0].length)
157
- continue
158
- }
159
- }
160
161
  // 『もしj>hakosuならばhakosu←jを実行する』のような単文のもし文
161
162
  const rif = line.match(/^もし(.+)を実行する(。|.)*/)
162
163
  if (rif) {
@@ -181,8 +182,7 @@ function dncl2nako(src, filename) {
181
182
  }
182
183
 
183
184
  // 1文字削る
184
- src = src.substring(1)
185
- result += ch
185
+ result += nextChar()
186
186
  }
187
187
  return result
188
188
  }
package/src/nako_gen.js CHANGED
@@ -476,6 +476,9 @@ try {
476
476
  case 'let':
477
477
  code += this.convLet(node)
478
478
  break
479
+ case 'inc':
480
+ code += this.convInc(node)
481
+ break
479
482
  case 'word':
480
483
  case 'variable':
481
484
  code += this.convGetVar(node)
@@ -856,11 +859,13 @@ try {
856
859
  let codeArray = ''
857
860
  // codeInit?
858
861
  if (node.checkInit) {
859
- codeInit += `\n/*配列初期化*/if (typeof(${name}) !== 'object') { ${name} = [] }; `
860
- for (let i = 0; i < list.length; i++) {
862
+ const arrayDefCode = '[0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0]'
863
+ codeInit += `\n/*配列初期化*/if (!(${name} instanceof Array)) { ${name} = ${arrayDefCode}; console.log('初期化:${name}') };`
864
+ for (let i = 0; i < list.length - 1; i++) {
861
865
  const idx = this._convGen(list[i], true)
862
866
  codeArray += `[${idx}]`
863
- codeInit += `if (typeof(${name}${codeArray}) !== 'object') { ${name}${codeArray} = [] }; `
867
+ codeInit += `\n/*配列初期化${i}*/if (!(${name}${codeArray} instanceof Array)) { ${name}${codeArray} = ${arrayDefCode}; };`
868
+ // codeInit += `\n/*配列初期化${i}*/if (!(${name}${codeArray} instanceof Array)) { ${name}${codeArray} = ${arrayDefCode}; console.log('初期化:${i}:${name}${codeArray}',JSON.stringify(${name})) }; `
864
869
  }
865
870
  codeInit += '\n'
866
871
  }
@@ -872,7 +877,8 @@ try {
872
877
  const value = this._convGen(node.value, true)
873
878
  code += ' = ' + value + ';\n'
874
879
  // generate code
875
- return this.convLineno(node, false) + codeInit + code
880
+ const src = this.convLineno(node, false) + codeInit + code
881
+ return src
876
882
  }
877
883
 
878
884
  convGenLoop (node) {
@@ -1373,6 +1379,24 @@ try {
1373
1379
  return `(${left} ${op} ${right})`
1374
1380
  }
1375
1381
 
1382
+ convInc (node) {
1383
+ // もし値が省略されていたら、変数「それ」に代入する
1384
+ let value = null
1385
+ if (this.speedMode.invalidSore === 0) { value = this.varname('それ') }
1386
+ if (node.value) { value = this._convGen(node.value, true) }
1387
+ if (value == null) {
1388
+ throw NakoSyntaxError.fromNode('加算する先の変数名がありません。', node)
1389
+ }
1390
+ // 変数名
1391
+ const name = node.name.value
1392
+ const res = this.findVar(name)
1393
+ let code = ''
1394
+ if (res === null) { this.varsSet.names.add(name) }
1395
+ code += `if (typeof(${this.varname(name)}) === 'undefined') { ${this.varname(name)} = 0; }`
1396
+ code += `${this.varname(name)} += ${value}`
1397
+ return ';' + this.convLineno(node, false) + code + '\n'
1398
+ }
1399
+
1376
1400
  convLet (node) {
1377
1401
  // もし値が省略されていたら、変数「それ」に代入する
1378
1402
  let value = null
@@ -154,7 +154,7 @@ function cbWordParser (src, isTrimOkurigana = true) {
154
154
  // 助詞の判定
155
155
  const j = josiRE.exec(src)
156
156
  if (j) {
157
- josi = j[0]
157
+ josi = j[0].replace(/^\s+/, '')
158
158
  src = src.substr(j[0].length)
159
159
  // 助詞の直後にある「,」を飛ばす #877
160
160
  if (src.charAt(0) === ',') { src = src.substr(1) }
@@ -229,7 +229,7 @@ function cbString (beginTag, closeTag, src) {
229
229
  // 文字列直後の助詞を取得
230
230
  const j = josiRE.exec(src)
231
231
  if (j) {
232
- josi = j[0]
232
+ josi = j[0].replace(/^\s+/, '')
233
233
  src = src.substr(j[0].length)
234
234
  // 助詞の後のカンマ #877
235
235
  if (src.charAt(0) === ',') { src = src.substr(1) }
@@ -96,6 +96,7 @@ class NakoParser extends NakoParserBase {
96
96
  /** @returns {Ast | null} */
97
97
  ySentence () {
98
98
  const map = this.peekSourceMap()
99
+
99
100
  // 最初の語句が決まっている構文
100
101
  if (this.check('eol')) { return this.yEOL() }
101
102
  if (this.check('もし')) { return this.yIF() }
@@ -103,18 +104,11 @@ class NakoParser extends NakoParserBase {
103
104
  if (this.check('逐次実行')) { return this.yTikuji() }
104
105
  if (this.accept(['抜ける'])) { return { type: 'break', josi: '', ...map, end: this.peekSourceMap() } }
105
106
  if (this.accept(['続ける'])) { return { type: 'continue', josi: '', ...map, end: this.peekSourceMap() } }
106
- if (this.accept(['require', 'string', '取込'])) {
107
- return {
108
- type: 'require',
109
- value: this.y[1].value,
110
- josi: '',
111
- ...map,
112
- end: this.peekSourceMap()
113
- }
114
- }
107
+ if (this.accept(['require', 'string', '取込'])) { return { type: 'require', value: this.y[1].value, josi: '', ...map, end: this.peekSourceMap() } }
115
108
  if (this.accept(['not', '非同期モード'])) { return this.yASyncMode() }
116
109
  if (this.accept(['not', 'DNCLモード'])) { return this.yDNCLMode() }
117
110
  if (this.accept(['not', 'string', 'モード設定'])) { return this.ySetGenMode(this.y[1].value) }
111
+
118
112
  // 関数呼び出し演算子
119
113
  if (this.check2(['func', '←'])) { return this.yCallOp() }
120
114
  if (this.check2(['func', 'eq'])) {
@@ -128,7 +122,9 @@ class NakoParser extends NakoParserBase {
128
122
  if (this.accept([this.yLet])) { return this.y[0] }
129
123
  if (this.accept([this.yDefTest])) { return this.y[0] }
130
124
  if (this.accept([this.yDefFunc])) { return this.y[0] }
131
- if (this.accept([this.yCall])) { // 関数呼び出しの他、各種構文の実装
125
+
126
+ // 関数呼び出しの他、各種構文の実装
127
+ if (this.accept([this.yCall])) {
132
128
  const c1 = this.y[0]
133
129
  if (c1.josi === 'して') { // 連文をblockとして接続する(もし構文、逐次実行構文などのため)
134
130
  const c2 = this.ySentence()
@@ -944,52 +940,107 @@ class NakoParser extends NakoParserBase {
944
940
  }
945
941
  }
946
942
 
943
+ /** @returns {import('./nako3').Ast | null | undefined} */
944
+ yDainyu () {
945
+ const map = this.peekSourceMap()
946
+ const dainyu = this.get() // 代入
947
+ if (dainyu === null) { return null }
948
+ const value = this.popStack(['を'])
949
+ const word = this.popStack(['へ', 'に'])
950
+ if (!word || (word.type !== 'word' && word.type !== 'func' && word.type !== '配列参照')) {
951
+ throw NakoSyntaxError.fromNode('代入文で代入先の変数が見当たりません。『(変数名)に(値)を代入』のように使います。', dainyu)
952
+ }
953
+ // 配列への代入
954
+ if (word.type === '配列参照') {
955
+ return {
956
+ type: 'let_array',
957
+ name: word.name,
958
+ index: word.index,
959
+ value: value,
960
+ josi: '',
961
+ checkInit: this.flagCheckArrayInit,
962
+ ...map, end: this.peekSourceMap()
963
+ };
964
+ }
965
+ // 一般的な変数への代入
966
+ return {
967
+ type: 'let', name: word,
968
+ value: value, josi: '',
969
+ ...map, end: this.peekSourceMap()
970
+ }
971
+ }
972
+
973
+ /** @returns {import('./nako3').Ast | null | undefined} */
974
+ ySadameru () {
975
+ const map = this.peekSourceMap()
976
+ const sadameru = this.get() // 定める
977
+ if (sadameru === null) { return null }
978
+ const word = this.popStack(['を'])
979
+ const value = this.popStack(['へ', 'に'])
980
+ console.log(word)
981
+ if (!word || (word.type !== 'word' && word.type !== 'func' && word.type !== '配列参照')) {
982
+ throw NakoSyntaxError.fromNode('『定める』文で定数が見当たりません。『(定数名)を(値)に定める』のように使います。', sadameru)
983
+ }
984
+ return {
985
+ type: 'def_local_var', name: word, vartype: '定数',
986
+ value: value, josi: '',
987
+ ...map, end: this.peekSourceMap()
988
+ };
989
+ }
990
+
991
+ /** @returns {import('./nako3').Ast | null | undefined} */
992
+ yIncDec () {
993
+ const map = this.peekSourceMap()
994
+ const action = this.get() // (増やす|減らす)
995
+ if (action === null) { return null }
996
+
997
+ // 『Nずつ増やして繰り返す』文か?
998
+ if (this.check('繰返')) {
999
+ this.pushStack({type: 'word', value: action.value, josi: action.josi, ...map, end: this.peekSourceMap})
1000
+ return this.yFor();
1001
+ }
1002
+
1003
+ // スタックから引数をポップ
1004
+ let value = this.popStack(['だけ', '']);
1005
+ const word = this.popStack(['を'])
1006
+ if (!word || (word.type !== 'word' && word.type !== '配列参照')) {
1007
+ throw NakoSyntaxError.fromNode(
1008
+ `『${action.type}』文で定数が見当たりません。『(変数名)を(値)だけ${action.type}』のように使います。`,
1009
+ action)
1010
+ }
1011
+
1012
+ // 減らすなら-1かける
1013
+ if (action.value === '減') {
1014
+ value = { type: 'op', operator: '*', left: value, right: {type: 'number', value: -1, line: action.line}, josi: '', ...map }
1015
+ }
1016
+
1017
+ return {
1018
+ type: 'inc',
1019
+ name: word,
1020
+ value: value,
1021
+ josi: action.josi,
1022
+ ...map, end: this.peekSourceMap()
1023
+ };
1024
+ }
1025
+
947
1026
  /** @returns {import('./nako3').Ast | null | undefined} */
948
1027
  yCall () {
949
1028
  if (this.isEOF()) { return null }
1029
+
1030
+ // スタックに積んでいく
950
1031
  while (!this.isEOF()) {
951
- const map = this.peekSourceMap()
1032
+ if (this.check('ここから')) { this.get() }
952
1033
  // 代入
953
- if (this.check('代入')) {
954
- const dainyu = this.get()
955
- const value = this.popStack(['を'])
956
- const word = this.popStack(['へ', 'に'])
957
- if (!word || (word.type !== 'word' && word.type !== 'func' && word.type !== '配列参照')) {
958
- throw NakoSyntaxError.fromNode('代入文で代入先の変数が見当たりません。', dainyu)
959
- }
960
-
961
- switch (word.type) {
962
- case '配列参照': // 配列への代入
963
- return { type: 'let_array', name: word.name, index: word.index, value: value, josi: '', checkInit: this.flagCheckArrayInit, ...map, end: this.peekSourceMap() }
964
- default:
965
- return { type: 'let', name: word, value: value, josi: '', ...map, end: this.peekSourceMap() }
966
- }
967
- }
968
- if (this.check('定める')) {
969
- const dainyu = this.get()
970
- const word = this.popStack(['を'])
971
- const value = this.popStack(['に'])
972
- if (!word || word.type !== 'word') {
973
- throw NakoSyntaxError.fromNode('代入文で代入先の変数が見当たりません。', dainyu)
974
- }
975
- return {
976
- type: 'def_local_var',
977
- name: word,
978
- vartype: '定数',
979
- value: value,
980
- ...map,
981
- end: this.peekSourceMap()
982
- }
983
- }
1034
+ if (this.check('代入')) { return this.yDainyu(); }
1035
+ if (this.check('定める')) { return this.ySadameru(); }
984
1036
  // 制御構文
985
- if (this.check('ここから')) { this.get() }
986
1037
  if (this.check('回')) { return this.yRepeatTime() }
987
1038
  if (this.check('間')) { return this.yWhile() }
988
1039
  if (this.check('繰返') || this.check('増繰返') || this.check('減繰返')) { return this.yFor() }
989
1040
  if (this.check('反復')) { return this.yForEach() }
990
1041
  if (this.check('条件分岐')) { return this.ySwitch() }
991
- // 戻す
992
1042
  if (this.check('戻る')) { return this.yReturn() }
1043
+ if (this.check('増') || this.check('減')) { return this.yIncDec() }
993
1044
  // C言語風関数
994
1045
  if (this.check2([['func', 'word'], '(']) && this.peek().josi === '') { // C言語風
995
1046
  const t = this.yValue()
@@ -1020,6 +1071,7 @@ class NakoParser extends NakoParserBase {
1020
1071
  }
1021
1072
  break
1022
1073
  } // end of while
1074
+
1023
1075
  // 助詞が余ってしまった場合
1024
1076
  if (this.stack.length > 0) {
1025
1077
  this.logger.debug('--- stack dump ---\n' + JSON.stringify(this.stack, null, 2) + '\npeek: ' + JSON.stringify(this.peek(), null, 2))
@@ -23,6 +23,8 @@ module.exports = {
23
23
  '定': '定める',
24
24
  '逐次実行': '逐次実行',
25
25
  '条件分岐': '条件分岐',
26
+ '増': '増',
27
+ '減': '減',
26
28
  '変数': '変数',
27
29
  '定数': '定数',
28
30
  'エラー監視': 'エラー監視', // 例外処理:エラーならばと対
@@ -1,8 +1,8 @@
1
1
  // なでしこバージョン
2
2
  const nakoVersion = {
3
- version: '3.2.35',
3
+ version: '3.2.39',
4
4
  major: 3,
5
5
  minor: 2,
6
- patch: 35
6
+ patch: 39
7
7
  }
8
8
  module.exports = nakoVersion
@@ -220,6 +220,14 @@ const PluginMath = {
220
220
  return Math.floor(Math.random() * a)
221
221
  }
222
222
  },
223
+ '乱数範囲': { // @AからBまでの範囲の乱数を返す // @らんすうはんい
224
+ type: 'func',
225
+ josi: [['から'],['までの','の']],
226
+ pure: true,
227
+ fn: function (a, b) {
228
+ return (Math.floor(Math.random() * (b - a + 1)) + a)
229
+ }
230
+ },
223
231
  'SQRT': { // @Aの平方根を返す // @SQRT
224
232
  type: 'func',
225
233
  josi: [['の']],
@@ -202,6 +202,30 @@ const PluginSystem = {
202
202
  },
203
203
  return_none: true
204
204
  },
205
+ '連続表示': { // @引数に指定した引数を全て表示する // @れんぞく表示
206
+ type: 'func',
207
+ josi: [['と', 'を']],
208
+ isVariableJosi: true,
209
+ pure: true,
210
+ fn: function (...a) {
211
+ const sys = a.pop()
212
+ const v = a.join('')
213
+ sys.__exec('表示', [v, sys])
214
+ },
215
+ return_none: true
216
+ },
217
+ '連続無改行表示': { // @引数に指定した引数を全て表示する(改行しない) // @れんぞくむかいぎょうひょうじ
218
+ type: 'func',
219
+ josi: [['と', 'を']],
220
+ isVariableJosi: true,
221
+ pure: true,
222
+ fn: function (...a) {
223
+ const sys = a.pop()
224
+ const v = a.join('')
225
+ sys.__exec('継続表示', [v, sys])
226
+ },
227
+ return_none: true
228
+ },
205
229
  '表示ログ': { type: 'const', value: '' }, // @ひょうじろぐ
206
230
  '表示ログクリア': { // @表示ログを空にする // @ひょうじろぐくりあ
207
231
  type: 'func',
@@ -281,6 +305,22 @@ const PluginSystem = {
281
305
  return a % b
282
306
  }
283
307
  },
308
+ '偶数': { // @Aが偶数なら真を返す // @ぐうすう
309
+ type: 'func',
310
+ josi: [['が']],
311
+ pure: true,
312
+ fn: function (a) {
313
+ return (a % 2 == 0)
314
+ }
315
+ },
316
+ '奇数': { // @Aが奇数なら真を返す // @きすう
317
+ type: 'func',
318
+ josi: [['が']],
319
+ pure: true,
320
+ fn: function (a) {
321
+ return (a % 2 == 1)
322
+ }
323
+ },
284
324
  '二乗': { // @Aを二乗する // @にじょう
285
325
  type: 'func',
286
326
  josi: [['の', 'を']],
@@ -676,6 +716,23 @@ const PluginSystem = {
676
716
  return parseInt(v).toString(n)
677
717
  }
678
718
  },
719
+ '二進': { // @値Vを2進数に変換 // @にしん
720
+ type: 'func',
721
+ josi: [['を', 'の', 'から']],
722
+ pure: true,
723
+ fn: function (v) {
724
+ return parseInt(v).toString(2)
725
+ }
726
+ },
727
+ '二進表示': { // @値Vを2進数に変換して表示 // @にしんひょうじ
728
+ type: 'func',
729
+ josi: [['を', 'の', 'から']],
730
+ pure: true,
731
+ fn: function (v, sys) {
732
+ const s = parseInt(v).toString(2)
733
+ sys.__exec('表示', [s, sys])
734
+ }
735
+ },
679
736
  'RGB': { // @HTML用のカラーコードを返すRGB(R,G,B)で各値は0-255 // @RGB
680
737
  type: 'func',
681
738
  josi: [['と'], ['の'], ['で']],
@@ -314,4 +314,15 @@ describe('basic', () => {
314
314
  it('もし文で「ならば」の前の空行でエラー #1079', () => {
315
315
  cmp('A=5;もし、A > 3 ならば「OK」と表示;', 'OK')
316
316
  })
317
+ it('『増やす』『減らす』文の追加 #1145', () => {
318
+ // 増やす
319
+ cmp('A=0;Aを1増やす。Aと表示;', '1')
320
+ cmp('A=0;Aを123だけ増やす。Aと表示;', '123')
321
+ // 減らす
322
+ cmp('A=10;Aを1減らす。Aと表示;', '9')
323
+ cmp('A=10;Aを5だけ減らす。Aと表示;', '5')
324
+ // 初期化しないで使うと0になる
325
+ cmp('Aを3増やす;Aと表示;', '3')
326
+ cmp('Aを3減らす;Aと表示;', '-3')
327
+ })
317
328
  })
@@ -46,12 +46,31 @@ describe('dncl (#1140)', () => {
46
46
  cmpNako('!DNCLモード\nA={{11,12,13},{21,22,23}}。C=2;AA=A[1+C,1];AAを表示', '13')
47
47
  cmpNako('!DNCLモード\nA={{11,12,13},{21,22,23}}。X=2;Y=1;AA=A[X,Y+1];AAを表示', '22')
48
48
  })
49
- it('配列の自動初期化', () => {
50
- cmpNako('!DNCLモード\nA[1]←111。AをJSONエンコードして表示する', '[111]')
51
- cmpNako('!DNCLモード\nA[1]=1,A[2]=2;AをJSONエンコードして表示する', '[1,2]')
49
+ it('配列の自動初期化(#1143)', () => {
50
+ cmpNako('!DNCLモード\nA[1]←111。A[1]を表示する', '111')
51
+ cmpNako('!DNCLモード\nA[3,3]=3;A[3,3]を表示する', '3')
52
+ cmpNako('!DNCLモード\nA[3,2,1]=30;A[3,2,1]を表示する', '30')
53
+ cmpNako('!DNCLモード\nA[1,1]=11,A[1,2]=12;A[1,2]を表示する', '12')
52
54
  })
53
55
  it('インデントを|で表現する', () => {
54
56
  cmpNako('!DNCLモード\nA=3;もしA>1ならば\n|A←A+1\nを実行する。\nAを表示する。', '4')
55
57
  })
58
+ it('表示エミュレート', () => {
59
+ cmpNako('!DNCLモード\nx←10,y←20\nxと"-"とyを表示する。', '10-20')
60
+ cmpNako('!DNCLモード\nx←10,y←20\n"("とxと","とyと")"を表示する。', '(10,20)')
61
+ cmpNako('!DNCLモード\nx←10,y←20,z←30\n"("とxと","とyと","とzと")"を表示する。', '(10,20,30)')
62
+ cmpNako('!DNCLモード\nx←10,y←20\n「<」とxと","とyと「>」を表示する。', '<10,20>')
63
+ // #1079
64
+ cmpNako('!DNCLモード\nx←10,y←20\n「<」 と x と "," と y と 「>」 を 表示する。', '<10,20>')
65
+ })
66
+ it('乱数エミュレート #1146', () => {
67
+ cmpNako('!DNCLモード\nr ← 乱数 (5,10)\nもし(rが5以上)かつ(rが10以下)ならば「OK」と表示する。', 'OK')
68
+ cmpNako('!DNCLモード\nr ← 乱数 (1,6)\nもし(rが1以上)かつ(rが6以下)ならば「OK」と表示する。', 'OK')
69
+ })
70
+ it('二進 #1146', () => {
71
+ cmpNako('!DNCLモード\nA← 二進 (9)\nAを表示する。', '1001')
72
+ cmpNako('!DNCLモード\nA← 二進 (255)\nAを表示する。', '11111111')
73
+ cmpNako('!DNCLモード\n二進で表示 (255)', '11111111')
74
+ })
56
75
  })
57
76
 
@@ -143,4 +143,7 @@ describe('lex_test', () => {
143
143
  cmp('もし、3=3ならば \n『OK』と表示;違えば;「NG」と表示;ここまで。', 'OK')
144
144
  cmp('もし、3=3ならば \n『OK』と表示;違えば;「NG」と表示;ここまで。', 'OK')
145
145
  })
146
+ it('助詞の前後に空白があるとエラーになる問題 #1079', () => {
147
+ cmp('x=1;x と 2 と "3" を連続表示', '123')
148
+ })
146
149
  })
@@ -595,4 +595,8 @@ describe('plugin_system_test', () => {
595
595
  cmp('3の二乗を表示', '9')
596
596
  cmp('2の3のべき乗を表示', '8')
597
597
  })
598
+ it('『偶数』『奇数』 #1146', () => {
599
+ cmp('もし4が偶数ならば「OK」と表示。', 'OK')
600
+ cmp('もし3が奇数ならば「OK」と表示。', 'OK')
601
+ })
598
602
  })