UNPKG

nadesiko3

Version:
510 lines (507 loc) 21.3 kB
/* eslint-disable no-undef */ import assert from 'assert' import { NakoCompiler } from '../src/nako3.mjs' describe('flow_test', async () => { // nako.logger.addListener('trace', ({ browserConsole }) => { console.log(...browserConsole) }) const cmp = async (/** @type {string} */ code, /** @type {string} */ res) => { const nako = new NakoCompiler() assert.strictEqual((await nako.runAsync(code, 'main.nako3')).log, res) } it('もし', async () => { await cmp('もし3>1ならば「あ」と表示。', 'あ') await cmp('もし3<1ならば「あ」と表示。違えば「い」と表示。', 'い') }) it('もし - AがBならば', async () => { await cmp('もし3が3ならば\n「OK」と表示。\n違えば\n「NG」と表示。\nここまで\n', 'OK') }) it('もし - ネスト', async () => { await cmp('A=5\n' + 'もしAが3以上ならば\n' + '  もしA=5ならば\n' + '    「OK」と表示。\n' + '  違えば\n' + '    「NG」と表示。\n' + '  ここまで。\n' + '違えば\n' + '  「NG」と表示。\n' + 'ここまで。\n', 'OK') await cmp('A=1\n' + 'もしAが3以上ならば\n' + '  もしA=5ならば\n' + '    「NG」と表示。\n' + '  違えば\n' + '    「NG」と表示。\n' + '  ここまで。\n' + '違えば\n' + '  「OK」と表示。\n' + 'ここまで。\n', 'OK') }) it('もし - ネスト - 違えばの一致', async () => { await cmp('A=2\n' + 'もしAが3以上ならば\n' + '  もしA=5ならば\n' + '    「NG」と表示。\n' + '  ここまで\n' + '違えば\n' + '  「OK」と表示。\n' + 'ここまで。\n' + '', 'OK') }) it('違えばもし', async () => { // 「違えば」の次がeolではないときfalse_blockが単文扱いになり「ここまで」が不要。 await cmp('もし0ならば\n' + ' 「NG」を表示\n' + '違えばもし0ならば\n' + ' 「NG」を表示\n' + '違えばもし1ならば\n' + ' 「OK」を表示\n' + '違えば\n' + ' 「NG」を表示\n' + 'ここまで\n', 'OK') await cmp('もし0ならば\n' + ' 「NG」を表示\n' + '違えば、もし0ならば\n' + ' 「NG」を表示\n' + '違えば、もし1ならば\n' + ' 「OK」を表示\n' + '違えば\n' + ' 「NG」を表示\n' + 'ここまで\n', 'OK') }) it('回', async () => { await cmp('3回「あ」と表示。', 'あ\nあ\nあ') await cmp('A=3;(A)回、Aを表示。', '3\n3\n3') }) it('回、ここから', async () => { await cmp('A=3;(A)回、ここから\nAを表示。\nここまで\n', '3\n3\n3') await cmp('A=3;(A)回ここから\nAを表示。\nここまで\n', '3\n3\n3') }) it('回、繰り返す(#924)', async () => { await cmp('A=3;(A)回、繰り返す\nAを表示。\nここまで\n', '3\n3\n3') await cmp('A=3;(A)回ここから、繰り返す\nAを表示。\nここまで\n', '3\n3\n3') }) it('回繰り返す(#924)', async () => { await cmp('A=3;(A)回繰り返す\nAを表示。\nここまで\n', '3\n3\n3') await cmp('A=3;(A)回繰り返す、ここから\nAを表示。\nここまで\n', '3\n3\n3') }) it('回 - 「それ」の自動挿入', async () => { await cmp('1と2を足す\n回\n1を表示\nここまで', '1\n1\n1') }) it('の間', async () => { await cmp('N=3;\n(N>0)の間\nNを表示\nN=N-1\nここまで', '3\n2\n1') }) it('の間、ここから', async () => { await cmp('N=3;\n(N>0)の間、ここから\nNを表示\nN=N-1\nここまで', '3\n2\n1') await cmp('N=3;\n(N>0)の間ここから\nNを表示\nN=N-1\nここまで', '3\n2\n1') }) it('の間、繰り返す #927', async () => { await cmp('N=3;\n(N>0)の間、繰り返す\nNを表示\nN=N-1\nここまで', '3\n2\n1') await cmp('N=3;\n(N>0)の間繰り返す\nNを表示\nN=N-1\nここまで', '3\n2\n1') }) it('一致する間', async () => { await cmp('●(AとBが)超一致するとは\n' + ' それはAとBが等しい\n' + 'ここまで\n' + 'a=1\n' + 'i=0\n' + 'aと1が超一致する間\n' + ' iを表示\n' + ' i=i+1\n' + ' もしiが3以上ならば\n' + ' a=0\n' + ' ここまで\n' + 'ここまで', // --- '0\n1\n2') }) it('等しい間', async () => { await cmp('a=1\n' + 'i=0\n' + 'aと1が等しい間\n' + ' iを表示\n' + ' i=i+1\n' + ' もしiが3以上ならば\n' + ' a=0\n' + ' ここまで\n' + 'ここまで', // --- '0\n1\n2') }) it('未満の間', async () => { await cmp('i=0\n' + 'iが3未満の間\n' + ' iを表示\n' + ' i=i+1\n' + 'ここまで', // --- '0\n1\n2') }) it('超えの間', async () => { await cmp('i=0' + 'iが-3超えの間\n' + ' iを表示\n' + ' i=i-1\n' + 'ここまで', // --- '0\n-1\n-2') }) it('範囲内の間', async () => { await cmp('i=0' + 'iが-3から3の範囲内の間\n' + ' iを表示\n' + ' i=i+1\n' + 'ここまで', // --- '0\n1\n2\n3') }) it('繰り返す', async () => { await cmp('Nを1から3まで繰り返す\nNを表示\nここまで', '1\n2\n3') await cmp('Nを1から3まで繰り返す\n  Nを表示\nここまで', '1\n2\n3') }) it('繰り返す2', async () => { await cmp('1から3まで繰り返す\nそれを表示\nここまで', '1\n2\n3') }) it('連続計算', async () => { await cmp('3に5を足してNに代入;Nを表示', '8') await cmp('3に5を足して2を掛けて表示', '16') }) it('もし-日本語による比較', async () => { await cmp('もし3が3と等しいならば「OK」と表示。', 'OK') await cmp('もし(3+2)が5と等しいならば「OK」と表示。', 'OK') await cmp('もし(3+2)が1以上ならば「OK」と表示。', 'OK') await cmp('もし3が5未満ならば「OK」と表示。', 'OK') await cmp('もし(3+10)が(5+10)以下ならば「OK」と表示。', 'OK') }) it('もし--一行文。違えば', async () => { await cmp('もし(3+10)が5以下ならば「ng」と表示。違えば「ok」と表示。', 'ok') }) it('もし-しなければ', async () => { await cmp('もし{ "a": 30 }に「b」がハッシュキー存在しなければ\n「ok」と表示\nここまで', 'ok') await cmp('もし1と2が等しくなければ\n「ok」と表示\nここまで', 'ok') }) it('回-break', async () => { await cmp('3回\n\'a\'と表示。もし(回数=2)ならば、抜ける;\n;ここまで;', 'a\na') await cmp('3回\n\'a\'と表示。もし、回数が2ならば、抜ける;\n;ここまで;', 'a\na') }) it('反復 - 配列', async () => { await cmp('[1,2,3]を反復\n対象を表示\nここまで\n', '1\n2\n3') }) it('反復 - オブジェクト', async () => { await cmp('{\'a\':1,\'b\':2,\'c\':3}を反復\n対象を表示\nここまで\n', '1\n2\n3') await cmp('{\'a\':1,\'b\':2,\'c\':3}を反復\n対象キーを表示\nここまで\n', 'a\nb\nc') }) it('反復 - 変数付き', async () => { await cmp('A=[1,2,3];NでAを反復\nNを表示\nここまで\n', '1\n2\n3') await cmp('Nで[1,2,3]を反復\nNを表示\nここまで\n', '1\n2\n3') }) it('反復2 - 変数付き', async () => { await cmp('A=[[3,30],[1,10],[2,20]];NでAを反復\nN[1]を表示\nここまで\n', '30\n10\n20') }) it('反復 - prototypeを無視', async () => { await cmp('f=『function F(){}; F.prototype.foo = 20; const f = new F(); f.p1 = 10; f』をJS実行。fを反復して表示', '10') }) it('ここから反復', async () => { await cmp('それは[1,2,3];ここから反復\n表示\nここまで\n', '1\n2\n3') }) it('ここから繰り返し', async () => { await cmp('ここから1から3まで繰り返し\n表示\nここまで\n', '1\n2\n3') }) it('ここから3回', async () => { await cmp('ここから3回\n表示\nここまで\n', '1\n2\n3') }) it('不等号', async () => { await cmp('もし、5≧5ならば、「あ」と表示。', 'あ') await cmp('もし、5≧3ならば、「あ」と表示。', 'あ') await cmp('もし、5≦5ならば、「あ」と表示。', 'あ') await cmp('もし、3≦5ならば、「あ」と表示。', 'あ') await cmp('もし、5=5ならば、「あ」と表示。', 'あ') await cmp('もし、3≠5ならば、「あ」と表示。', 'あ') }) it('繰り返しのネスト', async () => { await cmp('C=0;Iを0から3まで繰り返す\nJを0から3まで繰り返す\nC=C+1;ここまで;ここまで;Cを表示', '16') }) it('繰り返し:AからBまででA>Bの時', async () => { await cmp('Iを3から0まで繰り返す;Iを表示;ここまで', '3\n2\n1\n0') await cmp('Iを11から9まで繰り返す;Iを表示;ここまで', '11\n10\n9') }) it('繰り返し:AからBまででA>Bの時', async () => { await cmp('Iを3から0まで繰り返す;Iを表示;ここまで', '3\n2\n1\n0') await cmp('Iを11から9まで繰り返す;Iを表示;ここまで', '11\n10\n9') }) it('もし、と戻るの組み合わせ', async () => { await cmp('●テスト処理\n' + '  「あ」と表示\n' + '  もし、3=3ならば、戻る。\n' + '  「ここには来ない」と表示\n' + 'ここまで\n' + 'テスト処理。', 'あ') await cmp('●(Sを)テスト処理\n' + '  Sを大文字変換して表示。\n' + '  もし、そうならば、戻る。\n' + '  「ここには来ない」と表示\n' + 'ここまで\n' + '「a」をテスト処理。', 'A') }) it('もしと抜けるの組み合わせ', async () => { await cmp('Iを1から3まで繰り返す\n' + '  「あ」と表示\n' + '  もし、I=2ならば、抜ける。\n' + '  「い」と表示\n' + 'ここまで\n', 'あ\nい\nあ') await cmp('Iを1から3まで繰り返す\n' + '  2回、「あ」と表示。\n' + '  もし、I=2ならば、抜ける。\n' + '  「い」と表示\n' + 'ここまで\n', 'あ\nあ\nい\nあ\nあ') await cmp('Iを1から3まで繰り返す\n' + '  「あ」と表示\n' + '  もし、I=2ならば、「う」と表示して、抜ける。\n' + '  「い」と表示\n' + 'ここまで\n', 'あ\nい\nあ\nう') }) it('もし文のエラー(#378)', async () => { await cmp('●AAAとは\n' + '  列を1から3まで繰り返す。\n' + '   列を表示。' + '    もし、列=2ならば、「*」と表示。\n' + '  ここまで。\n' + 'ここまで\n' + 'AAA', '1\n2\n*\n3') }) it('条件分岐(#694)', async () => { await cmp('2で条件分岐\n' + ' 1ならば\n「a」と表示\nここまで\n' + ' 2ならば\n「b」と表示\nここまで\n' + ' 3ならば\n「c」と表示\nここまで\n' + ' 違えば\n「d」と表示\nここまで\n' + 'ここまで\n', 'b') await cmp('3で条件分岐\n' + ' 1ならば\n「a」と表示\nここまで\n' + ' 2ならば\n「b」と表示\nここまで\n' + ' 3ならば\n「c」と表示\nここまで\n' + ' 違えば\n「d」と表示\nここまで\n' + 'ここまで\n', 'c') await cmp('5で条件分岐\n' + ' 1ならば\n「a」と表示\nここまで\n' + ' 2ならば\n「b」と表示\nここまで\n' + ' 3ならば\n「c」と表示\nここまで\n' + ' 違えば\n「d」と表示\nここまで\n' + 'ここまで\n', 'd') }) it('条件分岐で違えばを省略', async () => { await cmp('2で条件分岐\n' + ' 1ならば\n「a」と表示\nここまで\n' + ' 2ならば\n「b」と表示\nここまで\n' + ' 3ならば\n「c」と表示\nここまで\n' + 'ここまで\n', 'b') await cmp('5で条件分岐\n' + ' 1ならば\n「a」と表示\nここまで\n' + ' 2ならば\n「b」と表示\nここまで\n' + ' 3ならば\n「c」と表示\nここまで\n' + 'ここまで\n', '') }) it('条件分岐で違えばの後にカンマがあってもエラーにならない #942', async () => { await cmp('A=0;2で条件分岐\n' + ' 1ならば、A=A+1\nここまで\n' + ' 2ならば、A=A+2\nここまで\n' + ' 3ならば、A=A+3\nここまで\n' + ' 違えば、A=A+10\nここまで\n' + 'ここまで\nAを表示', '2') }) it('N回をN|回に分ける', async () => { await cmp('S="";N=3;N回、S=S&"a";Sを表示。', 'aaa') await cmp('S="";N=3;N回\nS=S&"a";💧;Sを表示。', 'aaa') }) it('「、」と「,」の違いが分かりづらい #877', async () => { await cmp('もし,0ならば,\n' + ' 「NG」を表示\n' + '違えば,もし,0ならば\n' + ' 「NG」を表示\n' + '違えば,もし,1ならば\n' + ' 「OK」を表示\n' + '違えば,\n' + ' 「NG」を表示\n' + 'ここまで\n', 'OK') await cmp('S="";[1,2,3]を,反復,\n' + ' S=S&対象\n' + 'ここまで。Sを表示。\n', '123') await cmp('S="";[1,2,3]を,反復,ここから,\n' + ' S=S&対象\n' + 'ここまで。Sを表示。\n', '123') }) it('「。。。」=「ここまで」#925', async () => { await cmp('S="";3回;S=S&"a";;;Sを表示。', 'aaa') await cmp('A=0;3回\nA=A+1;;;Aを表示。', '3') await cmp( 'A=0;3回\n' + ' A=A+1;\n' + ' A=A+1;\n' + '。。。;Aを表示。', '6') await cmp( 'S=「」。3回\n' + ' S=S&「a」\n' + ' S=S&「b」。。。\n' + 'Sを表示。\n', 'ababab') }) it('「或いは」「あるいは」を追加#987', async () => { await cmp('A=3;もし、A=3或いはA=5あるいはA=7ならば「OK」と表示。違えば「NG」と表示。', 'OK') await cmp('A=3;もし、A=5あるいはA=3ならば「OK」と表示。違えば「NG」と表示。', 'OK') await cmp('A=空;B=3;もし(A=空)あるいは(B=空)ならば、"OK"と表示;違えば「NG」と表示。', 'OK') }) it('「増繰り返す」「減繰り返す」を追加#1140', async () => { await cmp('Nを0から4まで2ずつ増やし繰り返す\nNを表示\nここまで\n', '0\n2\n4') await cmp('A=2;Nを0から4までAずつ増やし繰り返す\nNを表示\nここまで\n', '0\n2\n4') await cmp('Nを4から0まで2ずつ減らし繰り返す\nNを表示\nここまで\n', '4\n2\n0') }) it('「増やして繰り返す」「減らして繰り返す」を追加#1140', async () => { // トークンをスタックからポップして処理するので確認 await cmp('Nを0から4まで2ずつ増やして繰り返す\nNを表示\nここまで\n', '0\n2\n4') await cmp('A=2;Nを0から4までAずつ増やして繰り返す\nNを表示\nここまで\n', '0\n2\n4') await cmp('Nを4から0まで2ずつ減らして繰り返す\nNを表示\nここまで\n', '4\n2\n0') }) it('ならばの直前に空白があるとエラー(#1141)', async () => { await cmp('A=30。もし、A>5 ならば、「OK」と表示。', 'OK') }) it('-1を含む「もし」文が動かない core #47', async () => { await cmp( 'A=0; もし、A != -1ならば\n' + '  「あ」と表示\n' + 'ここまで\n' + '', 'あ') }) it('「もし」...「でなければ」', async () => { await cmp( 'A=0; もし、A==-1でなければ\n' + '  「あ」と表示\n' + 'ここまで\n' + '', 'あ') await cmp( 'A=0; もし、INT(A)==-1でなければ\n' + '  「あ」と表示\n' + 'ここまで\n' + '', 'あ') await cmp( 'A=0; もし、Aが-1でなければ\n' + '  「あ」と表示\n' + 'ここまで\n' + '', 'あ') await cmp( 'A=0; もし、Aが-5以下でなければ\n' + '  「あ」と表示\n' + 'ここまで\n' + '', 'あ') }) it('「もし」AがBならば', async () => { await cmp( 'A=0; もし、Aが0ならば\n' + '  「あ」と表示\n' + 'ここまで\n' + '', 'あ') await cmp( 'A=0; もし、INT(A)が0ならば\n' + '  「あ」と表示\n' + 'ここまで\n' + '', 'あ') }) it('「AからBまでNずつ増やし繰り返す」文でBからAまでも実行してしまう問題 #79', async () => { await cmp( 'A="";Nを3から1まで繰り返す\n' + '  A=A&N\n' + 'ここまで\n' + 'Aを表示;', '321') // 増やすのに減らさない await cmp( 'A="";Nを3から1まで1ずつ増やし繰り返す\n' + '  A=A&N\n' + 'ここまで\n' + 'Aを表示;', '') await cmp( 'A="";Nを3から1まで1ずつ減らし繰り返す\n' + '  A=A&N\n' + 'ここまで\n' + 'Aを表示;', '321') }) it('「AからBまでNずつ減らし繰り返す」文でBからAまでも実行してしまう問題 #1753', async () => { await cmp( 'A="";Nを1から3まで繰り返す\n' + '  A=A&N\n' + 'ここまで\n' + 'Aを表示;', '123') // 増やすのに減らさない await cmp( 'A="";Nを1から3まで1ずつ増やし繰り返す\n' + '  A=A&N\n' + 'ここまで\n' + 'Aを表示;', '123') await cmp( 'A="";Nを1から3まで1ずつ減らし繰り返す\n' + '  A=A&N\n' + 'ここまで\n' + 'Aを表示;', '') }) it('「AからBまでNずつ減らし繰り返す」文でAとBが等しい時に実行されない問題 #2203', async () => { await cmp( 'A="";Nを1から1まで繰り返す\n' + '  A=A&N\n' + 'ここまで\n' + 'Aを表示;', '1') await cmp( 'A="";Nを2から2まで1ずつ増やし繰り返す\n' + '  A=A&N\n' + 'ここまで\n' + 'Aを表示;', '2') await cmp( 'A="";Nを3から3まで1ずつ減らし繰り返す\n' + '  A=A&N\n' + 'ここまで\n' + 'Aを表示;', '3') await cmp( 'A="";Nを4から4まで-1ずつ増やし繰り返す\n' + '  A=A&N\n' + 'ここまで\n' + 'Aを表示;', '4') }) it('もしの省略を実装する nadesiko3#1604', async () => { await cmp( 'A=10;Aが10と一致するならば\n' + '  「OK」と表示\n' + 'ここまで\n' + '', 'OK') await cmp( 'A=10;Aが9と一致するならば\n' + '  「NG2」と表示\n' + '違えば\n' + '  「OK2」と表示\n' + 'ここまで\n' + '', 'OK2') await cmp( 'A=10;Aが10と等しいならば、「OK3」と表示。\n' + '', 'OK3') }) it('範囲オブジェクトを指定した繰り返し #1704', async () => { await cmp('N=0;1…3を繰り返す\nN=N+それ;\nここまで;Nを表示。', '6') await cmp('N=「」;1から3の範囲を繰り返す\nN=N&それ;\nここまで;Nを表示。', '123') await cmp('N=「」;0…9を繰り返す\nN=N&それ;\nここまで;Nを表示。', '0123456789') }) it('対象がローカル変数になっていた問題 #1723', async () => { await cmp('関数 Fとは; [1]を反復; ここまで。対象=1;ここまで;対象=50;F;対象を表示。', '1') }) it('多重ループ内の反復で、回数や対象の値を復元するように配慮する #1735', async () => { // 回: 回数 await cmp('2回;TMP=回数;2回「i{回数}」を表示;「o{TMP}={回数}」を表示;ここまで。', 'i1\ni2\no1=1\ni1\ni2\no2=2') // 回: それ await cmp('2回;TMP=それ;2回「i{それ}」を表示;「o{TMP}={それ}」を表示;ここまで。', 'i1\ni2\no1=1\ni1\ni2\no2=2') // 反復: 対象 await cmp('[1,2]を反復;TMP=対象;[4]を反復,「i{対象}」を表示;「o{TMP}={対象}」を表示;ここまで;', 'i4\no1=1\ni4\no2=2') // 反復: 対象キー await cmp('[1,2]を反復;TMP=対象キー;[4]を反復,「i{対象キー}」を表示;「o{TMP}={対象キー}」を表示;ここまで;', 'i0\no0=0\ni0\no1=1') // 反復: それ await cmp('[1,2]を反復;TMP=それ;[4]を反復,「i{それ}」を表示;「o{TMP}={それ}」を表示;ここまで;', 'i4\no1=1\ni4\no2=2') }) })