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.
- package/package.json +2 -2
- package/release/_hash.txt +24 -24
- package/release/_script-tags.txt +13 -13
- 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/stats.json +1 -1
- package/release/version.js +1 -1
- package/release/wnako3.js +1 -1
- package/release/wnako3webworker.js +1 -1
- package/release/yoyakugo.json +2 -0
- package/src/nako_from_dncl.js +62 -62
- package/src/nako_gen.js +28 -4
- package/src/nako_lex_rules.js +2 -2
- package/src/nako_parser3.js +96 -44
- package/src/nako_reserved_words.js +2 -0
- package/src/nako_version.js +2 -2
- package/src/plugin_math.js +8 -0
- package/src/plugin_system.js +57 -0
- package/test/common/basic_test.js +11 -0
- package/test/common/dncl_test.js +22 -3
- package/test/common/lex_test.js +3 -0
- package/test/common/plugin_system_test.js +4 -0
package/release/yoyakugo.json
CHANGED
package/src/nako_from_dncl.js
CHANGED
|
@@ -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 +=
|
|
93
|
-
|
|
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
|
-
|
|
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
|
-
|
|
860
|
-
|
|
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 +=
|
|
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
|
-
|
|
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
|
package/src/nako_lex_rules.js
CHANGED
|
@@ -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) }
|
package/src/nako_parser3.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
1032
|
+
if (this.check('ここから')) { this.get() }
|
|
952
1033
|
// 代入
|
|
953
|
-
if (this.check('代入')) {
|
|
954
|
-
|
|
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))
|
package/src/nako_version.js
CHANGED
package/src/plugin_math.js
CHANGED
|
@@ -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: [['の']],
|
package/src/plugin_system.js
CHANGED
|
@@ -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
|
})
|
package/test/common/dncl_test.js
CHANGED
|
@@ -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
|
|
51
|
-
cmpNako('!DNCLモード\nA[
|
|
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
|
|
package/test/common/lex_test.js
CHANGED